0

Using Swift 2.2; Xcode 7.3.1 running under El Capitan

Created a private/public key pair with SecKeyGeneratePair Got a copy of my public key using this code ... which I then encode so I can send it across a bluetooth link.

internal func generateKeyPair(publicKeyTag: String, privateKeyTag:String, keySize: Int)   {

    let privateKeyAttr: [NSString: AnyObject] = [
        kSecAttrIsPermanent: true,
        kSecAttrApplicationTag: privateKeyTag.dataUsingEncoding(NSUTF8StringEncoding)!
    ]
    let publicKeyAttr: [NSString: AnyObject] = [
        kSecAttrIsPermanent: true,
        kSecAttrApplicationTag: publicKeyTag.dataUsingEncoding(NSUTF8StringEncoding)!
    ]
    let parameters: [NSString: AnyObject] = [
        kSecAttrKeyType: kSecAttrKeyTypeRSA,
        kSecAttrKeySizeInBits: keySize,
        kSecPrivateKeyAttrs: privateKeyAttr,
        kSecPublicKeyAttrs: publicKeyAttr
    ]

    let result = SecKeyGeneratePair(parameters, &publicKey, &privateKey)

   if errSecSuccess != result {
        print("generateKeyPair fail",errSecSuccess, result)
   } else {
       //print("\(publicKey)\n\n","\(privateKey)")

    var dataPtr: AnyObject?
    let query: [NSString:AnyObject] = [
        kSecClass: kSecClassKey,
        kSecAttrApplicationTag: publicKeyTag.dataUsingEncoding(NSUTF8StringEncoding)!,
        kSecReturnData: true
    ]
    let qResult = SecItemCopyMatching(query, &dataPtr)
    if (qResult == errSecSuccess) {
        let PublicKeyText = dataPtr as? NSData
        base64Encoded = PublicKeyText!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
        print("PublicKeyText \(base64Encoded)")
    }
    }
}

Now I can unencoded my base64EncodedString blob with this code ...

 let data = NSData(base64EncodedString: superString8, options:   NSDataBase64DecodingOptions(rawValue:0))

But how to get it back to a usable SecKey object using Swift?I found this reference and started to translate it; but I fear I am way out of my depth here?

get SecKeyRef from base64 coded string

This is what I managed so far ..

      let cert:SecCertificateRef!
            let policy:SecPolicyRef!
            cert = SecCertificateCreateWithData(kCFAllocatorDefault, data!)
            policy = SecPolicyCreateBasicX509();
            //var status:OSStatus!
            var publicKey: SecKeyRef!
            //var publicKeyPtr = withUnsafeMutablePointer(&publicKey, { $0 })
            var trust:SecTrust?
            let trustPtr = withUnsafeMutablePointer(&trust , { $0} )
            var certArray:[SecCertificateRef] = []
            certArray.append(cert)

            var unsafeVariable:UnsafePointer<Void>

            let certArrayPtr = withUnsafeMutablePointer(&unsafeVariable, {$0})
            var newTrustType: SecTrustResultType = UInt32(kSecTrustResultInvalid)
            let newTrustTypePtr = withUnsafeMutablePointer(&newTrustType, {$0})

            if (cert != nil) {
                //certArray[1] = {cert}()
               // let certs:[SecCertificateRef] = CFArrayCreate(kCFAllocatorDefault, certArrayPtr, 1, nil) as! [SecCertificateRef]
                let certs:[SecCertificateRef] = CFArrayCreate(kCFAllocatorDefault, certArrayPtr, 1, nil) as! [SecCertificateRef]
                var status = SecTrustCreateWithCertificates(certs, policy, trustPtr)
                if (status == errSecSuccess){
                    //status = SecTrustEvaluate(trust!, trustTypePtr)
                      status = SecTrustEvaluate(trust!, newTrustTypePtr)
                    // Evaulate the trust.
                   switch (Int(newTrustType)) {
                   case kSecTrustResultInvalid: break
                   case kSecTrustResultDeny: break
                   case kSecTrustResultUnspecified: break
                   case kSecTrustResultFatalTrustFailure: break
                   case kSecTrustResultOtherError: break
                    case kSecTrustResultRecoverableTrustFailure:
                        publicKey = SecTrustCopyPublicKey(trust!);
                        break;
                    case kSecTrustResultProceed:
                        publicKey = SecTrustCopyPublicKey(trust!);
                        break;
                    }

                }
            }
        } else {
            superString8 = superString8 + stringFromData!
        }
    }

enter image description here

Community
  • 1
  • 1
user3069232
  • 8,587
  • 7
  • 46
  • 87

1 Answers1

1

Try something like this:

    let certArrayPtr = withUnsafeMutablePointer(&certArray, {$0})
    var newTrustType: SecTrustResultType = UInt32(kSecTrustResultInvalid)
    let newTrustTypePtr = withUnsafeMutablePointer(&newTrustType, {$0})

    if (cert != nil) {
        certArray[1] = {cert}()
        let certs = CFArrayCreate(kCFAllocatorDefault, unsafeBitCast(certArrayPtr, UnsafeMutablePointer<UnsafePointer<Void>>.self), 1, nil) as! [SecCertificateRef]

(the first and last lines here are different... no need for certArrayPtr to be a var, and unsafeBitCast is gross but it should get you over your hurdle; I found it in this related question).

Community
  • 1
  • 1
Michael Dautermann
  • 88,797
  • 17
  • 166
  • 215
  • Wow, a quick THANKS; it compiles, now for the acid test does it work!! – user3069232 May 05 '16 at 08:43
  • Michael, voted cause it compiles; but sadly doesn't work. It seems that SeccertificateCreateWithData fails to create anything, it just returns a nil. Going to port the code back to the client that send the public key to rule out the bluetooth base64 conversation and transfer. – user3069232 May 05 '16 at 08:53