Post

Replies

Boosts

Views

Activity

Reply to Create an SecIdentityRef from a certificate and private key
Did I say I won't bother you xD, one question when I restart my app are the cert and private key still there ? Because just after identity creation I can call hasIdentity: + (BOOL)hasIdentity:(NSDictionary *)aliases { NSString *certAlias = aliases[@"certAlias"]; if (!certAlias) { return NO; } OSStatus status = -1; NSDictionary *identityQuery = @{ (__bridge id)kSecClass : (__bridge id)kSecClassIdentity, (__bridge id)kSecAttrLabel : certAlias }; status = SecItemCopyMatching((__bridge CFDictionaryRef)identityQuery, (CFTypeRef *)NULL); // NSDictionary *certQuery = @{ // (__bridge id)kSecClass : (__bridge id)kSecClassCertificate, // (__bridge id)kSecAttrLabel : certAlias // }; // status = SecItemCopyMatching((__bridge CFDictionaryRef)certQuery, (CFTypeRef *)NULL); return status == errSecSuccess; } return true but once I restart my app it's false. So I know that identity is not stored but is a kind of runtime creation but even when I try with certAlias it returns item not found. So is there a magic parameter to pass to persist them ? When Adding key/cert I added kSecAttrAccessibleAfterFirstUnlock but don't seem to work.
Topic: Privacy & Security SubTopic: General Tags:
Mar ’25
Reply to Create an SecIdentityRef from a certificate and private key
NSDictionary *identityQuery = @{ (__bridge id)kSecClass : (__bridge id)kSecClassIdentity, (__bridge id)kSecReturnRef : @YES, }; status = SecItemCopyMatching((__bridge CFDictionaryRef)identityQuery, (CFTypeRef *)&identity); I get status = -25300 (errSecItemNotFound). I have also added attributes (__bridge id)kSecAttrIsPermanent : @"YES", when adding key but does not help.
Topic: Privacy & Security SubTopic: General Tags:
Feb ’25
Reply to Create an SecIdentityRef from a certificate and private key
Cert Attributes: { accc = "<SecAccessControlRef: dk>"; agrp = "D27Q6535KW.com.lotalogic.testandroidtvremoteapp"; cdat = "2025-02-01 16:18:58 +0000"; cenc = 3; ctyp = 3; issr = {length = 89, bytes = 0x310b3009 06035504 06130246 52310c30 ... 69636520 4e616d65 }; labl = cert; mdat = "2025-02-01 16:18:58 +0000"; musr = {length = 0, bytes = 0x}; pdmn = dk; pkhh = {length = 20, bytes = 0x312ede000df0366b3b5fb559a48177ca23215516}; sha1 = {length = 20, bytes = 0x0d8661f2c1cf641dade7d7ed53475beed6c1e654}; skid = {length = 20, bytes = 0x312ede000df0366b3b5fb559a48177ca23215516}; slnr = {length = 20, bytes = 0x5c2576d44745619b3cab62ebcc402d19741150d4}; subj = {length = 89, bytes = 0x310b3009 06035504 06130246 52310c30 ... 69636520 4e616d65 }; sync = 0; tomb = 0; } Key Attributes: { accc = "<SecAccessControlRef: ak>"; agrp = "D27Q6535KW.com.lotalogic.testandroidtvremoteapp"; atag = ""; bsiz = 0; cdat = "2025-02-01 16:19:01 +0000"; crtr = 0; edat = "2001-01-01 00:00:00 +0000"; esiz = 0; kcls = 1; klbl = {length = 20, bytes = 0x312ede000df0366b3b5fb559a48177ca23215516}; labl = cert; mdat = "2025-02-01 16:19:01 +0000"; musr = {length = 0, bytes = 0x}; pdmn = ak; sdat = "2001-01-01 00:00:00 +0000"; sha1 = {length = 20, bytes = 0x66164ac9fd9272542996070684f5346e2e5b86da}; sync = 0; tomb = 0; type = 42; } So this time klbl and pkhh are identical, so what is the next step of this escape game ? I am creating cert (SecCertificateCreateWithData), adding it to keystore, retrieving attributes to get pkhh creating private key (SecKeyCreateWithData), adding it to keystore with the kSecAttrApplicationLabel filled with the cert's pkhh... CODE
Topic: Privacy & Security SubTopic: General Tags:
Feb ’25
Reply to Create an SecIdentityRef from a certificate and private key
Hum actually if we pass a Label to SecItemDelete it fails ... no error is allowed. So finally I am dumping attributes: Key Attributes: { accc = "<SecAccessControlRef: ak>"; agrp = "D27Q6535KW.com.lotalogic.testandroidtvremoteapp"; atag = ""; bsiz = 0; cdat = "2025-02-01 11:09:49 +0000"; crtr = 0; edat = "2001-01-01 00:00:00 +0000"; esiz = 0; kcls = 1; klbl = {length = 0, bytes = 0x}; labl = cert; mdat = "2025-02-01 11:09:49 +0000"; musr = {length = 0, bytes = 0x}; pdmn = ak; sdat = "2001-01-01 00:00:00 +0000"; sha1 = {length = 20, bytes = 0xdc6b0c25a45f014b2d6da9f668e0d4cd325f3b35}; sync = 0; tomb = 0; type = 42; } Cert Attributes: { accc = "<SecAccessControlRef: dk>"; agrp = "D27Q6535KW.com.lotalogic.testandroidtvremoteapp"; cdat = "2025-02-01 11:10:04 +0000"; cenc = 3; ctyp = 3; issr = {length = 89, bytes = 0x310b3009 06035504 06130246 52310c30 ... 69636520 4e616d65 }; labl = cert; mdat = "2025-02-01 11:10:04 +0000"; musr = {length = 0, bytes = 0x}; pdmn = dk; pkhh = {length = 20, bytes = 0x312ede000df0366b3b5fb559a48177ca23215516}; sha1 = {length = 20, bytes = 0xaf3c77416df73b8d8ba4449c797f16ef8f5ac59c}; skid = {length = 20, bytes = 0x312ede000df0366b3b5fb559a48177ca23215516}; slnr = {length = 20, bytes = 0x5c2576d44745619b3cab62ebcc402d19741150d4}; subj = {length = 89, bytes = 0x310b3009 06035504 06130246 52310c30 ... 69636520 4e616d65 }; sync = 0; tomb = 0; but still no identity: NSDictionary *identityQuery = @{ (__bridge id)kSecClass: (__bridge id)kSecClassIdentity, (__bridge id)kSecReturnRef: @YES, }; status = SecItemCopyMatching((__bridge CFDictionaryRef)identityQuery, (CFTypeRef *)&identity); I think I will reverse SecIdentityCreate it will be easier.
Topic: Privacy & Security SubTopic: General Tags:
Feb ’25
Reply to Create an SecIdentityRef from a certificate and private key
So now my code is: privateKey:(NSString *)pemKey settings:(NSDictionary *)settings { RCTLogWarn(@"createIdentity: Starting identity creation"); SecIdentityRef identity = NULL; // Strip PEM headers and convert to data NSString *cleanedCert = [self stripPEMHeader:pemCert prefix:@"CERTIFICATE"]; NSString *cleanedPrivateKey = [self stripPEMHeader:pemKey prefix:@"PRIVATE KEY"]; NSString *certAlias = settings[@"certAlias"]; NSString *keyAlias= settings[@"keyAlias"]; NSData *certData = [[NSData alloc] initWithBase64EncodedString:cleanedCert options:NSDataBase64DecodingIgnoreUnknownCharacters]; NSData *pkcs8KeyData = [[NSData alloc] initWithBase64EncodedString:cleanedPrivateKey options:NSDataBase64DecodingIgnoreUnknownCharacters]; if (!certData || !pkcs8KeyData) { RCTLogWarn(@"createIdentity: Failed to create data from base64"); return NULL; } // Creates a certificate object from its DER representation SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData); if (!cert) { RCTLogWarn(@"createIdentity: Failed to create certificate from data"); return NULL; } // Extract RSA key from PKCS#8 - TODO use a ASN1 decoder to detect the key format ... // For my own use I know it's a pem but I prefer not to trust a file extension and // it's better to check from asn1 data NSData *rsaKeyData = [self extractRSAKeyFromPKCS8:pkcs8KeyData]; if (!rsaKeyData) { RCTLogWarn(@"Failed to extract RSA key from PKCS#8"); CFRelease(cert); return NULL; } NSDictionary *privateKeyAttributes = @{ //(__bridge id)kSecClass: (__bridge id)kSecClassKey, (__bridge id)kSecAttrKeyType: (__bridge id)kSecAttrKeyTypeRSA, (__bridge id)kSecAttrKeyClass: (__bridge id)kSecAttrKeyClassPrivate, //(__bridge id)kSecAttrLabel: kKeychainPrivateKeyLabel, //(__bridge id)kSecAttrApplicationTag: [kKeychainApplicationTag dataUsingEncoding:NSUTF8StringEncoding], }; CFErrorRef error = NULL; SecKeyRef privateKey = SecKeyCreateWithData((__bridge CFDataRef)rsaKeyData, (__bridge CFDictionaryRef)privateKeyAttributes, &error); if (!privateKey) { RCTLogWarn(@"createIdentity: Failed to create private key: %@", error); CFRelease(cert); if (error) CFRelease(error); return NULL; } NSDictionary *deleteKeyQuery = @{ (__bridge id)kSecClass: (__bridge id)kSecClassKey, (__bridge id)kSecAttrLabel: keyAlias }; SecItemDelete((__bridge CFDictionaryRef)deleteKeyQuery); // Import certificate in keychain NSDictionary *deleteCertQuery = @{ (__bridge id)kSecClass: (__bridge id)kSecClassCertificate, (__bridge id)kSecAttrLabel: certAlias }; SecItemDelete((__bridge CFDictionaryRef)deleteCertQuery); NSDictionary *certAttributes = @{ (__bridge id)kSecClass: (__bridge id)kSecClassCertificate, (__bridge id)kSecValueRef: (__bridge id)cert, (__bridge id)kSecAttrLabel: certAlias }; OSStatus status = SecItemAdd((__bridge CFDictionaryRef)certAttributes, NULL); if (status != errSecSuccess && status != errSecDuplicateItem) { RCTLogWarn(@"createIdentity: Failed to store certificate, status: %d", (int)status); CFRelease(cert); CFRelease(privateKey); return NULL; } // Add the private key to keychain NSDictionary *keyAttributes = @{ (__bridge id)kSecClass: (__bridge id)kSecClassKey, (__bridge id)kSecAttrKeyType: (__bridge id)kSecAttrKeyTypeRSA, (__bridge id)kSecAttrKeyClass: (__bridge id)kSecAttrKeyClassPrivate, //(__bridge id)kSecAttrAccessible: (__bridge id)kSecAttrAccessibleAfterFirstUnlock, (__bridge id)kSecAttrLabel: keyAlias, //(__bridge id)kSecAttrApplicationTag: [kKeychainApplicationTag dataUsingEncoding:NSUTF8StringEncoding], }; status = SecItemAdd((__bridge CFDictionaryRef)keyAttributes, NULL); if (status != errSecSuccess && status != errSecDuplicateItem) { RCTLogWarn(@"createIdentity: Failed to store private key, status: %d", (int)status); CFRelease(cert); CFRelease(privateKey); return NULL; } //------ PRIVATE API: need to find the proper way of doing it ------- if (YES) { identity = SecIdentityCreate(NULL, cert, privateKey); } else { NSDictionary *identityQuery = @{ (__bridge id)kSecClass: (__bridge id)kSecClassIdentity, (__bridge id)kSecReturnRef: @YES, (__bridge id)kSecMatchItemList:@[(__bridge id)cert], (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne, //(__bridge id)kSecAttrLabel: @"My Certificate", //(__bridge id)kSecUseDataProtectionKeychain: @YES }; status = SecItemCopyMatching((__bridge CFDictionaryRef)identityQuery, (CFTypeRef *)&identity); if (status != errSecSuccess || !identity) { RCTLogWarn(@"createIdentity: Failed to find identity, status: %d", (int)status); } else { RCTLogWarn(@"createIdentity: Successfully found identity"); } } // Clean up CFRelease(cert); CFRelease(privateKey); return identity; } One last effort and it should be ok ...
Topic: Privacy & Security SubTopic: General Tags:
Jan ’25
Reply to Create an SecIdentityRef from a certificate and private key
it's so obvious that even on SO they still are looking for how to do it: https://stackoverflow.com/questions/45997841/how-to-get-a-secidentityref-from-a-seccertificateref-and-a-seckeyref https://stackoverflow.com/questions/53897612/how-to-get-secidentity-after-seccertificatecreatewithdata-and-secitemadd Answer is either to use SecIdentityCreate or use some SecItemExport/SecItemImport ...
Topic: Privacy & Security SubTopic: General Tags:
Jan ’25
Reply to Create an SecIdentityRef from a certificate and private key
Ok so I really don"t know what I am doing wrong... // Function declaration from private API SecIdentityRef SecIdentityCreate(CFAllocatorRef allocator, SecCertificateRef certificate, SecKeyRef privateKey); static NSString * const kKeychainPrivateKeyLabel = @"My PrivateKey"; static NSString * const kKeychainCertificateLabel = @"My Certificate"; - (SecIdentityRef)createIdentityWithCert:(NSString *)pemCert privateKey:(NSString *)pemKey { RCTLogWarn(@"createIdentity: Starting identity creation"); // Strip PEM headers and convert to data NSString *cleanedCert = [self stripPEMHeader:pemCert prefix:@"CERTIFICATE"]; NSString *cleanedKey = [self stripPEMHeader:pemKey prefix:@"PRIVATE KEY"]; NSData *certData = [[NSData alloc] initWithBase64EncodedString:cleanedCert options:NSDataBase64DecodingIgnoreUnknownCharacters]; NSData *keyData = [[NSData alloc] initWithBase64EncodedString:cleanedKey options:NSDataBase64DecodingIgnoreUnknownCharacters]; if (!certData || !keyData) { RCTLogWarn(@"createIdentity: Failed to create data from base64"); return NULL; } // Creates a certificate object from its DER representation SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData); if (!cert) { RCTLogWarn(@"createIdentity: Failed to create certificate from data"); return NULL; } // Creates a private key object from its DER representation NSDictionary *privateKeyAttributes = @{ //(__bridge id)kSecClass: (__bridge id)kSecClassKey, (__bridge id)kSecAttrKeyType: (__bridge id)kSecAttrKeyTypeRSA, (__bridge id)kSecAttrKeyClass: (__bridge id)kSecAttrKeyClassPrivate, //(__bridge id)kSecAttrLabel: kKeychainPrivateKeyLabel, //(__bridge id)kSecAttrApplicationTag: [kKeychainApplicationTag dataUsingEncoding:NSUTF8StringEncoding], }; CFErrorRef error = NULL; SecKeyRef privateKey = SecKeyCreateWithData((__bridge CFDataRef)keyData, (__bridge CFDictionaryRef)privateKeyAttributes, &error); if (!privateKey) { RCTLogWarn(@"createIdentity: Failed to create private key: %@", error); CFRelease(cert); if (error) CFRelease(error); return NULL; } I can see inside the debugger that cleanedKey contains the same string without the header as the attached file client-selfsigned.key.txt but privateKey is NULL client-selfsigned.key.txt client-selfsigned.crt.txt
Topic: Privacy & Security SubTopic: General Tags:
Jan ’25
Reply to Create an SecIdentityRef from a certificate and private key
Thanks, personally I would prefer a GitHub with some examples instead of reading all the documentation. But I have followed what is described ie: // Creates a certificate object from a DER representation of a certificate SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData); // Import certificate in keychain NSDictionary *certAttributes = @{ (__bridge id)kSecClass: (__bridge id)kSecClassCertificate, (__bridge id)kSecValueRef: (__bridge id)cert, (__bridge id)kSecAttrLabel: kKeychainCertificateLabel }; OSStatus status = SecItemAdd((__bridge CFDictionaryRef)certAttributes, NULL); NSDictionary *privateKeyAttributes = @{ (__bridge id)kSecClass: (__bridge id)kSecClassKey, (__bridge id)kSecAttrKeyType: (__bridge id)kSecAttrKeyTypeRSA, (__bridge id)kSecAttrKeyClass: (__bridge id)kSecAttrKeyClassPrivate, (__bridge id)kSecAttrKeySizeInBits: @(keySize), (__bridge id)kSecAttrLabel: @"My PrivateKey", //(__bridge id)kSecAttrApplicationTag: [kKeychainApplicationTag dataUsingEncoding:NSUTF8StringEncoding], }; // Creating private key CFErrorRef error = NULL; SecKeyRef privateKey = SecKeyCreateWithData((__bridge CFDataRef)keyData, (__bridge CFDictionaryRef)privateKeyAttributes, &error); but SecKeyCreateWithData return NULL, am I supposed to use this API or should I directly use SecItemAdd for for the private key ? Thanks
Topic: Privacy & Security SubTopic: General Tags:
Jan ’25