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
[1].tag
= kSecLabelItemAttr
;
183 attrs
[1].length
= strlen(nickname
)+1;
184 attrs
[1].data
= nickname
;
186 attrs
[1].tag
= kSecSerialNumberItemAttr
;
187 attrs
[1].length
= strlen(serialNumber
)+1;
188 attrs
[1].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
;
232 status
= SecPolicySearchCreate(CSSM_CERT_X_509v3
, &CSSMOID_APPLE_X509_BASIC
, NULL
, &searchRef
);
235 status
= SecPolicySearchCopyNext(searchRef
, &policy
);
239 wrappedCert
= CERT_CertListFromCert(cert
);
240 status
= SecTrustCreateWithCertificates(wrappedCert
, policy
, &trust
);
244 status
= SecTrustEvaluate(trust
, NULL
);
248 status
= SecTrustGetResult(trust
, NULL
, &certChain
, &statusChain
);
252 /* We don't drop the root if there is only 1 (self signed) certificate in the chain. */
253 if (!includeRoot
&& CFArrayGetCount(certChain
) > 1)
255 CFMutableArrayRef subChain
= CFArrayCreateMutableCopy(NULL
, 0, certChain
);
256 CFRelease(certChain
);
257 certChain
= subChain
;
259 CFArrayRemoveValueAtIndex(subChain
, CFArrayGetCount(subChain
) - 1);
264 CFRelease(searchRef
);
268 CFRelease(wrappedCert
);
271 if (certChain
&& status
)
273 CFRelease(certChain
);
280 CFArrayRef
CERT_CertListFromCert(SecCertificateRef cert
)
282 const void *value
= cert
;
283 return cert
? CFArrayCreate(NULL
, &value
, 1, &kCFTypeArrayCallBacks
) : NULL
;
286 CFArrayRef
CERT_DupCertList(CFArrayRef oldList
)
292 // Extract a public key object from a SubjectPublicKeyInfo
293 SecPublicKeyRef
CERT_ExtractPublicKey(SecCertificateRef cert
)
295 SecPublicKeyRef keyRef
= NULL
;
296 SecCertificateCopyPublicKey(cert
,&keyRef
);
300 SECStatus
CERT_CheckCertUsage (SecCertificateRef cert
,unsigned char usage
)
303 // @@@ It's all good, it's ok.
307 // Find a certificate in the database by a email address
308 // "emailAddr" is the email address to look up
309 SecCertificateRef
CERT_FindCertByEmailAddr(SecKeychainRef keychainOrArray
, char *emailAddr
)
315 // Find a certificate in the database by a DER encoded certificate
316 // "derCert" is the DER encoded certificate
317 SecCertificateRef
CERT_FindCertByDERCert(SecKeychainRef keychainOrArray
, const SECItem
*derCert
)
319 // @@@ Technically this should look though keychainOrArray for a cert matching this one I guess.
320 SecCertificateRef cert
= NULL
;
323 rv
= SecCertificateCreateFromData(derCert
, CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
, &cert
);
326 PORT_SetError(SEC_ERROR_NO_EMAIL_CERT
);
334 // Generate a certificate key from the issuer and serialnumber, then look it up in the database.
335 // Return the cert if found. "issuerAndSN" is the issuer and serial number to look for
336 SecCertificateRef
CERT_FindCertByIssuerAndSN (CFTypeRef keychainOrArray
, const SecCmsIssuerAndSN
*issuerAndSN
)
338 SecCertificateRef certificate
;
339 OSStatus status
= SecCertificateFindByIssuerAndSN(keychainOrArray
, &issuerAndSN
->derIssuer
,
340 &issuerAndSN
->serialNumber
, &certificate
);
343 PORT_SetError(SEC_ERROR_NO_EMAIL_CERT
);
350 SecCertificateRef
CERT_FindCertBySubjectKeyID (CFTypeRef keychainOrArray
, const SecAsn1Item
*subjKeyID
)
352 SecCertificateRef certificate
;
353 OSStatus status
= SecCertificateFindBySubjectKeyID(keychainOrArray
,subjKeyID
,&certificate
);
356 PORT_SetError(SEC_ERROR_NO_EMAIL_CERT
);
363 static SecIdentityRef
364 CERT_FindIdentityByCertificate (CFTypeRef keychainOrArray
, SecCertificateRef certificate
)
366 SecIdentityRef identity
= NULL
;
367 SecIdentityCreateWithCertificate(keychainOrArray
, certificate
, &identity
);
369 PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT
);
375 CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray
, const SecCmsIssuerAndSN
*issuerAndSN
)
377 SecCertificateRef certificate
= CERT_FindCertByIssuerAndSN(keychainOrArray
, issuerAndSN
);
381 return CERT_FindIdentityByCertificate(keychainOrArray
, certificate
);
385 CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray
, const SECItem
*subjKeyID
)
387 SecCertificateRef certificate
= CERT_FindCertBySubjectKeyID(keychainOrArray
, subjKeyID
);
391 return CERT_FindIdentityByCertificate(keychainOrArray
, certificate
);
394 // find the smime symmetric capabilities profile for a given cert
395 SECItem
*CERT_FindSMimeProfile(SecCertificateRef cert
)
400 // Return the decoded value of the subjectKeyID extension. The caller should
401 // free up the storage allocated in retItem->data.
402 SECStatus
CERT_FindSubjectKeyIDExtension (SecCertificateRef cert
,SECItem
*retItem
)
404 fprintf(stderr
, "WARNING: CERT_FindSubjectKeyIDExtension unimplemented\n");
408 static void * appMalloc (uint32 size
, void *allocRef
) {
409 return (malloc (size
));
412 static void appFree (void *mem_ptr
, void *allocRef
) {
417 static void * appRealloc (void *ptr
, uint32 size
, void *allocRef
) {
418 return (realloc (ptr
, size
));
421 static void * appCalloc (uint32 num
, uint32 size
, void *allocRef
) {
422 return (calloc (num
, size
));
425 static CSSM_API_MEMORY_FUNCS memFuncs
= {
433 // return a valid CL handle
434 static int InitializeCL (CSSM_CL_HANDLE
*clHandle
)
436 CSSM_VERSION version
= {2, 0};
439 CSSM_RETURN result
= CSSM_ModuleLoad (&gGuidAppleX509CL
, CSSM_KEY_HIERARCHY_NONE
, NULL
, NULL
);
445 result
= CSSM_ModuleAttach (&gGuidAppleX509CL
, &version
, &memFuncs
, 0, CSSM_SERVICE_CL
, 0, 0, NULL
, 0, NULL
, clHandle
);
454 // cleanup a CL handle
455 static void CloseCL (CSSM_CL_HANDLE clHandle
)
457 CSSM_ModuleDetach (clHandle
);
458 CSSM_ModuleUnload (&gGuidAppleX509CL
, NULL
, NULL
);
461 // Extract the issuer and serial number from a certificate
462 SecCmsIssuerAndSN
*CERT_GetCertIssuerAndSN(PRArenaPool
*pl
, SecCertificateRef cert
)
465 SecCmsIssuerAndSN
*certIssuerAndSN
;
466 CSSM_CL_HANDLE clHandle
;
467 CSSM_DATA_PTR serialNumber
= 0;
468 CSSM_DATA_PTR issuer
= 0;
469 CSSM_DATA certData
= {};
470 CSSM_HANDLE resultsHandle
= 0;
471 uint32 numberOfFields
= 0;
475 mark
= PORT_ArenaMark(pl
);
477 if (!InitializeCL (&clHandle
))
479 status
= SecCertificateGetData(cert
, &certData
);
483 /* Get the issuer from the cert. */
484 result
= CSSM_CL_CertGetFirstFieldValue(clHandle
, &certData
, &OID_X509V1IssuerNameStd
, &resultsHandle
, &numberOfFields
, &issuer
);
486 /* @@@ Remove this once we are sure CSSMOID_X509V1IssuerNameStd is working. */
487 /* Fall back on old normalized issuer if the new oid isn't supported yet. */
489 result
= CSSM_CL_CertGetFirstFieldValue(clHandle
, &certData
, &CSSMOID_X509V1IssuerName
, &resultsHandle
, &numberOfFields
, &issuer
);
491 if (result
|| numberOfFields
< 1)
493 result
= CSSM_CL_CertAbortQuery(clHandle
, resultsHandle
);
498 /* Get the serialNumber from the cert. */
499 result
= CSSM_CL_CertGetFirstFieldValue(clHandle
, &certData
, &CSSMOID_X509V1SerialNumber
, &resultsHandle
, &numberOfFields
, &serialNumber
);
500 if (result
|| numberOfFields
< 1)
502 result
= CSSM_CL_CertAbortQuery(clHandle
, resultsHandle
);
506 /* Allocate the SecCmsIssuerAndSN struct. */
507 certIssuerAndSN
= (SecCmsIssuerAndSN
*)PORT_ArenaZAlloc (pl
, sizeof(SecCmsIssuerAndSN
));
508 if (certIssuerAndSN
== NULL
)
511 /* Copy the issuer. */
512 certIssuerAndSN
->derIssuer
.Data
= (uint8
*) PORT_ArenaAlloc(pl
, issuer
->Length
);
513 if (!certIssuerAndSN
->derIssuer
.Data
)
515 PORT_Memcpy(certIssuerAndSN
->derIssuer
.Data
, issuer
->Data
, issuer
->Length
);
516 certIssuerAndSN
->derIssuer
.Length
= issuer
->Length
;
518 /* Copy the serialNumber. */
519 certIssuerAndSN
->serialNumber
.Data
= (uint8
*) PORT_ArenaAlloc(pl
, serialNumber
->Length
);
520 if (!certIssuerAndSN
->serialNumber
.Data
)
522 PORT_Memcpy(certIssuerAndSN
->serialNumber
.Data
, serialNumber
->Data
, serialNumber
->Length
);
523 certIssuerAndSN
->serialNumber
.Length
= serialNumber
->Length
;
525 PORT_ArenaUnmark(pl
, mark
);
527 CSSM_CL_FreeFieldValue(clHandle
, &CSSMOID_X509V1SerialNumber
, serialNumber
);
528 CSSM_CL_FreeFieldValue(clHandle
, &OID_X509V1IssuerNameStd
, issuer
);
532 return certIssuerAndSN
;
535 PORT_ArenaRelease(pl
, mark
);
538 CSSM_CL_FreeFieldValue(clHandle
, &CSSMOID_X509V1SerialNumber
, serialNumber
);
540 CSSM_CL_FreeFieldValue(clHandle
, &OID_X509V1IssuerNameStd
, issuer
);
544 PORT_SetError(SEC_INTERNAL_ONLY
);
548 // import a collection of certs into the temporary or permanent cert database
549 SECStatus
CERT_ImportCerts(SecKeychainRef keychain
, SECCertUsage usage
, unsigned int ncerts
,
550 SECItem
**derCerts
, SecCertificateRef
**retCerts
, Boolean keepCerts
, Boolean caOnly
, char *nickname
)
552 OSStatus rv
= SECFailure
;
553 SecCertificateRef cert
;
556 // @@@ Do something with caOnly and nickname
557 if (caOnly
|| nickname
)
560 for (ci
= 0; ci
< ncerts
; ++ci
)
562 rv
= SecCertificateCreateFromData(derCerts
[ci
], CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
, &cert
);
567 rv
= SecCertificateAddToKeychain(cert
, keychain
);
570 if (rv
== errKCDuplicateItem
)
592 SECStatus
CERT_SaveSMimeProfile(SecCertificateRef cert
, SECItem
*emailProfile
,SECItem
*profileTime
)
594 fprintf(stderr
, "WARNING: CERT_SaveSMimeProfile unimplemented\n");
598 // Check the hostname to make sure that it matches the shexp that
599 // is given in the common name of the certificate.
600 SECStatus
CERT_VerifyCertName(SecCertificateRef cert
, const char *hostname
)
602 fprintf(stderr
, "WARNING: CERT_VerifyCertName unimplemented\n");
607 ** OLD OBSOLETE FUNCTIONS with enum SECCertUsage - DO NOT USE FOR NEW CODE
608 ** verify a certificate by checking validity times against a certain time,
609 ** that we trust the issuer, and that the signature on the certificate is
611 ** "cert" the certificate to verify
612 ** "checkSig" only check signatures if true
615 CERT_VerifyCert(SecKeychainRef keychainOrArray
, SecCertificateRef cert
,
616 CFTypeRef policies
, CFAbsoluteTime stime
, SecTrustRef
*trustRef
)
618 CFArrayRef certificates
;
619 const void *certs
= cert
;
620 SecTrustRef trust
= NULL
;
623 certificates
= CFArrayCreate(NULL
, &certs
, 1, &kCFTypeArrayCallBacks
);
624 rv
= SecTrustCreateWithCertificates(certificates
, policies
, &trust
);
625 CFRelease(certificates
);
629 rv
= SecTrustSetKeychains(trust
, keychainOrArray
);
633 CFDateRef verifyDate
= CFDateCreate(NULL
, stime
);
634 rv
= SecTrustSetVerifyDate(trust
, verifyDate
);
635 CFRelease(verifyDate
);
645 SecTrustResultType result
;
646 /* The caller doesn't want a SecTrust object, so let's evaluate it for them. */
647 rv
= SecTrustEvaluate(trust
, &result
);
653 case kSecTrustResultProceed
:
654 case kSecTrustResultUnspecified
:
655 /* TP Verification succeeded and there was either a UserTurst entry
656 telling us to procceed, or no user trust setting was specified. */
660 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT
);
676 CERT_PolicyForCertUsage(SECCertUsage certUsage
)
678 SecPolicySearchRef search
;
679 SecPolicyRef policy
= NULL
;
680 const CSSM_OID
*policyOID
;
685 case certUsageSSLServerWithStepUp
:
687 case certUsageVerifyCA
:
691 case certUsageSSLClient
:
692 case certUsageSSLServer
:
693 policyOID
= &CSSMOID_APPLE_TP_SSL
;
695 case certUsageUserCertImport
:
696 policyOID
= &CSSMOID_APPLE_TP_CSR_GEN
;
698 case certUsageStatusResponder
:
699 policyOID
= &CSSMOID_APPLE_TP_REVOCATION_OCSP
;
701 case certUsageObjectSigner
:
702 case certUsageProtectedObjectSigner
:
703 policyOID
= &CSSMOID_APPLE_ISIGN
;
705 case certUsageEmailSigner
:
706 case certUsageEmailRecipient
:
707 policyOID
= &CSSMOID_APPLE_X509_BASIC
;
712 rv
= SecPolicySearchCreate(CSSM_CERT_X_509v3
, policyOID
, NULL
, &search
);
716 rv
= SecPolicySearchCopyNext(search
, &policy
);