generate secIdentity from certificate & private key

Hi

I want to create secIdentity from certificate & key.

I receive certificate from my server and I have private key of that.

My certificate is like this -----BEGIN CERTIFICATE-----\nMIIEyTC...jix0=\n-----END CERTIFICATE-----

And private key is like this -----BEGIN RSA PRIVATE KEY-----\nMIIEp...5KM=\n-----END RSA PRIVATE KEY-----\n

I am trying to create secIdentity by saving certificate and key in keychain, but I am getting -25300 as error.

To create the identity my code is like this.

func deleteCertificateAndKey(certLabel:String, keyTag:Data) -> Bool {
    // Query for the certificate
    let query: [String: Any] = [kSecClass as String: kSecClassCertificate,
                                       kSecAttrLabel as String: certLabel]
    // Attempt to delete the certificate
    let certificateDeleteStatus = SecItemDelete(query as CFDictionary)
    print("certificateDeleteStatus: \(certificateDeleteStatus)")
//     if certificateDeleteStatus == errSecSuccess {
//         print("Certificate Certificate deleted successfully.")
//     } else {
//         print("Failed to delete certificate Certificate. Error: \(certificateDeleteStatus)")
//         return false
//     }
//    
    // Query for the private key associated with the certificate
    let keyQuery: [String: Any] = [
         kSecClass as String: kSecClassKey,
         kSecAttrApplicationTag as String: keyTag
       ]
    
    // Attempt to delete the private key
    let keyDeleteStatus = SecItemDelete(keyQuery as CFDictionary)
    print("keyDeleteStatus: \(keyDeleteStatus)")
//     if keyDeleteStatus == errSecSuccess {
//         print("Private key associated with Key deleted successfully.")
//         return true
//     } else {
//         print("Failed to delete private key for Key. Error: \(keyDeleteStatus)")
//         return false
//     }
    return true;
}
func stripPemHeaders(_ pemString: String) -> String {
    var result = pemString
    //
    result = result.replacingOccurrences(of: "-----BEGIN RSA PRIVATE KEY-----\n", with: "")
    result = result.replacingOccurrences(of: "\n-----END RSA PRIVATE KEY-----\n", with: "")
    //
    result = result.replacingOccurrences(of: "-----BEGIN CERTIFICATE-----\n", with: "")
    result = result.replacingOccurrences(of: "\n-----END CERTIFICATE-----", with: "")
    return result
  }

func loadIdentity(certificate: String, privateKey: String)-> SecIdentity? {
    
    let strippedCertificate = stripPemHeaders(certificate)
    print("strippedCertificate : \(strippedCertificate)")
        guard let certData = Data(base64Encoded: strippedCertificate, options:NSData.Base64DecodingOptions.ignoreUnknownCharacters) else {
            print("Unable to decode certificate PEM")
            return nil
        }
        print("certData: \(certData)")
    
    // Create certificate object
        guard let cert = SecCertificateCreateWithData(kCFAllocatorDefault, certData as CFData) else {
            print("Unable to create certificate")
            return nil
        }
    let addCertQuery: [String: Any] = [kSecClass as String: kSecClassCertificate,
                                       kSecValueRef as String: cert,
                                       kSecAttrLabel as String: "shahanshahAlam"]
    

    let tag = "fedvfdvjjkdf-tag".data(using: .utf8)!
    _ = deleteCertificateAndKey(certLabel: "shahanshahAlam",keyTag: tag )
//    print("deleteStatus finished with status: \(deleteStatus)")
    let certAddStatus = SecItemAdd(addCertQuery as CFDictionary, nil)

    print("certAddStatus finished with status: \(certAddStatus)")
    let strippedPrivateKey = stripPemHeaders(privateKey)
    print("strippedPrivateKey : \(strippedPrivateKey)")
    guard let pemKeyData = Data(base64Encoded: strippedPrivateKey, options:NSData.Base64DecodingOptions.ignoreUnknownCharacters) else {
         print("Error: couldn't parse the privateKeyString, pls check if headers were removed: \(privateKey)")
         return nil
       }
    print("pemKeyData finished with status: \(pemKeyData)")
    let sizeInBits = pemKeyData.count * 8
    let keyDict: [CFString: Any] = [
      kSecAttrKeyType: kSecAttrKeyTypeRSA,
      kSecAttrKeyClass: kSecAttrKeyClassPrivate,
      kSecAttrKeySizeInBits: NSNumber(value: sizeInBits),
      kSecReturnPersistentRef: true
    ]

    var error: Unmanaged<CFError>?
       guard let key = SecKeyCreateWithData(pemKeyData as CFData, keyDict as CFDictionary, &error) else {
         print("Failed creating a Certificate from data \(error.debugDescription)")
         return nil
       }
    let addKeyQuery: [String: Any] = [
         kSecClass as String: kSecClassKey,
         kSecAttrIsPermanent as String: true,
         kSecValueRef as String: key,
         kSecAttrApplicationTag as String: tag
       ]
     
       let privKeyAddStatus = SecItemAdd(addKeyQuery as CFDictionary, nil)
    print("privKeyAddStatus status finished with status: \(privKeyAddStatus)")
    // query for all avaiable identities
    let getIdentityQuery = [
        kSecClass : kSecClassIdentity,
//        kSecReturnData : true,
//        kSecReturnAttributes : true,
        kSecReturnRef : true,
        kSecAttrApplicationTag as String: tag,
        kSecMatchLimit : kSecMatchLimitAll
        ] as CFDictionary
    var identityItem: CFTypeRef?
    let status = SecItemCopyMatching(getIdentityQuery , &identityItem)
    print("identityItem finished with status: \(String(describing: identityItem))")
    print("status finished with status: \(status)")
    guard status == errSecSuccess else {
           print("Unable to create identity")
           return nil
       }
    return (identityItem as! SecIdentity);

}

How can I fix that.

It looks like you are trying to import data in PKCS12 format. There is an API for doing that SecPKCS12Import. Are you considering if the private key blob needs a password?

There is an API for doing that SecPKCS12Import.

Right. If you can convince your server to send you a PKCS#12, life will be a lot easier.

If you can’t, then you have to import each item separately and rely on the system to form a digital identity. We’re talking about exactly that topic over in Mutual TLS using Private Key and Certificate.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

generate secIdentity from certificate &amp; private key
 
 
Q