5 * Created by john on Wed Mar 12 2003.
6 * Copyright (c) 2003 __MyCompanyName__. All rights reserved.
12 #include <security_asn1/secerr.h>
13 #include <Security/SecKeychain.h>
14 #include <Security/SecKeychainItem.h>
15 #include <Security/SecKeychainSearch.h>
16 #include <Security/SecIdentityPriv.h>
17 #include <Security/SecIdentitySearch.h>
18 #include <Security/SecCertificatePriv.h>
19 #include <Security/SecPolicySearch.h>
20 #include <Security/oidsalg.h>
21 #include <Security/cssmapi.h>
22 #include <Security/oidscert.h>
23 #include <Security/oidscert.h>
25 /* for errKCDuplicateItem */
26 #include <Security/SecBase.h>
28 /* @@@ Remove this once it's back in the appropriate header. */
29 static const uint8 X509V1IssuerNameStd
[] = {INTEL_X509V3_CERT_R08
, 23};
30 static const CSSM_OID OID_X509V1IssuerNameStd
= {INTEL_X509V3_CERT_R08_LENGTH
+1, (uint8
*)X509V1IssuerNameStd
};
33 * Normalize a Printable String. Per RFC2459 (4.1.2.4), printable strings are case
34 * insensitive and we're supposed to ignore leading and trailing
35 * whitespace, and collapse multiple whitespace characters into one.
38 CERT_NormalizeString(CSSM_DATA_PTR string
)
40 char *pD
, *pCh
, *pEos
;
45 pD
= pCh
= (char *)string
->Data
;
46 pEos
= pCh
+ string
->Length
- 1;
48 /* Strip trailing NULL terminators */
52 /* Remove trailing spaces */
56 /* Point to one past last non-space character */
59 /* skip all leading whitespace */
60 while(isspace(*pCh
) && (pCh
< pEos
))
63 /* Eliminate multiple whitespace and convent to upper case.
64 * pCh points to first non-white char.
65 * pD still points to start of string. */
72 /* skip 'til next nonwhite */
73 while(isspace(*pCh
) && (pCh
< pEos
))
78 string
->Length
= pD
- (char *)string
->Data
;
82 * Normalize an RDN. Per RFC2459 (4.1.2.4), printable strings are case
83 * insensitive and we're supposed to ignore leading and trailing
84 * whitespace, and collapse multiple whitespace characters into one.
86 * Incoming NSS_Name is assumed to be entirely within specifed coder's
87 * address space; we'll be munging some of that and possibly replacing
88 * some pointers with others allocated from the same space.
91 CERT_NormalizeX509NameNSS(NSS_Name
*nssName
)
95 for (rdn
= *nssName
->rdns
; rdn
; ++rdn
)
98 for (attr
= *rdn
->atvs
; attr
; ++attr
)
101 * attr->value is an ASN_ANY containing an encoded
102 * string. We only normalize Prinatable String types.
103 * If we find one, decode it, normalize it, encode the
104 * result, and put the encoding back in attr->value.
105 * We temporarily "leak" the original string, which only
106 * has a lifetime of the incoming SecNssCoder.
108 NSS_TaggedItem
*attrVal
= &attr
->value
;
109 if(attrVal
->tag
!= SEC_ASN1_PRINTABLE_STRING
)
112 CERT_NormalizeString(&attrVal
->item
);
117 SecCertificateRef
CERT_FindCertByNicknameOrEmailAddr(SecKeychainRef keychainOrArray
, char *name
)
119 SecCertificateRef certificate
;
120 OSStatus status
=SecCertificateFindByEmail(keychainOrArray
,name
,&certificate
);
121 return status
==errSecSuccess
?certificate
:NULL
;
124 SecPublicKeyRef
SECKEY_CopyPublicKey(SecPublicKeyRef pubKey
)
130 void SECKEY_DestroyPublicKey(SecPublicKeyRef pubKey
)
135 SecPublicKeyRef
SECKEY_CopyPrivateKey(SecPublicKeyRef privKey
)
141 void SECKEY_DestroyPrivateKey(SecPublicKeyRef privKey
)
146 void CERT_DestroyCertificate(SecCertificateRef cert
)
151 SecCertificateRef
CERT_DupCertificate(SecCertificateRef cert
)
157 SecIdentityRef
CERT_FindIdentityByUsage(SecKeychainRef keychainOrArray
,
158 char *nickname
, SECCertUsage usage
, Boolean validOnly
, void *proto_win
)
160 SecIdentityRef identityRef
= NULL
;
161 SecCertificateRef cert
= CERT_FindCertByNicknameOrEmailAddr(keychainOrArray
, nickname
);
165 SecIdentityCreateWithCertificate(keychainOrArray
, cert
, &identityRef
);
171 SecCertificateRef
CERT_FindUserCertByUsage(SecKeychainRef keychainOrArray
,
172 char *nickname
,SECCertUsage usage
,Boolean validOnly
,void *proto_win
)
174 SecItemClass itemClass
= kSecCertificateItemClass
;
175 SecKeychainSearchRef searchRef
;
176 SecKeychainItemRef itemRef
= NULL
;
178 SecKeychainAttribute attrs
[1];
179 const char *serialNumber
= "12345678";
180 // const SecKeychainAttributeList attrList;
182 attrs
[0].tag
= kSecLabelItemAttr
;
183 attrs
[0].length
= strlen(nickname
)+1;
184 attrs
[0].data
= nickname
;
186 attrs
[0].tag
= kSecSerialNumberItemAttr
;
187 attrs
[0].length
= strlen(serialNumber
)+1;
188 attrs
[0].data
= (uint8
*)serialNumber
;
190 SecKeychainAttributeList attrList
= { 0, attrs
};
192 status
= SecKeychainSearchCreateFromAttributes(keychainOrArray
,itemClass
,&attrList
,&searchRef
);
195 printf("CERT_FindUserCertByUsage: SecKeychainSearchCreateFromAttributes:%ld",status
);
198 status
= SecKeychainSearchCopyNext(searchRef
,&itemRef
);
200 printf("CERT_FindUserCertByUsage: SecKeychainSearchCopyNext:%ld",status
);
201 CFRelease(searchRef
);
202 return (SecCertificateRef
)itemRef
;
206 startNewClass(X509Certificate)
207 CertType, kSecCertTypeItemAttr, "CertType", 0, NULL, UINT32)
208 CertEncoding, kSecCertEncodingItemAttr, "CertEncoding", 0, NULL, UINT32)
209 PrintName, kSecLabelItemAttr, "PrintName", 0, NULL, BLOB)
210 Alias, kSecAliasItemAttr, "Alias", 0, NULL, BLOB)
211 Subject, kSecSubjectItemAttr, "Subject", 0, NULL, BLOB)
212 Issuer, kSecIssuerItemAttr, "Issuer", 0, NULL, BLOB)
213 SerialNumber, kSecSerialNumberItemAttr, "SerialNumber", 0, NULL, BLOB)
214 SubjectKeyIdentifier, kSecSubjectKeyIdentifierItemAttr, "SubjectKeyIdentifier", 0, NULL, BLOB)
215 PublicKeyHash, kSecPublicKeyHashItemAttr, "PublicKeyHash", 0, NULL, BLOB)
219 CFArrayRef
CERT_CertChainFromCert(SecCertificateRef cert
, SECCertUsage usage
, Boolean includeRoot
)
221 SecPolicySearchRef searchRef
= NULL
;
222 SecPolicyRef policy
= NULL
;
223 CFArrayRef wrappedCert
= NULL
;
224 SecTrustRef trust
= NULL
;
225 CFArrayRef certChain
= NULL
;
226 CSSM_TP_APPLE_EVIDENCE_INFO
*statusChain
;
228 SecTrustResultType trustResult
= kSecTrustResultInvalid
;
233 status
= SecPolicySearchCreate(CSSM_CERT_X_509v3
, &CSSMOID_APPLE_X509_BASIC
, NULL
, &searchRef
);
236 status
= SecPolicySearchCopyNext(searchRef
, &policy
);
240 wrappedCert
= CERT_CertListFromCert(cert
);
241 status
= SecTrustCreateWithCertificates(wrappedCert
, policy
, &trust
);
245 status
= SecTrustEvaluate(trust
, &trustResult
);
249 status
= SecTrustGetResult(trust
, NULL
, &certChain
, &statusChain
);
253 /* We don't drop the root if there is only 1 (self signed) certificate in the chain. */
254 if (!includeRoot
&& CFArrayGetCount(certChain
) > 1)
256 CFMutableArrayRef subChain
= CFArrayCreateMutableCopy(NULL
, 0, certChain
);
257 CFRelease(certChain
);
258 certChain
= subChain
;
260 CFArrayRemoveValueAtIndex(subChain
, CFArrayGetCount(subChain
) - 1);
265 CFRelease(searchRef
);
269 CFRelease(wrappedCert
);
272 if (certChain
&& status
)
274 CFRelease(certChain
);
281 CFArrayRef
CERT_CertListFromCert(SecCertificateRef cert
)
283 const void *value
= cert
;
284 return cert
? CFArrayCreate(NULL
, &value
, 1, &kCFTypeArrayCallBacks
) : NULL
;
287 CFArrayRef
CERT_DupCertList(CFArrayRef oldList
)
293 // Extract a public key object from a SubjectPublicKeyInfo
294 SecPublicKeyRef
CERT_ExtractPublicKey(SecCertificateRef cert
)
296 SecPublicKeyRef keyRef
= NULL
;
297 SecCertificateCopyPublicKey(cert
,&keyRef
);
301 SECStatus
CERT_CheckCertUsage (SecCertificateRef cert
,unsigned char usage
)
304 // @@@ It's all good, it's ok.
308 // Find a certificate in the database by a email address
309 // "emailAddr" is the email address to look up
310 SecCertificateRef
CERT_FindCertByEmailAddr(SecKeychainRef keychainOrArray
, char *emailAddr
)
316 // Find a certificate in the database by a DER encoded certificate
317 // "derCert" is the DER encoded certificate
318 SecCertificateRef
CERT_FindCertByDERCert(SecKeychainRef keychainOrArray
, const SECItem
*derCert
)
320 // @@@ Technically this should look though keychainOrArray for a cert matching this one I guess.
321 SecCertificateRef cert
= NULL
;
324 rv
= SecCertificateCreateFromData(derCert
, CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
, &cert
);
327 PORT_SetError(SEC_ERROR_NO_EMAIL_CERT
);
335 // Generate a certificate key from the issuer and serialnumber, then look it up in the database.
336 // Return the cert if found. "issuerAndSN" is the issuer and serial number to look for
337 SecCertificateRef
CERT_FindCertByIssuerAndSN (CFTypeRef keychainOrArray
, const SecCmsIssuerAndSN
*issuerAndSN
)
339 SecCertificateRef certificate
;
340 OSStatus status
= SecCertificateFindByIssuerAndSN(keychainOrArray
, &issuerAndSN
->derIssuer
,
341 &issuerAndSN
->serialNumber
, &certificate
);
344 PORT_SetError(SEC_ERROR_NO_EMAIL_CERT
);
351 SecCertificateRef
CERT_FindCertBySubjectKeyID (CFTypeRef keychainOrArray
, const SecAsn1Item
*subjKeyID
)
353 SecCertificateRef certificate
;
354 OSStatus status
= SecCertificateFindBySubjectKeyID(keychainOrArray
,subjKeyID
,&certificate
);
357 PORT_SetError(SEC_ERROR_NO_EMAIL_CERT
);
364 static SecIdentityRef
365 CERT_FindIdentityByCertificate (CFTypeRef keychainOrArray
, SecCertificateRef certificate
)
367 SecIdentityRef identity
= NULL
;
368 SecIdentityCreateWithCertificate(keychainOrArray
, certificate
, &identity
);
370 PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT
);
376 CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray
, const SecCmsIssuerAndSN
*issuerAndSN
)
378 SecCertificateRef certificate
= CERT_FindCertByIssuerAndSN(keychainOrArray
, issuerAndSN
);
382 return CERT_FindIdentityByCertificate(keychainOrArray
, certificate
);
386 CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray
, const SECItem
*subjKeyID
)
388 SecCertificateRef certificate
= CERT_FindCertBySubjectKeyID(keychainOrArray
, subjKeyID
);
392 return CERT_FindIdentityByCertificate(keychainOrArray
, certificate
);
395 // find the smime symmetric capabilities profile for a given cert
396 SECItem
*CERT_FindSMimeProfile(SecCertificateRef cert
)
401 // Return the decoded value of the subjectKeyID extension. The caller should
402 // free up the storage allocated in retItem->data.
403 SECStatus
CERT_FindSubjectKeyIDExtension (SecCertificateRef cert
,SECItem
*retItem
)
405 fprintf(stderr
, "WARNING: CERT_FindSubjectKeyIDExtension unimplemented\n");
409 static void * appMalloc (uint32 size
, void *allocRef
) {
410 return (malloc (size
));
413 static void appFree (void *mem_ptr
, void *allocRef
) {
418 static void * appRealloc (void *ptr
, uint32 size
, void *allocRef
) {
419 return (realloc (ptr
, size
));
422 static void * appCalloc (uint32 num
, uint32 size
, void *allocRef
) {
423 return (calloc (num
, size
));
426 static CSSM_API_MEMORY_FUNCS memFuncs
= {
434 // return a valid CL handle
435 static int InitializeCL (CSSM_CL_HANDLE
*clHandle
)
437 CSSM_VERSION version
= {2, 0};
440 CSSM_RETURN result
= CSSM_ModuleLoad (&gGuidAppleX509CL
, CSSM_KEY_HIERARCHY_NONE
, NULL
, NULL
);
446 result
= CSSM_ModuleAttach (&gGuidAppleX509CL
, &version
, &memFuncs
, 0, CSSM_SERVICE_CL
, 0, 0, NULL
, 0, NULL
, clHandle
);
455 // cleanup a CL handle
456 static void CloseCL (CSSM_CL_HANDLE clHandle
)
458 CSSM_ModuleDetach (clHandle
);
459 CSSM_ModuleUnload (&gGuidAppleX509CL
, NULL
, NULL
);
462 // Extract the issuer and serial number from a certificate
463 SecCmsIssuerAndSN
*CERT_GetCertIssuerAndSN(PRArenaPool
*pl
, SecCertificateRef cert
)
466 SecCmsIssuerAndSN
*certIssuerAndSN
;
467 CSSM_CL_HANDLE clHandle
;
468 CSSM_DATA_PTR serialNumber
= 0;
469 CSSM_DATA_PTR issuer
= 0;
470 CSSM_DATA certData
= {};
471 CSSM_HANDLE resultsHandle
= 0;
472 uint32 numberOfFields
= 0;
476 mark
= PORT_ArenaMark(pl
);
478 if (!InitializeCL (&clHandle
))
480 status
= SecCertificateGetData(cert
, &certData
);
484 /* Get the issuer from the cert. */
485 result
= CSSM_CL_CertGetFirstFieldValue(clHandle
, &certData
, &OID_X509V1IssuerNameStd
, &resultsHandle
, &numberOfFields
, &issuer
);
487 /* @@@ Remove this once we are sure CSSMOID_X509V1IssuerNameStd is working. */
488 /* Fall back on old normalized issuer if the new oid isn't supported yet. */
490 result
= CSSM_CL_CertGetFirstFieldValue(clHandle
, &certData
, &CSSMOID_X509V1IssuerName
, &resultsHandle
, &numberOfFields
, &issuer
);
492 if (result
|| numberOfFields
< 1)
494 result
= CSSM_CL_CertAbortQuery(clHandle
, resultsHandle
);
499 /* Get the serialNumber from the cert. */
500 result
= CSSM_CL_CertGetFirstFieldValue(clHandle
, &certData
, &CSSMOID_X509V1SerialNumber
, &resultsHandle
, &numberOfFields
, &serialNumber
);
501 if (result
|| numberOfFields
< 1)
503 result
= CSSM_CL_CertAbortQuery(clHandle
, resultsHandle
);
507 /* Allocate the SecCmsIssuerAndSN struct. */
508 certIssuerAndSN
= (SecCmsIssuerAndSN
*)PORT_ArenaZAlloc (pl
, sizeof(SecCmsIssuerAndSN
));
509 if (certIssuerAndSN
== NULL
)
512 /* Copy the issuer. */
513 certIssuerAndSN
->derIssuer
.Data
= (uint8
*) PORT_ArenaAlloc(pl
, issuer
->Length
);
514 if (!certIssuerAndSN
->derIssuer
.Data
)
516 PORT_Memcpy(certIssuerAndSN
->derIssuer
.Data
, issuer
->Data
, issuer
->Length
);
517 certIssuerAndSN
->derIssuer
.Length
= issuer
->Length
;
519 /* Copy the serialNumber. */
520 certIssuerAndSN
->serialNumber
.Data
= (uint8
*) PORT_ArenaAlloc(pl
, serialNumber
->Length
);
521 if (!certIssuerAndSN
->serialNumber
.Data
)
523 PORT_Memcpy(certIssuerAndSN
->serialNumber
.Data
, serialNumber
->Data
, serialNumber
->Length
);
524 certIssuerAndSN
->serialNumber
.Length
= serialNumber
->Length
;
526 PORT_ArenaUnmark(pl
, mark
);
528 CSSM_CL_FreeFieldValue(clHandle
, &CSSMOID_X509V1SerialNumber
, serialNumber
);
529 CSSM_CL_FreeFieldValue(clHandle
, &OID_X509V1IssuerNameStd
, issuer
);
533 return certIssuerAndSN
;
536 PORT_ArenaRelease(pl
, mark
);
539 CSSM_CL_FreeFieldValue(clHandle
, &CSSMOID_X509V1SerialNumber
, serialNumber
);
541 CSSM_CL_FreeFieldValue(clHandle
, &OID_X509V1IssuerNameStd
, issuer
);
545 PORT_SetError(SEC_INTERNAL_ONLY
);
549 // import a collection of certs into the temporary or permanent cert database
550 SECStatus
CERT_ImportCerts(SecKeychainRef keychain
, SECCertUsage usage
, unsigned int ncerts
,
551 SECItem
**derCerts
, SecCertificateRef
**retCerts
, Boolean keepCerts
, Boolean caOnly
, char *nickname
)
553 OSStatus rv
= SECFailure
;
554 SecCertificateRef cert
;
557 // @@@ Do something with caOnly and nickname
558 if (caOnly
|| nickname
)
561 for (ci
= 0; ci
< ncerts
; ++ci
)
563 rv
= SecCertificateCreateFromData(derCerts
[ci
], CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
, &cert
);
568 rv
= SecCertificateAddToKeychain(cert
, keychain
);
571 if (rv
== errKCDuplicateItem
)
593 SECStatus
CERT_SaveSMimeProfile(SecCertificateRef cert
, SECItem
*emailProfile
,SECItem
*profileTime
)
595 fprintf(stderr
, "WARNING: CERT_SaveSMimeProfile unimplemented\n");
599 // Check the hostname to make sure that it matches the shexp that
600 // is given in the common name of the certificate.
601 SECStatus
CERT_VerifyCertName(SecCertificateRef cert
, const char *hostname
)
603 fprintf(stderr
, "WARNING: CERT_VerifyCertName unimplemented\n");
608 ** OLD OBSOLETE FUNCTIONS with enum SECCertUsage - DO NOT USE FOR NEW CODE
609 ** verify a certificate by checking validity times against a certain time,
610 ** that we trust the issuer, and that the signature on the certificate is
612 ** "cert" the certificate to verify
613 ** "checkSig" only check signatures if true
616 CERT_VerifyCert(SecKeychainRef keychainOrArray
, SecCertificateRef cert
,
617 CFTypeRef policies
, CFAbsoluteTime stime
, SecTrustRef
*trustRef
)
619 CFArrayRef certificates
;
620 const void *certs
= cert
;
621 SecTrustRef trust
= NULL
;
624 certificates
= CFArrayCreate(NULL
, &certs
, 1, &kCFTypeArrayCallBacks
);
625 rv
= SecTrustCreateWithCertificates(certificates
, policies
, &trust
);
626 CFRelease(certificates
);
630 rv
= SecTrustSetKeychains(trust
, keychainOrArray
);
634 CFDateRef verifyDate
= CFDateCreate(NULL
, stime
);
635 rv
= SecTrustSetVerifyDate(trust
, verifyDate
);
636 CFRelease(verifyDate
);
646 SecTrustResultType result
;
647 /* The caller doesn't want a SecTrust object, so let's evaluate it for them. */
648 rv
= SecTrustEvaluate(trust
, &result
);
654 case kSecTrustResultProceed
:
655 case kSecTrustResultUnspecified
:
656 /* TP Verification succeeded and there was either a UserTurst entry
657 telling us to procceed, or no user trust setting was specified. */
661 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT
);
677 CERT_PolicyForCertUsage(SECCertUsage certUsage
)
679 SecPolicySearchRef search
;
680 SecPolicyRef policy
= NULL
;
681 const CSSM_OID
*policyOID
;
686 case certUsageSSLServerWithStepUp
:
688 case certUsageVerifyCA
:
692 case certUsageSSLClient
:
693 case certUsageSSLServer
:
694 policyOID
= &CSSMOID_APPLE_TP_SSL
;
696 case certUsageUserCertImport
:
697 policyOID
= &CSSMOID_APPLE_TP_CSR_GEN
;
699 case certUsageStatusResponder
:
700 policyOID
= &CSSMOID_APPLE_TP_REVOCATION_OCSP
;
702 case certUsageObjectSigner
:
703 case certUsageProtectedObjectSigner
:
704 policyOID
= &CSSMOID_APPLE_ISIGN
;
706 case certUsageEmailSigner
:
707 case certUsageEmailRecipient
:
708 policyOID
= &CSSMOID_APPLE_X509_BASIC
;
713 rv
= SecPolicySearchCreate(CSSM_CERT_X_509v3
, policyOID
, NULL
, &search
);
717 rv
= SecPolicySearchCopyNext(search
, &policy
);