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