X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5c19dc3ae3bd8e40a9c028b0deddd50ff337692c..7e6b461318c8a779d91381531435a68ee4e8b6ed:/OSX/libsecurity_ssl/lib/sslCrypto.c diff --git a/OSX/libsecurity_ssl/lib/sslCrypto.c b/OSX/libsecurity_ssl/lib/sslCrypto.c index df6d9707..e26fff2f 100644 --- a/OSX/libsecurity_ssl/lib/sslCrypto.c +++ b/OSX/libsecurity_ssl/lib/sslCrypto.c @@ -28,7 +28,6 @@ #include "sslCrypto.h" #include "sslContext.h" #include "sslMemory.h" -#include "sslUtils.h" #include "sslDebug.h" #include @@ -47,144 +46,39 @@ #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 -} +#include -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; idxpeerSecTrust); - 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: 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; 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(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;