1/* 2 * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * sslCrypto.c - interface between SSL and crypto libraries 26 */ 27 28#include "sslCrypto.h" 29#include "sslContext.h" 30#include "sslMemory.h" 31#include "sslUtils.h" 32#include "sslDebug.h" 33 34#include <string.h> 35#include <stdlib.h> 36#include <assert.h> 37 38#include <Security/SecTrust.h> 39#include <Security/SecPolicy.h> 40#include <Security/SecCertificate.h> 41 42#include <AssertMacros.h> 43#include "utilities/SecCFRelease.h" 44 45#if TARGET_OS_IPHONE 46#include <Security/SecRSAKey.h> 47#include <Security/SecECKey.h> 48#endif 49 50/* 51 * Get algorithm id for a SSLPubKey object. 52 */ 53CFIndex sslPubKeyGetAlgorithmID(SecKeyRef pubKey) 54{ 55#if TARGET_OS_IPHONE 56 return SecKeyGetAlgorithmID(pubKey); 57#else 58 return SecKeyGetAlgorithmId(pubKey); 59#endif 60} 61 62/* 63 * Get algorithm id for a SSLPrivKey object. 64 */ 65CFIndex sslPrivKeyGetAlgorithmID(SecKeyRef privKey) 66{ 67#if TARGET_OS_IPHONE 68 return SecKeyGetAlgorithmID(privKey); 69#else 70 return SecKeyGetAlgorithmId(privKey); 71#endif 72} 73 74 75OSStatus 76sslCreateSecTrust( 77 SSLContext *ctx, 78 CFArrayRef certChain, 79 bool arePeerCerts, 80 SecTrustRef *pTrust) /* RETURNED */ 81{ 82 OSStatus status = errSecAllocate; 83 CFStringRef peerDomainName = NULL; 84 CFTypeRef policies = NULL; 85 SecTrustRef trust = NULL; 86 const char *peerDomainNameData = NULL; 87 size_t peerDomainNameLen = 0; 88 89 if(ctx->protocolSide==kSSLClientSide) { 90 tls_handshake_get_peer_hostname(ctx->hdsk, &peerDomainNameData, &peerDomainNameLen); 91 } 92 93 if (CFArrayGetCount(certChain) == 0) { 94 status = errSSLBadCert; 95 goto errOut; 96 } 97 98 if (arePeerCerts) { 99 if (peerDomainNameLen && peerDomainNameData) { 100 CFIndex len = peerDomainNameLen; 101 if (peerDomainNameData[len - 1] == 0) { 102 len--; 103 //secwarning("peerDomainName is zero terminated!"); 104 } 105 /* @@@ Double check that this is the correct encoding. */ 106 require(peerDomainName = CFStringCreateWithBytes(kCFAllocatorDefault, 107 (const UInt8 *)peerDomainNameData, len, 108 kCFStringEncodingUTF8, false), errOut); 109 } 110 } 111 /* If we are the client, our peer certificates must satisfy the 112 ssl server policy. */ 113 bool server = ctx->protocolSide == kSSLClientSide; 114 require(policies = SecPolicyCreateSSL(server, peerDomainName), errOut); 115 116 require_noerr(status = SecTrustCreateWithCertificates(certChain, policies, 117 &trust), errOut); 118 119 /* If we have trustedAnchors we set them here. */ 120 if (ctx->trustedCerts) { 121 require_noerr(status = SecTrustSetAnchorCertificates(trust, 122 ctx->trustedCerts), errOut); 123 require_noerr(status = SecTrustSetAnchorCertificatesOnly(trust, 124 ctx->trustedCertsOnly), errOut); 125 } 126 127 status = errSecSuccess; 128 129errOut: 130 CFReleaseSafe(peerDomainName); 131 CFReleaseSafe(policies); 132 133 *pTrust = trust; 134 135 return status; 136} 137 138/* Return the first certificate reference from the supplied array 139 * whose data matches the given certificate, or NULL if none match. 140 */ 141static 142SecCertificateRef 143sslGetMatchingCertInArray( 144 SecCertificateRef certRef, 145 CFArrayRef certArray) 146{ 147 SecCertificateRef matchedCert = NULL; 148 149 if (certRef == NULL || certArray == NULL) { 150 return NULL; 151 } 152 153 CFDataRef certData = SecCertificateCopyData(certRef); 154 if (certData) { 155 CFIndex idx, count = CFArrayGetCount(certArray); 156 for(idx=0; idx<count; idx++) { 157 SecCertificateRef aCert = (SecCertificateRef)CFArrayGetValueAtIndex(certArray, idx); 158 CFDataRef aData = SecCertificateCopyData(aCert); 159 if (aData && CFEqual(aData, certData)) { 160 matchedCert = aCert; 161 } 162 CFReleaseSafe(aData); 163 if (matchedCert) 164 break; 165 } 166 CFReleaseSafe(certData); 167 } 168 169 return matchedCert; 170} 171 172/* 173 * Verify a chain of DER-encoded certs. 174 * Last cert in a chain is the leaf; this must also be present 175 * in ctx->trustedCerts. 176 * 177 * If arePeerCerts is true, host name verification is enabled and we 178 * save the resulting SecTrustRef in ctx->peerSecTrust. Otherwise 179 * we're just validating our own certs; no host name checking and 180 * peerSecTrust is transient. 181 */ 182static OSStatus sslVerifyCertChain( 183 SSLContext *ctx, 184 CFArrayRef certChain, 185 bool arePeerCerts) 186{ 187 OSStatus status; 188 SecTrustRef trust = NULL; 189 190 assert(certChain); 191 192 if (arePeerCerts) { 193 /* renegotiate - start with a new SecTrustRef */ 194 CFReleaseNull(ctx->peerSecTrust); 195 } 196 197 status = sslCreateSecTrust(ctx, certChain, arePeerCerts, &trust); 198 199 if (!ctx->enableCertVerify) { 200 /* trivial case, this is caller's responsibility */ 201 status = errSecSuccess; 202 goto errOut; 203 } 204 205 SecTrustResultType secTrustResult; 206 require_noerr(status = SecTrustEvaluate(trust, &secTrustResult), errOut); 207 switch (secTrustResult) { 208 case kSecTrustResultUnspecified: 209 /* cert chain valid, no special UserTrust assignments */ 210 case kSecTrustResultProceed: 211 /* cert chain valid AND user explicitly trusts this */ 212 status = errSecSuccess; 213 break; 214 case kSecTrustResultDeny: 215 case kSecTrustResultConfirm: 216 case kSecTrustResultRecoverableTrustFailure: 217 default: 218 if(ctx->allowAnyRoot) { 219 sslErrorLog("***Warning: accepting unverified cert chain\n"); 220 status = errSecSuccess; 221 } 222 else { 223 /* 224 * If the caller provided a list of trusted leaf certs, check them here 225 */ 226 if(ctx->trustedLeafCerts) { 227 if (sslGetMatchingCertInArray((SecCertificateRef)CFArrayGetValueAtIndex(certChain, 0), 228 ctx->trustedLeafCerts)) { 229 status = errSecSuccess; 230 goto errOut; 231 } 232 } 233 status = errSSLXCertChainInvalid; 234 } 235 /* Do we really need to return things like: 236 errSSLNoRootCert 237 errSSLUnknownRootCert 238 errSSLCertExpired 239 errSSLCertNotYetValid 240 errSSLHostNameMismatch 241 for our client to see what went wrong, or should we just always 242 return 243 errSSLXCertChainInvalid 244 when something is wrong? */ 245 break; 246 } 247 248errOut: 249 if (arePeerCerts) 250 ctx->peerSecTrust = trust; 251 else 252 CFReleaseSafe(trust); 253 254 return status; 255} 256 257/* Extract public SecKeyRef from Certificate Chain */ 258static 259int sslCopyPeerPubKey(const SSLCertificate *certchain, 260 SecKeyRef *pubKey) 261{ 262 int err; 263 check(pubKey); 264 SecTrustRef trust = NULL; 265 const SSLCertificate *cert; 266 CFMutableArrayRef certArray = NULL; 267 CFDataRef certData = NULL; 268 SecCertificateRef cfCert = NULL; 269 270 err = errSSLInternal; 271 272 certArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 273 cert = certchain; 274 while(cert) { 275 require((certData = CFDataCreate(kCFAllocatorDefault, cert->derCert.data, cert->derCert.length)), out); 276 require((cfCert = SecCertificateCreateWithData(kCFAllocatorDefault, certData)), out); 277 CFArrayAppendValue(certArray, cfCert); 278 CFReleaseNull(cfCert); 279 CFReleaseNull(certData); 280 cert=cert->next; 281 } 282 283 require_noerr((err=SecTrustCreateWithCertificates(certArray, NULL, &trust)), out); 284 SecKeyRef key = SecTrustCopyPublicKey(trust); 285 require_action(key, out, err=-9808); // errSSLBadCert 286 287 *pubKey = key; 288 289 err = errSecSuccess; 290 291out: 292 CFReleaseSafe(certData); 293 CFReleaseSafe(cfCert); 294 CFReleaseSafe(trust); 295 CFReleaseSafe(certArray); 296 297 return err; 298} 299 300/* Extract the pubkey from a cert chain, and send it to the tls_handshake context */ 301static int tls_set_peer_pubkey(tls_handshake_t hdsk, const SSLCertificate *certchain) 302{ 303 int err; 304 CFIndex algId; 305 SecKeyRef pubkey = NULL; 306 CFDataRef modulus = NULL; 307 CFDataRef exponent = NULL; 308 CFDataRef ecpubdata = NULL; 309 310#if 0 311 { /* dump certs */ 312 int i=0; 313 int j; 314 const SSLCertificate *tmp = certchain; 315 while(tmp) { 316 printf("cert%d[] = {", i); 317 for(j=0; j<tmp->derCert.length; j++) { 318 if((j&0xf)==0) 319 printf("\n"); 320 printf("0x%02x, ", tmp->derCert.data[j]); 321 } 322 printf("}\n"); 323 tmp=tmp->next; 324 i++; 325 } 326 } 327#endif 328 329 require_noerr((err=sslCopyPeerPubKey(certchain, &pubkey)), errOut); 330 331#if TARGET_OS_IPHONE 332 algId = SecKeyGetAlgorithmID(pubkey); 333#else 334 algId = SecKeyGetAlgorithmId(pubkey); 335#endif 336 337 err = errSSLCrypto; 338 339 switch(algId) { 340 case kSecRSAAlgorithmID: 341 { 342 require((modulus = SecKeyCopyModulus(pubkey)), errOut); 343 require((exponent = SecKeyCopyExponent(pubkey)), errOut); 344 345 tls_buffer mod; 346 tls_buffer exp; 347 348 mod.data = (uint8_t *)CFDataGetBytePtr(modulus); 349 mod.length = CFDataGetLength(modulus); 350 351 exp.data = (uint8_t *)CFDataGetBytePtr(exponent); 352 exp.length = CFDataGetLength(exponent); 353 354 err = tls_handshake_set_peer_rsa_public_key(hdsk, &mod, &exp); 355 break; 356 } 357 case kSecECDSAAlgorithmID: 358 { 359 tls_named_curve curve = SecECKeyGetNamedCurve(pubkey); 360 require((ecpubdata = SecECKeyCopyPublicBits(pubkey)), errOut); 361 362 tls_buffer pubdata; 363 pubdata.data = (uint8_t *)CFDataGetBytePtr(ecpubdata); 364 pubdata.length = CFDataGetLength(ecpubdata); 365 366 err = tls_handshake_set_peer_ec_public_key(hdsk, curve, &pubdata); 367 368 break; 369 } 370 default: 371 break; 372 } 373 374errOut: 375 CFReleaseSafe(pubkey); 376 CFReleaseSafe(modulus); 377 CFReleaseSafe(exponent); 378 CFReleaseSafe(ecpubdata); 379 380 return err; 381} 382 383/* Convert cert in DER format into an CFArray of SecCertificateRef */ 384CFArrayRef 385tls_get_peer_certs(const SSLCertificate *certs) 386{ 387 const SSLCertificate *cert; 388 389 CFMutableArrayRef certArray = NULL; 390 CFDataRef certData = NULL; 391 SecCertificateRef cfCert = NULL; 392 393 certArray = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); 394 require(certArray, out); 395 cert = certs; 396 while(cert) { 397 require((certData = CFDataCreate(kCFAllocatorDefault, cert->derCert.data, cert->derCert.length)), out); 398 require((cfCert = SecCertificateCreateWithData(kCFAllocatorDefault, certData)), out); 399 CFArrayAppendValue(certArray, cfCert); 400 CFReleaseNull(cfCert); 401 CFReleaseNull(certData); 402 cert=cert->next; 403 } 404 405 return certArray; 406 407out: 408 CFReleaseNull(cfCert); 409 CFReleaseNull(certData); 410 CFReleaseNull(certArray); 411 return NULL; 412} 413 414int 415tls_verify_peer_cert(SSLContext *ctx) 416{ 417 int err; 418 const SSLCertificate *certs; 419 420 certs = tls_handshake_get_peer_certificates(ctx->hdsk); 421 CFReleaseNull(ctx->peerCert); 422 ctx->peerCert = tls_get_peer_certs(certs); 423 424 err = sslVerifyCertChain(ctx, ctx->peerCert, true); 425 tls_handshake_trust_t trust; 426 switch (err) { 427 case errSecSuccess: 428 trust = tls_handshake_trust_ok; 429 break; 430 case errSSLUnknownRootCert: 431 case errSSLNoRootCert: 432 trust = tls_handshake_trust_unknown_root; 433 break; 434 case errSSLCertExpired: 435 case errSSLCertNotYetValid: 436 trust = tls_handshake_trust_cert_expired; 437 break; 438 case errSSLXCertChainInvalid: 439 default: 440 trust = tls_handshake_trust_cert_invalid; 441 break; 442 } 443 444 tls_handshake_set_peer_trust(ctx->hdsk, trust); 445 446 if(err) 447 goto out; 448 449 /* Set the public key */ 450 tls_set_peer_pubkey(ctx->hdsk, certs); 451 452 /* Now that cert verification is done, update context state */ 453 /* (this code was formerly in SSLProcessHandshakeMessage, */ 454 /* directly after the return from SSLProcessCertificate) */ 455 if(ctx->protocolSide == kSSLServerSide) { 456 /* 457 * Schedule return to the caller to verify the client's identity. 458 * Note that an error during processing will cause early 459 * termination of the handshake. 460 */ 461 if (ctx->breakOnClientAuth) { 462 err = errSSLClientAuthCompleted; 463 } 464 } else { 465 /* 466 * Schedule return to the caller to verify the server's identity. 467 * Note that an error during processing will cause early 468 * termination of the handshake. 469 */ 470 if (ctx->breakOnServerAuth) { 471 err = errSSLServerAuthCompleted; 472 } 473 } 474 475out: 476 477 return err; 478} 479 480/* 481 * After ciphersuite negotiation is complete, verify that we have 482 * the capability of actually performing the selected cipher. 483 * Currently we just verify that we have a cert and private signing 484 * key, if needed, and that the signing key's algorithm matches the 485 * expected key exchange method. 486 * 487 * This is currently called from FindCipherSpec(), after it sets 488 * ctx->selectedCipherSpec to a (supposedly) valid value, and from 489 * sslBuildCipherSpecArray(), in server mode (pre-negotiation) only. 490 */ 491 492#if 0 493OSStatus sslVerifySelectedCipher(SSLContext *ctx) 494{ 495 496 if(ctx->protocolSide == kSSLClientSide) { 497 return errSecSuccess; 498 } 499#if SSL_PAC_SERVER_ENABLE 500 if((ctx->masterSecretCallback != NULL) && 501 (ctx->sessionTicket.data != NULL)) { 502 /* EAP via PAC resumption; we can do it */ 503 return errSecSuccess; 504 } 505#endif /* SSL_PAC_SERVER_ENABLE */ 506 507 CFIndex requireAlg; 508 switch (ctx->selectedCipherSpecParams.keyExchangeMethod) { 509 case SSL_RSA: 510 case SSL_RSA_EXPORT: 511 case SSL_DH_RSA: 512 case SSL_DH_RSA_EXPORT: 513 case SSL_DHE_RSA: 514 case SSL_DHE_RSA_EXPORT: 515 requireAlg = kSecRSAAlgorithmID; 516 break; 517 case SSL_DHE_DSS: 518 case SSL_DHE_DSS_EXPORT: 519 case SSL_DH_DSS: 520 case SSL_DH_DSS_EXPORT: 521 requireAlg = kSecDSAAlgorithmID; 522 break; 523 case SSL_DH_anon: 524 case SSL_DH_anon_EXPORT: 525 case TLS_PSK: 526 requireAlg = kSecNullAlgorithmID; /* no signing key */ 527 break; 528 /* 529 * When SSL_ECDSA_SERVER is true and we support ECDSA on the server side, 530 * we'll need to add some logic here... 531 */ 532#if SSL_ECDSA_SERVER 533 case SSL_ECDHE_ECDSA: 534 case SSL_ECDHE_RSA: 535 case SSL_ECDH_ECDSA: 536 case SSL_ECDH_RSA: 537 case SSL_ECDH_anon: 538 requireAlg = kSecECDSAAlgorithmID; 539 break; 540#endif 541 542 default: 543 /* needs update per cipherSpecs.c */ 544 assert(0); 545 sslErrorLog("sslVerifySelectedCipher: unknown key exchange method\n"); 546 return errSSLInternal; 547 } 548 549 if(requireAlg == kSecNullAlgorithmID) { 550 return errSecSuccess; 551 } 552 553 /* private signing key required */ 554 if(ctx->signingPrivKeyRef == NULL) { 555 sslErrorLog("sslVerifySelectedCipher: no signing key\n"); 556 return errSSLBadConfiguration; 557 } 558 559 /* Check the alg of our signing key. */ 560 CFIndex keyAlg = sslPrivKeyGetAlgorithmID(ctx->signingPrivKeyRef); 561 if (requireAlg != keyAlg) { 562 sslErrorLog("sslVerifySelectedCipher: signing key alg mismatch\n"); 563 return errSSLBadConfiguration; 564 } 565 566 return errSecSuccess; 567} 568 569#endif 570