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