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