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