X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/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 index 600916cc..00000000 --- a/Security/libsecurity_ssl/lib/sslCrypto.c +++ /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 -#include -#include - -#include -#include -#include - -#include -#include "utilities/SecCFRelease.h" - -#if TARGET_OS_IPHONE -#include -#include -#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; idxtrustedCerts. - * - * 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; jderCert.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