-/* Extract public SecKeyRef from Certificate Chain */
-static
-int sslCopyPeerPubKey(const SSLCertificate *certchain,
- SecKeyRef *pubKey)
-{
- int err;
- check(pubKey);
- SecTrustRef trust = NULL;
- const SSLCertificate *cert;
- CFMutableArrayRef certArray = NULL;
- CFDataRef certData = NULL;
- SecCertificateRef cfCert = NULL;
-
- err = errSSLInternal;
-
- certArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
- cert = certchain;
- while(cert) {
- require((certData = CFDataCreate(kCFAllocatorDefault, cert->derCert.data, cert->derCert.length)), out);
- require_action((cfCert = SecCertificateCreateWithData(kCFAllocatorDefault, certData)), out, err=errSSLBadCert);
- CFArrayAppendValue(certArray, cfCert);
- CFReleaseNull(cfCert);
- CFReleaseNull(certData);
- cert=cert->next;
- }
-
- require_noerr((err=SecTrustCreateWithCertificates(certArray, NULL, &trust)), out);
- SecKeyRef key = SecTrustCopyPublicKey(trust);
- require_action(key, out, err=errSSLBadCert);
-
- *pubKey = key;
-
- err = errSecSuccess;
-
-out:
- CFReleaseSafe(certData);
- CFReleaseSafe(cfCert);
- CFReleaseSafe(trust);
- CFReleaseSafe(certArray);
-
- return err;
-}
-
-/* Extract the pubkey from a cert chain, and send it to the tls_handshake context */
-int tls_set_peer_pubkey(SSLContext *ctx)
-{
- int err;
- CFIndex algId;
- SecKeyRef pubkey = NULL;
- CFDataRef modulus = NULL;
- CFDataRef exponent = NULL;
- CFDataRef ecpubdata = NULL;
- const SSLCertificate *certchain = NULL;
-
- certchain = tls_handshake_get_peer_certificates(ctx->hdsk);
- CFReleaseNull(ctx->peerCert);
-
- /* If there is no certchain, then we don't need to set the pubkey in coreTLS */
- /* We should really set it to "NULL" or none, but we need to fix the coreTLS API */
- /* See: <rdar://problem/19723662> coreTLS: replace tls_handshake_set_peer_rsa_public_key and tls_handshake_set_peer_ec_public_key with a common function */
- if(!certchain)
- return 0;
-
- ctx->peerCert = tls_get_peer_certs(certchain);
-
-#if 0
- { /* dump certs */
- int i=0;
- int j;
- const SSLCertificate *tmp = certchain;
- while(tmp) {
- printf("cert%d[] = {", i);
- for(j=0; j<tmp->derCert.length; j++) {
- if((j&0xf)==0)
- printf("\n");
- printf("0x%02x, ", tmp->derCert.data[j]);
- }
- printf("}\n");
- tmp=tmp->next;
- i++;
- }
- }
-#endif
-
- require_noerr((err=sslCopyPeerPubKey(certchain, &pubkey)), errOut);
-
-#if TARGET_OS_IPHONE
- algId = SecKeyGetAlgorithmID(pubkey);
-#else
- algId = SecKeyGetAlgorithmId(pubkey);
-#endif
-
- err = errSSLCrypto;
-
- switch(algId) {
- case kSecRSAAlgorithmID:
- {
- require((modulus = SecKeyCopyModulus(pubkey)), errOut);
- require((exponent = SecKeyCopyExponent(pubkey)), errOut);
-
- tls_buffer mod;
- tls_buffer exp;
-
- mod.data = (uint8_t *)CFDataGetBytePtr(modulus);
- mod.length = CFDataGetLength(modulus);
-
- exp.data = (uint8_t *)CFDataGetBytePtr(exponent);
- exp.length = CFDataGetLength(exponent);
-
- err = tls_handshake_set_peer_rsa_public_key(ctx->hdsk, &mod, &exp);
- break;
- }
- case kSecECDSAAlgorithmID:
- {
- tls_named_curve curve = SecECKeyGetNamedCurve(pubkey);
- require((ecpubdata = SecECKeyCopyPublicBits(pubkey)), errOut);
-
- tls_buffer pubdata;
- pubdata.data = (uint8_t *)CFDataGetBytePtr(ecpubdata);
- pubdata.length = CFDataGetLength(ecpubdata);
-
- err = tls_handshake_set_peer_ec_public_key(ctx->hdsk, curve, &pubdata);
-
- break;
- }
- default:
- break;
- }
-
-errOut:
- CFReleaseSafe(pubkey);
- CFReleaseSafe(modulus);
- CFReleaseSafe(exponent);
- CFReleaseSafe(ecpubdata);
-
- return err;
-}
-
-/* Convert cert in DER format into an CFArray of SecCertificateRef */
-CFArrayRef
-tls_get_peer_certs(const SSLCertificate *certs)
-{
- const SSLCertificate *cert;
-
- CFMutableArrayRef certArray = NULL;
- CFDataRef certData = NULL;
- SecCertificateRef cfCert = NULL;
-
- certArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
- require(certArray, out);
- cert = certs;
- while(cert) {
- require((certData = CFDataCreate(kCFAllocatorDefault, cert->derCert.data, cert->derCert.length)), out);
- require((cfCert = SecCertificateCreateWithData(kCFAllocatorDefault, certData)), out);
- CFArrayAppendValue(certArray, cfCert);
- CFReleaseNull(cfCert);
- CFReleaseNull(certData);
- cert=cert->next;
- }
-
- return certArray;
-
-out:
- CFReleaseNull(cfCert);
- CFReleaseNull(certData);
- CFReleaseNull(certArray);
- return NULL;
-}
-