1/* 2 * Copyright (c) 2003,2011-2012,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#include "cert.h" 26#include "cmstpriv.h" 27#include "cmslocal.h" 28#include "secitem.h" 29#include <security_asn1/secerr.h> 30#include <Security/SecKeychain.h> 31#include <Security/SecKeychainItem.h> 32#include <Security/SecKeychainSearch.h> 33#include <Security/SecIdentity.h> 34#include <Security/SecIdentityPriv.h> 35#include <Security/SecIdentitySearch.h> 36#include <Security/SecCertificatePriv.h> 37#include <Security/SecPolicySearch.h> 38#include <Security/oidsalg.h> 39#include <Security/cssmapi.h> 40#include <Security/oidscert.h> 41#include <Security/oidscert.h> 42 43/* for errKCDuplicateItem */ 44#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h> 45 46#define CERT_DEBUG 0 47#if CERT_DEBUG 48#define dprintf(args...) printf(args) 49#else 50#define dprintf(args...) 51#endif 52 53/* @@@ Remove this once it's back in the appropriate header. */ 54static const uint8 X509V1IssuerNameStd[] = {INTEL_X509V3_CERT_R08, 23}; 55static const CSSM_OID OID_X509V1IssuerNameStd = {INTEL_X509V3_CERT_R08_LENGTH+1, (uint8 *)X509V1IssuerNameStd}; 56 57/* 58 * Normalize a Printable String. Per RFC2459 (4.1.2.4), printable strings are case 59 * insensitive and we're supposed to ignore leading and trailing 60 * whitespace, and collapse multiple whitespace characters into one. 61 */ 62static void 63CERT_NormalizeString(CSSM_DATA_PTR string) 64{ 65 char *pD, *pCh, *pEos; 66 67 if (!string->Length) 68 return; 69 70 pD = pCh = (char *)string->Data; 71 pEos = pCh + string->Length - 1; 72 73 /* Strip trailing NULL terminators */ 74 while(*pEos == 0) 75 pEos--; 76 77 /* Remove trailing spaces */ 78 while(isspace(*pEos)) 79 pEos--; 80 81 /* Point to one past last non-space character */ 82 pEos++; 83 84 /* skip all leading whitespace */ 85 while(isspace(*pCh) && (pCh < pEos)) 86 pCh++; 87 88 /* Eliminate multiple whitespace and convent to upper case. 89 * pCh points to first non-white char. 90 * pD still points to start of string. */ 91 while(pCh < pEos) 92 { 93 char ch = *pCh++; 94 *pD++ = toupper(ch); 95 if(isspace(ch)) 96 { 97 /* skip 'til next nonwhite */ 98 while(isspace(*pCh) && (pCh < pEos)) 99 pCh++; 100 } 101 } 102 103 string->Length = pD - (char *)string->Data; 104} 105 106/* 107 * Normalize an RDN. Per RFC2459 (4.1.2.4), printable strings are case 108 * insensitive and we're supposed to ignore leading and trailing 109 * whitespace, and collapse multiple whitespace characters into one. 110 * 111 * Incoming NSS_Name is assumed to be entirely within specifed coder's 112 * address space; we'll be munging some of that and possibly replacing 113 * some pointers with others allocated from the same space. 114 */ 115void 116CERT_NormalizeX509NameNSS(NSS_Name *nssName) 117{ 118 NSS_RDN *rdn; 119 120 for (rdn = *nssName->rdns; rdn; ++rdn) 121 { 122 NSS_ATV *attr; 123 for (attr = *rdn->atvs; attr; ++attr) 124 { 125 /* 126 * attr->value is an ASN_ANY containing an encoded 127 * string. We only normalize Prinatable String types. 128 * If we find one, decode it, normalize it, encode the 129 * result, and put the encoding back in attr->value. 130 * We temporarily "leak" the original string, which only 131 * has a lifetime of the incoming SecNssCoder. 132 */ 133 NSS_TaggedItem *attrVal = &attr->value; 134 if(attrVal->tag != SEC_ASN1_PRINTABLE_STRING) 135 continue; 136 137 CERT_NormalizeString(&attrVal->item); 138 } 139 } 140} 141 142SecCertificateRef CERT_FindCertByNicknameOrEmailAddr(SecKeychainRef keychainOrArray, char *name) 143{ 144 SecCertificateRef certificate; 145 OSStatus status=SecCertificateFindByEmail(keychainOrArray,name,&certificate); 146 return status==noErr?certificate:NULL; 147} 148 149SecPublicKeyRef SECKEY_CopyPublicKey(SecPublicKeyRef pubKey) 150{ 151 CFRetain(pubKey); 152 return pubKey; 153} 154 155void SECKEY_DestroyPublicKey(SecPublicKeyRef pubKey) 156{ 157 CFRelease(pubKey); 158} 159 160SecPublicKeyRef SECKEY_CopyPrivateKey(SecPublicKeyRef privKey) 161{ 162 CFRetain(privKey); 163 return privKey; 164} 165 166void SECKEY_DestroyPrivateKey(SecPublicKeyRef privKey) 167{ 168 CFRelease(privKey); 169} 170 171void CERT_DestroyCertificate(SecCertificateRef cert) 172{ 173 CFRelease(cert); 174} 175 176SecCertificateRef CERT_DupCertificate(SecCertificateRef cert) 177{ 178 CFRetain(cert); 179 return cert; 180} 181 182SecIdentityRef CERT_FindIdentityByUsage(SecKeychainRef keychainOrArray, 183 char *nickname, SECCertUsage usage, Boolean validOnly, void *proto_win) 184{ 185 SecIdentityRef identityRef = NULL; 186 SecCertificateRef cert = CERT_FindCertByNicknameOrEmailAddr(keychainOrArray, nickname); 187 if (!cert) 188 return NULL; 189 190 SecIdentityCreateWithCertificate(keychainOrArray, cert, &identityRef); 191 CFRelease(cert); 192 193 return identityRef; 194} 195 196SecCertificateRef CERT_FindUserCertByUsage(SecKeychainRef keychainOrArray, 197 char *nickname,SECCertUsage usage,Boolean validOnly,void *proto_win) 198{ 199 SecItemClass itemClass = kSecCertificateItemClass; 200 SecKeychainSearchRef searchRef; 201 SecKeychainItemRef itemRef = NULL; 202 OSStatus status; 203 SecKeychainAttribute attrs[1]; 204 const char *serialNumber = "12345678"; 205 // const SecKeychainAttributeList attrList; 206#if 0 207 attrs[1].tag = kSecLabelItemAttr; 208 attrs[1].length = strlen(nickname)+1; 209 attrs[1].data = nickname; 210#else 211 attrs[1].tag = kSecSerialNumberItemAttr; 212 attrs[1].length = (UInt32)strlen(serialNumber)+1; 213 attrs[1].data = (uint8 *)serialNumber; 214#endif 215 SecKeychainAttributeList attrList = { 0, attrs }; 216 // 12 34 56 78 217 status = SecKeychainSearchCreateFromAttributes(keychainOrArray,itemClass,&attrList,&searchRef); 218 if (status) 219 { 220 printf("CERT_FindUserCertByUsage: SecKeychainSearchCreateFromAttributes:%d",(int)status); 221 return NULL; 222 } 223 status = SecKeychainSearchCopyNext(searchRef,&itemRef); 224 if (status) 225 printf("CERT_FindUserCertByUsage: SecKeychainSearchCopyNext:%d",(int)status); 226 CFRelease(searchRef); 227 return (SecCertificateRef)itemRef; 228} 229 230/* 231startNewClass(X509Certificate) 232CertType, kSecCertTypeItemAttr, "CertType", 0, NULL, UINT32) 233CertEncoding, kSecCertEncodingItemAttr, "CertEncoding", 0, NULL, UINT32) 234PrintName, kSecLabelItemAttr, "PrintName", 0, NULL, BLOB) 235Alias, kSecAlias, "Alias", 0, NULL, BLOB) 236Subject, kSecSubjectItemAttr, "Subject", 0, NULL, BLOB) 237Issuer, kSecIssuerItemAttr, "Issuer", 0, NULL, BLOB) 238SerialNumber, kSecSerialNumberItemAttr, "SerialNumber", 0, NULL, BLOB) 239SubjectKeyIdentifier, kSecSubjectKeyIdentifierItemAttr, "SubjectKeyIdentifier", 0, NULL, BLOB) 240PublicKeyHash, kSecPublicKeyHashItemAttr, "PublicKeyHash", 0, NULL, BLOB) 241endNewClass() 242*/ 243 244CFArrayRef CERT_CertChainFromCert(SecCertificateRef cert, SECCertUsage usage, Boolean includeRoot) 245{ 246 SecPolicySearchRef searchRef = NULL; 247 SecPolicyRef policy = NULL; 248 CFArrayRef wrappedCert = NULL; 249 SecTrustRef trust = NULL; 250 CFArrayRef certChain = NULL; 251 CSSM_TP_APPLE_EVIDENCE_INFO *statusChain; 252 CFDataRef actionData = NULL; 253 OSStatus status = 0; 254 255 if (!cert) 256 goto loser; 257 258 status = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef); 259 if (status) 260 goto loser; 261 status = SecPolicySearchCopyNext(searchRef, &policy); 262 if (status) 263 goto loser; 264 265 wrappedCert = CERT_CertListFromCert(cert); 266 status = SecTrustCreateWithCertificates(wrappedCert, policy, &trust); 267 if (status) 268 goto loser; 269 270 /* Tell SecTrust that we don't care if any certs in the chain have expired, 271 nor do we want to stop when encountering a cert with a trust setting; 272 we always want to build the full chain. 273 */ 274 CSSM_APPLE_TP_ACTION_DATA localActionData = { 275 CSSM_APPLE_TP_ACTION_VERSION, 276 CSSM_TP_ACTION_ALLOW_EXPIRED | CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT 277 }; 278 actionData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)&localActionData, sizeof(localActionData), kCFAllocatorNull); 279 if (!actionData) 280 goto loser; 281 282 status = SecTrustSetParameters(trust, CSSM_TP_ACTION_DEFAULT, actionData); 283 if (status) 284 goto loser; 285 286 status = SecTrustEvaluate(trust, NULL); 287 if (status) 288 goto loser; 289 290 status = SecTrustGetResult(trust, NULL, &certChain, &statusChain); 291 if (status) 292 goto loser; 293 294 /* We don't drop the root if there is only 1 (self signed) certificate in the chain. */ 295 if (!includeRoot && CFArrayGetCount(certChain) > 1) 296 { 297 CFMutableArrayRef subChain = CFArrayCreateMutableCopy(NULL, 0, certChain); 298 CFRelease(certChain); 299 certChain = subChain; 300 if (subChain) 301 CFArrayRemoveValueAtIndex(subChain, CFArrayGetCount(subChain) - 1); 302 } 303 304loser: 305 if (searchRef) 306 CFRelease(searchRef); 307 if (policy) 308 CFRelease(policy); 309 if (wrappedCert) 310 CFRelease(wrappedCert); 311 if (trust) 312 CFRelease(trust); 313 if (actionData) 314 CFRelease(actionData); 315 if (certChain && status) 316 { 317 CFRelease(certChain); 318 certChain = NULL; 319 } 320 321 return certChain; 322} 323 324CFArrayRef CERT_CertListFromCert(SecCertificateRef cert) 325{ 326 const void *value = cert; 327 return cert ? CFArrayCreate(NULL, &value, 1, &kCFTypeArrayCallBacks) : NULL; 328} 329 330CFArrayRef CERT_DupCertList(CFArrayRef oldList) 331{ 332 CFRetain(oldList); 333 return oldList; 334} 335 336// Extract a public key object from a SubjectPublicKeyInfo 337SecPublicKeyRef CERT_ExtractPublicKey(SecCertificateRef cert) 338{ 339 SecPublicKeyRef keyRef = NULL; 340 SecCertificateCopyPublicKey(cert,&keyRef); 341 return keyRef; 342} 343 344SECStatus CERT_CheckCertUsage (SecCertificateRef cert,unsigned char usage) 345{ 346 // abort(); 347 // @@@ It's all good, it's ok. 348 return SECSuccess; 349} 350 351// Find a certificate in the database by a email address 352// "emailAddr" is the email address to look up 353SecCertificateRef CERT_FindCertByEmailAddr(SecKeychainRef keychainOrArray, char *emailAddr) 354{ 355 abort(); 356 return NULL; 357} 358 359// Find a certificate in the database by a DER encoded certificate 360// "derCert" is the DER encoded certificate 361SecCertificateRef CERT_FindCertByDERCert(SecKeychainRef keychainOrArray, const SECItem *derCert) 362{ 363 // @@@ Technically this should look though keychainOrArray for a cert matching this one I guess. 364 SecCertificateRef cert = NULL; 365 OSStatus rv; 366 367 rv = SecCertificateCreateFromData(derCert, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &cert); 368 if (rv && cert) 369 { 370 PORT_SetError(SEC_ERROR_NO_EMAIL_CERT); 371 CFRelease(cert); 372 cert = NULL; 373 } 374 375 return cert; 376} 377 378static int compareCssmData( 379 const CSSM_DATA *d1, 380 const CSSM_DATA *d2) 381{ 382 if((d1 == NULL) || (d2 == NULL)) { 383 return 0; 384 } 385 if(d1->Length != d2->Length) { 386 return 0; 387 } 388 if(memcmp(d1->Data, d2->Data, d1->Length)) { 389 return 0; 390 } 391 return 1; 392} 393 394// Generate a certificate key from the issuer and serialnumber, then look it up in the database. 395// Return the cert if found. "issuerAndSN" is the issuer and serial number to look for 396SecCertificateRef CERT_FindCertByIssuerAndSN (CFTypeRef keychainOrArray, 397 CSSM_DATA_PTR *rawCerts, PRArenaPool *pl, const SecCmsIssuerAndSN *issuerAndSN) 398{ 399 SecCertificateRef certificate; 400 int numRawCerts = SecCmsArrayCount((void **)rawCerts); 401 int dex; 402 OSStatus ortn; 403 404 /* 405 * First search the rawCerts array. 406 */ 407 for(dex=0; dex<numRawCerts; dex++) { 408 ortn = SecCertificateCreateFromData(rawCerts[dex], 409 CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, 410 &certificate); 411 if(ortn) { 412 continue; 413 } 414 SecCmsIssuerAndSN *isn = CERT_GetCertIssuerAndSN(pl, certificate); 415 if(isn == NULL) { 416 CFRelease(certificate); 417 continue; 418 } 419 if(!compareCssmData(&isn->derIssuer, &issuerAndSN->derIssuer)) { 420 CFRelease(certificate); 421 continue; 422 } 423 if(!compareCssmData(&isn->serialNumber, &issuerAndSN->serialNumber)) { 424 CFRelease(certificate); 425 continue; 426 } 427 /* got it */ 428 dprintf("CERT_FindCertByIssuerAndSN: found cert %p\n", certificate); 429 return certificate; 430 } 431 432 /* now search keychain(s) */ 433 OSStatus status = SecCertificateFindByIssuerAndSN(keychainOrArray, &issuerAndSN->derIssuer, 434 &issuerAndSN->serialNumber, &certificate); 435 if (status) 436 { 437 PORT_SetError(SEC_ERROR_NO_EMAIL_CERT); 438 certificate = NULL; 439 } 440 441 return certificate; 442} 443 444SecCertificateRef CERT_FindCertBySubjectKeyID (CFTypeRef keychainOrArray, 445 CSSM_DATA_PTR *rawCerts, const SECItem *subjKeyID) 446{ 447 SecCertificateRef certificate; 448 int numRawCerts = SecCmsArrayCount((void **)rawCerts); 449 int dex; 450 OSStatus ortn; 451 SECItem skid; 452 453 /* 454 * First search the rawCerts array. 455 */ 456 for(dex=0; dex<numRawCerts; dex++) { 457 int match; 458 ortn = SecCertificateCreateFromData(rawCerts[dex], 459 CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, 460 &certificate); 461 if(ortn) { 462 continue; 463 } 464 if(CERT_FindSubjectKeyIDExtension(certificate, &skid)) { 465 CFRelease(certificate); 466 /* not present */ 467 continue; 468 } 469 match = compareCssmData(subjKeyID, &skid); 470 SECITEM_FreeItem(&skid, PR_FALSE); 471 if(match) { 472 /* got it */ 473 return certificate; 474 } 475 CFRelease(certificate); 476 } 477 478 /* now search keychain(s) */ 479 OSStatus status = SecCertificateFindBySubjectKeyID(keychainOrArray,subjKeyID,&certificate); 480 if (status) 481 { 482 PORT_SetError(SEC_ERROR_NO_EMAIL_CERT); 483 certificate = NULL; 484 } 485 486 return certificate; 487} 488 489static SecIdentityRef 490CERT_FindIdentityByCertificate (CFTypeRef keychainOrArray, SecCertificateRef certificate) 491{ 492 SecIdentityRef identity = NULL; 493 SecIdentityCreateWithCertificate(keychainOrArray, certificate, &identity); 494 if (!identity) 495 PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT); 496 497 return identity; 498} 499 500SecIdentityRef 501CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN) 502{ 503 SecCertificateRef certificate = CERT_FindCertByIssuerAndSN(keychainOrArray, NULL, NULL, issuerAndSN); 504 if (!certificate) 505 return NULL; 506 507 return CERT_FindIdentityByCertificate(keychainOrArray, certificate); 508} 509 510SecIdentityRef 511CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray, const SECItem *subjKeyID) 512{ 513 SecCertificateRef certificate = CERT_FindCertBySubjectKeyID(keychainOrArray, NULL, subjKeyID); 514 if (!certificate) 515 return NULL; 516 517 return CERT_FindIdentityByCertificate(keychainOrArray, certificate); 518} 519 520// find the smime symmetric capabilities profile for a given cert 521SECItem *CERT_FindSMimeProfile(SecCertificateRef cert) 522{ 523 return NULL; 524} 525 526// Return the decoded value of the subjectKeyID extension. The caller should 527// free up the storage allocated in retItem->data. 528SECStatus CERT_FindSubjectKeyIDExtension (SecCertificateRef cert, SECItem *retItem) 529{ 530 CSSM_DATA_PTR fieldValue = NULL; 531 OSStatus ortn; 532 CSSM_X509_EXTENSION *extp; 533 CE_SubjectKeyID *skid; 534 535 ortn = SecCertificateCopyFirstFieldValue(cert, &CSSMOID_SubjectKeyIdentifier, 536 &fieldValue); 537 if(ortn || (fieldValue == NULL)) { 538 /* this cert doesn't have that extension */ 539 return SECFailure; 540 } 541 extp = (CSSM_X509_EXTENSION *)fieldValue->Data; 542 skid = (CE_SubjectKeyID *)extp->value.parsedValue; 543 retItem->Data = (uint8 *)PORT_Alloc(skid->Length); 544 retItem->Length = skid->Length; 545 memmove(retItem->Data, skid->Data, retItem->Length); 546 SecCertificateReleaseFirstFieldValue(cert, &CSSMOID_SubjectKeyIdentifier, 547 fieldValue); 548 return SECSuccess; 549} 550 551// Extract the issuer and serial number from a certificate 552SecCmsIssuerAndSN *CERT_GetCertIssuerAndSN(PRArenaPool *pl, SecCertificateRef cert) 553{ 554 OSStatus status; 555 SecCmsIssuerAndSN *certIssuerAndSN; 556 CSSM_CL_HANDLE clHandle; 557 CSSM_DATA_PTR serialNumber = 0; 558 CSSM_DATA_PTR issuer = 0; 559 CSSM_DATA certData = {}; 560 CSSM_HANDLE resultsHandle = 0; 561 uint32 numberOfFields = 0; 562 CSSM_RETURN result; 563 void *mark; 564 565 mark = PORT_ArenaMark(pl); 566 567 status = SecCertificateGetCLHandle(cert, &clHandle); 568 if (status) 569 goto loser; 570 status = SecCertificateGetData(cert, &certData); 571 if (status) 572 goto loser; 573 574 /* Get the issuer from the cert. */ 575 result = CSSM_CL_CertGetFirstFieldValue(clHandle, &certData, 576 &OID_X509V1IssuerNameStd, &resultsHandle, &numberOfFields, &issuer); 577 578 if (result || numberOfFields < 1) 579 goto loser; 580 result = CSSM_CL_CertAbortQuery(clHandle, resultsHandle); 581 if (result) 582 goto loser; 583 584 585 /* Get the serialNumber from the cert. */ 586 result = CSSM_CL_CertGetFirstFieldValue(clHandle, &certData, 587 &CSSMOID_X509V1SerialNumber, &resultsHandle, &numberOfFields, &serialNumber); 588 if (result || numberOfFields < 1) 589 goto loser; 590 result = CSSM_CL_CertAbortQuery(clHandle, resultsHandle); 591 if (result) 592 goto loser; 593 594 /* Allocate the SecCmsIssuerAndSN struct. */ 595 certIssuerAndSN = (SecCmsIssuerAndSN *)PORT_ArenaZAlloc (pl, sizeof(SecCmsIssuerAndSN)); 596 if (certIssuerAndSN == NULL) 597 goto loser; 598 599 /* Copy the issuer. */ 600 certIssuerAndSN->derIssuer.Data = (uint8 *) PORT_ArenaAlloc(pl, issuer->Length); 601 if (!certIssuerAndSN->derIssuer.Data) 602 goto loser; 603 PORT_Memcpy(certIssuerAndSN->derIssuer.Data, issuer->Data, issuer->Length); 604 certIssuerAndSN->derIssuer.Length = issuer->Length; 605 606 /* Copy the serialNumber. */ 607 certIssuerAndSN->serialNumber.Data = (uint8 *) PORT_ArenaAlloc(pl, serialNumber->Length); 608 if (!certIssuerAndSN->serialNumber.Data) 609 goto loser; 610 PORT_Memcpy(certIssuerAndSN->serialNumber.Data, serialNumber->Data, serialNumber->Length); 611 certIssuerAndSN->serialNumber.Length = serialNumber->Length; 612 613 PORT_ArenaUnmark(pl, mark); 614 615 CSSM_CL_FreeFieldValue(clHandle, &CSSMOID_X509V1SerialNumber, serialNumber); 616 CSSM_CL_FreeFieldValue(clHandle, &OID_X509V1IssuerNameStd, issuer); 617 618 return certIssuerAndSN; 619 620loser: 621 PORT_ArenaRelease(pl, mark); 622 623 if (serialNumber) 624 CSSM_CL_FreeFieldValue(clHandle, &CSSMOID_X509V1SerialNumber, serialNumber); 625 if (issuer) 626 CSSM_CL_FreeFieldValue(clHandle, &OID_X509V1IssuerNameStd, issuer); 627 628 PORT_SetError(SEC_INTERNAL_ONLY); 629 return NULL; 630} 631 632// import a collection of certs into the temporary or permanent cert database 633SECStatus CERT_ImportCerts(SecKeychainRef keychain, SECCertUsage usage, unsigned int ncerts, 634 SECItem **derCerts, SecCertificateRef **retCerts, Boolean keepCerts, Boolean caOnly, char *nickname) 635{ 636 OSStatus rv = SECFailure; 637 SecCertificateRef cert; 638 unsigned int ci; 639 640 // @@@ Do something with caOnly and nickname 641 if (caOnly || nickname) 642 abort(); 643 644 for (ci = 0; ci < ncerts; ++ci) 645 { 646 rv = SecCertificateCreateFromData(derCerts[ci], CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &cert); 647 if (rv) 648 break; 649 if (keepCerts) 650 { 651 rv = SecCertificateAddToKeychain(cert, keychain); 652 if (rv) 653 { 654 if (rv == errKCDuplicateItem) 655 rv = noErr; 656 else 657 { 658 CFRelease(cert); 659 break; 660 } 661 } 662 } 663 664 if (retCerts) 665 { 666 // @@@ not yet 667 abort(); 668 } 669 else 670 CFRelease(cert); 671 } 672 673 return rv; 674} 675 676SECStatus CERT_SaveSMimeProfile(SecCertificateRef cert, SECItem *emailProfile,SECItem *profileTime) 677{ 678 fprintf(stderr, "WARNING: CERT_SaveSMimeProfile unimplemented\n"); 679 return SECSuccess; 680} 681 682// Check the hostname to make sure that it matches the shexp that 683// is given in the common name of the certificate. 684SECStatus CERT_VerifyCertName(SecCertificateRef cert, const char *hostname) 685{ 686 fprintf(stderr, "WARNING: CERT_VerifyCertName unimplemented\n"); 687 return SECSuccess; 688} 689 690/* 691** OLD OBSOLETE FUNCTIONS with enum SECCertUsage - DO NOT USE FOR NEW CODE 692** verify a certificate by checking validity times against a certain time, 693** that we trust the issuer, and that the signature on the certificate is 694** valid. 695** "cert" the certificate to verify 696** "checkSig" only check signatures if true 697*/ 698SECStatus 699CERT_VerifyCert(SecKeychainRef keychainOrArray, SecCertificateRef cert, 700 const CSSM_DATA_PTR *otherCerts, /* intermediates */ 701 CFTypeRef policies, CFAbsoluteTime stime, SecTrustRef *trustRef) 702{ 703 CFMutableArrayRef certificates = NULL; 704 SecTrustRef trust = NULL; 705 OSStatus rv; 706 int numOtherCerts = SecCmsArrayCount((void **)otherCerts); 707 int dex; 708 709 /* 710 * Certs to evaluate: first the leaf - our cert - then all the rest we know 711 * about. It's OK for otherCerts to contain a copy of the leaf. 712 */ 713 certificates = CFArrayCreateMutable(NULL, numOtherCerts + 1, &kCFTypeArrayCallBacks); 714 CFArrayAppendValue(certificates, cert); 715 for(dex=0; dex<numOtherCerts; dex++) { 716 SecCertificateRef intCert; 717 718 rv = SecCertificateCreateFromData(otherCerts[dex], 719 CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, 720 &intCert); 721 if(rv) { 722 goto loser; 723 } 724 CFArrayAppendValue(certificates, intCert); 725 CFRelease(intCert); 726 } 727 rv = SecTrustCreateWithCertificates(certificates, policies, &trust); 728 CFRelease(certificates); 729 certificates = NULL; 730 if (rv) 731 goto loser; 732 733 rv = SecTrustSetKeychains(trust, keychainOrArray); 734 if (rv) 735 goto loser; 736 737 CFDateRef verifyDate = CFDateCreate(NULL, stime); 738 rv = SecTrustSetVerifyDate(trust, verifyDate); 739 CFRelease(verifyDate); 740 if (rv) 741 goto loser; 742 743 if (trustRef) 744 { 745 *trustRef = trust; 746 } 747 else 748 { 749 SecTrustResultType result; 750 /* The caller doesn't want a SecTrust object, so let's evaluate it for them. */ 751 rv = SecTrustEvaluate(trust, &result); 752 if (rv) 753 goto loser; 754 755 switch (result) 756 { 757 case kSecTrustResultProceed: 758 case kSecTrustResultUnspecified: 759 /* TP Verification succeeded and there was either a UserTurst entry 760 telling us to procceed, or no user trust setting was specified. */ 761 CFRelease(trust); 762 break; 763 default: 764 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); 765 rv = SECFailure; 766 goto loser; 767 break; 768 } 769 } 770 771 return SECSuccess; 772loser: 773 if (trust) 774 CFRelease(trust); 775 if(certificates) 776 CFRelease(certificates); 777 return rv; 778} 779 780CFTypeRef 781CERT_PolicyForCertUsage(SECCertUsage certUsage) 782{ 783 SecPolicySearchRef search = NULL; 784 SecPolicyRef policy = NULL; 785 const CSSM_OID *policyOID; 786 OSStatus rv; 787 788 switch (certUsage) 789 { 790 case certUsageSSLServerWithStepUp: 791 case certUsageSSLCA: 792 case certUsageVerifyCA: 793 case certUsageAnyCA: 794 goto loser; 795 break; 796 case certUsageSSLClient: 797 case certUsageSSLServer: 798 policyOID = &CSSMOID_APPLE_TP_SSL; 799 break; 800 case certUsageUserCertImport: 801 policyOID = &CSSMOID_APPLE_TP_CSR_GEN; 802 break; 803 case certUsageStatusResponder: 804 policyOID = &CSSMOID_APPLE_TP_REVOCATION_OCSP; 805 break; 806 case certUsageObjectSigner: 807 case certUsageProtectedObjectSigner: 808 policyOID = &CSSMOID_APPLE_ISIGN; 809 break; 810 case certUsageEmailSigner: 811 case certUsageEmailRecipient: 812 policyOID = &CSSMOID_APPLE_X509_BASIC; 813 break; 814 default: 815 goto loser; 816 } 817 rv = SecPolicySearchCreate(CSSM_CERT_X_509v3, policyOID, NULL, &search); 818 if (rv) 819 goto loser; 820 821 rv = SecPolicySearchCopyNext(search, &policy); 822 if (rv) 823 goto loser; 824 825loser: 826 if(search) CFRelease(search); 827 return policy; 828} 829