]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_smime/lib/cert.c
Security-58286.1.32.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 <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 SecPolicyRef policy = NULL;
248 CFArrayRef wrappedCert = NULL;
249 SecTrustRef trust = NULL;
250 CFMutableArrayRef certs = NULL;
251 OSStatus status = 0;
252
253 if (!cert)
254 goto loser;
255
256 policy = SecPolicyCreateBasicX509();
257 if (!policy)
258 goto loser;
259
260 wrappedCert = CERT_CertListFromCert(cert);
261 status = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
262 if (status)
263 goto loser;
264
265 /* SecTrustEvaluate will build us the best chain available using its heuristics.
266 * We'll ignore the trust result. */
267 status = SecTrustEvaluate(trust, NULL);
268 if (status)
269 goto loser;
270 CFIndex idx, count = SecTrustGetCertificateCount(trust);
271
272 /* If we weren't able to build a chain to a self-signed cert, warn. */
273 Boolean isSelfSigned = false;
274 SecCertificateRef lastCert = SecTrustGetCertificateAtIndex(trust, count - 1);
275 if (lastCert && (0 == SecCertificateIsSelfSigned(lastCert, &isSelfSigned)) && !isSelfSigned) {
276 CFStringRef commonName = NULL;
277 (void)SecCertificateCopyCommonName(cert, &commonName);
278 fprintf(stderr, "Warning: unable to build chain to self-signed root for signer \"%s\"",
279 commonName ? CFStringGetCStringPtr(commonName, kCFStringEncodingUTF8) : "");
280 if (commonName) { CFRelease(commonName); }
281 }
282
283 /* We don't drop the root if there is only 1 certificate in the chain. */
284 if (!includeRoot && count > 1) { count--; }
285
286 certs = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
287 for(idx = 0; idx < count; idx++)
288 CFArrayAppendValue(certs, SecTrustGetCertificateAtIndex(trust, idx));
289
290 loser:
291 if (policy)
292 CFRelease(policy);
293 if (wrappedCert)
294 CFRelease(wrappedCert);
295 if (trust)
296 CFRelease(trust);
297 if (certs && status)
298 {
299 CFRelease(certs);
300 certs = NULL;
301 }
302
303 return certs;
304 }
305
306 CFArrayRef CERT_CertListFromCert(SecCertificateRef cert)
307 {
308 const void *value = cert;
309 return cert ? CFArrayCreate(NULL, &value, 1, &kCFTypeArrayCallBacks) : NULL;
310 }
311
312 CFArrayRef CERT_DupCertList(CFArrayRef oldList)
313 {
314 CFRetain(oldList);
315 return oldList;
316 }
317
318 // Extract a public key object from a SubjectPublicKeyInfo
319 SecPublicKeyRef CERT_ExtractPublicKey(SecCertificateRef cert)
320 {
321 SecPublicKeyRef keyRef = NULL;
322 SecCertificateCopyPublicKey(cert,&keyRef);
323 return keyRef;
324 }
325
326 SECStatus CERT_CheckCertUsage (SecCertificateRef cert,unsigned char usage)
327 {
328 // abort();
329 // @@@ It's all good, it's ok.
330 return SECSuccess;
331 }
332
333 // Find a certificate in the database by a email address
334 // "emailAddr" is the email address to look up
335 SecCertificateRef CERT_FindCertByEmailAddr(SecKeychainRef keychainOrArray, char *emailAddr)
336 {
337 abort();
338 return NULL;
339 }
340
341 // Find a certificate in the database by a DER encoded certificate
342 // "derCert" is the DER encoded certificate
343 SecCertificateRef CERT_FindCertByDERCert(SecKeychainRef keychainOrArray, const SECItem *derCert)
344 {
345 // @@@ Technically this should look though keychainOrArray for a cert matching this one I guess.
346 SecCertificateRef cert = NULL;
347 OSStatus rv;
348
349 rv = SecCertificateCreateFromData(derCert, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &cert);
350 if (rv && cert)
351 {
352 PORT_SetError(SEC_ERROR_NO_EMAIL_CERT);
353 CFRelease(cert);
354 cert = NULL;
355 }
356
357 return cert;
358 }
359
360 static int compareCssmData(
361 const CSSM_DATA *d1,
362 const CSSM_DATA *d2)
363 {
364 if((d1 == NULL) || (d2 == NULL)) {
365 return 0;
366 }
367 if(d1->Length != d2->Length) {
368 return 0;
369 }
370 if(memcmp(d1->Data, d2->Data, d1->Length)) {
371 return 0;
372 }
373 return 1;
374 }
375
376 // Generate a certificate key from the issuer and serialnumber, then look it up in the database.
377 // Return the cert if found. "issuerAndSN" is the issuer and serial number to look for
378 SecCertificateRef CERT_FindCertByIssuerAndSN (CFTypeRef keychainOrArray,
379 CSSM_DATA_PTR *rawCerts, CFArrayRef certList, PRArenaPool *pl, const SecCmsIssuerAndSN *issuerAndSN)
380 {
381 SecCertificateRef certificate = NULL;
382 int numRawCerts = SecCmsArrayCount((void **)rawCerts);
383 int dex;
384 OSStatus ortn;
385
386 /*
387 * First search the rawCerts array.
388 */
389 for(dex=0; dex<numRawCerts; dex++) {
390 ortn = SecCertificateCreateFromData(rawCerts[dex],
391 CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
392 &certificate);
393 if(ortn) {
394 continue;
395 }
396 SecCmsIssuerAndSN *isn = CERT_GetCertIssuerAndSN(pl, certificate);
397 if(isn == NULL) {
398 CFRelease(certificate);
399 continue;
400 }
401 if(!compareCssmData(&isn->derIssuer, &issuerAndSN->derIssuer)) {
402 CFRelease(certificate);
403 continue;
404 }
405 if(!compareCssmData(&isn->serialNumber, &issuerAndSN->serialNumber)) {
406 CFRelease(certificate);
407 continue;
408 }
409 /* got it */
410 dprintf("CERT_FindCertByIssuerAndSN: found cert %p\n", certificate);
411 return certificate;
412 }
413
414 /* Search the user-added certList */
415 if (certList && CFArrayGetCount(certList)) {
416 CFIndex c, count = CFArrayGetCount(certList);
417 for (c = 0; c < count; c++) {
418 SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certList, c);
419 SecCmsIssuerAndSN *isn = CERT_GetCertIssuerAndSN(pl, cert);
420 if(isn == NULL) {
421 continue;
422 }
423 if(!compareCssmData(&isn->derIssuer, &issuerAndSN->derIssuer)) {
424 continue;
425 }
426 if(!compareCssmData(&isn->serialNumber, &issuerAndSN->serialNumber)) {
427 continue;
428 }
429 certificate = cert;
430 break;
431 }
432 if (certificate) { return certificate; }
433 }
434
435 /* now search keychain(s) */
436 OSStatus status = SecCertificateFindByIssuerAndSN(keychainOrArray, &issuerAndSN->derIssuer,
437 &issuerAndSN->serialNumber, &certificate);
438 if (status)
439 {
440 PORT_SetError(SEC_ERROR_NO_EMAIL_CERT);
441 certificate = NULL;
442 }
443
444 return certificate;
445 }
446
447 SecCertificateRef CERT_FindCertBySubjectKeyID (CFTypeRef keychainOrArray,
448 CSSM_DATA_PTR *rawCerts, CFArrayRef certList, const SECItem *subjKeyID)
449 {
450 SecCertificateRef certificate;
451 int numRawCerts = SecCmsArrayCount((void **)rawCerts);
452 int dex;
453 OSStatus ortn;
454 SECItem skid;
455
456 /*
457 * First search the rawCerts array.
458 */
459 for(dex=0; dex<numRawCerts; dex++) {
460 int match;
461 ortn = SecCertificateCreateFromData(rawCerts[dex],
462 CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
463 &certificate);
464 if(ortn) {
465 continue;
466 }
467 if(CERT_FindSubjectKeyIDExtension(certificate, &skid)) {
468 CFRelease(certificate);
469 /* not present */
470 continue;
471 }
472 match = compareCssmData(subjKeyID, &skid);
473 SECITEM_FreeItem(&skid, PR_FALSE);
474 if(match) {
475 /* got it */
476 return certificate;
477 }
478 CFRelease(certificate);
479 }
480
481 /* Search the user-added certList */
482 if (certList && CFArrayGetCount(certList)) {
483 CFDataRef subjectkeyid = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, subjKeyID->Data, subjKeyID->Length, kCFAllocatorNull);
484 CFIndex c, count = CFArrayGetCount(certList);
485 for (c = 0; c < count; c++) {
486 SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certList, c);
487 CFDataRef skid = (cert) ? SecCertificateGetSubjectKeyID(cert) : NULL;
488 if (skid && CFEqual(skid, subjectkeyid)) {
489 CFRetain(cert);
490 certificate = cert;
491 break;
492 }
493 }
494 if (subjectkeyid) { CFRelease(subjectkeyid); };
495 if (certificate) { return certificate; }
496 }
497
498 /* now search keychain(s) */
499 OSStatus status = SecCertificateFindBySubjectKeyID(keychainOrArray,subjKeyID,&certificate);
500 if (status)
501 {
502 PORT_SetError(SEC_ERROR_NO_EMAIL_CERT);
503 certificate = NULL;
504 }
505
506 return certificate;
507 }
508
509 static SecIdentityRef
510 CERT_FindIdentityByCertificate (CFTypeRef keychainOrArray, SecCertificateRef CF_CONSUMED certificate)
511 {
512 SecIdentityRef identity = NULL;
513 SecIdentityCreateWithCertificate(keychainOrArray, certificate, &identity);
514 if (!identity)
515 PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT);
516 if (certificate) {
517 CFRelease(certificate);
518 }
519
520 return identity;
521 }
522
523 SecIdentityRef
524 CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN)
525 {
526 SecCertificateRef certificate = CERT_FindCertByIssuerAndSN(keychainOrArray, NULL, NULL, NULL, issuerAndSN);
527 if (!certificate)
528 return NULL;
529
530 return CERT_FindIdentityByCertificate(keychainOrArray, certificate);
531 }
532
533 SecIdentityRef
534 CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray, const SECItem *subjKeyID)
535 {
536 SecCertificateRef certificate = CERT_FindCertBySubjectKeyID(keychainOrArray, NULL, NULL, subjKeyID);
537 if (!certificate)
538 return NULL;
539
540 return CERT_FindIdentityByCertificate(keychainOrArray, certificate);
541 }
542
543 // find the smime symmetric capabilities profile for a given cert
544 SECItem *CERT_FindSMimeProfile(SecCertificateRef cert)
545 {
546 return NULL;
547 }
548
549 // Return the decoded value of the subjectKeyID extension. The caller should
550 // free up the storage allocated in retItem->data.
551 SECStatus CERT_FindSubjectKeyIDExtension (SecCertificateRef cert, SECItem *retItem)
552 {
553 CSSM_DATA_PTR fieldValue = NULL;
554 OSStatus ortn;
555 CSSM_X509_EXTENSION *extp;
556 CE_SubjectKeyID *skid;
557
558 ortn = SecCertificateCopyFirstFieldValue(cert, &CSSMOID_SubjectKeyIdentifier,
559 &fieldValue);
560 if(ortn || (fieldValue == NULL)) {
561 /* this cert doesn't have that extension */
562 return SECFailure;
563 }
564 extp = (CSSM_X509_EXTENSION *)fieldValue->Data;
565 skid = (CE_SubjectKeyID *)extp->value.parsedValue;
566 retItem->Data = (uint8 *)PORT_Alloc(skid->Length);
567 retItem->Length = skid->Length;
568 memmove(retItem->Data, skid->Data, retItem->Length);
569 SecCertificateReleaseFirstFieldValue(cert, &CSSMOID_SubjectKeyIdentifier,
570 fieldValue);
571 return SECSuccess;
572 }
573
574 // Extract the issuer and serial number from a certificate
575 SecCmsIssuerAndSN *CERT_GetCertIssuerAndSN(PRArenaPool *pl, SecCertificateRef cert)
576 {
577 OSStatus status;
578 SecCmsIssuerAndSN *certIssuerAndSN;
579 SecCertificateRef certRef;
580 SecCertificateRef itemImplRef = NULL;
581 CSSM_CL_HANDLE clHandle;
582 CSSM_DATA_PTR serialNumber = 0;
583 CSSM_DATA_PTR issuer = 0;
584 CSSM_DATA certData = {};
585 CSSM_HANDLE resultsHandle = 0;
586 uint32 numberOfFields = 0;
587 CSSM_RETURN result;
588 void *mark;
589
590 mark = PORT_ArenaMark(pl);
591
592 /* Retain input cert and get pointer to its data */
593 certRef = (SecCertificateRef)((cert) ? CFRetain(cert) : NULL);
594 status = SecCertificateGetData(certRef, &certData);
595 if (status)
596 goto loser;
597 #if 1
598 // Convert unified input certRef to itemImpl instance.
599 // note: must not release this instance while we're using its CL handle!
600 itemImplRef = SecCertificateCreateItemImplInstance(cert);
601 status = SecCertificateGetCLHandle_legacy(itemImplRef, &clHandle);
602 #else
603 status = SecCertificateGetCLHandle(certRef, &clHandle);
604 #endif
605 if (status)
606 goto loser;
607
608 /* Get the issuer from the cert. */
609 result = CSSM_CL_CertGetFirstFieldValue(clHandle, &certData,
610 &OID_X509V1IssuerNameStd, &resultsHandle, &numberOfFields, &issuer);
611
612 if (result || numberOfFields < 1)
613 goto loser;
614 result = CSSM_CL_CertAbortQuery(clHandle, resultsHandle);
615 if (result)
616 goto loser;
617
618 /* Get the serialNumber from the cert. */
619 result = CSSM_CL_CertGetFirstFieldValue(clHandle, &certData,
620 &CSSMOID_X509V1SerialNumber, &resultsHandle, &numberOfFields, &serialNumber);
621 if (result || numberOfFields < 1)
622 goto loser;
623 result = CSSM_CL_CertAbortQuery(clHandle, resultsHandle);
624 if (result)
625 goto loser;
626
627 /* Allocate the SecCmsIssuerAndSN struct. */
628 certIssuerAndSN = (SecCmsIssuerAndSN *)PORT_ArenaZAlloc (pl, sizeof(SecCmsIssuerAndSN));
629 if (certIssuerAndSN == NULL)
630 goto loser;
631
632 /* Copy the issuer. */
633 certIssuerAndSN->derIssuer.Data = (uint8 *) PORT_ArenaAlloc(pl, issuer->Length);
634 if (!certIssuerAndSN->derIssuer.Data)
635 goto loser;
636 PORT_Memcpy(certIssuerAndSN->derIssuer.Data, issuer->Data, issuer->Length);
637 certIssuerAndSN->derIssuer.Length = issuer->Length;
638
639 /* Copy the serialNumber. */
640 certIssuerAndSN->serialNumber.Data = (uint8 *) PORT_ArenaAlloc(pl, serialNumber->Length);
641 if (!certIssuerAndSN->serialNumber.Data)
642 goto loser;
643 PORT_Memcpy(certIssuerAndSN->serialNumber.Data, serialNumber->Data, serialNumber->Length);
644 certIssuerAndSN->serialNumber.Length = serialNumber->Length;
645
646 PORT_ArenaUnmark(pl, mark);
647
648 CSSM_CL_FreeFieldValue(clHandle, &CSSMOID_X509V1SerialNumber, serialNumber);
649 CSSM_CL_FreeFieldValue(clHandle, &OID_X509V1IssuerNameStd, issuer);
650
651 if (itemImplRef)
652 CFRelease(itemImplRef);
653 if (certRef)
654 CFRelease(certRef);
655
656 return certIssuerAndSN;
657
658 loser:
659 PORT_ArenaRelease(pl, mark);
660
661 if (serialNumber)
662 CSSM_CL_FreeFieldValue(clHandle, &CSSMOID_X509V1SerialNumber, serialNumber);
663 if (issuer)
664 CSSM_CL_FreeFieldValue(clHandle, &OID_X509V1IssuerNameStd, issuer);
665 if (itemImplRef)
666 CFRelease(itemImplRef);
667 if (certRef)
668 CFRelease(certRef);
669
670 PORT_SetError(SEC_INTERNAL_ONLY);
671 return NULL;
672 }
673
674 // import a collection of certs into the temporary or permanent cert database
675 SECStatus CERT_ImportCerts(SecKeychainRef keychain, SECCertUsage usage, unsigned int ncerts,
676 SECItem **derCerts, SecCertificateRef **retCerts, Boolean keepCerts, Boolean caOnly, char *nickname)
677 {
678 OSStatus rv = SECFailure;
679 SecCertificateRef cert;
680 unsigned int ci;
681
682 // @@@ Do something with caOnly and nickname
683 if (caOnly || nickname)
684 abort();
685
686 for (ci = 0; ci < ncerts; ++ci)
687 {
688 rv = SecCertificateCreateFromData(derCerts[ci], CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &cert);
689 if (rv)
690 break;
691 if (keepCerts)
692 {
693 rv = SecCertificateAddToKeychain(cert, keychain);
694 if (rv)
695 {
696 if (rv == errKCDuplicateItem)
697 rv = noErr;
698 else
699 {
700 CFRelease(cert);
701 break;
702 }
703 }
704 }
705
706 if (retCerts)
707 {
708 // @@@ not yet
709 abort();
710 }
711 else
712 CFRelease(cert);
713 }
714
715 return rv;
716 }
717
718 SECStatus CERT_SaveSMimeProfile(SecCertificateRef cert, SECItem *emailProfile,SECItem *profileTime)
719 {
720 fprintf(stderr, "WARNING: CERT_SaveSMimeProfile unimplemented\n");
721 return SECSuccess;
722 }
723
724 // Check the hostname to make sure that it matches the shexp that
725 // is given in the common name of the certificate.
726 SECStatus CERT_VerifyCertName(SecCertificateRef cert, const char *hostname)
727 {
728 fprintf(stderr, "WARNING: CERT_VerifyCertName unimplemented\n");
729 return SECSuccess;
730 }
731
732 /*
733 ** OLD OBSOLETE FUNCTIONS with enum SECCertUsage - DO NOT USE FOR NEW CODE
734 ** verify a certificate by checking validity times against a certain time,
735 ** that we trust the issuer, and that the signature on the certificate is
736 ** valid.
737 ** "cert" the certificate to verify
738 ** "checkSig" only check signatures if true
739 */
740 SECStatus
741 CERT_VerifyCert(SecKeychainRef keychainOrArray, SecCertificateRef cert,
742 const CSSM_DATA_PTR *otherCerts, /* intermediates */
743 CFTypeRef policies, CFAbsoluteTime stime, SecTrustRef *trustRef)
744 {
745 CFMutableArrayRef certificates = NULL;
746 SecTrustRef trust = NULL;
747 OSStatus rv;
748 int numOtherCerts = SecCmsArrayCount((void **)otherCerts);
749 int dex;
750
751 /*
752 * Certs to evaluate: first the leaf - our cert - then all the rest we know
753 * about. It's OK for otherCerts to contain a copy of the leaf.
754 */
755 certificates = CFArrayCreateMutable(NULL, numOtherCerts + 1, &kCFTypeArrayCallBacks);
756 CFArrayAppendValue(certificates, cert);
757 for(dex=0; dex<numOtherCerts; dex++) {
758 SecCertificateRef intCert;
759
760 rv = SecCertificateCreateFromData(otherCerts[dex],
761 CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
762 &intCert);
763 if(rv) {
764 goto loser;
765 }
766 CFArrayAppendValue(certificates, intCert);
767 CFRelease(intCert);
768 }
769 rv = SecTrustCreateWithCertificates(certificates, policies, &trust);
770 CFRelease(certificates);
771 certificates = NULL;
772 if (rv)
773 goto loser;
774
775 rv = SecTrustSetKeychains(trust, keychainOrArray);
776 if (rv)
777 goto loser;
778
779 CFDateRef verifyDate = CFDateCreate(NULL, stime);
780 rv = SecTrustSetVerifyDate(trust, verifyDate);
781 CFRelease(verifyDate);
782 if (rv)
783 goto loser;
784
785 if (trustRef)
786 {
787 *trustRef = trust;
788 }
789 else
790 {
791 SecTrustResultType result;
792 /* The caller doesn't want a SecTrust object, so let's evaluate it for them. */
793 rv = SecTrustEvaluate(trust, &result);
794 if (rv)
795 goto loser;
796
797 switch (result)
798 {
799 case kSecTrustResultProceed:
800 case kSecTrustResultUnspecified:
801 /* TP Verification succeeded and there was either a UserTurst entry
802 telling us to procceed, or no user trust setting was specified. */
803 CFRelease(trust);
804 break;
805 default:
806 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
807 rv = SECFailure;
808 goto loser;
809 break;
810 }
811 }
812
813 return SECSuccess;
814 loser:
815 #if 0 /* debugging */
816 syslog(LOG_ERR, "CERT_VerifyCert has failed with %d (input policies and output trust follow)",
817 (int)rv);
818 if (policies) CFShow(policies);
819 if (trust) CFShow(trust);
820 #endif
821 if (trust)
822 CFRelease(trust);
823 if(certificates)
824 CFRelease(certificates);
825 return rv;
826 }
827
828 CFTypeRef
829 CERT_PolicyForCertUsage(SECCertUsage certUsage)
830 {
831 SecPolicyRef policy = NULL;
832
833 switch (certUsage)
834 {
835 case certUsageSSLServerWithStepUp:
836 case certUsageSSLCA:
837 case certUsageVerifyCA:
838 case certUsageAnyCA:
839 goto loser;
840 break;
841 case certUsageSSLClient:
842 policy = SecPolicyCreateSSL(false, NULL);
843 break;
844 case certUsageSSLServer:
845 policy = SecPolicyCreateSSL(true, NULL);
846 break;
847 case certUsageStatusResponder:
848 policy = SecPolicyCreateOCSPSigner();
849 break;
850 case certUsageObjectSigner:
851 case certUsageProtectedObjectSigner:
852 case certUsageUserCertImport:
853 case certUsageEmailSigner:
854 case certUsageEmailRecipient:
855 policy = SecPolicyCreateBasicX509();
856 break;
857 default:
858 goto loser;
859 }
860
861 loser:
862 return policy;
863 }