]> git.saurik.com Git - apple/security.git/blame - OSX/libsecurity_smime/lib/cert.c
Security-57740.60.18.tar.gz
[apple/security.git] / OSX / libsecurity_smime / lib / cert.c
CommitLineData
d8f41ccd
A
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>
5c19dc3a 42#include <syslog.h>
d8f41ccd
A
43
44/* for errKCDuplicateItem */
45#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
46
47#define CERT_DEBUG 0
48#if CERT_DEBUG
5c19dc3a 49#define dprintf(args...) fprintf(stderr, args)
d8f41ccd
A
50#else
51#define dprintf(args...)
52#endif
53
54/* @@@ Remove this once it's back in the appropriate header. */
55static const uint8 X509V1IssuerNameStd[] = {INTEL_X509V3_CERT_R08, 23};
56static 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 */
63static void
64CERT_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 */
116void
117CERT_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
143SecCertificateRef 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
150SecPublicKeyRef SECKEY_CopyPublicKey(SecPublicKeyRef pubKey)
151{
152 CFRetain(pubKey);
153 return pubKey;
154}
155
156void SECKEY_DestroyPublicKey(SecPublicKeyRef pubKey)
157{
158 CFRelease(pubKey);
159}
160
161SecPublicKeyRef SECKEY_CopyPrivateKey(SecPublicKeyRef privKey)
162{
163 CFRetain(privKey);
164 return privKey;
165}
166
167void SECKEY_DestroyPrivateKey(SecPublicKeyRef privKey)
168{
169 CFRelease(privKey);
170}
171
172void CERT_DestroyCertificate(SecCertificateRef cert)
173{
174 CFRelease(cert);
175}
176
177SecCertificateRef CERT_DupCertificate(SecCertificateRef cert)
178{
179 CFRetain(cert);
180 return cert;
181}
182
183SecIdentityRef 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
197SecCertificateRef 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
5c19dc3a
A
208 attrs[0].tag = kSecLabelItemAttr;
209 attrs[0].length = strlen(nickname)+1;
210 attrs[0].data = nickname;
d8f41ccd 211#else
5c19dc3a
A
212 attrs[0].tag = kSecSerialNumberItemAttr;
213 attrs[0].length = (UInt32)strlen(serialNumber)+1;
214 attrs[0].data = (uint8 *)serialNumber;
d8f41ccd
A
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/*
232startNewClass(X509Certificate)
233CertType, kSecCertTypeItemAttr, "CertType", 0, NULL, UINT32)
234CertEncoding, kSecCertEncodingItemAttr, "CertEncoding", 0, NULL, UINT32)
235PrintName, kSecLabelItemAttr, "PrintName", 0, NULL, BLOB)
236Alias, kSecAlias, "Alias", 0, NULL, BLOB)
237Subject, kSecSubjectItemAttr, "Subject", 0, NULL, BLOB)
238Issuer, kSecIssuerItemAttr, "Issuer", 0, NULL, BLOB)
239SerialNumber, kSecSerialNumberItemAttr, "SerialNumber", 0, NULL, BLOB)
240SubjectKeyIdentifier, kSecSubjectKeyIdentifierItemAttr, "SubjectKeyIdentifier", 0, NULL, BLOB)
241PublicKeyHash, kSecPublicKeyHashItemAttr, "PublicKeyHash", 0, NULL, BLOB)
242endNewClass()
243*/
244
245CFArrayRef 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
305loser:
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
325CFArrayRef CERT_CertListFromCert(SecCertificateRef cert)
326{
327 const void *value = cert;
328 return cert ? CFArrayCreate(NULL, &value, 1, &kCFTypeArrayCallBacks) : NULL;
329}
330
331CFArrayRef CERT_DupCertList(CFArrayRef oldList)
332{
333 CFRetain(oldList);
334 return oldList;
335}
336
337// Extract a public key object from a SubjectPublicKeyInfo
338SecPublicKeyRef CERT_ExtractPublicKey(SecCertificateRef cert)
339{
340 SecPublicKeyRef keyRef = NULL;
341 SecCertificateCopyPublicKey(cert,&keyRef);
342 return keyRef;
343}
344
345SECStatus 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
354SecCertificateRef 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
362SecCertificateRef 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
379static 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
397SecCertificateRef 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
445SecCertificateRef 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
490static SecIdentityRef
6b200bc3 491CERT_FindIdentityByCertificate (CFTypeRef keychainOrArray, SecCertificateRef CF_CONSUMED certificate)
d8f41ccd
A
492{
493 SecIdentityRef identity = NULL;
494 SecIdentityCreateWithCertificate(keychainOrArray, certificate, &identity);
495 if (!identity)
496 PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT);
6b200bc3
A
497 if (certificate) {
498 CFRelease(certificate);
499 }
d8f41ccd
A
500
501 return identity;
502}
503
504SecIdentityRef
505CERT_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
514SecIdentityRef
515CERT_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
525SECItem *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.
532SECStatus 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
556SecCmsIssuerAndSN *CERT_GetCertIssuerAndSN(PRArenaPool *pl, SecCertificateRef cert)
557{
558 OSStatus status;
559 SecCmsIssuerAndSN *certIssuerAndSN;
5c19dc3a
A
560 SecCertificateRef certRef;
561 SecCertificateRef itemImplRef = NULL;
d8f41ccd
A
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
5c19dc3a
A
573 /* Retain input cert and get pointer to its data */
574 certRef = (SecCertificateRef)((cert) ? CFRetain(cert) : NULL);
575 status = SecCertificateGetData(certRef, &certData);
d8f41ccd 576 if (status)
5c19dc3a
A
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
d8f41ccd 586 if (status)
5c19dc3a 587 goto loser;
d8f41ccd
A
588
589 /* Get the issuer from the cert. */
5c19dc3a
A
590 result = CSSM_CL_CertGetFirstFieldValue(clHandle, &certData,
591 &OID_X509V1IssuerNameStd, &resultsHandle, &numberOfFields, &issuer);
d8f41ccd
A
592
593 if (result || numberOfFields < 1)
5c19dc3a 594 goto loser;
d8f41ccd
A
595 result = CSSM_CL_CertAbortQuery(clHandle, resultsHandle);
596 if (result)
5c19dc3a 597 goto loser;
d8f41ccd
A
598
599 /* Get the serialNumber from the cert. */
5c19dc3a
A
600 result = CSSM_CL_CertGetFirstFieldValue(clHandle, &certData,
601 &CSSMOID_X509V1SerialNumber, &resultsHandle, &numberOfFields, &serialNumber);
d8f41ccd 602 if (result || numberOfFields < 1)
5c19dc3a 603 goto loser;
d8f41ccd
A
604 result = CSSM_CL_CertAbortQuery(clHandle, resultsHandle);
605 if (result)
5c19dc3a 606 goto loser;
d8f41ccd
A
607
608 /* Allocate the SecCmsIssuerAndSN struct. */
609 certIssuerAndSN = (SecCmsIssuerAndSN *)PORT_ArenaZAlloc (pl, sizeof(SecCmsIssuerAndSN));
610 if (certIssuerAndSN == NULL)
5c19dc3a 611 goto loser;
d8f41ccd
A
612
613 /* Copy the issuer. */
614 certIssuerAndSN->derIssuer.Data = (uint8 *) PORT_ArenaAlloc(pl, issuer->Length);
615 if (!certIssuerAndSN->derIssuer.Data)
5c19dc3a 616 goto loser;
d8f41ccd
A
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)
5c19dc3a 623 goto loser;
d8f41ccd
A
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
5c19dc3a
A
632 if (itemImplRef)
633 CFRelease(itemImplRef);
634 if (certRef)
635 CFRelease(certRef);
636
d8f41ccd
A
637 return certIssuerAndSN;
638
639loser:
640 PORT_ArenaRelease(pl, mark);
641
642 if (serialNumber)
5c19dc3a 643 CSSM_CL_FreeFieldValue(clHandle, &CSSMOID_X509V1SerialNumber, serialNumber);
d8f41ccd 644 if (issuer)
5c19dc3a
A
645 CSSM_CL_FreeFieldValue(clHandle, &OID_X509V1IssuerNameStd, issuer);
646 if (itemImplRef)
647 CFRelease(itemImplRef);
648 if (certRef)
649 CFRelease(certRef);
d8f41ccd
A
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
656SECStatus 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
699SECStatus 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.
707SECStatus 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*/
721SECStatus
722CERT_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;
795loser:
5c19dc3a
A
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
d8f41ccd
A
802 if (trust)
803 CFRelease(trust);
804 if(certificates)
805 CFRelease(certificates);
806 return rv;
807}
808
809CFTypeRef
810CERT_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
854loser:
855 if(search) CFRelease(search);
856 return policy;
857}