]> git.saurik.com Git - apple/security.git/blob - Security/libsecurity_smime/lib/cert.c
Security-57031.40.6.tar.gz
[apple/security.git] / Security / 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/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. */
54 static const uint8 X509V1IssuerNameStd[] = {INTEL_X509V3_CERT_R08, 23};
55 static 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 */
62 static void
63 CERT_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 */
115 void
116 CERT_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
142 SecCertificateRef 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
149 SecPublicKeyRef SECKEY_CopyPublicKey(SecPublicKeyRef pubKey)
150 {
151 CFRetain(pubKey);
152 return pubKey;
153 }
154
155 void SECKEY_DestroyPublicKey(SecPublicKeyRef pubKey)
156 {
157 CFRelease(pubKey);
158 }
159
160 SecPublicKeyRef SECKEY_CopyPrivateKey(SecPublicKeyRef privKey)
161 {
162 CFRetain(privKey);
163 return privKey;
164 }
165
166 void SECKEY_DestroyPrivateKey(SecPublicKeyRef privKey)
167 {
168 CFRelease(privKey);
169 }
170
171 void CERT_DestroyCertificate(SecCertificateRef cert)
172 {
173 CFRelease(cert);
174 }
175
176 SecCertificateRef CERT_DupCertificate(SecCertificateRef cert)
177 {
178 CFRetain(cert);
179 return cert;
180 }
181
182 SecIdentityRef 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
196 SecCertificateRef 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 /*
231 startNewClass(X509Certificate)
232 CertType, kSecCertTypeItemAttr, "CertType", 0, NULL, UINT32)
233 CertEncoding, kSecCertEncodingItemAttr, "CertEncoding", 0, NULL, UINT32)
234 PrintName, kSecLabelItemAttr, "PrintName", 0, NULL, BLOB)
235 Alias, kSecAlias, "Alias", 0, NULL, BLOB)
236 Subject, kSecSubjectItemAttr, "Subject", 0, NULL, BLOB)
237 Issuer, kSecIssuerItemAttr, "Issuer", 0, NULL, BLOB)
238 SerialNumber, kSecSerialNumberItemAttr, "SerialNumber", 0, NULL, BLOB)
239 SubjectKeyIdentifier, kSecSubjectKeyIdentifierItemAttr, "SubjectKeyIdentifier", 0, NULL, BLOB)
240 PublicKeyHash, kSecPublicKeyHashItemAttr, "PublicKeyHash", 0, NULL, BLOB)
241 endNewClass()
242 */
243
244 CFArrayRef 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
304 loser:
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
324 CFArrayRef CERT_CertListFromCert(SecCertificateRef cert)
325 {
326 const void *value = cert;
327 return cert ? CFArrayCreate(NULL, &value, 1, &kCFTypeArrayCallBacks) : NULL;
328 }
329
330 CFArrayRef CERT_DupCertList(CFArrayRef oldList)
331 {
332 CFRetain(oldList);
333 return oldList;
334 }
335
336 // Extract a public key object from a SubjectPublicKeyInfo
337 SecPublicKeyRef CERT_ExtractPublicKey(SecCertificateRef cert)
338 {
339 SecPublicKeyRef keyRef = NULL;
340 SecCertificateCopyPublicKey(cert,&keyRef);
341 return keyRef;
342 }
343
344 SECStatus 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
353 SecCertificateRef 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
361 SecCertificateRef 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
378 static 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
396 SecCertificateRef 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
444 SecCertificateRef 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
489 static SecIdentityRef
490 CERT_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
500 SecIdentityRef
501 CERT_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
510 SecIdentityRef
511 CERT_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
521 SECItem *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.
528 SECStatus 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
552 SecCmsIssuerAndSN *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
620 loser:
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
633 SECStatus 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
676 SECStatus 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.
684 SECStatus 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 */
698 SECStatus
699 CERT_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;
772 loser:
773 if (trust)
774 CFRelease(trust);
775 if(certificates)
776 CFRelease(certificates);
777 return rv;
778 }
779
780 CFTypeRef
781 CERT_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
825 loser:
826 if(search) CFRelease(search);
827 return policy;
828 }