]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_ssl/lib/sslCrypto.c
Security-59306.61.1.tar.gz
[apple/security.git] / OSX / libsecurity_ssl / lib / sslCrypto.c
index df6d97070cfc1cd632b4f709f9129aef10a6a088..e26fff2fd14a87a7307b4d892aa4a1fb01cc8547 100644 (file)
@@ -28,7 +28,6 @@
 #include "sslCrypto.h"
 #include "sslContext.h"
 #include "sslMemory.h"
-#include "sslUtils.h"
 #include "sslDebug.h"
 
 #include <string.h>
 #include <Security/SecECKey.h>
 #endif
 
-/*
- * Get algorithm id for a SSLPubKey object.
- */
-CFIndex sslPubKeyGetAlgorithmID(SecKeyRef pubKey)
-{
-#if TARGET_OS_IPHONE
-       return SecKeyGetAlgorithmID(pubKey);
-#else
-       return SecKeyGetAlgorithmId(pubKey);
-#endif
-}
-
-/*
- * Get algorithm id for a SSLPrivKey object.
- */
-CFIndex sslPrivKeyGetAlgorithmID(SecKeyRef privKey)
-{
-#if TARGET_OS_IPHONE
-       return SecKeyGetAlgorithmID(privKey);
-#else
-       return SecKeyGetAlgorithmId(privKey);
-#endif
-}
+#include <tls_helpers.h>
 
-static
-OSStatus sslCreateCFArrayFromList(const tls_buffer_list_t *list, CFArrayRef *cfArray)
-{
-    int err;
-    CFMutableArrayRef array = NULL;
-    CFDataRef data = NULL;
-
-    err = errSSLInternal;
-
-    array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
-    require(array, out);
-
-    while(list) {
-        require((data = CFDataCreate(kCFAllocatorDefault, list->buffer.data, list->buffer.length)), out);
-        CFArrayAppendValue(array, data);
-        CFReleaseNull(data);
-        list=list->next;
-    }
-
-    *cfArray = array;
-    return errSecSuccess;
-
-out:
-    CFReleaseSafe(data);
-    CFReleaseSafe(array);
-    return err;
-}
 
 OSStatus
 sslCreateSecTrust(
        SSLContext                              *ctx,
-       CFArrayRef                              certChain,
     SecTrustRef             *pTrust)   /* RETURNED */
 {
        OSStatus status = errSecAllocate;
-       CFStringRef peerDomainName = NULL;
-       CFTypeRef policies = NULL;
        SecTrustRef trust = NULL;
-    const char *peerDomainNameData = NULL;
-    size_t peerDomainNameLen = 0;
-
-    if(ctx->protocolSide==kSSLClientSide) {
-        tls_handshake_get_peer_hostname(ctx->hdsk, &peerDomainNameData, &peerDomainNameLen);
-    }
 
-    if (CFArrayGetCount(certChain) == 0) {
-               status = errSSLBadCert;
-               goto errOut;
-       }
-
-    if (peerDomainNameLen && peerDomainNameData) {
-        CFIndex len = peerDomainNameLen;
-        if (peerDomainNameData[len - 1] == 0) {
-            len--;
-            //secwarning("peerDomainName is zero terminated!");
-        }
-        /* @@@ Double check that this is the correct encoding. */
-        require(peerDomainName = CFStringCreateWithBytes(kCFAllocatorDefault,
-            (const UInt8 *)peerDomainNameData, len,
-            kCFStringEncodingUTF8, false), errOut);
-    }
-
-    /* If we are the client, our peer certificates must satisfy the
-       ssl server policy. */
-    bool use_server_policy = (ctx->protocolSide == kSSLClientSide);
-       require(policies = SecPolicyCreateSSL(use_server_policy, peerDomainName), errOut);
-
-       require_noerr(status = SecTrustCreateWithCertificates(certChain, policies,
-               &trust), errOut);
-
-    /* If we are the client, let's see if we have OCSP responses and SCTs in the TLS handshake */
-    if(ctx->protocolSide == kSSLClientSide) {
-        const tls_buffer_list_t *sct_list = tls_handshake_get_peer_sct_list(ctx->hdsk);
-        const tls_buffer *ocsp_response = tls_handshake_get_peer_ocsp_response(ctx->hdsk);
-
-        if(ocsp_response) {
-            CFDataRef responseData = CFDataCreate(kCFAllocatorDefault, ocsp_response->data, ocsp_response->length);
-            status = SecTrustSetOCSPResponse(trust, responseData);
-            CFReleaseSafe(responseData);
-            require_noerr(status, errOut);
-        }
-
-        if(sct_list) {
-            CFArrayRef sctArray = NULL;
-            require_noerr(status = sslCreateCFArrayFromList(sct_list, &sctArray), errOut);
-#if TARGET_OS_IPHONE
-            status = SecTrustSetSignedCertificateTimestamps(trust, sctArray);
-#else
-            status = noErr;
-#endif
-            CFReleaseSafe(sctArray);
-            require_noerr(status, errOut);
-        }
-    }
+    require_noerr(status = tls_helper_create_peer_trust(ctx->hdsk, ctx->protocolSide==kSSLServerSide, &trust), errOut);
 
        /* If we have trustedAnchors we set them here. */
-    if (ctx->trustedCerts) {
-        require_noerr(status = SecTrustSetAnchorCertificates(trust,
-            ctx->trustedCerts), errOut);
-        require_noerr(status = SecTrustSetAnchorCertificatesOnly(trust,
-            ctx->trustedCertsOnly), errOut);
+    if (trust && ctx->trustedCerts) {
+        require_noerr(status = SecTrustSetAnchorCertificates(trust, ctx->trustedCerts), errOut);
+        require_noerr(status = SecTrustSetAnchorCertificatesOnly(trust, ctx->trustedCertsOnly), errOut);
     }
 
     status = errSecSuccess;
 
 errOut:
-       CFReleaseSafe(peerDomainName);
-       CFReleaseSafe(policies);
-
-       *pTrust = trust;
+    if(status != noErr) {
+        CFReleaseSafe(trust);
+        *pTrust = NULL;
+    } else {
+        *pTrust = trust;
+    }
 
        return status;
 }
 
+#if !TARGET_OS_IPHONE
 /* Return the first certificate reference from the supplied array
  * whose data matches the given certificate, or NULL if none match.
  */
@@ -200,31 +94,24 @@ sslGetMatchingCertInArray(
                return NULL;
        }
 
-       CFDataRef certData = SecCertificateCopyData(certRef);
-       if (certData) {
-               CFIndex idx, count = CFArrayGetCount(certArray);
-               for(idx=0; idx<count; idx++) {
-                       SecCertificateRef aCert = (SecCertificateRef)CFArrayGetValueAtIndex(certArray, idx);
-                       CFDataRef aData = SecCertificateCopyData(aCert);
-                       if (aData && CFEqual(aData, certData)) {
-                               matchedCert = aCert;
-                       }
-                       CFReleaseSafe(aData);
-                       if (matchedCert)
-                               break;
-               }
-               CFReleaseSafe(certData);
-       }
+    CFIndex idx, count = CFArrayGetCount(certArray);
+    for (idx = 0; idx < count; idx++) {
+        SecCertificateRef otherCert = (SecCertificateRef) CFArrayGetValueAtIndex(certArray, idx);
+        if (CFEqual(certRef, otherCert)) {
+            matchedCert = otherCert;
+            break;
+        }
+    }
 
     return matchedCert;
 }
+#endif
 
 /*
  * Verify a chain of DER-encoded certs.
  */
 static OSStatus sslVerifyCertChain(
-       SSLContext                              *ctx,
-       CFArrayRef                              certChain)
+       SSLContext                              *ctx)
 {
        OSStatus status;
        SecTrustRef trust = NULL;
@@ -232,7 +119,10 @@ static OSStatus sslVerifyCertChain(
     /* renegotiate - start with a new SecTrustRef */
     CFReleaseNull(ctx->peerSecTrust);
 
-    if(certChain==NULL) {
+    /* on failure, we always return trust==NULL, so we don't check the returned status here */
+    sslCreateSecTrust(ctx, &trust);
+
+    if(trust==NULL) {
         if(ctx->protocolSide == kSSLClientSide) {
             /* No cert chain is always a trust failure on the server side */
             status = errSSLXCertChainInvalid;
@@ -249,7 +139,6 @@ static OSStatus sslVerifyCertChain(
         goto errOut;
     }
 
-       status = sslCreateSecTrust(ctx, certChain, &trust);
 
        if (!ctx->enableCertVerify) {
                /* trivial case, this is caller's responsibility */
@@ -258,7 +147,8 @@ static OSStatus sslVerifyCertChain(
        }
 
        SecTrustResultType secTrustResult;
-       require_noerr(status = SecTrustEvaluate(trust, &secTrustResult), errOut);
+    require_noerr(status = SecTrustEvaluate(trust, &secTrustResult), errOut);
+
        switch (secTrustResult) {
         case kSecTrustResultUnspecified:
             /* cert chain valid, no special UserTrust assignments */
@@ -267,7 +157,6 @@ static OSStatus sslVerifyCertChain(
             status = errSecSuccess;
             break;
         case kSecTrustResultDeny:
-        case kSecTrustResultConfirm:
         case kSecTrustResultRecoverableTrustFailure:
         default:
             if(ctx->allowAnyRoot) {
@@ -275,16 +164,18 @@ static OSStatus sslVerifyCertChain(
                 status = errSecSuccess;
             }
             else {
+#if !TARGET_OS_IPHONE
                                /*
                                 * If the caller provided a list of trusted leaf certs, check them here
                                 */
-                               if(ctx->trustedLeafCerts) {
-                                       if (sslGetMatchingCertInArray((SecCertificateRef)CFArrayGetValueAtIndex(certChain, 0),
-                                                               ctx->trustedLeafCerts)) {
-                                               status = errSecSuccess;
-                                               goto errOut;
-                                       }
-                               }
+                if(ctx->trustedLeafCerts) {
+                    if (sslGetMatchingCertInArray(SecTrustGetCertificateAtIndex(trust, 0),
+                                                  ctx->trustedLeafCerts)) {
+                        status = errSecSuccess;
+                        goto errOut;
+                    }
+                }
+#endif
                                status = errSSLXCertChainInvalid;
             }
             /* Do we really need to return things like:
@@ -306,175 +197,6 @@ errOut:
        return status;
 }
 
-/* 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;
-}
-
 int
 tls_verify_peer_cert(SSLContext *ctx)
 {
@@ -487,7 +209,7 @@ tls_verify_peer_cert(SSLContext *ctx)
        call to tls_handshake_set_peer_trust(). In some case a verification failure here is 
        normal, for example if there is no cert (eg: PSK and Anon DH ciphersuites) */
 
-    st = sslVerifyCertChain(ctx, ctx->peerCert);
+    st = sslVerifyCertChain(ctx);
     tls_handshake_trust_t trust;
     switch (st) {
         case errSecSuccess:
@@ -519,7 +241,7 @@ tls_verify_peer_cert(SSLContext *ctx)
         if (ctx->breakOnClientAuth) {
             err = errSSLClientAuthCompleted;
         }
-    } else if(ctx->peerCert) {
+    } else if(ctx->peerSecTrust) {
         /*
          * Schedule return to the caller to verify the server's identity.
          * This will only return if a server cert was sent. In other cases
@@ -613,7 +335,7 @@ OSStatus sslVerifySelectedCipher(SSLContext *ctx)
     }
 
     /* Check the alg of our signing key. */
-    CFIndex keyAlg = sslPrivKeyGetAlgorithmID(ctx->signingPrivKeyRef);
+    CFIndex keyAlg = SecKeyGetAlgorithmId(ctx->signingPrivKeyRef);
     if (requireAlg != keyAlg) {
        sslErrorLog("sslVerifySelectedCipher: signing key alg mismatch\n");
        return errSSLBadConfiguration;