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