]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_ssl/lib/sslCrypto.c
Security-57336.1.9.tar.gz
[apple/security.git] / Security / libsecurity_ssl / lib / sslCrypto.c
diff --git a/Security/libsecurity_ssl/lib/sslCrypto.c b/Security/libsecurity_ssl/lib/sslCrypto.c
deleted file mode 100644 (file)
index 600916c..0000000
+++ /dev/null
@@ -1,579 +0,0 @@
-/*
- * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_LICENSE_HEADER_END@
- */
-
-/*
- * sslCrypto.c - interface between SSL and crypto libraries
- */
-
-#include "sslCrypto.h"
-#include "sslContext.h"
-#include "sslMemory.h"
-#include "sslUtils.h"
-#include "sslDebug.h"
-
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#include <Security/SecTrust.h>
-#include <Security/SecPolicy.h>
-#include <Security/SecCertificate.h>
-
-#include <AssertMacros.h>
-#include "utilities/SecCFRelease.h"
-
-#if TARGET_OS_IPHONE
-#include <Security/SecRSAKey.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
-}
-
-
-OSStatus
-sslCreateSecTrust(
-       SSLContext                              *ctx,
-       CFArrayRef                              certChain,
-       bool                                    arePeerCerts,
-    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 (arePeerCerts) {
-               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 server = ctx->protocolSide == kSSLClientSide;
-       require(policies = SecPolicyCreateSSL(server, peerDomainName), errOut);
-
-       require_noerr(status = SecTrustCreateWithCertificates(certChain, policies,
-               &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);
-    }
-
-    status = errSecSuccess;
-
-errOut:
-       CFReleaseSafe(peerDomainName);
-       CFReleaseSafe(policies);
-
-       *pTrust = trust;
-
-       return status;
-}
-
-/* Return the first certificate reference from the supplied array
- * whose data matches the given certificate, or NULL if none match.
- */
-static
-SecCertificateRef
-sslGetMatchingCertInArray(
-       SecCertificateRef       certRef,
-       CFArrayRef                      certArray)
-{
-       SecCertificateRef matchedCert = NULL;
-
-       if (certRef == NULL || certArray == NULL) {
-               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);
-       }
-
-    return matchedCert;
-}
-
-/*
- * Verify a chain of DER-encoded certs.
- * Last cert in a chain is the leaf; this must also be present
- * in ctx->trustedCerts.
- *
- * If arePeerCerts is true, host name verification is enabled and we
- * save the resulting SecTrustRef in ctx->peerSecTrust. Otherwise
- * we're just validating our own certs; no host name checking and
- * peerSecTrust is transient.
- */
-static OSStatus sslVerifyCertChain(
-       SSLContext                              *ctx,
-       CFArrayRef                              certChain,
-       bool                                    arePeerCerts)
-{
-       OSStatus status;
-       SecTrustRef trust = NULL;
-
-    if (arePeerCerts) {
-               /* renegotiate - start with a new SecTrustRef */
-        CFReleaseNull(ctx->peerSecTrust);
-    }
-
-    if(certChain==NULL) {
-        sslErrorLog("***Error: NULL cert chain\n");
-        status = errSSLXCertChainInvalid;
-        goto errOut;
-    }
-
-       status = sslCreateSecTrust(ctx, certChain, arePeerCerts, &trust);
-
-       if (!ctx->enableCertVerify) {
-               /* trivial case, this is caller's responsibility */
-               status = errSecSuccess;
-               goto errOut;
-       }
-
-       SecTrustResultType secTrustResult;
-       require_noerr(status = SecTrustEvaluate(trust, &secTrustResult), errOut);
-       switch (secTrustResult) {
-        case kSecTrustResultUnspecified:
-            /* cert chain valid, no special UserTrust assignments */
-        case kSecTrustResultProceed:
-            /* cert chain valid AND user explicitly trusts this */
-            status = errSecSuccess;
-            break;
-        case kSecTrustResultDeny:
-        case kSecTrustResultConfirm:
-        case kSecTrustResultRecoverableTrustFailure:
-        default:
-            if(ctx->allowAnyRoot) {
-                sslErrorLog("***Warning: accepting unverified cert chain\n");
-                status = errSecSuccess;
-            }
-            else {
-                               /*
-                                * 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;
-                                       }
-                               }
-                               status = errSSLXCertChainInvalid;
-            }
-            /* Do we really need to return things like:
-                   errSSLNoRootCert
-                   errSSLUnknownRootCert
-                   errSSLCertExpired
-                   errSSLCertNotYetValid
-                   errSSLHostNameMismatch
-               for our client to see what went wrong, or should we just always
-               return
-                   errSSLXCertChainInvalid
-               when something is wrong? */
-            break;
-       }
-
-errOut:
-       if (arePeerCerts)
-               ctx->peerSecTrust = trust;
-       else
-        CFReleaseSafe(trust);
-
-       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((cfCert = SecCertificateCreateWithData(kCFAllocatorDefault, certData)), out);
-        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=-9808); // 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 */
-static int tls_set_peer_pubkey(tls_handshake_t hdsk, const SSLCertificate *certchain)
-{
-    int err;
-    CFIndex algId;
-    SecKeyRef pubkey = NULL;
-    CFDataRef modulus = NULL;
-    CFDataRef exponent = NULL;
-    CFDataRef ecpubdata = NULL;
-
-#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(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(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)
-{
-    int err;
-    const SSLCertificate *certs;
-
-    certs = tls_handshake_get_peer_certificates(ctx->hdsk);
-    CFReleaseNull(ctx->peerCert);
-    ctx->peerCert = tls_get_peer_certs(certs);
-
-    err = sslVerifyCertChain(ctx, ctx->peerCert, true);
-    tls_handshake_trust_t trust;
-    switch (err) {
-        case errSecSuccess:
-            trust = tls_handshake_trust_ok;
-            break;
-        case errSSLUnknownRootCert:
-        case errSSLNoRootCert:
-            trust = tls_handshake_trust_unknown_root;
-            break;
-        case errSSLCertExpired:
-        case errSSLCertNotYetValid:
-            trust = tls_handshake_trust_cert_expired;
-            break;
-        case errSSLXCertChainInvalid:
-        default:
-            trust = tls_handshake_trust_cert_invalid;
-            break;
-    }
-
-    tls_handshake_set_peer_trust(ctx->hdsk, trust);
-
-    if(err)
-        goto out;
-
-    /* Set the public key, only if we have certs.
-       We don't return an handshake error if there is no cert,
-       The fact that there is no cert should be reflected in the
-       trust results above, or will be handle when the application
-       does its own trust evaluation. */
-    if(certs) {
-        require_noerr(err=tls_set_peer_pubkey(ctx->hdsk, certs), out);
-    }
-
-    /* Now that cert verification is done, update context state */
-    /* (this code was formerly in SSLProcessHandshakeMessage, */
-    /* directly after the return from SSLProcessCertificate) */
-    if(ctx->protocolSide == kSSLServerSide) {
-        /*
-         * Schedule return to the caller to verify the client's identity.
-         * Note that an error during processing will cause early
-         * termination of the handshake.
-         */
-        if (ctx->breakOnClientAuth) {
-            err = errSSLClientAuthCompleted;
-        }
-    } else {
-        /*
-         * Schedule return to the caller to verify the server's identity.
-         * Note that an error during processing will cause early
-         * termination of the handshake.
-         */
-        if (ctx->breakOnServerAuth) {
-            err = errSSLServerAuthCompleted;
-        }
-    }
-
-out:
-
-    return err;
-}
-
-/*
- * After ciphersuite negotiation is complete, verify that we have
- * the capability of actually performing the selected cipher.
- * Currently we just verify that we have a cert and private signing
- * key, if needed, and that the signing key's algorithm matches the
- * expected key exchange method.
- *
- * This is currently called from FindCipherSpec(), after it sets
- * ctx->selectedCipherSpec to a (supposedly) valid value, and from
- * sslBuildCipherSpecArray(), in server mode (pre-negotiation) only.
- */
-
-#if 0
-OSStatus sslVerifySelectedCipher(SSLContext *ctx)
-{
-
-    if(ctx->protocolSide == kSSLClientSide) {
-        return errSecSuccess;
-    }
-#if SSL_PAC_SERVER_ENABLE
-    if((ctx->masterSecretCallback != NULL) &&
-       (ctx->sessionTicket.data != NULL)) {
-            /* EAP via PAC resumption; we can do it */
-       return errSecSuccess;
-    }
-#endif /* SSL_PAC_SERVER_ENABLE */
-
-    CFIndex requireAlg;
-    switch (ctx->selectedCipherSpecParams.keyExchangeMethod) {
-        case SSL_RSA:
-        case SSL_RSA_EXPORT:
-       case SSL_DH_RSA:
-       case SSL_DH_RSA_EXPORT:
-       case SSL_DHE_RSA:
-       case SSL_DHE_RSA_EXPORT:
-            requireAlg = kSecRSAAlgorithmID;
-            break;
-       case SSL_DHE_DSS:
-       case SSL_DHE_DSS_EXPORT:
-       case SSL_DH_DSS:
-       case SSL_DH_DSS_EXPORT:
-            requireAlg = kSecDSAAlgorithmID;
-            break;
-       case SSL_DH_anon:
-       case SSL_DH_anon_EXPORT:
-        case TLS_PSK:
-            requireAlg = kSecNullAlgorithmID; /* no signing key */
-            break;
-        /*
-         * When SSL_ECDSA_SERVER is true and we support ECDSA on the server side,
-         * we'll need to add some logic here...
-         */
-#if SSL_ECDSA_SERVER
-        case SSL_ECDHE_ECDSA:
-        case SSL_ECDHE_RSA:
-        case SSL_ECDH_ECDSA:
-        case SSL_ECDH_RSA:
-        case SSL_ECDH_anon:
-            requireAlg = kSecECDSAAlgorithmID;
-            break;
-#endif
-
-       default:
-            /* needs update per cipherSpecs.c */
-            assert(0);
-            sslErrorLog("sslVerifySelectedCipher: unknown key exchange method\n");
-            return errSSLInternal;
-    }
-
-    if(requireAlg == kSecNullAlgorithmID) {
-       return errSecSuccess;
-    }
-
-    /* private signing key required */
-    if(ctx->signingPrivKeyRef == NULL) {
-       sslErrorLog("sslVerifySelectedCipher: no signing key\n");
-       return errSSLBadConfiguration;
-    }
-
-    /* Check the alg of our signing key. */
-    CFIndex keyAlg = sslPrivKeyGetAlgorithmID(ctx->signingPrivKeyRef);
-    if (requireAlg != keyAlg) {
-       sslErrorLog("sslVerifySelectedCipher: signing key alg mismatch\n");
-       return errSSLBadConfiguration;
-    }
-
-    return errSecSuccess;
-}
-
-#endif