]> git.saurik.com Git - apple/security.git/blame - OSX/include/security_smime/cert.c
Security-57336.1.9.tar.gz
[apple/security.git] / OSX / include / security_smime / 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
491CERT_FindIdentityByCertificate (CFTypeRef keychainOrArray, SecCertificateRef certificate)
492{
493 SecIdentityRef identity = NULL;
494 SecIdentityCreateWithCertificate(keychainOrArray, certificate, &identity);
495 if (!identity)
496 PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT);
497
498 return identity;
499}
500
501SecIdentityRef
502CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN)
503{
504 SecCertificateRef certificate = CERT_FindCertByIssuerAndSN(keychainOrArray, NULL, NULL, issuerAndSN);
505 if (!certificate)
506 return NULL;
507
508 return CERT_FindIdentityByCertificate(keychainOrArray, certificate);
509}
510
511SecIdentityRef
512CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray, const SECItem *subjKeyID)
513{
514 SecCertificateRef certificate = CERT_FindCertBySubjectKeyID(keychainOrArray, NULL, subjKeyID);
515 if (!certificate)
516 return NULL;
517
518 return CERT_FindIdentityByCertificate(keychainOrArray, certificate);
519}
520
521// find the smime symmetric capabilities profile for a given cert
522SECItem *CERT_FindSMimeProfile(SecCertificateRef cert)
523{
524 return NULL;
525}
526
527// Return the decoded value of the subjectKeyID extension. The caller should
528// free up the storage allocated in retItem->data.
529SECStatus CERT_FindSubjectKeyIDExtension (SecCertificateRef cert, SECItem *retItem)
530{
531 CSSM_DATA_PTR fieldValue = NULL;
532 OSStatus ortn;
533 CSSM_X509_EXTENSION *extp;
534 CE_SubjectKeyID *skid;
535
536 ortn = SecCertificateCopyFirstFieldValue(cert, &CSSMOID_SubjectKeyIdentifier,
537 &fieldValue);
538 if(ortn || (fieldValue == NULL)) {
539 /* this cert doesn't have that extension */
540 return SECFailure;
541 }
542 extp = (CSSM_X509_EXTENSION *)fieldValue->Data;
543 skid = (CE_SubjectKeyID *)extp->value.parsedValue;
544 retItem->Data = (uint8 *)PORT_Alloc(skid->Length);
545 retItem->Length = skid->Length;
546 memmove(retItem->Data, skid->Data, retItem->Length);
547 SecCertificateReleaseFirstFieldValue(cert, &CSSMOID_SubjectKeyIdentifier,
548 fieldValue);
549 return SECSuccess;
550}
551
552// Extract the issuer and serial number from a certificate
553SecCmsIssuerAndSN *CERT_GetCertIssuerAndSN(PRArenaPool *pl, SecCertificateRef cert)
554{
555 OSStatus status;
556 SecCmsIssuerAndSN *certIssuerAndSN;
5c19dc3a
A
557 SecCertificateRef certRef;
558 SecCertificateRef itemImplRef = NULL;
d8f41ccd
A
559 CSSM_CL_HANDLE clHandle;
560 CSSM_DATA_PTR serialNumber = 0;
561 CSSM_DATA_PTR issuer = 0;
562 CSSM_DATA certData = {};
563 CSSM_HANDLE resultsHandle = 0;
564 uint32 numberOfFields = 0;
565 CSSM_RETURN result;
566 void *mark;
567
568 mark = PORT_ArenaMark(pl);
569
5c19dc3a
A
570 /* Retain input cert and get pointer to its data */
571 certRef = (SecCertificateRef)((cert) ? CFRetain(cert) : NULL);
572 status = SecCertificateGetData(certRef, &certData);
d8f41ccd 573 if (status)
5c19dc3a
A
574 goto loser;
575#if 1
576 // Convert unified input certRef to itemImpl instance.
577 // note: must not release this instance while we're using its CL handle!
578 itemImplRef = SecCertificateCreateItemImplInstance(cert);
579 status = SecCertificateGetCLHandle_legacy(itemImplRef, &clHandle);
580#else
581 status = SecCertificateGetCLHandle(certRef, &clHandle);
582#endif
d8f41ccd 583 if (status)
5c19dc3a 584 goto loser;
d8f41ccd
A
585
586 /* Get the issuer from the cert. */
5c19dc3a
A
587 result = CSSM_CL_CertGetFirstFieldValue(clHandle, &certData,
588 &OID_X509V1IssuerNameStd, &resultsHandle, &numberOfFields, &issuer);
d8f41ccd
A
589
590 if (result || numberOfFields < 1)
5c19dc3a 591 goto loser;
d8f41ccd
A
592 result = CSSM_CL_CertAbortQuery(clHandle, resultsHandle);
593 if (result)
5c19dc3a 594 goto loser;
d8f41ccd
A
595
596 /* Get the serialNumber from the cert. */
5c19dc3a
A
597 result = CSSM_CL_CertGetFirstFieldValue(clHandle, &certData,
598 &CSSMOID_X509V1SerialNumber, &resultsHandle, &numberOfFields, &serialNumber);
d8f41ccd 599 if (result || numberOfFields < 1)
5c19dc3a 600 goto loser;
d8f41ccd
A
601 result = CSSM_CL_CertAbortQuery(clHandle, resultsHandle);
602 if (result)
5c19dc3a 603 goto loser;
d8f41ccd
A
604
605 /* Allocate the SecCmsIssuerAndSN struct. */
606 certIssuerAndSN = (SecCmsIssuerAndSN *)PORT_ArenaZAlloc (pl, sizeof(SecCmsIssuerAndSN));
607 if (certIssuerAndSN == NULL)
5c19dc3a 608 goto loser;
d8f41ccd
A
609
610 /* Copy the issuer. */
611 certIssuerAndSN->derIssuer.Data = (uint8 *) PORT_ArenaAlloc(pl, issuer->Length);
612 if (!certIssuerAndSN->derIssuer.Data)
5c19dc3a 613 goto loser;
d8f41ccd
A
614 PORT_Memcpy(certIssuerAndSN->derIssuer.Data, issuer->Data, issuer->Length);
615 certIssuerAndSN->derIssuer.Length = issuer->Length;
616
617 /* Copy the serialNumber. */
618 certIssuerAndSN->serialNumber.Data = (uint8 *) PORT_ArenaAlloc(pl, serialNumber->Length);
619 if (!certIssuerAndSN->serialNumber.Data)
5c19dc3a 620 goto loser;
d8f41ccd
A
621 PORT_Memcpy(certIssuerAndSN->serialNumber.Data, serialNumber->Data, serialNumber->Length);
622 certIssuerAndSN->serialNumber.Length = serialNumber->Length;
623
624 PORT_ArenaUnmark(pl, mark);
625
626 CSSM_CL_FreeFieldValue(clHandle, &CSSMOID_X509V1SerialNumber, serialNumber);
627 CSSM_CL_FreeFieldValue(clHandle, &OID_X509V1IssuerNameStd, issuer);
628
5c19dc3a
A
629 if (itemImplRef)
630 CFRelease(itemImplRef);
631 if (certRef)
632 CFRelease(certRef);
633
d8f41ccd
A
634 return certIssuerAndSN;
635
636loser:
637 PORT_ArenaRelease(pl, mark);
638
639 if (serialNumber)
5c19dc3a 640 CSSM_CL_FreeFieldValue(clHandle, &CSSMOID_X509V1SerialNumber, serialNumber);
d8f41ccd 641 if (issuer)
5c19dc3a
A
642 CSSM_CL_FreeFieldValue(clHandle, &OID_X509V1IssuerNameStd, issuer);
643 if (itemImplRef)
644 CFRelease(itemImplRef);
645 if (certRef)
646 CFRelease(certRef);
d8f41ccd
A
647
648 PORT_SetError(SEC_INTERNAL_ONLY);
649 return NULL;
650}
651
652// import a collection of certs into the temporary or permanent cert database
653SECStatus CERT_ImportCerts(SecKeychainRef keychain, SECCertUsage usage, unsigned int ncerts,
654 SECItem **derCerts, SecCertificateRef **retCerts, Boolean keepCerts, Boolean caOnly, char *nickname)
655{
656 OSStatus rv = SECFailure;
657 SecCertificateRef cert;
658 unsigned int ci;
659
660 // @@@ Do something with caOnly and nickname
661 if (caOnly || nickname)
662 abort();
663
664 for (ci = 0; ci < ncerts; ++ci)
665 {
666 rv = SecCertificateCreateFromData(derCerts[ci], CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &cert);
667 if (rv)
668 break;
669 if (keepCerts)
670 {
671 rv = SecCertificateAddToKeychain(cert, keychain);
672 if (rv)
673 {
674 if (rv == errKCDuplicateItem)
675 rv = noErr;
676 else
677 {
678 CFRelease(cert);
679 break;
680 }
681 }
682 }
683
684 if (retCerts)
685 {
686 // @@@ not yet
687 abort();
688 }
689 else
690 CFRelease(cert);
691 }
692
693 return rv;
694}
695
696SECStatus CERT_SaveSMimeProfile(SecCertificateRef cert, SECItem *emailProfile,SECItem *profileTime)
697{
698 fprintf(stderr, "WARNING: CERT_SaveSMimeProfile unimplemented\n");
699 return SECSuccess;
700}
701
702// Check the hostname to make sure that it matches the shexp that
703// is given in the common name of the certificate.
704SECStatus CERT_VerifyCertName(SecCertificateRef cert, const char *hostname)
705{
706 fprintf(stderr, "WARNING: CERT_VerifyCertName unimplemented\n");
707 return SECSuccess;
708}
709
710/*
711** OLD OBSOLETE FUNCTIONS with enum SECCertUsage - DO NOT USE FOR NEW CODE
712** verify a certificate by checking validity times against a certain time,
713** that we trust the issuer, and that the signature on the certificate is
714** valid.
715** "cert" the certificate to verify
716** "checkSig" only check signatures if true
717*/
718SECStatus
719CERT_VerifyCert(SecKeychainRef keychainOrArray, SecCertificateRef cert,
720 const CSSM_DATA_PTR *otherCerts, /* intermediates */
721 CFTypeRef policies, CFAbsoluteTime stime, SecTrustRef *trustRef)
722{
723 CFMutableArrayRef certificates = NULL;
724 SecTrustRef trust = NULL;
725 OSStatus rv;
726 int numOtherCerts = SecCmsArrayCount((void **)otherCerts);
727 int dex;
728
729 /*
730 * Certs to evaluate: first the leaf - our cert - then all the rest we know
731 * about. It's OK for otherCerts to contain a copy of the leaf.
732 */
733 certificates = CFArrayCreateMutable(NULL, numOtherCerts + 1, &kCFTypeArrayCallBacks);
734 CFArrayAppendValue(certificates, cert);
735 for(dex=0; dex<numOtherCerts; dex++) {
736 SecCertificateRef intCert;
737
738 rv = SecCertificateCreateFromData(otherCerts[dex],
739 CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER,
740 &intCert);
741 if(rv) {
742 goto loser;
743 }
744 CFArrayAppendValue(certificates, intCert);
745 CFRelease(intCert);
746 }
747 rv = SecTrustCreateWithCertificates(certificates, policies, &trust);
748 CFRelease(certificates);
749 certificates = NULL;
750 if (rv)
751 goto loser;
752
753 rv = SecTrustSetKeychains(trust, keychainOrArray);
754 if (rv)
755 goto loser;
756
757 CFDateRef verifyDate = CFDateCreate(NULL, stime);
758 rv = SecTrustSetVerifyDate(trust, verifyDate);
759 CFRelease(verifyDate);
760 if (rv)
761 goto loser;
762
763 if (trustRef)
764 {
765 *trustRef = trust;
766 }
767 else
768 {
769 SecTrustResultType result;
770 /* The caller doesn't want a SecTrust object, so let's evaluate it for them. */
771 rv = SecTrustEvaluate(trust, &result);
772 if (rv)
773 goto loser;
774
775 switch (result)
776 {
777 case kSecTrustResultProceed:
778 case kSecTrustResultUnspecified:
779 /* TP Verification succeeded and there was either a UserTurst entry
780 telling us to procceed, or no user trust setting was specified. */
781 CFRelease(trust);
782 break;
783 default:
784 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
785 rv = SECFailure;
786 goto loser;
787 break;
788 }
789 }
790
791 return SECSuccess;
792loser:
5c19dc3a
A
793#if 0 /* debugging */
794 syslog(LOG_ERR, "CERT_VerifyCert has failed with %d (input policies and output trust follow)",
795 (int)rv);
796 if (policies) CFShow(policies);
797 if (trust) CFShow(trust);
798#endif
d8f41ccd
A
799 if (trust)
800 CFRelease(trust);
801 if(certificates)
802 CFRelease(certificates);
803 return rv;
804}
805
806CFTypeRef
807CERT_PolicyForCertUsage(SECCertUsage certUsage)
808{
809 SecPolicySearchRef search = NULL;
810 SecPolicyRef policy = NULL;
811 const CSSM_OID *policyOID;
812 OSStatus rv;
813
814 switch (certUsage)
815 {
816 case certUsageSSLServerWithStepUp:
817 case certUsageSSLCA:
818 case certUsageVerifyCA:
819 case certUsageAnyCA:
820 goto loser;
821 break;
822 case certUsageSSLClient:
823 case certUsageSSLServer:
824 policyOID = &CSSMOID_APPLE_TP_SSL;
825 break;
826 case certUsageUserCertImport:
827 policyOID = &CSSMOID_APPLE_TP_CSR_GEN;
828 break;
829 case certUsageStatusResponder:
830 policyOID = &CSSMOID_APPLE_TP_REVOCATION_OCSP;
831 break;
832 case certUsageObjectSigner:
833 case certUsageProtectedObjectSigner:
834 policyOID = &CSSMOID_APPLE_ISIGN;
835 break;
836 case certUsageEmailSigner:
837 case certUsageEmailRecipient:
838 policyOID = &CSSMOID_APPLE_X509_BASIC;
839 break;
840 default:
841 goto loser;
842 }
843 rv = SecPolicySearchCreate(CSSM_CERT_X_509v3, policyOID, NULL, &search);
844 if (rv)
845 goto loser;
846
847 rv = SecPolicySearchCopyNext(search, &policy);
848 if (rv)
849 goto loser;
850
851loser:
852 if(search) CFRelease(search);
853 return policy;
854}