]> git.saurik.com Git - apple/security.git/blob - libsecurity_smime/lib/cert.c
Security-55163.44.tar.gz
[apple/security.git] / libsecurity_smime / lib / cert.c
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. */
39 static const uint8 X509V1IssuerNameStd[] = {INTEL_X509V3_CERT_R08, 23};
40 static 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 */
47 static void
48 CERT_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 */
100 void
101 CERT_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
127 SecCertificateRef 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
134 SecPublicKeyRef SECKEY_CopyPublicKey(SecPublicKeyRef pubKey)
135 {
136 CFRetain(pubKey);
137 return pubKey;
138 }
139
140 void SECKEY_DestroyPublicKey(SecPublicKeyRef pubKey)
141 {
142 CFRelease(pubKey);
143 }
144
145 SecPublicKeyRef SECKEY_CopyPrivateKey(SecPublicKeyRef privKey)
146 {
147 CFRetain(privKey);
148 return privKey;
149 }
150
151 void SECKEY_DestroyPrivateKey(SecPublicKeyRef privKey)
152 {
153 CFRelease(privKey);
154 }
155
156 void CERT_DestroyCertificate(SecCertificateRef cert)
157 {
158 CFRelease(cert);
159 }
160
161 SecCertificateRef CERT_DupCertificate(SecCertificateRef cert)
162 {
163 CFRetain(cert);
164 return cert;
165 }
166
167 SecIdentityRef 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
181 SecCertificateRef 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 = 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 /*
216 startNewClass(X509Certificate)
217 CertType, kSecCertTypeItemAttr, "CertType", 0, NULL, UINT32)
218 CertEncoding, kSecCertEncodingItemAttr, "CertEncoding", 0, NULL, UINT32)
219 PrintName, kSecLabelItemAttr, "PrintName", 0, NULL, BLOB)
220 Alias, kSecAlias, "Alias", 0, NULL, BLOB)
221 Subject, kSecSubjectItemAttr, "Subject", 0, NULL, BLOB)
222 Issuer, kSecIssuerItemAttr, "Issuer", 0, NULL, BLOB)
223 SerialNumber, kSecSerialNumberItemAttr, "SerialNumber", 0, NULL, BLOB)
224 SubjectKeyIdentifier, kSecSubjectKeyIdentifierItemAttr, "SubjectKeyIdentifier", 0, NULL, BLOB)
225 PublicKeyHash, kSecPublicKeyHashItemAttr, "PublicKeyHash", 0, NULL, BLOB)
226 endNewClass()
227 */
228
229 CFArrayRef 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
289 loser:
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
309 CFArrayRef CERT_CertListFromCert(SecCertificateRef cert)
310 {
311 const void *value = cert;
312 return cert ? CFArrayCreate(NULL, &value, 1, &kCFTypeArrayCallBacks) : NULL;
313 }
314
315 CFArrayRef CERT_DupCertList(CFArrayRef oldList)
316 {
317 CFRetain(oldList);
318 return oldList;
319 }
320
321 // Extract a public key object from a SubjectPublicKeyInfo
322 SecPublicKeyRef CERT_ExtractPublicKey(SecCertificateRef cert)
323 {
324 SecPublicKeyRef keyRef = NULL;
325 SecCertificateCopyPublicKey(cert,&keyRef);
326 return keyRef;
327 }
328
329 SECStatus 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
338 SecCertificateRef 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
346 SecCertificateRef 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
363 static 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
381 SecCertificateRef 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
429 SecCertificateRef 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
474 static SecIdentityRef
475 CERT_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
485 SecIdentityRef
486 CERT_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
495 SecIdentityRef
496 CERT_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
506 SECItem *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.
513 SECStatus 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
537 SecCmsIssuerAndSN *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
605 loser:
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
618 SECStatus 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
661 SECStatus 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.
669 SECStatus 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 */
683 SECStatus
684 CERT_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;
757 loser:
758 if (trust)
759 CFRelease(trust);
760 if(certificates)
761 CFRelease(certificates);
762 return rv;
763 }
764
765 CFTypeRef
766 CERT_PolicyForCertUsage(SECCertUsage certUsage)
767 {
768 SecPolicySearchRef search;
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
810 loser:
811 CFRelease(search);
812 return policy;
813 }