@@ -597,11 +597,13 @@ - (SecIdentityRef)createIdentityWithCert:(NSString *)pemCert
597597 settings : (NSDictionary *)settings {
598598 RCTLogWarn (@" createIdentity: Starting identity creation" );
599599
600+ SecIdentityRef identity = NULL ;
601+
600602 // Strip PEM headers and convert to data
601603 NSString *cleanedCert = [self stripPEMHeader: pemCert prefix: @" CERTIFICATE" ];
602604 NSString *cleanedPrivateKey = [self stripPEMHeader: pemKey prefix: @" PRIVATE KEY" ];
603605 NSString *certAlias = settings[@" certAlias" ];
604- NSString *keyAlias= settings[ @" keyAlias " ];
606+ NSString *keyAlias = certAlias; // On iOS we must use the same label to create an identity
605607
606608 NSData *certData = [[NSData alloc ] initWithBase64EncodedString: cleanedCert
607609 options: NSDataBase64DecodingIgnoreUnknownCharacters ];
@@ -620,18 +622,17 @@ - (SecIdentityRef)createIdentityWithCert:(NSString *)pemCert
620622 return NULL ;
621623 }
622624
623- // Extract RSA key from PKCS#8 - TODO use a ASN1 decoder to detect the key format ...
624- // For my own use I know it's a pem but I prefer not to trust a file extension and
625- // it's better to check from asn1 data
625+ // Extract RSA key from PKCS#8
626+ // For my own use I know it's a pem but it would be better to not trust a file extension and
627+ // TODO use a ASN1 decoder to detect the key format ...
626628 NSData *rsaKeyData = [self extractRSAKeyFromPKCS8: pkcs8KeyData];
627629 if (!rsaKeyData) {
628630 RCTLogWarn (@" Failed to extract RSA key from PKCS#8" );
629631 CFRelease (cert);
630632 return NULL ;
631633 }
632-
634+
633635 NSDictionary *privateKeyAttributes = @{
634- // (__bridge id)kSecClass: (__bridge id)kSecClassKey,
635636 (__bridge id )kSecAttrKeyType : (__bridge id )kSecAttrKeyTypeRSA ,
636637 (__bridge id )kSecAttrKeyClass : (__bridge id )kSecAttrKeyClassPrivate ,
637638 // (__bridge id)kSecAttrLabel: kKeychainPrivateKeyLabel,
@@ -655,35 +656,11 @@ - (SecIdentityRef)createIdentityWithCert:(NSString *)pemCert
655656 };
656657 SecItemDelete ((__bridge CFDictionaryRef)deleteKeyQuery);
657658
658- // Import certificate in keychain
659- NSDictionary *deleteCertQuery = @{
660- (__bridge id )kSecClass : (__bridge id )kSecClassCertificate ,
661- (__bridge id )kSecAttrLabel : certAlias
662- };
663- SecItemDelete ((__bridge CFDictionaryRef)deleteCertQuery);
664-
665- NSDictionary *certAttributes = @{
666- (__bridge id )kSecClass : (__bridge id )kSecClassCertificate ,
667- (__bridge id )kSecValueRef : (__bridge id )cert,
668- (__bridge id )kSecAttrLabel : certAlias
669- };
670- OSStatus status = SecItemAdd ((__bridge CFDictionaryRef)certAttributes, NULL );
671- if (status != errSecSuccess && status != errSecDuplicateItem) {
672- RCTLogWarn (@" createIdentity: Failed to store certificate, status: %d " , (int )status);
673- CFRelease (cert);
674- // CFRelease(privateKey);
675- return NULL ;
676- }
677-
678659 // Add the private key to keychain
679660 NSDictionary *keyAttributes = @{
680661 (__bridge id )kSecClass : (__bridge id )kSecClassKey ,
681662 (__bridge id )kSecAttrKeyType : (__bridge id )kSecAttrKeyTypeRSA ,
682663 (__bridge id )kSecAttrKeyClass : (__bridge id )kSecAttrKeyClassPrivate ,
683- // (__bridge id)kSecValueData: keyData,
684- // (__bridge id)kSecReturnPersistentRef: @YES,
685- // (__bridge id)kSecAttrKeySizeInBits: @(keySize),
686- // (__bridge id)kSecAttrIsPermanent: @YES,
687664 // (__bridge id)kSecAttrAccessible: (__bridge id)kSecAttrAccessibleAfterFirstUnlock,
688665 (__bridge id )kSecAttrLabel : keyAlias,
689666 // (__bridge id)kSecAttrApplicationTag: [kKeychainApplicationTag dataUsingEncoding:NSUTF8StringEncoding],
@@ -693,72 +670,52 @@ - (SecIdentityRef)createIdentityWithCert:(NSString *)pemCert
693670 if (status != errSecSuccess && status != errSecDuplicateItem) {
694671 RCTLogWarn (@" createIdentity: Failed to store private key, status: %d " , (int )status);
695672 CFRelease (cert);
696- // CFRelease(privateKey);
673+ CFRelease (privateKey);
697674 return NULL ;
698675 }
676+
677+ // Import certificate in keychain
678+ NSDictionary *deleteCertQuery = @{
679+ (__bridge id )kSecClass : (__bridge id )kSecClassCertificate ,
680+ (__bridge id )kSecAttrLabel : certAlias
681+ };
682+ SecItemDelete ((__bridge CFDictionaryRef)deleteCertQuery);
699683
700- // Try to retrieve private key from keychain
701- // NSDictionary *privateKeyQuery = @{
702- // (__bridge id)kSecClass: (__bridge id)kSecClassKey,
703- // (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne,
704- // (__bridge id)kSecReturnRef: @YES,
705- // (__bridge id)kSecReturnData: @YES,
706- // (__bridge id)kSecAttrLabel: @"My PrivateKey",
707- // //(__bridge id)kSecAttrApplicationTag: [kKeychainApplicationTag dataUsingEncoding:NSUTF8StringEncoding],
708- // //(__bridge id)kSecUseDataProtectionKeychain: @YES
709- // };
710- // SecKeyRef privateKey = NULL;
711- // status = SecItemCopyMatching((__bridge CFDictionaryRef)privateKeyQuery, (CFTypeRef *)&privateKey);
712-
713- // Add the certificate to keychain
714- // NSDictionary *certAttributes = @{
715- // (__bridge id)kSecClass: (__bridge id)kSecClassCertificate,
716- // (__bridge id)kSecValueRef: (__bridge id)cert,
717- // (__bridge id)kSecAttrLabel: kKeychainCertificateLabel
718- // };
719- //
720- // status = SecItemAdd((__bridge CFDictionaryRef)certAttributes, NULL);
721- // if (status != errSecSuccess && status != errSecDuplicateItem) {
722- // RCTLogWarn(@"createIdentity: Failed to store certificate, status: %d", (int)status);
723- // CFRelease(cert);
724- // CFRelease(privateKey);
725- // return NULL;
726- // }
727-
728- // // Query for the identity with correct attributes
729- // NSDictionary *identityQuery = @{
730- // (__bridge id)kSecClass: (__bridge id)kSecClassIdentity,
731- // (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne,
732- // (__bridge id)kSecReturnRef: @YES,
733- // //(__bridge id)kSecAttrLabel: @"My Certificate",
734- // //(__bridge id)kSecUseDataProtectionKeychain: @YES
735- // };
736- NSDictionary *identityQuery = @{
737- (__bridge id )kSecClass : (__bridge id )kSecClassIdentity ,
738- (__bridge id )kSecReturnRef : @YES ,
739- (__bridge id )kSecMatchItemList :@[(__bridge id )cert],
740- (__bridge id )kSecMatchLimit : (__bridge id )kSecMatchLimitOne ,
741- // (__bridge id)kSecAttrLabel: @"My Certificate",
742- // (__bridge id)kSecUseDataProtectionKeychain: @YES
684+ NSDictionary *certAttributes = @{
685+ (__bridge id )kSecClass : (__bridge id )kSecClassCertificate ,
686+ (__bridge id )kSecValueRef : (__bridge id )cert,
687+ (__bridge id )kSecAttrLabel : certAlias
743688 };
689+ OSStatus status = SecItemAdd ((__bridge CFDictionaryRef)certAttributes, NULL );
690+ if (status != errSecSuccess && status != errSecDuplicateItem) {
691+ RCTLogWarn (@" createIdentity: Failed to store certificate, status: %d " , (int )status);
692+ CFRelease (cert);
693+ CFRelease (privateKey);
694+ return NULL ;
695+ }
744696
745697
746- // Query for the identity
747- // NSDictionary *identityQuery = @{
748- // (__bridge id)kSecClass: (__bridge id)kSecClassIdentity,
749- // (__bridge id)kSecReturnRef: @YES,
750- // (__bridge id)kSecMatchLimit: (__bridge id)kSecMatchLimitOne
751- // };
752698
753- SecIdentityRef identity = NULL ;
754- identity = SecIdentityCreate (NULL , cert, privateKey);
755- // status = SecItemCopyMatching((__bridge CFDictionaryRef)identityQuery, (CFTypeRef *)&identity);
756- //
757- // if (status != errSecSuccess || !identity) {
758- // RCTLogWarn(@"createIdentity: Failed to find identity, status: %d", (int)status);
759- // } else {
760- // RCTLogWarn(@"createIdentity: Successfully found identity");
761- // }
699+ // ------ PRIVATE API: need to find the proper way of doing it -------
700+ if (NO ) {
701+ identity = SecIdentityCreate (NULL , cert, privateKey);
702+ } else {
703+ NSDictionary *identityQuery = @{
704+ (__bridge id )kSecClass : (__bridge id )kSecClassIdentity ,
705+ (__bridge id )kSecReturnRef : @YES ,
706+ // (__bridge id)kSecMatchItemList:@[(__bridge id)cert],
707+ (__bridge id )kSecMatchLimit : (__bridge id )kSecMatchLimitOne ,
708+ (__bridge id )kSecAttrLabel : certAlias,
709+ // (__bridge id)kSecUseDataProtectionKeychain: @YES
710+ };
711+ status = SecItemCopyMatching ((__bridge CFDictionaryRef)identityQuery, (CFTypeRef *)&identity);
712+
713+ if (status != errSecSuccess || !identity) {
714+ RCTLogWarn (@" createIdentity: Failed to find identity, status: %d " , (int )status);
715+ } else {
716+ RCTLogWarn (@" createIdentity: Successfully found identity" );
717+ }
718+ }
762719
763720 // Clean up
764721 CFRelease (cert);
@@ -829,6 +786,9 @@ - (NSDictionary *)getCertificate {
829786 return result;
830787}
831788
789+ // We need an ASN1 decoder to parse properly but for my case I only need modulus and exponent
790+ // In addition SecCertificateCopyNormalizedIssuerSequence has some issues since it normalizes
791+ // issuer and we don't want that
832792- (NSDictionary *)certificateToDict : (SecCertificateRef)certificate detailed : (BOOL )detailed {
833793 NSMutableDictionary *certInfo = [NSMutableDictionary dictionary ];
834794
@@ -882,66 +842,6 @@ - (NSDictionary *)certificateToDict:(SecCertificateRef)certificate detailed:(BOO
882842 CFRelease (issuerSequence);
883843 }
884844
885- // NSData *certData = (__bridge_transfer NSData *)SecCertificateCopyData(certificate);
886- // if (certData) {
887- //
888- // }
889- // // Get validity dates
890- // CFDictionaryRef values = NULL;
891- // status = SecCertificateCopyValues(certificate, NULL, &values);
892- // if (status == errSecSuccess && values) {
893- // CFDictionaryRef validityPeriod = CFDictionaryGetValue(values, kSecOIDValidityPeriod);
894- // if (validityPeriod) {
895- // CFArrayRef validityArray = CFDictionaryGetValue(validityPeriod, kSecPropertyKeyValue);
896- // if (validityArray && CFArrayGetCount(validityArray) == 2) {
897- // CFDictionaryRef notBeforeDict = CFArrayGetValueAtIndex(validityArray, 0);
898- // CFDictionaryRef notAfterDict = CFArrayGetValueAtIndex(validityArray, 1);
899- //
900- // CFStringRef notBefore = CFDictionaryGetValue(notBeforeDict, kSecPropertyKeyValue);
901- // CFStringRef notAfter = CFDictionaryGetValue(notAfterDict, kSecPropertyKeyValue);
902- //
903- // if (notBefore) {
904- // NSDate *fromDate = (__bridge NSDate *)notBefore;
905- // certInfo[@"valid_from"] = [self formatDate:fromDate];
906- // }
907- // if (notAfter) {
908- // NSDate *toDate = (__bridge NSDate *)notAfter;
909- // certInfo[@"valid_to"] = [self formatDate:toDate];
910- // }
911- // }
912- // }
913- //
914- // // Check if it's a CA
915- // CFDictionaryRef basicConstraints = CFDictionaryGetValue(values, kSecOIDBasicConstraints);
916- // if (basicConstraints) {
917- // CFTypeRef value = CFDictionaryGetValue(basicConstraints, kSecPropertyKeyValue);
918- // if (value) {
919- // certInfo[@"ca"] = @(CFBooleanGetValue(value));
920- // }
921- // }
922- //
923- // CFRelease(values);
924- // }
925- //
926- // // Get serial number
927- // NSData *serialData = (__bridge_transfer NSData *)SecCertificateCopySerialNumber(certificate, NULL);
928- // if (serialData) {
929- // NSMutableString *serialHex = [NSMutableString string];
930- // const unsigned char *bytes = serialData.bytes;
931- // for (NSInteger i = 0; i < serialData.length; i++) {
932- // [serialHex appendFormat:@"%02X", bytes[i]];
933- // }
934- // certInfo[@"serialNumber"] = serialHex;
935- // }
936- //
937- // // Get fingerprints
938- // NSData *certData = (__bridge_transfer NSData *)SecCertificateCopyData(certificate);
939- // if (certData) {
940- // certInfo[@"fingerprint"] = [self calculateFingerprint:certData algorithm:CC_SHA1 length:CC_SHA1_DIGEST_LENGTH];
941- // certInfo[@"fingerprint256"] = [self calculateFingerprint:certData algorithm:CC_SHA256 length:CC_SHA256_DIGEST_LENGTH];
942- // certInfo[@"fingerprint512"] = [self calculateFingerprint:certData algorithm:CC_SHA512 length:CC_SHA512_DIGEST_LENGTH];
943- // }
944-
945845 return certInfo;
946846}
947847
@@ -1001,47 +901,6 @@ - (NSArray *)parseRSAPublicKey:(NSData *)keyData {
1001901 return @[modulus, exponent];
1002902}
1003903
1004- - (NSString *)calculateFingerprint : (NSData *)data algorithm : (unsigned char * (^)(const void *, CC_LONG, unsigned char *))hashFunction length : (CC_LONG)hashLength {
1005- unsigned char digest[hashLength];
1006- hashFunction (data.bytes , (CC_LONG)data.length , digest);
1007-
1008- NSMutableString *fingerprint = [NSMutableString stringWithCapacity: hashLength * 3 ];
1009- for (int i = 0 ; i < hashLength; i++) {
1010- [fingerprint appendFormat: @" %02X :" , digest[i]];
1011- }
1012- return [fingerprint substringToIndex: fingerprint.length - 1 ]; // Remove last colon
1013- }
1014-
1015- // - (NSDictionary *)parseDN:(NSDictionary *)dnDict {
1016- // NSMutableDictionary *result = [NSMutableDictionary dictionary];
1017- //
1018- // // Map common DN fields
1019- // NSDictionary *mapping = @{
1020- // (id)kSecOIDCommonName: @"CN",
1021- // (id)kSecOIDDNQualifier: @"dnQualifier"
1022- // };
1023- //
1024- // for (id key in dnDict) {
1025- // NSString *mappedKey = mapping[key];
1026- // if (mappedKey) {
1027- // NSString *value = dnDict[key];
1028- // if ([value isKindOfClass:[NSString class]]) {
1029- // result[mappedKey] = value;
1030- // }
1031- // }
1032- // }
1033- //
1034- // return result;
1035- // }
1036-
1037- - (NSString *)formatDate : (NSDate *)date {
1038- NSDateFormatter *formatter = [[NSDateFormatter alloc ] init ];
1039- formatter.locale = [[NSLocale alloc ] initWithLocaleIdentifier: @" en_US" ];
1040- formatter.dateFormat = @" MMM dd HH:mm:ss yyyy 'GMT'" ;
1041- formatter.timeZone = [NSTimeZone timeZoneWithAbbreviation: @" GMT" ];
1042- return [formatter stringFromDate: date];
1043- }
1044-
1045904- (NSError *)badInvocationError : (NSString *)errMsg {
1046905 NSDictionary *userInfo =
1047906 [NSDictionary dictionaryWithObject: errMsg
0 commit comments