test: reproduce native import retention without managed caller
This commit is contained in:
@@ -130,13 +130,19 @@ static void load_bridge(const char *path){
|
||||
#undef LOAD
|
||||
image_guard();
|
||||
}
|
||||
struct copy_result {const char *stage;int32_t status;int present,associated;};
|
||||
struct copy_result {
|
||||
const char *stage,*action;int32_t status;int present,associated;
|
||||
unsigned owners_before,owners_after;int native_owner_before,native_owner_after;
|
||||
};
|
||||
struct operation_state {
|
||||
SecCertificateRef cert,copied;SecIdentityRef identity;SecKeyRef modern,public_key,legacy;
|
||||
CFDataRef external;SecKeychainRef keychain,keychain_identity,outer;CFErrorRef error;
|
||||
char path[PATH_MAX],backing[PATH_MAX];
|
||||
unsigned logical_owners;int initial_owner,cert_tracked,copied_tracked,identity_tracked;
|
||||
int failed,path_verified,deleted,delete_during_identity_untrack,fallback_cleanup;
|
||||
int failed,path_verified,deleted,fallback_cleanup,import_state_released,leaf_checked,leaf_matches;
|
||||
unsigned import_owners_before,import_owners_after;
|
||||
const char *delete_stage;
|
||||
int delete_copy_live,delete_cert_live,delete_copied_live,delete_identity_live,delete_legacy_live;
|
||||
int32_t cert_return,cert_status,modern_return,create_status,lock_status,external_return,key_return,key_status,move_return,move_status,copy_cert_status,delete_status,path_status;
|
||||
CFIndex modern_error,external_error;int modern_error_present,external_error_present;unsigned copy_count;
|
||||
struct copy_result copies[16];
|
||||
@@ -146,18 +152,19 @@ static int private_path(struct operation_state *s,SecKeychainRef keychain){
|
||||
char actual[PATH_MAX];memset(actual,0,sizeof(actual));int32_t status=keychain_path(keychain,actual);
|
||||
return status==0 && (!strcmp(actual,s->path)||!strcmp(actual,s->backing));
|
||||
}
|
||||
static void delete_owner(struct operation_state *s,const char *stage){
|
||||
static void delete_owner(struct operation_state *s,const char *stage,int copy_live){
|
||||
if(!s->keychain)return;
|
||||
if(s->deleted){s->failed=1;return;}
|
||||
s->path_verified=private_path(s,s->keychain);
|
||||
if(s->path_verified){s->delete_status=delete_chain(s->keychain);s->deleted=1;}
|
||||
if(!s->path_verified||s->delete_status)s->failed=1;
|
||||
s->delete_during_identity_untrack=!strcmp(stage,"release-identity")&&s->identity!=NULL&&s->copied==NULL;
|
||||
s->delete_stage=stage;s->delete_copy_live=copy_live;s->delete_cert_live=s->cert!=NULL;
|
||||
s->delete_copied_live=s->copied!=NULL;s->delete_identity_live=s->identity!=NULL;s->delete_legacy_live=s->legacy!=NULL;
|
||||
DROP(s->keychain);released_refs++;
|
||||
}
|
||||
static void relinquish(struct operation_state *s,const char *stage){
|
||||
static void relinquish(struct operation_state *s,const char *stage,int copy_live){
|
||||
if(!s->logical_owners){s->failed=1;return;}
|
||||
if(--s->logical_owners==0)delete_owner(s,stage);
|
||||
if(--s->logical_owners==0)delete_owner(s,stage,copy_live);
|
||||
}
|
||||
static SecKeychainRef copied_chain(struct operation_state *s,CFTypeRef item,const char *stage,int *associated){
|
||||
*associated=0;if(!item)return NULL;
|
||||
@@ -165,20 +172,29 @@ static SecKeychainRef copied_chain(struct operation_state *s,CFTypeRef item,cons
|
||||
SecKeychainRef result=NULL;int32_t status=copy_chain(item,&result);owned(result);
|
||||
int type_ok=!result||CFGetTypeID(result)==SecKeychainGetTypeID();
|
||||
int belongs=result&&type_ok&&s->keychain_identity==result&&private_path(s,result);
|
||||
if(s->copy_count<16)s->copies[s->copy_count++]=(struct copy_result){stage,status,result!=NULL,belongs};else s->failed=1;
|
||||
if(s->copy_count<16)s->copies[s->copy_count++]=(struct copy_result){stage,"lookup",status,result!=NULL,belongs,
|
||||
s->logical_owners,s->logical_owners,s->keychain!=NULL,s->keychain!=NULL};else s->failed=1;
|
||||
if(status || !type_ok || (result&&!belongs))s->failed=1;
|
||||
*associated=status==0&&belongs;return result;
|
||||
}
|
||||
static void record_copy_action(struct operation_state *s,unsigned index,const char *action){
|
||||
if(s->copy_count==index+1){struct copy_result *copy=&s->copies[index];copy->action=action;
|
||||
copy->owners_after=s->logical_owners;copy->native_owner_after=s->keychain!=NULL;}
|
||||
}
|
||||
static void track(struct operation_state *s,CFTypeRef item,const char *stage,int *tracked){
|
||||
int associated=0;SecKeychainRef copy=copied_chain(s,item,stage,&associated);
|
||||
unsigned index=s->copy_count;int associated=0;SecKeychainRef copy=copied_chain(s,item,stage,&associated);
|
||||
// Installed TrackItem does nothing for a null copy; never invent an owner.
|
||||
if(associated){if(*tracked||!s->keychain)s->failed=1;else{s->logical_owners++;*tracked=1;}}
|
||||
DROP(copy);
|
||||
record_copy_action(s,index,"track");DROP(copy);
|
||||
}
|
||||
static void untrack(struct operation_state *s,CFTypeRef item,const char *stage,int *tracked){
|
||||
if(!item)return;
|
||||
int associated=0;SecKeychainRef copy=copied_chain(s,item,stage,&associated);
|
||||
if(*tracked){if(associated){*tracked=0;relinquish(s,stage);}else s->failed=1;}
|
||||
else if(associated)s->failed=1;
|
||||
unsigned index=s->copy_count;int associated=0;SecKeychainRef copy=copied_chain(s,item,stage,&associated);
|
||||
if(*tracked){if(associated){*tracked=0;relinquish(s,stage,copy!=NULL);}else s->failed=1;}
|
||||
// A still-registered private keychain must never consume an untracked owner.
|
||||
// After deletion the installed managed registry has no entry to release.
|
||||
else if(associated&&s->keychain)s->failed=1;
|
||||
record_copy_action(s,index,"untrack");
|
||||
// Final logical-owner release above precedes this copy's CFRelease.
|
||||
DROP(copy);
|
||||
}
|
||||
@@ -222,23 +238,25 @@ static void import_operation(unsigned iteration,const unsigned char *der,size_t
|
||||
if(s.failed)goto cleanup;
|
||||
s.move_return=move_key(s.cert,s.keychain,s.legacy,&s.identity,&s.move_status);owned(s.identity);
|
||||
track(&s,s.cert,"move-cert-track",&s.cert_tracked);track(&s,s.identity,"move-identity-track",&s.identity_tracked);DROP(s.outer);
|
||||
if(s.move_return!=1||s.move_status||!s.identity||CFGetTypeID(s.identity)!=SecIdentityGetTypeID()||!s.cert_tracked||!s.identity_tracked||s.failed){s.failed=1;goto cleanup;}
|
||||
if(s.move_return!=1||s.move_status||!s.identity||CFGetTypeID(s.identity)!=SecIdentityGetTypeID()||s.failed){s.failed=1;goto cleanup;}
|
||||
s.copy_cert_status=copy_cert(s.identity,&s.copied);owned(s.copied);track(&s,s.copied,"identity-cert-track",&s.copied_tracked);
|
||||
if(s.copy_cert_status||!s.copied||CFGetTypeID(s.copied)!=SecCertificateGetTypeID()||!s.copied_tracked||s.failed){s.failed=1;goto cleanup;}
|
||||
if((iteration==1||iteration==REPETITIONS)&&!leaf_equal(s.copied,der,der_length)){s.failed=1;goto cleanup;}
|
||||
if(s.copy_cert_status||!s.copied||CFGetTypeID(s.copied)!=SecCertificateGetTypeID()||s.failed){s.failed=1;goto cleanup;}
|
||||
if(iteration==1||iteration==REPETITIONS){s.leaf_checked=1;s.leaf_matches=leaf_equal(s.copied,der,der_length);
|
||||
if(!s.leaf_matches){s.failed=1;goto cleanup;}}
|
||||
cleanup:
|
||||
wipe(password,sizeof(password));DROP(s.error);DROP(s.external);DROP(s.modern);DROP(s.public_key);DROP(s.outer);
|
||||
untrack(&s,s.cert,"release-original-cert",&s.cert_tracked);DROP(s.cert);
|
||||
if(s.initial_owner){s.initial_owner=0;relinquish(&s,"release-import-state");}
|
||||
if(s.initial_owner){s.initial_owner=0;s.import_state_released=1;s.import_owners_before=s.logical_owners;
|
||||
relinquish(&s,"release-import-state",0);s.import_owners_after=s.logical_owners;}
|
||||
untrack(&s,s.copied,"release-copied-cert",&s.copied_tracked);DROP(s.copied);
|
||||
untrack(&s,s.identity,"release-identity",&s.identity_tracked);DROP(s.identity);
|
||||
DROP(s.legacy); // Explicit lifetime; managed helper does not scope this local with using.
|
||||
if(s.keychain){s.failed=1;s.fallback_cleanup=1;delete_owner(&s,"failure-fallback-after-items");}
|
||||
if(s.keychain){s.failed=1;s.fallback_cleanup=1;delete_owner(&s,"failure-fallback-after-items",0);}
|
||||
unsigned made=all_created-before_created,released=all_released-before_released;
|
||||
if(made!=released||s.logical_owners||s.cert_tracked||s.copied_tracked||s.identity_tracked)s.failed=1;
|
||||
if(!s.failed&&(s.copy_count!=9||!s.delete_during_identity_untrack||!s.deleted))s.failed=1;
|
||||
fprintf(stdout,"{\"kind\":\"operation\",\"iteration\":%u,\"certReturn\":%d,\"certStatus\":%d,\"modernReturn\":%d,\"modernErrorCode\":%ld,\"modernErrorPresent\":%s,\"createStatus\":%d,\"pathStatus\":%d,\"neverLockStatus\":%d,\"externalReturn\":%d,\"externalErrorCode\":%ld,\"externalErrorPresent\":%s,\"legacyReturn\":%d,\"legacyStatus\":%d,\"moveReturn\":%d,\"moveStatus\":%d,\"copyCertStatus\":%d,\"deleteStatus\":%d,\"privatePathVerified\":%s,\"deleteDuringFinalIdentityUntrack\":%s,\"fallbackCleanup\":%s,\"logicalOwnersRemaining\":%u,\"ownedOutputs\":%u,\"releasedOutputs\":%u,\"failed\":%s,\"copies\":[",iteration,s.cert_return,s.cert_status,s.modern_return,(long)s.modern_error,s.modern_error_present?"true":"false",s.create_status,s.path_status,s.lock_status,s.external_return,(long)s.external_error,s.external_error_present?"true":"false",s.key_return,s.key_status,s.move_return,s.move_status,s.copy_cert_status,s.delete_status,s.path_verified?"true":"false",s.delete_during_identity_untrack?"true":"false",s.fallback_cleanup?"true":"false",s.logical_owners,made,released,s.failed?"true":"false");
|
||||
for(unsigned i=0;i<s.copy_count;i++){struct copy_result c=s.copies[i];fprintf(stdout,"%s{\"stage\":\"%s\",\"status\":%d,\"returnedRef\":%s,\"privateAssociation\":%s}",i?",":"",c.stage,c.status,c.present?"true":"false",c.associated?"true":"false");}
|
||||
if(!s.failed&&(s.copy_count!=9||!s.import_state_released||!s.deleted))s.failed=1;
|
||||
fprintf(stdout,"{\"kind\":\"operation\",\"iteration\":%u,\"certReturn\":%d,\"certStatus\":%d,\"modernReturn\":%d,\"modernErrorCode\":%ld,\"modernErrorPresent\":%s,\"createStatus\":%d,\"pathStatus\":%d,\"neverLockStatus\":%d,\"externalReturn\":%d,\"externalErrorCode\":%ld,\"externalErrorPresent\":%s,\"legacyReturn\":%d,\"legacyStatus\":%d,\"moveReturn\":%d,\"moveStatus\":%d,\"copyCertStatus\":%d,\"deleteStatus\":%d,\"privatePathVerified\":%s,\"deleteStage\":\"%s\",\"deleteLiveReferences\":{\"copy\":%s,\"originalCertificate\":%s,\"copiedCertificate\":%s,\"identity\":%s,\"legacyKey\":%s},\"importStateReleased\":%s,\"importOwnersBefore\":%u,\"importOwnersAfter\":%u,\"leafIdentityChecked\":%s,\"leafIdentityMatches\":%s,\"fallbackCleanup\":%s,\"logicalOwnersRemaining\":%u,\"ownedOutputs\":%u,\"releasedOutputs\":%u,\"failed\":%s,\"copies\":[",iteration,s.cert_return,s.cert_status,s.modern_return,(long)s.modern_error,s.modern_error_present?"true":"false",s.create_status,s.path_status,s.lock_status,s.external_return,(long)s.external_error,s.external_error_present?"true":"false",s.key_return,s.key_status,s.move_return,s.move_status,s.copy_cert_status,s.delete_status,s.path_verified?"true":"false",s.delete_stage?s.delete_stage:"not-attempted",s.delete_copy_live?"true":"false",s.delete_cert_live?"true":"false",s.delete_copied_live?"true":"false",s.delete_identity_live?"true":"false",s.delete_legacy_live?"true":"false",s.import_state_released?"true":"false",s.import_owners_before,s.import_owners_after,s.leaf_checked?"true":"false",s.leaf_matches?"true":"false",s.fallback_cleanup?"true":"false",s.logical_owners,made,released,s.failed?"true":"false");
|
||||
for(unsigned i=0;i<s.copy_count;i++){struct copy_result c=s.copies[i];fprintf(stdout,"%s{\"stage\":\"%s\",\"action\":\"%s\",\"status\":%d,\"returnedRef\":%s,\"privateAssociation\":%s,\"logicalOwnersBefore\":%u,\"logicalOwnersAfter\":%u,\"nativeOwnerBefore\":%s,\"nativeOwnerAfter\":%s}",i?",":"",c.stage,c.action,c.status,c.present?"true":"false",c.associated?"true":"false",c.owners_before,c.owners_after,c.native_owner_before?"true":"false",c.native_owner_after?"true":"false");}
|
||||
fprintf(stdout,"]}\n");fflush(stdout);if(s.failed)die("Native bridge import operation failed after ownership cleanup");
|
||||
}
|
||||
static unsigned char *read_fixture(const char *name,size_t *length){
|
||||
|
||||
Reference in New Issue
Block a user