1/* 2 * Copyright (c) 1999-2001,2005-2008,2010-2012 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 * sslKeychain.c - Apple Keychain routines 26 */ 27 28#include "ssl.h" 29#include "sslContext.h" 30#include "sslMemory.h" 31 32#include "sslCrypto.h" 33#ifdef USE_CDSA_CRYPTO 34#include <Security/Security.h> 35#else 36#include <Security/SecBase.h> 37#include <Security/SecCertificate.h> 38#include <Security/SecIdentity.h> 39#include <Security/SecPolicy.h> 40#include <Security/SecTrust.h> 41#endif /* !USE_CDSA_CRYPTO */ 42#include "utilities/SecCFRelease.h" 43 44#include "sslDebug.h" 45#include "sslKeychain.h" 46#include "sslUtils.h" 47#include <string.h> 48#include <assert.h> 49 50#if TARGET_OS_IPHONE 51#include "utilities/SecCFRelease.h" 52#endif 53 54#ifdef USE_SSLCERTIFICATE 55 56/* 57 * Given an array of certs (as SecIdentityRefs, specified by caller 58 * in SSLSetCertificate or SSLSetEncryptionCertificate) and a 59 * destination SSLCertificate: 60 * 61 * -- free destCerts if we have any 62 * -- Get raw cert data, convert to array of SSLCertificates in *destCert 63 * -- validate cert chain 64 * -- get pub, priv keys from certRef[0], store in *pubKey, *privKey 65 */ 66 67/* Convert a SecCertificateRef to an SSLCertificate * */ 68static OSStatus secCertToSslCert( 69 SSLContext *ctx, 70 SecCertificateRef certRef, 71 SSLCertificate **sslCert) 72{ 73 CSSM_DATA certData; // struct is transient, referent owned by 74 // Sec layer 75 OSStatus ortn; 76 SSLCertificate *thisSslCert = NULL; 77 78 ortn = SecCertificateGetData(certRef, &certData); 79 if(ortn) { 80 sslErrorLog("SecCertificateGetData() returned %d\n", (int)ortn); 81 return ortn; 82 } 83 84 thisSslCert = (SSLCertificate *)sslMalloc(sizeof(SSLCertificate)); 85 if(thisSslCert == NULL) { 86 return errSecAllocate; 87 } 88 if(SSLAllocBuffer(&thisSslCert->derCert, certData.Length, 89 ctx)) { 90 return errSecAllocate; 91 } 92 memcpy(thisSslCert->derCert.data, certData.Data, certData.Length); 93 thisSslCert->derCert.length = certData.Length; 94 *sslCert = thisSslCert; 95 return errSecSuccess; 96} 97 98/* 99 * Determine the basic signing algorithm, without the digest, component, of 100 * a cert. The returned algorithm will be RSA, DSA, or ECDSA. 101 */ 102static OSStatus sslCertSignerAlg( 103 SecCertificateRef certRef, 104 CSSM_ALGORITHMS *signerAlg) 105{ 106 OSStatus ortn; 107 CSSM_DATA_PTR fieldPtr; 108 CSSM_X509_ALGORITHM_IDENTIFIER *algId; 109 CSSM_ALGORITHMS sigAlg; 110 111 /* 112 * Extract the full signature algorithm OID 113 */ 114 *signerAlg = CSSM_ALGID_NONE; 115 ortn = SecCertificateCopyFirstFieldValue(certRef, 116 &CSSMOID_X509V1SignatureAlgorithm, 117 &fieldPtr); 118 if(ortn) { 119 return ortn; 120 } 121 if(fieldPtr->Length != sizeof(CSSM_X509_ALGORITHM_IDENTIFIER)) { 122 sslErrorLog("sslCertSignerAlg() length error\n"); 123 ortn = errSSLCrypto; 124 goto errOut; 125 } 126 algId = (CSSM_X509_ALGORITHM_IDENTIFIER *)fieldPtr->Data; 127 if(!cssmOidToAlg(&algId->algorithm, &sigAlg)) { 128 /* Only way this could happen is if we're given a bad cert */ 129 sslErrorLog("sslCertSignerAlg() bad sigAlg OID\n"); 130 ortn = errSecParam; 131 goto errOut; 132 } 133 134 /* 135 * OK we have the full signature algorithm as a CSSM_ALGORITHMS. 136 * Extract the core signature alg. 137 */ 138 switch(sigAlg) { 139 case CSSM_ALGID_RSA: 140 case CSSM_ALGID_MD2WithRSA: 141 case CSSM_ALGID_MD5WithRSA: 142 case CSSM_ALGID_SHA1WithRSA: 143 case CSSM_ALGID_SHA224WithRSA: 144 case CSSM_ALGID_SHA256WithRSA: 145 case CSSM_ALGID_SHA384WithRSA: 146 case CSSM_ALGID_SHA512WithRSA: 147 *signerAlg = CSSM_ALGID_RSA; 148 break; 149 case CSSM_ALGID_SHA1WithECDSA: 150 case CSSM_ALGID_SHA224WithECDSA: 151 case CSSM_ALGID_SHA256WithECDSA: 152 case CSSM_ALGID_SHA384WithECDSA: 153 case CSSM_ALGID_SHA512WithECDSA: 154 case CSSM_ALGID_ECDSA: 155 case CSSM_ALGID_ECDSA_SPECIFIED: 156 *signerAlg = CSSM_ALGID_ECDSA; 157 break; 158 case CSSM_ALGID_DSA: 159 case CSSM_ALGID_SHA1WithDSA: 160 *signerAlg = CSSM_ALGID_DSA; 161 break; 162 default: 163 sslErrorLog("sslCertSignerAlg() unknown sigAlg\n"); 164 ortn = errSecParam; 165 break; 166 } 167errOut: 168 SecCertificateReleaseFirstFieldValue(certRef, 169 &CSSMOID_X509V1SignatureAlgorithm, fieldPtr); 170 return ortn; 171} 172 173OSStatus 174parseIncomingCerts( 175 SSLContext *ctx, 176 CFArrayRef certs, 177 SSLCertificate **destCert, /* &ctx->{localCert,encryptCert} */ 178 CSSM_KEY_PTR *pubKey, /* &ctx->signingPubKey, etc. */ 179 SecKeyRef *privKeyRef, /* &ctx->signingPrivKeyRef, etc. */ 180 CSSM_ALGORITHMS *signerAlg) /* optional */ 181{ 182 CFIndex numCerts; 183 CFIndex cert; 184 SSLCertificate *certChain = NULL; 185 SSLCertificate *thisSslCert; 186 OSStatus ortn; 187 SecIdentityRef identity; 188 SecCertificateRef certRef; 189 SecKeyRef keyRef; 190 CSSM_DATA certData; 191 CSSM_CL_HANDLE clHand; // carefully derive from a SecCertificateRef 192 CSSM_RETURN crtn; 193 CSSM_KEY_PTR *pubKey; 194 SecKeyRef *privKeyRef; 195 196 assert(ctx != NULL); 197 assert(destCert != NULL); /* though its referent may be NULL */ 198 assert(sslPubKey != NULL); 199 assert(sslPrivKeyRef != NULL); 200 201 pubKey = &sslPubKey->key; 202 privKeyRef = &sslPrivKey->key; 203 204 sslDeleteCertificateChain(*destCert, ctx); 205 *destCert = NULL; 206 *pubKey = NULL; 207 *privKeyRef = NULL; 208 209 if(certs == NULL) { 210 sslErrorLog("parseIncomingCerts: NULL incoming cert array\n"); 211 return errSSLBadCert; 212 } 213 numCerts = CFArrayGetCount(certs); 214 if(numCerts == 0) { 215 sslErrorLog("parseIncomingCerts: empty incoming cert array\n"); 216 return errSSLBadCert; 217 } 218 219 /* 220 * Certs[0] is an SecIdentityRef from which we extract subject cert, 221 * privKeyRef, pubKey. 222 * 223 * 1. ensure the first element is a SecIdentityRef. 224 */ 225 identity = (SecIdentityRef)CFArrayGetValueAtIndex(certs, 0); 226 if(identity == NULL) { 227 sslErrorLog("parseIncomingCerts: bad cert array (1)\n"); 228 return errSecParam; 229 } 230 if(CFGetTypeID(identity) != SecIdentityGetTypeID()) { 231 sslErrorLog("parseIncomingCerts: bad cert array (2)\n"); 232 return errSecParam; 233 } 234 235 /* 236 * 2. Extract cert, keys and convert to local format. 237 */ 238 ortn = SecIdentityCopyCertificate(identity, &certRef); 239 if(ortn) { 240 sslErrorLog("parseIncomingCerts: bad cert array (3)\n"); 241 return ortn; 242 } 243 ortn = secCertToSslCert(ctx, certRef, &thisSslCert); 244 if(ortn) { 245 sslErrorLog("parseIncomingCerts: bad cert array (4)\n"); 246 return ortn; 247 } 248 /* enqueue onto head of cert chain */ 249 thisSslCert->next = certChain; 250 certChain = thisSslCert; 251 252 if(signerAlg != NULL) { 253 ortn = sslCertSignerAlg(certRef, signerAlg); 254 if(ortn) { 255 return ortn; 256 } 257 } 258 259 /* fetch private key from identity */ 260 ortn = SecIdentityCopyPrivateKey(identity, &keyRef); 261 if(ortn) { 262 sslErrorLog("parseIncomingCerts: SecIdentityCopyPrivateKey err %d\n", 263 (int)ortn); 264 return ortn; 265 } 266 *privKeyRef = keyRef; 267 268 /* obtain public key from cert */ 269 ortn = SecCertificateGetCLHandle(certRef, &clHand); 270 if(ortn) { 271 sslErrorLog("parseIncomingCerts: SecCertificateGetCLHandle err %d\n", 272 (int)ortn); 273 return ortn; 274 } 275 certData.Data = thisSslCert->derCert.data; 276 certData.Length = thisSslCert->derCert.length; 277 crtn = CSSM_CL_CertGetKeyInfo(clHand, &certData, pubKey); 278 if(crtn) { 279 sslErrorLog("parseIncomingCerts: CSSM_CL_CertGetKeyInfo err\n"); 280 return (OSStatus)crtn; 281 } 282 283 /* OK, that's the subject cert. Fetch optional remaining certs. */ 284 /* 285 * Convert: CFArray of SecCertificateRefs --> chain of SSLCertificates. 286 * Incoming certs have root last; SSLCertificate chain has root 287 * first. 288 */ 289 for(cert=1; cert<numCerts; cert++) { 290 certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certs, cert); 291 if(certRef == NULL) { 292 sslErrorLog("parseIncomingCerts: bad cert array (5)\n"); 293 return errSecParam; 294 } 295 if(CFGetTypeID(certRef) != SecCertificateGetTypeID()) { 296 sslErrorLog("parseIncomingCerts: bad cert array (6)\n"); 297 return errSecParam; 298 } 299 300 /* Extract cert, convert to local format. 301 */ 302 ortn = secCertToSslCert(ctx, certRef, &thisSslCert); 303 if(ortn) { 304 sslErrorLog("parseIncomingCerts: bad cert array (7)\n"); 305 return ortn; 306 } 307 /* enqueue onto head of cert chain */ 308 thisSslCert->next = certChain; 309 certChain = thisSslCert; 310 } 311 312 /* SUCCESS */ 313 *destCert = certChain; 314 return errSecSuccess; 315 316 /* free certChain, everything in it, other vars, return ortn */ 317 sslDeleteCertificateChain(certChain, ctx); 318 /* FIXME - anything else? */ 319 return ortn; 320} 321 322#else /* !USE_SSLCERTIFICATE */ 323 324OSStatus 325parseIncomingCerts( 326 SSLContext *ctx, 327 CFArrayRef certs, 328 CFArrayRef *destCertChain, /* &ctx->{localCertChain,encryptCertChain} */ 329 SSLPubKey **sslPubKey, /* &ctx->signingPubKey, etc. */ 330 SSLPrivKey **sslPrivKey, /* &ctx->signingPrivKeyRef, etc. */ 331 CFIndex *signerAlg) /* optional */ 332{ 333 OSStatus ortn; 334 CFIndex ix, numCerts; 335 SecIdentityRef identity; 336 CFMutableArrayRef certChain = NULL; /* Retained */ 337 SecCertificateRef leafCert = NULL; /* Retained */ 338 SecKeyRef pubKey = NULL; /* Retained */ 339 SecKeyRef privKey = NULL; /* Retained */ 340 SecTrustRef trust = NULL; /* Retained */ 341 342 assert(ctx != NULL); 343 assert(destCertChain != NULL); /* though its referent may be NULL */ 344 assert(sslPubKey != NULL); 345 assert(sslPrivKey != NULL); 346 347 if (certs == NULL) { 348 sslErrorLog("parseIncomingCerts: NULL incoming cert array\n"); 349 ortn = errSSLBadCert; 350 goto errOut; 351 } 352 numCerts = CFArrayGetCount(certs); 353 if (numCerts == 0) { 354 sslErrorLog("parseIncomingCerts: empty incoming cert array\n"); 355 ortn = errSSLBadCert; 356 goto errOut; 357 } 358 359 /* 360 * Certs[0] is an SecIdentityRef from which we extract subject cert, 361 * privKey, pubKey. 362 * 363 * 1. ensure the first element is a SecIdentityRef. 364 */ 365 identity = (SecIdentityRef)CFArrayGetValueAtIndex(certs, 0); 366 if (identity == NULL) { 367 sslErrorLog("parseIncomingCerts: bad cert array (1)\n"); 368 ortn = errSecParam; 369 goto errOut; 370 } 371 if (CFGetTypeID(identity) != SecIdentityGetTypeID()) { 372 sslErrorLog("parseIncomingCerts: bad cert array (2)\n"); 373 ortn = errSecParam; 374 goto errOut; 375 } 376 377 /* 378 * 2. Extract cert, keys and convert to local format. 379 */ 380 ortn = SecIdentityCopyCertificate(identity, &leafCert); 381 if (ortn) { 382 sslErrorLog("parseIncomingCerts: bad cert array (3)\n"); 383 goto errOut; 384 } 385 386 /* Fetch private key from identity */ 387 ortn = SecIdentityCopyPrivateKey(identity, &privKey); 388 if (ortn) { 389 sslErrorLog("parseIncomingCerts: SecIdentityCopyPrivateKey err %d\n", 390 (int)ortn); 391 goto errOut; 392 } 393 394 /* Convert the input array of SecIdentityRef at the start to an array of 395 all certificates. */ 396 certChain = CFArrayCreateMutable(kCFAllocatorDefault, numCerts, 397 &kCFTypeArrayCallBacks); 398 if (!certChain) { 399 ortn = errSecAllocate; 400 goto errOut; 401 } 402 CFArrayAppendValue(certChain, leafCert); 403 for (ix = 1; ix < numCerts; ++ix) { 404 SecCertificateRef intermediate = 405 (SecCertificateRef)CFArrayGetValueAtIndex(certs, ix); 406 if (intermediate == NULL) { 407 sslErrorLog("parseIncomingCerts: bad cert array (5)\n"); 408 ortn = errSecParam; 409 goto errOut; 410 } 411 if (CFGetTypeID(intermediate) != SecCertificateGetTypeID()) { 412 sslErrorLog("parseIncomingCerts: bad cert array (6)\n"); 413 ortn = errSecParam; 414 goto errOut; 415 } 416 417 CFArrayAppendValue(certChain, intermediate); 418 } 419 420 /* Obtain public key from cert */ 421#if TARGET_OS_IPHONE 422 ortn = SecTrustCreateWithCertificates(certChain, NULL, &trust); 423#else 424 { 425 SecPolicyRef policy = SecPolicyCreateBasicX509(); 426 ortn = SecTrustCreateWithCertificates(certChain, policy, &trust); 427 CFReleaseSafe(policy); 428 if (!ortn) { 429 /* We are only interested in getting the public key from the leaf 430 * cert here, so for best performance, don't try to build a chain 431 * or search any keychains. 432 */ 433 CFArrayRef emptyArray = CFArrayCreate(NULL, NULL, 0, NULL); 434 (void)SecTrustSetAnchorCertificates(trust, emptyArray); 435 (void)SecTrustSetKeychains(trust, emptyArray); 436 CFReleaseSafe(emptyArray); 437 } 438 } 439#endif 440 if (ortn) { 441 sslErrorLog("parseIncomingCerts: SecTrustCreateWithCertificates err %d\n", 442 (int)ortn); 443 goto errOut; 444 } 445 446 447#if !TARGET_OS_IPHONE 448 /* This is not required on iOS, but still required on osx */ 449 SecTrustResultType trustResult; 450 ortn = SecTrustEvaluate(trust, &trustResult); 451 if (ortn) { 452 sslErrorLog("parseIncomingCerts: SecTrustEvaluate err %d\n", 453 (int)ortn); 454 goto errOut; 455 } 456#endif 457 458 459 pubKey = SecTrustCopyPublicKey(trust); 460 if (!pubKey) { 461 /* We parsed the private key succesfully but could not get the public key: return an error */ 462 sslErrorLog("parseIncomingCerts: SecTrustCopyPublicKey failed\n"); 463 ortn = errSecParam; 464 goto errOut; 465 } 466 467 /* SUCCESS */ 468errOut: 469 CFReleaseSafe(trust); 470 CFReleaseSafe(leafCert); 471 CFReleaseSafe(*destCertChain); 472 sslFreePubKey(sslPubKey); 473 sslFreePrivKey(sslPrivKey); 474 475 if (ortn) { 476 CFReleaseSafe(certChain); 477 CFReleaseSafe(pubKey); 478 CFReleaseSafe(privKey); 479 480 *destCertChain = NULL; 481 } else { 482 *destCertChain = certChain; 483 *sslPubKey = (SSLPubKey*)pubKey; 484 *sslPrivKey = (SSLPrivKey*)privKey; 485 } 486 487 return ortn; 488} 489#endif /* !USE_SSLCERTIFICATE */ 490