2 * Copyright (c) 2000-2013 Apple Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
20 policies.cpp - TP module policy implementation
23 #include <Security/cssmtype.h>
24 #include <Security/cssmapi.h>
25 #include "tpPolicies.h"
26 #include <Security/cssmerr.h>
27 #include "tpdebugging.h"
28 #include "certGroupUtils.h"
29 #include <Security/x509defs.h>
30 #include <Security/oidsalg.h>
31 #include <Security/oidsattr.h>
32 #include <Security/oidscert.h>
33 #include <Security/certextensions.h>
34 #include <Security/cssmapple.h>
35 #include <Security/SecCertificate.h>
36 #include <Security/SecCertificatePriv.h>
40 #include <CoreFoundation/CFString.h>
41 #include <CommonCrypto/CommonDigest.h>
44 * Our private per-extension info. One of these per (understood) extension per
50 CE_Data
*extnData
; // mallocd by CL
51 CSSM_DATA
*valToFree
; // the data we pass to freeField()
55 * Struct to keep track of info pertinent to one cert.
59 /* extensions we're interested in */
60 iSignExtenInfo authorityId
;
61 iSignExtenInfo subjectId
;
62 iSignExtenInfo keyUsage
;
63 iSignExtenInfo extendKeyUsage
;
64 iSignExtenInfo basicConstraints
;
65 iSignExtenInfo netscapeCertType
;
66 iSignExtenInfo subjectAltName
;
67 iSignExtenInfo certPolicies
;
68 iSignExtenInfo qualCertStatements
;
69 iSignExtenInfo nameConstraints
;
70 iSignExtenInfo policyMappings
;
71 iSignExtenInfo policyConstraints
;
72 iSignExtenInfo inhibitAnyPolicy
;
73 iSignExtenInfo certificatePolicies
;
75 /* flag indicating presence of CSSMOID_APPLE_EXTENSION_PASSBOOK_SIGNING */
76 CSSM_BOOL foundPassbookSigning
;
77 /* flag indicating presence of CSSMOID_APPLE_EXTENSION_SYSINT2_INTERMEDIATE */
78 CSSM_BOOL foundAppleSysInt2Marker
;
79 /* flag indicating presence of CSSMOID_APPLE_EXTENSION_ESCROW_SERVICE */
80 CSSM_BOOL foundEscrowServiceMarker
;
81 /* flag indicating presence of a critical extension we don't understand */
82 CSSM_BOOL foundUnknownCritical
;
83 /* flag indicating that this certificate was signed with a known-broken algorithm */
84 CSSM_BOOL untrustedSigAlg
;
89 * The list of Qualified Cert Statement statementIds we understand, even though
90 * we don't actually do anything with them; if these are found in a Qualified
91 * Cert Statement that's critical, we can truthfully say "yes we understand this".
93 static const CSSM_OID_PTR knownQualifiedCertStatements
[] =
95 (const CSSM_OID_PTR
)&CSSMOID_OID_QCS_SYNTAX_V1
,
96 (const CSSM_OID_PTR
)&CSSMOID_OID_QCS_SYNTAX_V2
,
97 (const CSSM_OID_PTR
)&CSSMOID_ETSI_QCS_QC_COMPLIANCE
,
98 (const CSSM_OID_PTR
)&CSSMOID_ETSI_QCS_QC_LIMIT_VALUE
,
99 (const CSSM_OID_PTR
)&CSSMOID_ETSI_QCS_QC_RETENTION
,
100 (const CSSM_OID_PTR
)&CSSMOID_ETSI_QCS_QC_SSCD
102 #define NUM_KNOWN_QUAL_CERT_STATEMENTS (sizeof(knownQualifiedCertStatements) / sizeof(CSSM_OID_PTR))
104 static CSSM_RETURN
tp_verifyMacAppStoreReceiptOpts(TPCertGroup
&certGroup
,
105 const CSSM_DATA
*fieldOpts
, const iSignCertInfo
*certInfo
);
107 static CSSM_RETURN
tp_verifyPassbookSigningOpts(TPCertGroup
&certGroup
,
108 const CSSM_DATA
*fieldOpts
, const iSignCertInfo
*certInfo
);
110 bool certificatePoliciesContainsOID(const CE_CertPolicies
*certPolicies
, const CSSM_OID
*oidToFind
);
112 #define kSecPolicySHA1Size 20
113 static const UInt8 kAppleCASHA1
[kSecPolicySHA1Size
] = {
114 0x61, 0x1E, 0x5B, 0x66, 0x2C, 0x59, 0x3A, 0x08, 0xFF, 0x58,
115 0xD1, 0x4A, 0xE2, 0x24, 0x52, 0xD1, 0x98, 0xDF, 0x6C, 0x60
118 static const UInt8 kMobileRootSHA1
[kSecPolicySHA1Size
] = {
119 0xBD, 0xD6, 0x7C, 0x34, 0xD0, 0xB2, 0x68, 0x5D, 0x31, 0x82,
120 0xCD, 0x32, 0xCB, 0xF4, 0x54, 0x69, 0xA1, 0xF1, 0x6B, 0x09
124 * Certificate policy OIDs
128 #define ANY_POLICY_OID OID_EXTENSION, 0x32, 0x00
129 #define ANY_POLICY_OID_LEN OID_EXTENSION_LENGTH + 2
132 #define INHIBIT_ANY_POLICY_OID OID_EXTENSION, 0x54
133 #define INHIBIT_ANY_POLICY_OID_LEN OID_EXTENSION_LENGTH + 1
135 /* 2.16.840.1.101.2.1 */
136 #define US_DOD_INFOSEC 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01
137 #define US_DOD_INFOSEC_LEN 7
139 /* 2.16.840.1.101.2.1.11.10 */
140 #define PIV_AUTH_OID US_DOD_INFOSEC, 0x0B, 0x0A
141 #define PIV_AUTH_OID_LEN US_DOD_INFOSEC_LEN + 2
143 /* 2.16.840.1.101.2.1.11.20 */
144 #define PIV_AUTH_2048_OID US_DOD_INFOSEC, 0x0B, 0x14
145 #define PIV_AUTH_2048_OID_LEN US_DOD_INFOSEC_LEN + 2
147 static const uint8 OID_ANY_POLICY
[] = {ANY_POLICY_OID
};
148 const CSSM_OID CSSMOID_ANY_POLICY
= {ANY_POLICY_OID_LEN
, (uint8
*)OID_ANY_POLICY
};
149 static const uint8 OID_INHIBIT_ANY_POLICY
[] = {INHIBIT_ANY_POLICY_OID
};
150 const CSSM_OID CSSMOID_INHIBIT_ANY_POLICY
= {INHIBIT_ANY_POLICY_OID_LEN
, (uint8
*)OID_INHIBIT_ANY_POLICY
};
151 static const uint8 OID_PIV_AUTH
[] = {PIV_AUTH_OID
};
152 const CSSM_OID CSSMOID_PIV_AUTH
= {PIV_AUTH_OID_LEN
, (uint8
*)OID_PIV_AUTH
};
153 static const uint8 OID_PIV_AUTH_2048
[] = {PIV_AUTH_2048_OID
};
154 const CSSM_OID CSSMOID_PIV_AUTH_2048
= {PIV_AUTH_2048_OID_LEN
, (uint8
*)OID_PIV_AUTH_2048
};
156 static CSSM_RETURN
tp_verifyAppleIDSharingOpts(TPCertGroup
&certGroup
,
157 const CSSM_DATA
*fieldOpts
, // optional Common Name
158 const iSignCertInfo
*certInfo
);
160 * Setup a single iSignExtenInfo. Called once per known extension
163 static CSSM_RETURN
tpSetupExtension(
166 iSignExtenInfo
*extnInfo
) // which component of certInfo
168 if(extnData
->Length
!= sizeof(CSSM_X509_EXTENSION
)) {
169 tpPolicyError("tpSetupExtension: malformed CSSM_FIELD");
170 return CSSMERR_TP_UNKNOWN_FORMAT
;
172 CSSM_X509_EXTENSION
*cssmExt
= (CSSM_X509_EXTENSION
*)extnData
->Data
;
173 extnInfo
->present
= CSSM_TRUE
;
174 extnInfo
->critical
= cssmExt
->critical
;
175 extnInfo
->extnData
= (CE_Data
*)cssmExt
->value
.parsedValue
;
176 extnInfo
->valToFree
= extnData
;
181 * Fetch a known extension, set up associated iSignExtenInfo if present.
183 static CSSM_RETURN
iSignFetchExtension(
186 const CSSM_OID
*fieldOid
, // which extension to fetch
187 iSignExtenInfo
*extnInfo
) // where the info goes
189 CSSM_DATA_PTR fieldValue
; // mallocd by CL
192 crtn
= tpCert
->fetchField(fieldOid
, &fieldValue
);
196 case CSSMERR_CL_NO_FIELD_VALUES
:
197 /* field not present, OK */
202 return tpSetupExtension(alloc
,
208 * This function performs a check of an extension marked 'critical'
209 * to see if it's one we understand. Returns CSSM_OK if the extension
210 * is acceptable, CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN if unknown.
212 static CSSM_RETURN
iSignVerifyCriticalExtension(
213 CSSM_X509_EXTENSION
*cssmExt
)
215 if (!cssmExt
|| !cssmExt
->extnId
.Data
)
216 return CSSMERR_TP_INVALID_FIELD_POINTER
;
218 if (!cssmExt
->critical
)
221 /* FIXME: remove when policyConstraints NSS template is fixed */
222 if (!memcmp(cssmExt
->extnId
.Data
, CSSMOID_PolicyConstraints
.Data
, CSSMOID_PolicyConstraints
.Length
))
225 if (cssmExt
->extnId
.Length
> APPLE_EXTENSION_OID_LENGTH
&&
226 !memcmp(cssmExt
->extnId
.Data
, CSSMOID_APPLE_EXTENSION
.Data
, APPLE_EXTENSION_OID_LENGTH
)) {
227 /* This extension's OID is under the appleCertificateExtensions arc */
231 return CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN
;
235 * Search for all unknown extensions. If we find one which is flagged critical,
236 * flag certInfo->foundUnknownCritical. Only returns error on gross errors.
238 static CSSM_RETURN
iSignSearchUnknownExtensions(
240 iSignCertInfo
*certInfo
)
243 CSSM_DATA_PTR fieldValue
= NULL
;
244 CSSM_HANDLE searchHand
= CSSM_INVALID_HANDLE
;
245 uint32 numFields
= 0;
247 certInfo
->foundPassbookSigning
= CSSM_FALSE
;
248 certInfo
->foundAppleSysInt2Marker
= CSSM_FALSE
;
249 certInfo
->foundEscrowServiceMarker
= CSSM_FALSE
;
251 crtn
= CSSM_CL_CertGetFirstCachedFieldValue(tpCert
->clHand(),
253 &CSSMOID_X509V3CertificateExtensionCStruct
,
259 /* found one, proceed */
261 case CSSMERR_CL_NO_FIELD_VALUES
:
262 /* no unknown extensions present, OK */
268 if(fieldValue
->Length
!= sizeof(CSSM_X509_EXTENSION
)) {
269 tpPolicyError("iSignSearchUnknownExtensions: malformed CSSM_FIELD");
270 return CSSMERR_TP_UNKNOWN_FORMAT
;
273 CSSM_X509_EXTENSION
*cssmExt
= (CSSM_X509_EXTENSION
*)fieldValue
->Data
;
274 if (cssmExt
->extnId
.Length
== APPLE_EXTENSION_CODE_SIGNING_LENGTH
+1 &&
275 !memcmp(cssmExt
->extnId
.Data
, CSSMOID_APPLE_EXTENSION_PASSBOOK_SIGNING
.Data
,
276 APPLE_EXTENSION_CODE_SIGNING_LENGTH
+1)) {
277 /* this is the Passbook Signing extension */
278 certInfo
->foundPassbookSigning
= CSSM_TRUE
;
280 if (cssmExt
->extnId
.Length
== APPLE_EXTENSION_SYSINT2_INTERMEDIATE_LENGTH
&&
281 !memcmp(cssmExt
->extnId
.Data
, CSSMOID_APPLE_EXTENSION_SYSINT2_INTERMEDIATE
.Data
,
282 APPLE_EXTENSION_SYSINT2_INTERMEDIATE_LENGTH
)) {
283 /* this is the Apple System Integration 2 Signing extension */
284 certInfo
->foundAppleSysInt2Marker
= CSSM_TRUE
;
286 if (cssmExt
->extnId
.Length
== APPLE_EXTENSION_ESCROW_SERVICE_LENGTH
&&
287 !memcmp(cssmExt
->extnId
.Data
, CSSMOID_APPLE_EXTENSION_ESCROW_SERVICE
.Data
,
288 APPLE_EXTENSION_ESCROW_SERVICE_LENGTH
)) {
289 /* this is the Escrow Service Signing extension */
290 certInfo
->foundEscrowServiceMarker
= CSSM_TRUE
;
293 if(iSignVerifyCriticalExtension(cssmExt
) != CSSM_OK
) {
294 /* BRRZAPP! Found an unknown extension marked critical */
295 certInfo
->foundUnknownCritical
= CSSM_TRUE
;
298 CSSM_CL_FreeFieldValue(tpCert
->clHand(),
299 &CSSMOID_X509V3CertificateExtensionCStruct
,
303 /* process remaining unknown extensions */
304 for(unsigned i
=1; i
<numFields
; i
++) {
305 crtn
= CSSM_CL_CertGetNextCachedFieldValue(tpCert
->clHand(),
309 /* should never happen */
310 tpPolicyError("searchUnknownExtensions: GetNextCachedFieldValue"
314 if(fieldValue
->Length
!= sizeof(CSSM_X509_EXTENSION
)) {
315 tpPolicyError("iSignSearchUnknownExtensions: "
316 "malformed CSSM_FIELD");
317 crtn
= CSSMERR_TP_UNKNOWN_FORMAT
;
321 CSSM_X509_EXTENSION
*cssmExt
= (CSSM_X509_EXTENSION
*)fieldValue
->Data
;
322 if (cssmExt
->extnId
.Length
== APPLE_EXTENSION_CODE_SIGNING_LENGTH
+1 &&
323 !memcmp(cssmExt
->extnId
.Data
, CSSMOID_APPLE_EXTENSION_PASSBOOK_SIGNING
.Data
,
324 APPLE_EXTENSION_CODE_SIGNING_LENGTH
+1)) {
325 /* this is the Passbook Signing extension */
326 certInfo
->foundPassbookSigning
= CSSM_TRUE
;
328 if (cssmExt
->extnId
.Length
== APPLE_EXTENSION_SYSINT2_INTERMEDIATE_LENGTH
&&
329 !memcmp(cssmExt
->extnId
.Data
, CSSMOID_APPLE_EXTENSION_SYSINT2_INTERMEDIATE
.Data
,
330 APPLE_EXTENSION_SYSINT2_INTERMEDIATE_LENGTH
)) {
331 /* this is the Apple System Integration 2 Signing extension */
332 certInfo
->foundAppleSysInt2Marker
= CSSM_TRUE
;
334 if (cssmExt
->extnId
.Length
== APPLE_EXTENSION_ESCROW_SERVICE_LENGTH
&&
335 !memcmp(cssmExt
->extnId
.Data
, CSSMOID_APPLE_EXTENSION_ESCROW_SERVICE
.Data
,
336 APPLE_EXTENSION_ESCROW_SERVICE_LENGTH
)) {
337 /* this is the Escrow Service Signing extension */
338 certInfo
->foundEscrowServiceMarker
= CSSM_TRUE
;
341 if(iSignVerifyCriticalExtension(cssmExt
) != CSSM_OK
) {
342 /* BRRZAPP! Found an unknown extension marked critical */
343 certInfo
->foundUnknownCritical
= CSSM_TRUE
;
346 CSSM_CL_FreeFieldValue(tpCert
->clHand(),
347 &CSSMOID_X509V3CertificateExtensionCStruct
,
350 } /* for additional fields */
354 CSSM_CL_FreeFieldValue(tpCert
->clHand(),
355 &CSSMOID_X509V3CertificateExtensionCStruct
,
358 if(searchHand
!= CSSM_INVALID_HANDLE
) {
359 CSSM_CL_CertAbortQuery(tpCert
->clHand(), searchHand
);
365 * Check the signature algorithm. If it's known to be untrusted,
366 * flag certInfo->untrustedSigAlg.
368 static void iSignCheckSignatureAlgorithm(
370 iSignCertInfo
*certInfo
)
372 CSSM_X509_ALGORITHM_IDENTIFIER
*algId
= NULL
;
373 CSSM_DATA_PTR valueToFree
= NULL
;
375 algId
= tp_CertGetAlgId(tpCert
, &valueToFree
);
377 tpCompareCssmData(&algId
->algorithm
, &CSSMOID_MD2
) ||
378 tpCompareCssmData(&algId
->algorithm
, &CSSMOID_MD2WithRSA
) ||
379 tpCompareCssmData(&algId
->algorithm
, &CSSMOID_MD5
) ||
380 tpCompareCssmData(&algId
->algorithm
, &CSSMOID_MD5WithRSA
) ) {
381 certInfo
->untrustedSigAlg
= CSSM_TRUE
;
383 certInfo
->untrustedSigAlg
= CSSM_FALSE
;
387 tp_CertFreeAlgId(tpCert
->clHand(), valueToFree
);
392 * Given a TPCertInfo, fetch the associated iSignCertInfo fields.
393 * Returns CSSM_FAIL on error.
395 static CSSM_RETURN
iSignGetCertInfo(
398 iSignCertInfo
*certInfo
)
402 /* first grind thru the extensions we're interested in */
403 crtn
= iSignFetchExtension(alloc
,
405 &CSSMOID_AuthorityKeyIdentifier
,
406 &certInfo
->authorityId
);
410 crtn
= iSignFetchExtension(alloc
,
412 &CSSMOID_SubjectKeyIdentifier
,
413 &certInfo
->subjectId
);
417 crtn
= iSignFetchExtension(alloc
,
420 &certInfo
->keyUsage
);
424 crtn
= iSignFetchExtension(alloc
,
426 &CSSMOID_ExtendedKeyUsage
,
427 &certInfo
->extendKeyUsage
);
431 crtn
= iSignFetchExtension(alloc
,
433 &CSSMOID_BasicConstraints
,
434 &certInfo
->basicConstraints
);
438 crtn
= iSignFetchExtension(alloc
,
440 &CSSMOID_NetscapeCertType
,
441 &certInfo
->netscapeCertType
);
445 crtn
= iSignFetchExtension(alloc
,
447 &CSSMOID_SubjectAltName
,
448 &certInfo
->subjectAltName
);
452 crtn
= iSignFetchExtension(alloc
,
454 &CSSMOID_CertificatePolicies
,
455 &certInfo
->certPolicies
);
459 crtn
= iSignFetchExtension(alloc
,
461 &CSSMOID_QC_Statements
,
462 &certInfo
->qualCertStatements
);
466 crtn
= iSignFetchExtension(alloc
,
468 &CSSMOID_NameConstraints
,
469 &certInfo
->nameConstraints
);
473 crtn
= iSignFetchExtension(alloc
,
475 &CSSMOID_PolicyMappings
,
476 &certInfo
->policyMappings
);
480 crtn
= iSignFetchExtension(alloc
,
482 &CSSMOID_PolicyConstraints
,
483 &certInfo
->policyConstraints
);
487 crtn
= iSignFetchExtension(alloc
,
489 &CSSMOID_InhibitAnyPolicy
,
490 &certInfo
->inhibitAnyPolicy
);
494 crtn
= iSignFetchExtension(alloc
,
496 &CSSMOID_CertificatePolicies
,
497 &certInfo
->certificatePolicies
);
502 /* check signature algorithm field */
503 iSignCheckSignatureAlgorithm(tpCert
, certInfo
);
505 /* now look for extensions we don't understand - the only thing we're interested
506 * in is the critical flag. */
507 return iSignSearchUnknownExtensions(tpCert
, certInfo
);
511 * Free (via CL) the fields allocated in iSignGetCertInfo().
513 static void iSignFreeCertInfo(
514 CSSM_CL_HANDLE clHand
,
515 iSignCertInfo
*certInfo
)
517 if(certInfo
->authorityId
.present
) {
518 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_AuthorityKeyIdentifier
,
519 certInfo
->authorityId
.valToFree
);
521 if(certInfo
->subjectId
.present
) {
522 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_SubjectKeyIdentifier
,
523 certInfo
->subjectId
.valToFree
);
525 if(certInfo
->keyUsage
.present
) {
526 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_KeyUsage
,
527 certInfo
->keyUsage
.valToFree
);
529 if(certInfo
->extendKeyUsage
.present
) {
530 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_ExtendedKeyUsage
,
531 certInfo
->extendKeyUsage
.valToFree
);
533 if(certInfo
->basicConstraints
.present
) {
534 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_BasicConstraints
,
535 certInfo
->basicConstraints
.valToFree
);
537 if(certInfo
->netscapeCertType
.present
) {
538 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_NetscapeCertType
,
539 certInfo
->netscapeCertType
.valToFree
);
541 if(certInfo
->subjectAltName
.present
) {
542 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_SubjectAltName
,
543 certInfo
->subjectAltName
.valToFree
);
545 if(certInfo
->certPolicies
.present
) {
546 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_CertificatePolicies
,
547 certInfo
->certPolicies
.valToFree
);
549 // if(certInfo->policyConstraints.present) {
550 // CSSM_CL_FreeFieldValue(clHand, &CSSMOID_PolicyConstraints,
551 // certInfo->policyConstraints.valToFree);
553 if(certInfo
->qualCertStatements
.present
) {
554 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_QC_Statements
,
555 certInfo
->qualCertStatements
.valToFree
);
557 if(certInfo
->certificatePolicies
.present
) {
558 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_CertificatePolicies
,
559 certInfo
->certificatePolicies
.valToFree
);
564 * See if cert's Subject.{commonName,EmailAddress} matches caller-specified
565 * string. Returns CSSM_TRUE if match, else returns CSSM_FALSE.
566 * Also indicates whether *any* of the specified fields were found, regardless
570 SN_CommonName
, // CSSMOID_CommonName, host name format
571 SN_Email
, // CSSMOID_EmailAddress
572 SN_UserID
, // CSSMOID_UserID
573 SN_OrgUnit
// CSSMOID_OrganizationalUnitName
574 } SubjSubjNameSearchType
;
576 static CSSM_BOOL
tpCompareSubjectName(
578 SubjSubjNameSearchType searchType
,
579 bool normalizeAll
, // for SN_Email case: lower-case all of
580 // the cert's value, not just the portion
582 const char *callerStr
, // already tpToLower'd
586 char *certName
= NULL
; // from cert's subject name
587 uint32 certNameLen
= 0;
588 CSSM_DATA_PTR subjNameData
= NULL
;
590 CSSM_BOOL ourRtn
= CSSM_FALSE
;
591 const CSSM_OID
*oidSrch
;
593 const char x500_userid_oid
[] = { 0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x01 };
594 CSSM_OID X500_UserID_OID
= { sizeof(x500_userid_oid
), (uint8
*)x500_userid_oid
};
599 oidSrch
= &CSSMOID_CommonName
;
602 oidSrch
= &CSSMOID_EmailAddress
;
605 oidSrch
= &X500_UserID_OID
;
608 oidSrch
= &CSSMOID_OrganizationalUnitName
;
614 crtn
= cert
.fetchField(&CSSMOID_X509V1SubjectNameCStruct
, &subjNameData
);
616 /* should never happen, we shouldn't be here if there is no subject */
617 tpPolicyError("tpCompareSubjectName: error retrieving subject name");
620 CSSM_X509_NAME_PTR x509name
= (CSSM_X509_NAME_PTR
)subjNameData
->Data
;
621 if((x509name
== NULL
) || (subjNameData
->Length
!= sizeof(CSSM_X509_NAME
))) {
622 tpPolicyError("tpCompareSubjectName: malformed CSSM_X509_NAME");
623 cert
.freeField(&CSSMOID_X509V1SubjectNameCStruct
, subjNameData
);
627 /* Now grunge thru the X509 name looking for a common name */
628 CSSM_X509_TYPE_VALUE_PAIR
*ptvp
;
629 CSSM_X509_RDN_PTR rdnp
;
633 for(rdnDex
=0; rdnDex
<x509name
->numberOfRDNs
; rdnDex
++) {
634 rdnp
= &x509name
->RelativeDistinguishedName
[rdnDex
];
635 for(pairDex
=0; pairDex
<rdnp
->numberOfPairs
; pairDex
++) {
636 ptvp
= &rdnp
->AttributeTypeAndValue
[pairDex
];
637 if(tpCompareOids(&ptvp
->type
, oidSrch
)) {
639 certName
= (char *)ptvp
->value
.Data
;
640 certNameLen
= (uint32
)ptvp
->value
.Length
;
644 /* handle odd encodings that we need to convert to 8-bit */
645 CFStringBuiltInEncodings encoding
;
646 CFDataRef cfd
= NULL
;
647 bool doConvert
= false;
648 switch(ptvp
->valueType
) {
649 case BER_TAG_T61_STRING
:
651 encoding
= kCFStringEncodingISOLatin1
;
654 case BER_TAG_PKIX_BMP_STRING
:
655 encoding
= kCFStringEncodingUnicode
;
659 * All others - either take as is, or let it fail due to
660 * illegal/incomprehensible format
666 /* raw data ==> CFString */
667 cfd
= CFDataCreate(NULL
, (UInt8
*)certName
, certNameLen
);
669 /* try next component */
672 CFStringRef cfStr
= CFStringCreateFromExternalRepresentation(
673 NULL
, cfd
, encoding
);
676 tpPolicyError("tpCompareSubjectName: bad str (1)");
680 /* CFString ==> straight ASCII */
681 cfd
= CFStringCreateExternalRepresentation(NULL
,
682 cfStr
, kCFStringEncodingASCII
, 0);
685 tpPolicyError("tpCompareSubjectName: bad str (2)");
688 certNameLen
= (uint32
)CFDataGetLength(cfd
);
689 certName
= (char *)CFDataGetBytePtr(cfd
);
691 ourRtn
= tpCompareHostNames(callerStr
, callerStrLen
,
692 certName
, certNameLen
);
700 ourRtn
= tpCompareEmailAddr(callerStr
, callerStrLen
,
701 certName
, certNameLen
, normalizeAll
);
705 /* exact match only here, for now */
706 ourRtn
= ((callerStrLen
== certNameLen
) &&
707 !memcmp(callerStr
, certName
, certNameLen
)) ?
708 CSSM_TRUE
: CSSM_FALSE
;
715 /* else keep going, maybe there's another common name */
722 cert
.freeField(&CSSMOID_X509V1SubjectNameCStruct
, subjNameData
);
727 * Compare ASCII form of an IP address to a CSSM_DATA containing
728 * the IP address's numeric components. Returns true on match.
730 static CSSM_BOOL
tpCompIpAddrStr(
733 const CSSM_DATA
*numeric
)
735 const char *cp
= str
;
739 if((numeric
== NULL
) || (numeric
->Length
== 0) || (str
== NULL
)) {
742 if(cp
[strLen
- 1] == '\0') {
743 /* ignore NULL terminator */
746 for(unsigned dex
=0; dex
<numeric
->Length
; dex
++) {
747 /* cp points to start of current string digit */
749 const char *lastChar
= cp
+ strLen
;
751 for( ; nextDot
<lastChar
; nextDot
++) {
752 if(*nextDot
== '.') {
756 if(nextDot
== lastChar
) {
757 /* legal and required on last digit */
758 if(dex
!= (numeric
->Length
- 1)) {
762 else if(dex
== (numeric
->Length
- 1)) {
765 ptrdiff_t digLen
= nextDot
- cp
;
766 if(digLen
>= sizeof(buf
)) {
770 memmove(buf
, cp
, digLen
);
772 /* incr digLen to include the next dot */
776 int digVal
= atoi(buf
);
777 if(digVal
!= numeric
->Data
[dex
]) {
785 * See if cert's subjectAltName contains an element matching caller-specified
786 * string, hostname, in the following forms:
788 * SAN_HostName : dnsName, iPAddress
789 * SAN_Email : RFC822Name
791 * Returns CSSM_TRUE if match, else returns CSSM_FALSE.
793 * Also indicates whether or not a dnsName (search type HostName) or
794 * RFC822Name (search type SAM_Email) was found, regardless of result
797 * The appStr/appStrLen args are optional - if NULL/0, only the
798 * search for dnsName/RFC822Name is done.
803 } SubjAltNameSearchType
;
805 static CSSM_BOOL
tpCompareSubjectAltName(
806 const iSignExtenInfo
&subjAltNameInfo
,
807 const char *appStr
, // caller has lower-cased as appropriate
809 SubjAltNameSearchType searchType
,
810 bool normalizeAll
, // for SAN_Email case: lower-case all of
811 // the cert's value, not just the portion
813 bool &dnsNameFound
, // RETURNED, SAN_HostName case
814 bool &emailFound
) // RETURNED, SAN_Email case
816 dnsNameFound
= false;
818 if(!subjAltNameInfo
.present
) {
819 /* common failure, no subjectAltName found */
823 CE_GeneralNames
*names
= &subjAltNameInfo
.extnData
->subjectAltName
;
824 CSSM_BOOL ourRtn
= CSSM_FALSE
;
828 /* Search thru the CE_GeneralNames looking for the appropriate attribute */
829 for(unsigned dex
=0; dex
<names
->numNames
; dex
++) {
830 CE_GeneralName
*name
= &names
->generalName
[dex
];
833 switch(name
->nameType
) {
836 /* nothing to do here */
839 ourRtn
= tpCompIpAddrStr(appStr
, appStrLen
, &name
->name
);
843 if(name
->berEncoded
) {
844 tpErrorLog("tpCompareSubjectAltName: malformed "
845 "CE_GeneralName (1)\n");
848 certName
= (char *)name
->name
.Data
;
849 if(certName
== NULL
) {
850 tpErrorLog("tpCompareSubjectAltName: malformed "
851 "CE_GeneralName (2)\n");
854 certNameLen
= (uint32
)(name
->name
.Length
);
857 /* skip if caller passed in NULL */
858 ourRtn
= tpCompareHostNames(appStr
, appStrLen
,
859 certName
, certNameLen
);
864 /* not interested, proceed to next name */
867 break; /* from case HostName */
870 if(name
->nameType
!= GNT_RFC822Name
) {
874 certName
= (char *)name
->name
.Data
;
875 if(certName
== NULL
) {
876 tpErrorLog("tpCompareSubjectAltName: malformed "
880 certNameLen
= (uint32
)(name
->name
.Length
);
883 ourRtn
= tpCompareEmailAddr(appStr
, appStrLen
, certName
,
884 certNameLen
, normalizeAll
);
896 /* is host name in the form of a.b.c.d, where a,b,c, and d are digits? */
897 static CSSM_BOOL
tpIsNumeric(
898 const char *hostName
,
899 unsigned hostNameLen
)
901 if(hostName
[hostNameLen
- 1] == '\0') {
902 /* ignore NULL terminator */
905 for(unsigned i
=0; i
<hostNameLen
; i
++) {
906 char c
= *hostName
++;
918 * Convert a typed string represented by a CSSM_X509_TYPE_VALUE_PAIR to a
919 * CFStringRef. Caller owns and must release the result. NULL return means
920 * unconvertible input "string".
922 static CFStringRef
tpTvpToCfString(
923 const CSSM_X509_TYPE_VALUE_PAIR
*tvp
)
925 CFStringBuiltInEncodings encoding
;
926 switch(tvp
->valueType
) {
927 case BER_TAG_T61_STRING
:
929 encoding
= kCFStringEncodingISOLatin1
;
931 case BER_TAG_PKIX_BMP_STRING
:
932 encoding
= kCFStringEncodingUnicode
;
934 case BER_TAG_PRINTABLE_STRING
:
935 case BER_TAG_IA5_STRING
:
936 case BER_TAG_PKIX_UTF8_STRING
:
937 encoding
= kCFStringEncodingUTF8
;
943 /* raw data ==> CFString */
944 CFDataRef cfd
= CFDataCreate(NULL
, tvp
->value
.Data
, tvp
->value
.Length
);
948 CFStringRef cfStr
= CFStringCreateFromExternalRepresentation(NULL
, cfd
, encoding
);
954 * Compare a CFString and a string represented by a CSSM_X509_TYPE_VALUE_PAIR.
955 * Returns CSSM_TRUE if they are equal.
957 static bool tpCompareTvpToCfString(
958 const CSSM_X509_TYPE_VALUE_PAIR
*tvp
,
960 CFOptionFlags flags
) // e.g., kCFCompareCaseInsensitive
962 CFStringRef cfStr
= tpTvpToCfString(tvp
);
966 CFComparisonResult res
= CFStringCompare(refStr
, cfStr
, flags
);
968 if(res
== kCFCompareEqualTo
) {
977 * Given one iSignCertInfo, determine whether or not the specified
978 * EKU OID, or - optionally - CSSMOID_ExtendedKeyUsageAny - is present.
979 * Returns true if so, else false.
981 static bool tpVerifyEKU(
982 const iSignCertInfo
&certInfo
,
983 const CSSM_OID
&ekuOid
,
984 bool ekuAnyOK
) // if true, CSSMOID_ExtendedKeyUsageAny counts as "found"
986 if(!certInfo
.extendKeyUsage
.present
) {
989 CE_ExtendedKeyUsage
*eku
= &certInfo
.extendKeyUsage
.extnData
->extendedKeyUsage
;
992 for(unsigned i
=0; i
<eku
->numPurposes
; i
++) {
993 const CSSM_OID
*foundEku
= &eku
->purposes
[i
];
994 if(tpCompareOids(foundEku
, &ekuOid
)) {
997 if(ekuAnyOK
&& tpCompareOids(foundEku
, &CSSMOID_ExtendedKeyUsageAny
)) {
1005 * Given one iSignCertInfo, determine whether or not the specified
1006 * Certificate Policy OID, or - optionally - CSSMOID_ANY_POLICY - is present.
1007 * Returns true if so, else false.
1009 static bool tpVerifyCPE(
1010 const iSignCertInfo
&certInfo
,
1011 const CSSM_OID
&cpOid
,
1012 bool anyPolicyOK
) // if true, CSSMOID_ANY_POLICY counts as "found"
1014 if(!certInfo
.certPolicies
.present
) {
1017 CE_CertPolicies
*cp
= &certInfo
.certPolicies
.extnData
->certPolicies
;
1020 for(unsigned i
=0; i
<cp
->numPolicies
; i
++) {
1021 const CE_PolicyInformation
*foundPolicy
= &cp
->policies
[i
];
1022 if(tpCompareOids(&foundPolicy
->certPolicyId
, &cpOid
)) {
1025 if(anyPolicyOK
&& tpCompareOids(&foundPolicy
->certPolicyId
, &CSSMOID_ANY_POLICY
)) {
1033 * Verify iChat handle. We search for a matching (case-insensitive) string
1036 * -- name component ("dmitch") from subject name's CommonName
1038 * -- domain name from subject name's organizationalUnit
1040 * Plus we require an Organization component of "Apple Computer, Inc." or "Apple Inc."
1042 static bool tpCompareIChatHandleName(
1044 const char *iChatHandle
, // UTF8
1045 uint32 iChatHandleLen
)
1047 CSSM_DATA_PTR subjNameData
= NULL
; // from fetchField
1049 bool ourRtn
= false;
1050 CSSM_X509_NAME_PTR x509name
;
1051 CSSM_X509_TYPE_VALUE_PAIR
*ptvp
;
1052 CSSM_X509_RDN_PTR rdnp
;
1056 /* search until all of these are true */
1057 CSSM_BOOL commonNameMatch
= CSSM_FALSE
; // name before '@'
1058 CSSM_BOOL orgUnitMatch
= CSSM_FALSE
; // domain after '@
1059 CSSM_BOOL orgMatch
= CSSM_FALSE
; // Apple Computer, Inc. (or Apple Inc.)
1062 * incoming UTF8 handle ==> two components.
1063 * First convert to CFString.
1065 if(iChatHandle
[iChatHandleLen
- 1] == '\0') {
1066 /* avoid NULL when creating CFStrings */
1069 CFDataRef cfd
= CFDataCreate(NULL
, (const UInt8
*)iChatHandle
, iChatHandleLen
);
1073 CFStringRef handleStr
= CFStringCreateFromExternalRepresentation(NULL
, cfd
,
1074 kCFStringEncodingUTF8
);
1076 if(handleStr
== NULL
) {
1077 tpPolicyError("tpCompareIChatHandleName: bad incoming handle (1)");
1082 * Find the '@' delimiter
1085 whereIsAt
= CFStringFind(handleStr
, CFSTR("@"), 0);
1086 if(whereIsAt
.length
== 0) {
1087 tpPolicyError("tpCompareIChatHandleName: bad incoming handle: no @");
1088 CFRelease(handleStr
);
1093 * Two components, before and after delimiter
1095 CFRange r
= {0, whereIsAt
.location
};
1096 CFStringRef iChatName
= CFStringCreateWithSubstring(NULL
, handleStr
, r
);
1097 if(iChatName
== NULL
) {
1098 tpPolicyError("tpCompareIChatHandleName: bad incoming handle (2)");
1099 CFRelease(handleStr
);
1102 r
.location
= whereIsAt
.location
+ 1; // after the '@'
1103 r
.length
= CFStringGetLength(handleStr
) - r
.location
;
1104 CFStringRef iChatDomain
= CFStringCreateWithSubstring(NULL
, handleStr
, r
);
1105 CFRelease(handleStr
);
1106 if(iChatDomain
== NULL
) {
1107 tpPolicyError("tpCompareIChatHandleName: bad incoming handle (3)");
1108 CFRelease(iChatName
);
1111 /* subsequent errors to errOut: */
1113 /* get subject name in CSSM form, all subsequent ops work on that */
1114 crtn
= cert
.fetchField(&CSSMOID_X509V1SubjectNameCStruct
, &subjNameData
);
1116 /* should never happen, we shouldn't be here if there is no subject */
1117 tpPolicyError("tpCompareIChatHandleName: error retrieving subject name");
1121 x509name
= (CSSM_X509_NAME_PTR
)subjNameData
->Data
;
1122 if((x509name
== NULL
) || (subjNameData
->Length
!= sizeof(CSSM_X509_NAME
))) {
1123 tpPolicyError("tpCompareIChatHandleName: malformed CSSM_X509_NAME");
1127 /* Now grunge thru the X509 name looking for three fields */
1129 for(rdnDex
=0; rdnDex
<x509name
->numberOfRDNs
; rdnDex
++) {
1130 rdnp
= &x509name
->RelativeDistinguishedName
[rdnDex
];
1131 for(pairDex
=0; pairDex
<rdnp
->numberOfPairs
; pairDex
++) {
1132 ptvp
= &rdnp
->AttributeTypeAndValue
[pairDex
];
1133 if(!commonNameMatch
&&
1134 tpCompareOids(&ptvp
->type
, &CSSMOID_CommonName
) &&
1135 tpCompareTvpToCfString(ptvp
, iChatName
, kCFCompareCaseInsensitive
)) {
1136 commonNameMatch
= CSSM_TRUE
;
1140 tpCompareOids(&ptvp
->type
, &CSSMOID_OrganizationalUnitName
) &&
1141 tpCompareTvpToCfString(ptvp
, iChatDomain
, kCFCompareCaseInsensitive
)) {
1142 orgUnitMatch
= CSSM_TRUE
;
1146 tpCompareOids(&ptvp
->type
, &CSSMOID_OrganizationName
) &&
1147 /* this one is case sensitive */
1148 (tpCompareTvpToCfString(ptvp
, CFSTR("Apple Computer, Inc."), 0) ||
1149 tpCompareTvpToCfString(ptvp
, CFSTR("Apple Inc."), 0))) {
1150 orgMatch
= CSSM_TRUE
;
1153 if(commonNameMatch
&& orgUnitMatch
&& orgMatch
) {
1161 cert
.freeField(&CSSMOID_X509V1SubjectNameCStruct
, subjNameData
);
1162 CFRelease(iChatName
);
1163 CFRelease(iChatDomain
);
1168 * Verify SSL options. Currently this just consists of matching the
1169 * leaf cert's subject common name against the caller's (optional)
1172 static CSSM_RETURN
tp_verifySslOpts(
1174 TPCertGroup
&certGroup
,
1175 const CSSM_DATA
*sslFieldOpts
,
1176 const iSignCertInfo
&leafCertInfo
)
1178 CSSM_APPLE_TP_SSL_OPTIONS
*sslOpts
= NULL
;
1179 unsigned hostNameLen
= 0;
1180 const char *serverName
= NULL
;
1181 TPCertInfo
*leaf
= certGroup
.certAtIndex(0);
1182 assert(leaf
!= NULL
);
1184 /* CSSM_APPLE_TP_SSL_OPTIONS is optional */
1185 if((sslFieldOpts
!= NULL
) && (sslFieldOpts
->Data
!= NULL
)) {
1186 sslOpts
= (CSSM_APPLE_TP_SSL_OPTIONS
*)sslFieldOpts
->Data
;
1187 switch(sslOpts
->Version
) {
1188 case CSSM_APPLE_TP_SSL_OPTS_VERSION
:
1189 if(sslFieldOpts
->Length
!= sizeof(CSSM_APPLE_TP_SSL_OPTIONS
)) {
1190 return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
1193 /* handle backwards compatibility here if necessary */
1195 return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
1197 hostNameLen
= sslOpts
->ServerNameLen
;
1198 serverName
= sslOpts
->ServerName
;
1201 /* host name check is optional */
1202 if(hostNameLen
!= 0) {
1203 if(serverName
== NULL
) {
1204 return CSSMERR_TP_INVALID_POINTER
;
1207 /* convert caller's hostname string to lower case */
1208 char *hostName
= (char *)certGroup
.alloc().malloc(hostNameLen
);
1209 memmove(hostName
, serverName
, hostNameLen
);
1210 tpToLower(hostName
, hostNameLen
);
1212 CSSM_BOOL match
= CSSM_FALSE
;
1214 /* First check subjectAltName... */
1215 bool dnsNameFound
= false;
1217 match
= tpCompareSubjectAltName(leafCertInfo
.subjectAltName
,
1218 hostName
, hostNameLen
,
1219 SAN_HostName
, false, dnsNameFound
, dummy
);
1222 * Then common name, if
1223 * -- no match from subjectAltName, AND
1224 * -- dnsName was NOT found, AND
1225 * -- hostName is not strictly numeric form (1.2.3.4)
1227 if(!match
&& !dnsNameFound
&& !tpIsNumeric(hostName
, hostNameLen
)) {
1229 match
= tpCompareSubjectName(*leaf
, SN_CommonName
, false, hostName
, hostNameLen
,
1232 certGroup
.alloc().free(hostName
);
1234 if(leaf
->addStatusCode(CSSMERR_APPLETP_HOSTNAME_MISMATCH
)) {
1235 return CSSMERR_APPLETP_HOSTNAME_MISMATCH
;
1241 * Ensure that, if an extendedKeyUsage extension is present in the
1242 * leaf, that either anyExtendedKeyUsage or the appropriate
1243 * CSSMOID_{Server,Client}Auth, or a SeverGatedCrypto usage is present.
1245 const iSignExtenInfo
&ekuInfo
= leafCertInfo
.extendKeyUsage
;
1246 if(ekuInfo
.present
) {
1247 bool foundGoodEku
= false;
1248 bool isServer
= true;
1249 CE_ExtendedKeyUsage
*eku
= (CE_ExtendedKeyUsage
*)ekuInfo
.extnData
;
1250 assert(eku
!= NULL
);
1253 * Determine appropriate extended key usage; default is SSL server
1255 const CSSM_OID
*extUse
= &CSSMOID_ServerAuth
;
1256 if((sslOpts
!= NULL
) && /* optional, default server side */
1257 (sslOpts
->Version
> 0) && /* this was added in struct version 1 */
1258 (sslOpts
->Flags
& CSSM_APPLE_TP_SSL_CLIENT
)) {
1259 extUse
= &CSSMOID_ClientAuth
;
1263 /* search for that one or for "any" indicator */
1264 for(unsigned i
=0; i
<eku
->numPurposes
; i
++) {
1265 const CSSM_OID
*purpose
= &eku
->purposes
[i
];
1266 if(tpCompareOids(purpose
, extUse
)) {
1267 foundGoodEku
= true;
1270 if(tpCompareOids(purpose
, &CSSMOID_ExtendedKeyUsageAny
)) {
1271 foundGoodEku
= true;
1274 if((policy
== kTP_IPSec
) && (tpCompareOids(purpose
, &CSSMOID_EKU_IPSec
))) {
1275 foundGoodEku
= true;
1279 /* server gated crypto: server side only */
1280 if(tpCompareOids(purpose
, &CSSMOID_NetscapeSGC
)) {
1281 foundGoodEku
= true;
1284 if(tpCompareOids(purpose
, &CSSMOID_MicrosoftSGC
)) {
1285 foundGoodEku
= true;
1291 if(leaf
->addStatusCode(CSSMERR_APPLETP_SSL_BAD_EXT_KEY_USE
)) {
1292 return CSSMERR_TP_VERIFY_ACTION_FAILED
;
1300 * Verify SMIME and iChat options.
1301 * This deals with both S/MIME and iChat policies; within the iChat domain it
1302 * deals with Apple-specific .mac certs as well as what we call "generic AIM"
1303 * certs, as used in the Windows AIM client.
1305 #define CE_CIPHER_MASK (~(CE_KU_EncipherOnly | CE_KU_DecipherOnly))
1307 static CSSM_RETURN
tp_verifySmimeOpts(
1309 TPCertGroup
&certGroup
,
1310 const CSSM_DATA
*smimeFieldOpts
,
1311 const iSignCertInfo
&leafCertInfo
)
1313 bool iChat
= (policy
== kTP_iChat
) ? true : false;
1316 * The CSSM_APPLE_TP_SMIME_OPTIONS pointer is optional as is everything in it.
1318 CSSM_APPLE_TP_SMIME_OPTIONS
*smimeOpts
= NULL
;
1319 if(smimeFieldOpts
!= NULL
) {
1320 smimeOpts
= (CSSM_APPLE_TP_SMIME_OPTIONS
*)smimeFieldOpts
->Data
;
1322 if(smimeOpts
!= NULL
) {
1323 switch(smimeOpts
->Version
) {
1324 case CSSM_APPLE_TP_SMIME_OPTS_VERSION
:
1325 if(smimeFieldOpts
->Length
!=
1326 sizeof(CSSM_APPLE_TP_SMIME_OPTIONS
)) {
1327 return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
1330 /* handle backwards compatibility here if necessary */
1332 return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
1336 TPCertInfo
*leaf
= certGroup
.certAtIndex(0);
1337 assert(leaf
!= NULL
);
1339 /* Verify optional email address, a.k.a. handle for iChat policy */
1340 unsigned emailLen
= 0;
1341 if(smimeOpts
!= NULL
) {
1342 emailLen
= smimeOpts
->SenderEmailLen
;
1346 bool emailFoundInSAN
= false;
1347 bool iChatHandleFound
= false; /* indicates a genuine Apple iChat cert */
1348 bool emailFoundInDN
= false;
1350 if(smimeOpts
->SenderEmail
== NULL
) {
1351 return CSSMERR_TP_INVALID_POINTER
;
1354 /* iChat - first try the Apple custom format */
1356 iChatHandleFound
= tpCompareIChatHandleName(*leaf
, smimeOpts
->SenderEmail
,
1358 if(iChatHandleFound
) {
1366 * normalize caller's email string
1367 * SMIME - lowercase only the portion after '@'
1368 * iChat - lowercase all of it
1370 char *email
= (char *)certGroup
.alloc().malloc(emailLen
);
1371 memmove(email
, smimeOpts
->SenderEmail
, emailLen
);
1372 tpNormalizeAddrSpec(email
, emailLen
, iChat
);
1376 * First check subjectAltName. The emailFound bool indicates
1377 * that *some* email address was found, regardless of a match
1381 match
= tpCompareSubjectAltName(leafCertInfo
.subjectAltName
,
1383 SAN_Email
, iChat
, dummy
, emailFoundInSAN
);
1386 * Then subject DN, CSSMOID_EmailAddress, if no match from
1387 * subjectAltName. In this case the whole email address is
1388 * case insensitive (RFC 3280, section 4.1.2.6), so
1392 tpNormalizeAddrSpec(email
, emailLen
, true);
1393 match
= tpCompareSubjectName(*leaf
, SN_Email
, true, email
, emailLen
,
1396 certGroup
.alloc().free(email
);
1399 * Error here if no match found but there was indeed *some*
1400 * email address in the cert.
1402 if(!match
&& (emailFoundInSAN
|| emailFoundInDN
)) {
1403 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND
)) {
1404 tpPolicyError("SMIME email addrs in cert but no match");
1405 return CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND
;
1411 * iChat only: error if app specified email address but there was
1414 if(iChat
&& !emailFoundInSAN
&& !emailFoundInDN
&& !iChatHandleFound
) {
1415 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_NO_EMAIL_ADDRS
)) {
1416 tpPolicyError("iChat: no email address or handle in cert");
1417 return CSSMERR_APPLETP_SMIME_NO_EMAIL_ADDRS
;
1423 * Going by the letter of the law, here's what RFC 2632 has to say
1424 * about the legality of an empty Subject Name:
1426 * ...the subject DN in a user's (i.e. end-entity) certificate MAY
1427 * be an empty SEQUENCE in which case the subjectAltName extension
1428 * will include the subject's identifier and MUST be marked as
1431 * OK, first examine the leaf cert's subject name.
1434 CSSM_DATA_PTR subjNameData
= NULL
;
1435 const iSignExtenInfo
&kuInfo
= leafCertInfo
.keyUsage
;
1436 const iSignExtenInfo
&ekuInfo
= leafCertInfo
.extendKeyUsage
;
1437 const CSSM_X509_NAME
*x509Name
= NULL
;
1440 /* empty subject name processing is S/MIME only */
1444 crtn
= leaf
->fetchField(&CSSMOID_X509V1SubjectNameCStruct
, &subjNameData
);
1446 /* This should really never happen */
1447 tpPolicyError("SMIME policy: error fetching subjectName");
1448 leaf
->addStatusCode(CSSMERR_TP_INVALID_CERTIFICATE
);
1449 return CSSMERR_TP_INVALID_CERTIFICATE
;
1451 /* must do a leaf->freeField(&CSSMOID_X509V1SubjectNameCStruct on exit */
1453 x509Name
= (const CSSM_X509_NAME
*)subjNameData
->Data
;
1454 if(x509Name
->numberOfRDNs
== 0) {
1456 * Empty subject name. If we haven't already seen a valid
1457 * email address in the subject alternate name (by looking
1458 * for a specific address specified by app), try to find
1461 if(!emailFoundInSAN
&& // haven't found one, and
1462 (emailLen
== 0)) { // didn't even look yet
1464 tpCompareSubjectAltName(leafCertInfo
.subjectAltName
,
1465 NULL
, 0, // email, emailLen,
1466 SAN_Email
, false, dummy
,
1467 emailFoundInSAN
); // the variable we're updating
1469 if(!emailFoundInSAN
) {
1470 tpPolicyError("SMIME policy fail: empty subject name and "
1471 "no Email Addrs in SubjectAltName");
1472 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_NO_EMAIL_ADDRS
)) {
1473 leaf
->freeField(&CSSMOID_X509V1SubjectNameCStruct
, subjNameData
);
1474 return CSSMERR_TP_VERIFY_ACTION_FAILED
;
1477 /* have to skip the next block */
1483 * One more thing: this leaf must indeed have a subjAltName
1484 * extension and it must be critical. We would not have gotten this
1485 * far if the subjAltName extension was not actually present....
1487 assert(leafCertInfo
.subjectAltName
.present
);
1488 if(!leafCertInfo
.subjectAltName
.critical
) {
1489 tpPolicyError("SMIME policy fail: empty subject name and "
1490 "no Email Addrs in SubjectAltName");
1491 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_SUBJ_ALT_NAME_NOT_CRIT
)) {
1492 leaf
->freeField(&CSSMOID_X509V1SubjectNameCStruct
, subjNameData
);
1493 return CSSMERR_TP_VERIFY_ACTION_FAILED
;
1498 leaf
->freeField(&CSSMOID_X509V1SubjectNameCStruct
, subjNameData
);
1501 * Enforce the usage of the key associated with the leaf cert.
1502 * Cert's KeyUsage must be a superset of what the app is trying to do.
1503 * Note the {en,de}cipherOnly flags are handled separately....
1505 if(kuInfo
.present
&& (smimeOpts
!= NULL
)) {
1506 CE_KeyUsage certKu
= *((CE_KeyUsage
*)kuInfo
.extnData
);
1507 CE_KeyUsage appKu
= smimeOpts
->IntendedUsage
;
1508 CE_KeyUsage intersection
= certKu
& appKu
;
1509 if((intersection
& CE_CIPHER_MASK
) != (appKu
& CE_CIPHER_MASK
)) {
1510 tpPolicyError("SMIME KeyUsage err: appKu 0x%x certKu 0x%x",
1512 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_KEY_USE
)) {
1513 return CSSMERR_TP_VERIFY_ACTION_FAILED
;
1517 /* Now the en/de cipher only bits - for keyAgreement only */
1518 if(appKu
& CE_KU_KeyAgreement
) {
1520 * 1. App wants to use this for key agreement; it must
1521 * say what it wants to do with the derived key.
1522 * In this context, the app's XXXonly bit means that
1523 * it wants to use the key for that op - not necessarliy
1526 if((appKu
& (CE_KU_EncipherOnly
| CE_KU_DecipherOnly
)) == 0) {
1527 tpPolicyError("SMIME KeyUsage err: KeyAgreement with "
1528 "no Encipher or Decipher");
1529 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_KEY_USE
)) {
1530 return CSSMERR_TP_VERIFY_ACTION_FAILED
;
1535 * 2. If cert restricts to encipher only make sure the
1536 * app isn't trying to decipher.
1538 if((certKu
& CE_KU_EncipherOnly
) &&
1539 (appKu
& CE_KU_DecipherOnly
)) {
1540 tpPolicyError("SMIME KeyUsage err: cert EncipherOnly, "
1541 "app wants to decipher");
1542 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_KEY_USE
)) {
1543 return CSSMERR_TP_VERIFY_ACTION_FAILED
;
1548 * 3. If cert restricts to decipher only make sure the
1549 * app isn't trying to encipher.
1551 if((certKu
& CE_KU_DecipherOnly
) &&
1552 (appKu
& CE_KU_EncipherOnly
)) {
1553 tpPolicyError("SMIME KeyUsage err: cert DecipherOnly, "
1554 "app wants to encipher");
1555 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_KEY_USE
)) {
1556 return CSSMERR_TP_VERIFY_ACTION_FAILED
;
1563 * Extended Key Use verification, which is different for the two policies.
1566 if(iChat
&& !ekuInfo
.present
) {
1568 * iChat: whether generic AIM cert or Apple .mac/iChat cert, we must have an
1569 * extended key use extension.
1571 tpPolicyError("iChat: No extended Key Use");
1572 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
)) {
1573 return CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
;
1577 if(!iChatHandleFound
) {
1579 * S/MIME and generic AIM certs when evaluating iChat policy.
1580 * Look for either emailProtection or anyExtendedKeyUsage usages.
1582 * S/MIME : the whole extension is optional.
1583 * iChat : extension must be there (which we've already covered, above)
1584 * and we must find one of those extensions.
1586 if(ekuInfo
.present
) {
1587 bool foundGoodEku
= false;
1588 CE_ExtendedKeyUsage
*eku
= (CE_ExtendedKeyUsage
*)ekuInfo
.extnData
;
1589 assert(eku
!= NULL
);
1590 for(unsigned i
=0; i
<eku
->numPurposes
; i
++) {
1591 if(tpCompareOids(&eku
->purposes
[i
], &CSSMOID_EmailProtection
)) {
1592 foundGoodEku
= true;
1595 if(tpCompareOids(&eku
->purposes
[i
], &CSSMOID_ExtendedKeyUsageAny
)) {
1596 foundGoodEku
= true;
1601 tpPolicyError("iChat/SMIME: No appropriate extended Key Use");
1602 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
)) {
1603 return CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
;
1610 * Apple iChat cert. Look for anyExtendedKeyUsage, iChatSigning,
1611 * ichatEncrypting - the latter of two which can optionally be
1614 assert(iChat
); /* or we could not have even looked for an iChat style handle */
1615 assert(ekuInfo
.present
); /* checked above */
1616 bool foundAnyEku
= false;
1617 bool foundIChatSign
= false;
1618 bool foundISignEncrypt
= false;
1619 CE_ExtendedKeyUsage
*eku
= (CE_ExtendedKeyUsage
*)ekuInfo
.extnData
;
1620 assert(eku
!= NULL
);
1622 for(unsigned i
=0; i
<eku
->numPurposes
; i
++) {
1623 if(tpCompareOids(&eku
->purposes
[i
],
1624 &CSSMOID_APPLE_EKU_ICHAT_SIGNING
)) {
1625 foundIChatSign
= true;
1627 else if(tpCompareOids(&eku
->purposes
[i
],
1628 &CSSMOID_APPLE_EKU_ICHAT_ENCRYPTION
)) {
1629 foundISignEncrypt
= true;
1631 else if(tpCompareOids(&eku
->purposes
[i
], &CSSMOID_ExtendedKeyUsageAny
)) {
1636 if(!foundAnyEku
&& !foundISignEncrypt
&& !foundIChatSign
) {
1637 /* No go - no acceptable uses found */
1638 tpPolicyError("iChat: No valid extended Key Uses found");
1639 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
)) {
1640 return CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
;
1644 /* check for specifically required uses */
1645 if((smimeOpts
!= NULL
) && (smimeOpts
->IntendedUsage
!= 0)) {
1646 if(smimeOpts
->IntendedUsage
& CE_KU_DigitalSignature
) {
1647 if(!foundIChatSign
) {
1648 tpPolicyError("iChat: ICHAT_SIGNING required, but missing");
1649 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
)) {
1650 return CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
;
1654 if(smimeOpts
->IntendedUsage
& CE_KU_DataEncipherment
) {
1655 if(!foundISignEncrypt
) {
1656 tpPolicyError("iChat: ICHAT_ENCRYPT required, but missing");
1657 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
)) {
1658 return CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
;
1662 } /* checking IntendedUsage */
1663 } /* iChat cert format */
1669 * Verify Apple SW Update signing (was Apple Code Signing, pre-Leopard) options.
1671 * -- Must have one intermediate cert
1672 * -- intermediate must have basic constraints with path length 0
1673 * -- intermediate has CSSMOID_APPLE_EKU_CODE_SIGNING EKU
1674 * -- leaf cert has either CODE_SIGNING or CODE_SIGN_DEVELOPMENT EKU (the latter of
1675 * which triggers a CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT error)
1677 static CSSM_RETURN
tp_verifySWUpdateSigningOpts(
1678 TPCertGroup
&certGroup
,
1679 const CSSM_DATA
*fieldOpts
, // currently unused
1680 const iSignCertInfo
*certInfo
) // all certs, size certGroup.numCerts()
1682 unsigned numCerts
= certGroup
.numCerts();
1683 const iSignCertInfo
*isCertInfo
;
1685 // const CE_BasicConstraints *bc; // currently unused
1686 CE_ExtendedKeyUsage
*eku
;
1687 CSSM_RETURN crtn
= CSSM_OK
;
1690 if(!certGroup
.isAllowedError(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
)) {
1691 tpPolicyError("tp_verifySWUpdateSigningOpts: numCerts %u", numCerts
);
1692 return CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
1694 else if(numCerts
< 3) {
1695 /* this error allowed, but no intermediate...check leaf */
1700 /* verify intermediate cert */
1701 isCertInfo
= &certInfo
[1];
1702 tpCert
= certGroup
.certAtIndex(1);
1704 if(!isCertInfo
->basicConstraints
.present
) {
1705 tpPolicyError("tp_verifySWUpdateSigningOpts: no basicConstraints in intermediate");
1706 if(tpCert
->addStatusCode(CSSMERR_APPLETP_CS_NO_BASIC_CONSTRAINTS
)) {
1707 return CSSMERR_APPLETP_CS_NO_BASIC_CONSTRAINTS
;
1711 /* ExtendedKeyUse required, one legal value */
1712 if(!isCertInfo
->extendKeyUsage
.present
) {
1713 tpPolicyError("tp_verifySWUpdateSigningOpts: no extendedKeyUse in intermediate");
1714 if(tpCert
->addStatusCode(CSSMERR_APPLETP_CS_NO_EXTENDED_KEY_USAGE
)) {
1715 return CSSMERR_APPLETP_CS_NO_EXTENDED_KEY_USAGE
;
1722 eku
= &isCertInfo
->extendKeyUsage
.extnData
->extendedKeyUsage
;
1723 assert(eku
!= NULL
);
1724 if(eku
->numPurposes
!= 1) {
1725 tpPolicyError("tp_verifySWUpdateSigningOpts: bad eku->numPurposes in intermediate (%lu)",
1726 (unsigned long)eku
->numPurposes
);
1727 if(tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
)) {
1728 return CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
1730 else if(eku
->numPurposes
== 0) {
1731 /* ignore that error but no EKU - skip EKU check */
1734 /* else ignore error and we have an intermediate EKU; proceed */
1737 if(!tpCompareOids(&eku
->purposes
[0], &CSSMOID_APPLE_EKU_CODE_SIGNING
)) {
1738 tpPolicyError("tp_verifySWUpdateSigningOpts: bad EKU");
1739 if(tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
)) {
1740 crtn
= CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
1746 /* verify leaf cert */
1747 isCertInfo
= &certInfo
[0];
1748 tpCert
= certGroup
.certAtIndex(0);
1749 if(!isCertInfo
->extendKeyUsage
.present
) {
1750 tpPolicyError("tp_verifySWUpdateSigningOpts: no extendedKeyUse in leaf");
1751 if(tpCert
->addStatusCode(CSSMERR_APPLETP_CS_NO_EXTENDED_KEY_USAGE
)) {
1752 return crtn
? crtn
: CSSMERR_APPLETP_CS_NO_EXTENDED_KEY_USAGE
;
1755 /* have to skip remainder */
1760 eku
= &isCertInfo
->extendKeyUsage
.extnData
->extendedKeyUsage
;
1761 assert(eku
!= NULL
);
1762 if(eku
->numPurposes
!= 1) {
1763 tpPolicyError("tp_verifySWUpdateSigningOpts: bad eku->numPurposes (%lu)",
1764 (unsigned long)eku
->numPurposes
);
1765 if(tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
)) {
1766 if(crtn
== CSSM_OK
) {
1767 crtn
= CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
1772 if(!tpCompareOids(&eku
->purposes
[0], &CSSMOID_APPLE_EKU_CODE_SIGNING
)) {
1773 if(tpCompareOids(&eku
->purposes
[0], &CSSMOID_APPLE_EKU_CODE_SIGNING_DEV
)) {
1774 tpPolicyError("tp_verifySWUpdateSigningOpts: DEVELOPMENT cert");
1775 if(tpCert
->addStatusCode(CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT
)) {
1776 if(crtn
== CSSM_OK
) {
1777 crtn
= CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT
;
1782 tpPolicyError("tp_verifySWUpdateSigningOpts: bad EKU in leaf");
1783 if(tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
)) {
1784 if(crtn
== CSSM_OK
) {
1785 crtn
= CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
1795 * Verify Apple Resource Signing options.
1797 * -- leaf cert must have CSSMOID_APPLE_EKU_RESOURCE_SIGNING EKU
1798 * -- chain length must be >= 2
1799 * -- mainline code already verified that leaf KeyUsage = digitalSignature (only)
1801 static CSSM_RETURN
tp_verifyResourceSigningOpts(
1802 TPCertGroup
&certGroup
,
1803 const CSSM_DATA
*fieldOpts
, // currently unused
1804 const iSignCertInfo
*certInfo
) // all certs, size certGroup.numCerts()
1806 unsigned numCerts
= certGroup
.numCerts();
1808 if(!certGroup
.isAllowedError(CSSMERR_APPLETP_RS_BAD_CERT_CHAIN_LENGTH
)) {
1809 tpPolicyError("tp_verifyResourceSigningOpts: numCerts %u", numCerts
);
1810 return CSSMERR_APPLETP_RS_BAD_CERT_CHAIN_LENGTH
;
1813 const iSignCertInfo
&leafCert
= certInfo
[0];
1814 TPCertInfo
*leaf
= certGroup
.certAtIndex(0);
1816 /* leaf ExtendedKeyUse required, one legal value */
1817 if(!tpVerifyEKU(leafCert
, CSSMOID_APPLE_EKU_RESOURCE_SIGNING
, false)) {
1818 tpPolicyError("tp_verifyResourceSigningOpts: no RESOURCE_SIGNING EKU");
1819 if(leaf
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
)) {
1820 return CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
1828 * Common code for Apple Code Signing and Apple Package Signing.
1829 * For now we just require an RFC3280-style CodeSigning EKU in the leaf
1830 * for both policies.
1832 static CSSM_RETURN
tp_verifyCodePkgSignOpts(
1834 TPCertGroup
&certGroup
,
1835 const CSSM_DATA
*fieldOpts
, // currently unused
1836 const iSignCertInfo
*certInfo
) // all certs, size certGroup.numCerts()
1838 const iSignCertInfo
&leafCert
= certInfo
[0];
1840 /* leaf ExtendedKeyUse required, one legal value */
1841 if(!tpVerifyEKU(leafCert
, CSSMOID_ExtendedUseCodeSigning
, false)) {
1842 TPCertInfo
*leaf
= certGroup
.certAtIndex(0);
1843 tpPolicyError("tp_verifyCodePkgSignOpts: no CodeSigning EKU");
1844 if(leaf
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
)) {
1845 return CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
1854 * Verify MacAppStore receipt verification policy options.
1856 * -- Must have one intermediate cert
1857 * -- intermediate must be the FairPlay intermediate
1858 * -- leaf cert has the CSSMOID_APPLE_EXTENSION_MACAPPSTORE_RECEIPT marker extension
1860 static CSSM_RETURN
tp_verifyMacAppStoreReceiptOpts(
1861 TPCertGroup
&certGroup
,
1862 const CSSM_DATA
*fieldOpts
, // currently unused
1863 const iSignCertInfo
*certInfo
) // all certs, size certGroup.numCerts()
1865 unsigned numCerts
= certGroup
.numCerts();
1868 if (!certGroup
.isAllowedError(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
))
1870 tpPolicyError("tp_verifyMacAppStoreReceiptOpts: numCerts %u", numCerts
);
1871 return CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
1875 const iSignCertInfo
*isCertInfo
;
1878 /* verify intermediate cert */
1879 isCertInfo
= &certInfo
[1];
1880 tpCert
= certGroup
.certAtIndex(1);
1882 if (!isCertInfo
->basicConstraints
.present
)
1884 tpPolicyError("tp_verifyAppleIDSharingOpts: no basicConstraints in intermediate");
1885 if (tpCert
->addStatusCode(CSSMERR_APPLETP_CS_NO_BASIC_CONSTRAINTS
))
1886 return CSSMERR_APPLETP_CS_NO_BASIC_CONSTRAINTS
;
1889 // Now check the leaf
1890 isCertInfo
= &certInfo
[0];
1891 tpCert
= certGroup
.certAtIndex(0);
1892 if (certInfo
->certificatePolicies
.present
)
1894 // syslog(LOG_ERR, "tp_verifyMacAppStoreReceiptOpts: found certificatePolicies");
1895 const CE_CertPolicies
*certPolicies
=
1896 &isCertInfo
->certificatePolicies
.extnData
->certPolicies
;
1897 if (!certificatePoliciesContainsOID(certPolicies
, &CSSMOID_MACAPPSTORE_RECEIPT_CERT_POLICY
))
1898 if (tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
))
1899 return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
1903 // syslog(LOG_ERR, "tp_verifyMacAppStoreReceiptOpts: no certificatePolicies present"); // DEBUG
1904 tpPolicyError("tp_verifyMacAppStoreReceiptOpts: no certificatePolicies present in leaf");
1905 if (tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
))
1906 return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
1912 bool certificatePoliciesContainsOID(const CE_CertPolicies
*certPolicies
, const CSSM_OID
*oidToFind
)
1914 // returns true if the given OID is present in the cert policies
1916 if (!certPolicies
|| !oidToFind
)
1919 const uint32 maxIndex
= 100; // sanity check
1920 for (uint32 policyIndex
= 0; policyIndex
< certPolicies
->numPolicies
&& policyIndex
< maxIndex
; policyIndex
++)
1922 CE_PolicyInformation
*certPolicyInfo
= &certPolicies
->policies
[policyIndex
];
1923 CSSM_OID_PTR oid
= &certPolicyInfo
->certPolicyId
;
1924 if (oid
&& tpCompareOids(oid
, oidToFind
)) // found it
1933 * Verify Apple ID Sharing options.
1935 * -- Do basic cert validation (OCSP-based certs)
1936 * -- Validate that the cert is an Apple ID sharing cert:
1937 * has a custom extension: OID: Apple ID Sharing Certificate ( 1 2 840 113635 100 4 7 )
1938 * (CSSMOID_APPLE_EXTENSION_APPLEID_SHARING)
1939 * EKU should have both client and server authentication
1940 * chains to the "Apple Application Integration Certification Authority" intermediate
1941 * -- optionally has a client-specified common name, which is the Apple ID account's UUID.
1943 * -- Must have one intermediate cert ("Apple Application Integration Certification Authority")
1944 * -- intermediate must have basic constraints with path length 0
1945 * -- intermediate has CSSMOID_APPLE_EXTENSION_AAI_INTERMEDIATE extension (OID 1 2 840 113635 100 6 2 3)
1946 OR APPLE_EXTENSION_AAI_INTERMEDIATE_2
1949 static CSSM_RETURN
tp_verifyAppleIDSharingOpts(TPCertGroup
&certGroup
,
1950 const CSSM_DATA
*fieldOpts
, // optional Common Name
1951 const iSignCertInfo
*certInfo
) // all certs, size certGroup.numCerts()
1953 unsigned numCerts
= certGroup
.numCerts();
1954 const iSignCertInfo
*isCertInfo
;
1956 // const CE_BasicConstraints *bc; // currently unused
1957 CE_ExtendedKeyUsage
*eku
;
1958 CSSM_RETURN crtn
= CSSM_OK
;
1959 unsigned int serverNameLen
= 0;
1960 const char *serverName
= NULL
;
1962 // The CSSM_APPLE_TP_SMIME_OPTIONS pointer is optional as is everything in it.
1963 if (fieldOpts
&& fieldOpts
->Data
)
1965 CSSM_APPLE_TP_SSL_OPTIONS
*sslOpts
= (CSSM_APPLE_TP_SSL_OPTIONS
*)fieldOpts
->Data
;
1966 switch (sslOpts
->Version
)
1968 case CSSM_APPLE_TP_SSL_OPTS_VERSION
:
1969 if (fieldOpts
->Length
!= sizeof(CSSM_APPLE_TP_SSL_OPTIONS
))
1970 return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
1972 /* handle backwards compatibility here if necessary */
1974 return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
1976 serverNameLen
= sslOpts
->ServerNameLen
;
1977 serverName
= sslOpts
->ServerName
;
1980 //------------------------------------------------------------------------
1984 if (!certGroup
.isAllowedError(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
))
1986 tpPolicyError("tp_verifyAppleIDSharingOpts: numCerts %u", numCerts
);
1987 return CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
1992 /* this error allowed, but no intermediate...check leaf */
1997 /* verify intermediate cert */
1998 isCertInfo
= &certInfo
[1];
1999 tpCert
= certGroup
.certAtIndex(1);
2001 if (!isCertInfo
->basicConstraints
.present
)
2003 tpPolicyError("tp_verifyAppleIDSharingOpts: no basicConstraints in intermediate");
2004 if (tpCert
->addStatusCode(CSSMERR_APPLETP_CS_NO_BASIC_CONSTRAINTS
))
2005 return CSSMERR_APPLETP_CS_NO_BASIC_CONSTRAINTS
;
2010 /* verify leaf cert */
2011 isCertInfo
= &certInfo
[0];
2012 tpCert
= certGroup
.certAtIndex(0);
2014 /* host name check is optional */
2015 if (serverNameLen
!= 0)
2017 if (serverName
== NULL
)
2018 return CSSMERR_TP_INVALID_POINTER
;
2020 /* convert caller's hostname string to lower case */
2021 char *hostName
= (char *)certGroup
.alloc().malloc(serverNameLen
);
2022 memmove(hostName
, serverName
, serverNameLen
);
2023 tpToLower(hostName
, serverNameLen
);
2025 /* Check common name... */
2028 CSSM_BOOL match
= tpCompareSubjectName(*tpCert
, SN_CommonName
, false, hostName
,
2029 serverNameLen
, fieldFound
);
2031 certGroup
.alloc().free(hostName
);
2032 if (!match
&& tpCert
->addStatusCode(CSSMERR_APPLETP_HOSTNAME_MISMATCH
))
2033 return CSSMERR_APPLETP_HOSTNAME_MISMATCH
;
2036 if (certInfo
->certificatePolicies
.present
)
2038 const CE_CertPolicies
*certPolicies
=
2039 &isCertInfo
->certificatePolicies
.extnData
->certPolicies
;
2040 if (!certificatePoliciesContainsOID(certPolicies
, &CSSMOID_APPLEID_SHARING_CERT_POLICY
))
2041 if (tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
))
2042 return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2045 if (tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
))
2046 return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2048 if (!isCertInfo
->extendKeyUsage
.present
)
2050 tpPolicyError("tp_verifyAppleIDSharingOpts: no extendedKeyUse in leaf");
2051 if (tpCert
->addStatusCode(CSSMERR_APPLETP_CS_NO_EXTENDED_KEY_USAGE
))
2052 return crtn
? crtn
: CSSMERR_APPLETP_CS_NO_EXTENDED_KEY_USAGE
;
2054 /* have to skip remainder */
2058 // Check that certificate can do Client and Server Authentication (EKU)
2059 eku
= &isCertInfo
->extendKeyUsage
.extnData
->extendedKeyUsage
;
2060 assert(eku
!= NULL
);
2061 if(eku
->numPurposes
!= 2)
2063 tpPolicyError("tp_verifyAppleIDSharingOpts: bad eku->numPurposes (%lu)",
2064 (unsigned long)eku
->numPurposes
);
2065 if (tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
))
2067 if (crtn
== CSSM_OK
)
2068 crtn
= CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
2072 bool canDoClientAuth
= false, canDoServerAuth
= false, ekuError
= false;
2073 for (int ix
=0;ix
<2;ix
++)
2075 if (tpCompareOids(&eku
->purposes
[ix
], &CSSMOID_ClientAuth
))
2076 canDoClientAuth
= true;
2078 if (tpCompareOids(&eku
->purposes
[ix
], &CSSMOID_ServerAuth
))
2079 canDoServerAuth
= true;
2087 if (!(canDoClientAuth
&& canDoServerAuth
))
2091 tpPolicyError("tp_verifyAppleIDSharingOpts: bad EKU in leaf");
2092 if (tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
))
2094 if (crtn
== CSSM_OK
)
2095 crtn
= CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
2103 * Verify Time Stamping (RFC3161) policy options.
2105 * -- Leaf must contain Extended Key Usage (EKU), marked critical
2106 * -- The EKU must contain the id-kp-timeStamping purpose and no other
2108 static CSSM_RETURN
tp_verifyTimeStampingOpts(TPCertGroup
&certGroup
,
2109 const CSSM_DATA
*fieldOpts
, // currently unused
2110 const iSignCertInfo
*certInfo
) // all certs, size certGroup.numCerts()
2112 //unsigned numCerts = certGroup.numCerts();
2113 const iSignCertInfo
*isCertInfo
;
2115 CE_ExtendedKeyUsage
*eku
;
2117 isCertInfo
= &certInfo
[0];
2118 tpCert
= certGroup
.certAtIndex(0);
2120 if (!isCertInfo
->extendKeyUsage
.present
)
2122 tpPolicyError("tp_verifyTimeStampingOpts: no extendedKeyUse in leaf");
2123 tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
);
2124 return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2127 if(!isCertInfo
->extendKeyUsage
.critical
)
2129 tpPolicyError("tp_verifyTimeStampingOpts: extended key usage !critical");
2130 tpCert
->addStatusCode(CSSMERR_APPLETP_EXT_KEYUSAGE_NOT_CRITICAL
);
2131 return CSSMERR_APPLETP_EXT_KEYUSAGE_NOT_CRITICAL
;
2134 eku
= &isCertInfo
->extendKeyUsage
.extnData
->extendedKeyUsage
;
2135 assert(eku
!= NULL
);
2137 if(eku
->numPurposes
!= 1)
2139 tpPolicyError("tp_verifyTimeStampingOpts: bad eku->numPurposes (%lu)",
2140 (unsigned long)eku
->numPurposes
);
2141 tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
);
2142 return CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
2145 if(!tpCompareOids(&eku
->purposes
[0], &CSSMOID_TimeStamping
))
2147 tpPolicyError("tp_verifyTimeStampingOpts: TimeStamping purpose not found");
2148 tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
);
2149 return CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
2156 * Verify Passbook Signing policy options.
2158 * -- Do basic cert validation (OCSP-based certs)
2159 * -- Chains to the Apple root CA
2160 * -- Has custom marker extension (1.2.840.113635.100.6.1.16)
2161 * (CSSMOID_APPLE_EXTENSION_PASSBOOK_SIGNING)
2162 * -- EKU contains Passbook Signing purpose (1.2.840.113635.100.4.14)
2163 * (CSSMOID_APPLE_EKU_PASSBOOK_SIGNING)
2164 * -- UID field of Subject must contain provided card signer string
2165 * -- OU field of Subject must contain provided team identifier string
2167 static CSSM_RETURN
tp_verifyPassbookSigningOpts(TPCertGroup
&certGroup
,
2168 const CSSM_DATA
*fieldOpts
,
2169 const iSignCertInfo
*certInfo
) // all certs, size certGroup.numCerts()
2171 unsigned numCerts
= certGroup
.numCerts();
2172 const iSignCertInfo
*isCertInfo
;
2174 CE_ExtendedKeyUsage
*eku
;
2175 CSSM_RETURN crtn
= CSSM_OK
;
2176 unsigned int nameLen
= 0;
2177 const char *name
= NULL
;
2178 char *p
, *signerName
= NULL
, *teamIdentifier
= NULL
;
2181 isCertInfo
= &certInfo
[0];
2182 tpCert
= certGroup
.certAtIndex(0);
2184 /* The CSSM_APPLE_TP_SMIME_OPTIONS pointer is required. */
2185 if (!fieldOpts
|| !fieldOpts
->Data
)
2186 return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
2188 CSSM_APPLE_TP_SMIME_OPTIONS
*opts
= (CSSM_APPLE_TP_SMIME_OPTIONS
*)fieldOpts
->Data
;
2189 switch (opts
->Version
)
2191 case CSSM_APPLE_TP_SMIME_OPTS_VERSION
:
2192 if (fieldOpts
->Length
!= sizeof(CSSM_APPLE_TP_SMIME_OPTIONS
))
2193 return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
2195 /* handle backwards compatibility here if necessary */
2197 return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
2199 nameLen
= opts
->SenderEmailLen
;
2200 name
= opts
->SenderEmail
;
2201 if (!name
|| !nameLen
)
2202 return CSSMERR_APPLETP_IDENTIFIER_MISSING
;
2205 /* Split the provided name into signer name and team identifier
2206 * (allocates memory, which must be freed at end) */
2207 signerName
= (char *)certGroup
.alloc().malloc(nameLen
);
2208 teamIdentifier
= (char *)certGroup
.alloc().malloc(nameLen
);
2209 memmove(signerName
, name
, nameLen
);
2210 teamIdentifier
[0] = '\0';
2211 if ((p
= strchr(signerName
, '\t')) != NULL
) {
2213 memmove(teamIdentifier
, p
, strlen(p
)+1);
2216 /* Check signer name in UID field */
2217 if (CSSM_FALSE
== tpCompareSubjectName(*tpCert
,
2218 SN_UserID
, false, signerName
, (unsigned int)strlen(signerName
), found
)) {
2219 tpPolicyError("tp_verifyPassbookSigningOpts: signer name not in subject UID field");
2220 tpCert
->addStatusCode(CSSMERR_APPLETP_IDENTIFIER_MISSING
);
2221 crtn
= CSSMERR_APPLETP_IDENTIFIER_MISSING
;
2225 /* Check team identifier in OU field */
2226 if (CSSM_FALSE
== tpCompareSubjectName(*tpCert
,
2227 SN_OrgUnit
, false, teamIdentifier
, (unsigned int)strlen(teamIdentifier
), found
)) {
2228 tpPolicyError("tp_verifyPassbookSigningOpts: team identifier not in subject OU field");
2229 tpCert
->addStatusCode(CSSMERR_APPLETP_IDENTIFIER_MISSING
);
2230 crtn
= CSSMERR_APPLETP_IDENTIFIER_MISSING
;
2234 /* Check that EKU extension is present */
2235 if (!isCertInfo
->extendKeyUsage
.present
) {
2236 tpPolicyError("tp_verifyPassbookSigningOpts: no extendedKeyUse in leaf");
2237 tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
);
2238 crtn
= CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2242 /* Check that EKU contains Passbook Signing purpose */
2243 eku
= &isCertInfo
->extendKeyUsage
.extnData
->extendedKeyUsage
;
2244 assert(eku
!= NULL
);
2246 for (int ix
=0;ix
<eku
->numPurposes
;ix
++) {
2247 if (tpCompareOids(&eku
->purposes
[ix
], &CSSMOID_APPLE_EKU_PASSBOOK_SIGNING
)) {
2253 tpPolicyError("tp_verifyPassbookSigningOpts: Passbook Signing purpose not found");
2254 tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
);
2255 crtn
= CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
2259 /* Check that Passbook Signing marker extension is present */
2260 if (!(isCertInfo
->foundPassbookSigning
== CSSM_TRUE
)) {
2261 tpPolicyError("tp_verifyPassbookSigningOpts: no Passbook Signing extension in leaf");
2262 tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
);
2263 crtn
= CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2267 /* Check that cert chain is anchored by the Apple Root CA */
2269 tpPolicyError("tp_verifyPassbookSigningOpts: numCerts %u", numCerts
);
2270 crtn
= CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
2274 tpCert
= certGroup
.certAtIndex(numCerts
-1);
2275 const CSSM_DATA
*certData
= tpCert
->itemData();
2276 unsigned char digest
[CC_SHA1_DIGEST_LENGTH
];
2277 CC_SHA1(certData
->Data
, (CC_LONG
)certData
->Length
, digest
);
2278 if (memcmp(digest
, kAppleCASHA1
, sizeof(digest
))) {
2279 tpPolicyError("tp_verifyPassbookSigningOpts: invalid anchor for policy");
2280 tpCert
->addStatusCode(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
);
2281 crtn
= CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
2288 certGroup
.alloc().free(signerName
);
2290 certGroup
.alloc().free(teamIdentifier
);
2296 * Verify Mobile Store policy options.
2298 * -- Do basic cert validation.
2299 * -- Chain length must be exactly 3.
2300 * -- Must chain to known Mobile Store root.
2301 * -- Intermediate must have CSSMOID_APPLE_EXTENSION_SYSINT2_INTERMEDIATE marker
2302 * (1.2.840.113635.100.6.2.10)
2303 * -- Key usage in leaf certificate must be Digital Signature.
2304 * -- Leaf has certificatePolicies extension with appropriate policy:
2305 * (1.2.840.113635.100.5.12) if testPolicy is false
2306 * (1.2.840.113635.100.5.12.1) if testPolicy is true
2308 static CSSM_RETURN
tp_verifyMobileStoreSigningOpts(TPCertGroup
&certGroup
,
2309 const CSSM_DATA
*fieldOpts
,
2310 const iSignCertInfo
*certInfo
, // all certs, size certGroup.numCerts()
2313 unsigned numCerts
= certGroup
.numCerts();
2314 const iSignCertInfo
*isCertInfo
;
2317 CSSM_RETURN crtn
= CSSM_OK
;
2319 isCertInfo
= &certInfo
[0];
2320 tpCert
= certGroup
.certAtIndex(0);
2322 /* Check that KU extension is present */
2323 if (!isCertInfo
->keyUsage
.present
) {
2324 tpPolicyError("tp_verifyMobileStoreSigningOpts: no keyUsage in leaf");
2325 tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
);
2326 crtn
= CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2330 /* Check that KU contains Digital Signature usage */
2331 ku
= isCertInfo
->keyUsage
.extnData
->keyUsage
;
2332 if (!(ku
& CE_KU_DigitalSignature
)) {
2333 tpPolicyError("tp_verifyMobileStoreSigningOpts: DigitalSignature usage not found");
2334 tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE
);
2335 crtn
= CSSMERR_APPLETP_INVALID_KEY_USAGE
;
2339 /* Check that Mobile Store Signing certicate policy is present in leaf */
2340 if (isCertInfo
->certificatePolicies
.present
)
2342 const CE_CertPolicies
*certPolicies
=
2343 &isCertInfo
->certificatePolicies
.extnData
->certPolicies
;
2344 const CSSM_OID
*policyOID
= (testPolicy
) ?
2345 &CSSMOID_TEST_MOBILE_STORE_SIGNING_POLICY
:
2346 &CSSMOID_MOBILE_STORE_SIGNING_POLICY
;
2347 if (!certificatePoliciesContainsOID(certPolicies
, policyOID
))
2348 if (tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
))
2349 return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2353 tpPolicyError("tp_verifyMobileStoreSigningOpts: no certificatePolicies present in leaf");
2354 if (tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
))
2355 return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2358 /* Check that cert chain length is 3 */
2359 if (numCerts
!= 3) {
2360 tpPolicyError("tp_verifyMobileStoreSigningOpts: numCerts %u", numCerts
);
2361 crtn
= CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
2365 /* Check that cert chain is anchored by a known root */
2367 tpCert
= certGroup
.certAtIndex(numCerts
-1);
2368 const CSSM_DATA
*certData
= tpCert
->itemData();
2369 unsigned char digest
[CC_SHA1_DIGEST_LENGTH
];
2370 CC_SHA1(certData
->Data
, (CC_LONG
)certData
->Length
, digest
);
2371 if (memcmp(digest
, kMobileRootSHA1
, sizeof(digest
))) {
2372 tpPolicyError("tp_verifyMobileStoreSigningOpts: invalid anchor for policy");
2373 tpCert
->addStatusCode(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
);
2374 crtn
= CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
2379 /* Check that Apple System Integration 2 marker extension is present in intermediate */
2380 isCertInfo
= &certInfo
[1];
2381 tpCert
= certGroup
.certAtIndex(1);
2382 if (!(isCertInfo
->foundAppleSysInt2Marker
== CSSM_TRUE
)) {
2383 tpPolicyError("tp_verifyMobileStoreSigningOpts: intermediate marker extension not found");
2384 tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
);
2385 crtn
= CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2394 * Verify Escrow Service policy options.
2396 * -- Chain length must be exactly 2.
2397 * -- Must be issued by known escrow root.
2398 * -- Key usage in leaf certificate must be Key Encipherment.
2399 * -- Leaf has CSSMOID_APPLE_EXTENSION_ESCROW_SERVICE_MARKER extension
2400 * (1.2.840.113635.100.6.23.1)
2402 static CSSM_RETURN
tp_verifyEscrowServiceSigningOpts(TPCertGroup
&certGroup
,
2403 const CSSM_DATA
*fieldOpts
,
2404 const iSignCertInfo
*certInfo
) // all certs, size certGroup.numCerts()
2406 unsigned numCerts
= certGroup
.numCerts();
2407 const iSignCertInfo
*isCertInfo
;
2410 CSSM_RETURN crtn
= CSSM_OK
;
2412 isCertInfo
= &certInfo
[0];
2413 tpCert
= certGroup
.certAtIndex(0);
2415 /* Check that KU extension is present */
2416 if (!isCertInfo
->keyUsage
.present
) {
2417 tpPolicyError("tp_verifyEscrowServiceSigningOpts: no keyUsage in leaf");
2418 tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
);
2419 crtn
= CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2423 /* Check that KU contains Key Encipherment usage */
2424 ku
= isCertInfo
->keyUsage
.extnData
->keyUsage
;
2425 if (!(ku
& CE_KU_KeyEncipherment
)) {
2426 tpPolicyError("tp_verifyEscrowServiceSigningOpts: KeyEncipherment usage not found");
2427 tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE
);
2428 crtn
= CSSMERR_APPLETP_INVALID_KEY_USAGE
;
2432 /* Check that Escrow Service marker extension is present */
2433 if (!(isCertInfo
->foundEscrowServiceMarker
== CSSM_TRUE
)) {
2434 tpPolicyError("tp_verifyEscrowServiceSigningOpts: no Escrow Service extension in leaf");
2435 tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
);
2436 crtn
= CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2440 /* Check that cert chain length is 2 */
2441 if (numCerts
!= 2) {
2442 tpPolicyError("tp_verifyEscrowServiceSigningOpts: numCerts %u", numCerts
);
2443 crtn
= CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
2447 /* Check that cert chain is anchored by a known root */
2449 tpCert
= certGroup
.certAtIndex(numCerts
-1);
2450 const CSSM_DATA
*certData
= tpCert
->itemData();
2451 bool anchorMatch
= false;
2452 SecCertificateRef anchor
= NULL
;
2453 OSStatus status
= SecCertificateCreateFromData(certData
, CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
, &anchor
);
2455 CFArrayRef anchors
= SecCertificateCopyEscrowRoots(kSecCertificateProductionEscrowRoot
);
2456 CFIndex idx
, count
= (anchors
) ? CFArrayGetCount(anchors
) : 0;
2457 for (idx
= 0; idx
< count
; idx
++) {
2458 SecCertificateRef cert
= (SecCertificateRef
) CFArrayGetValueAtIndex(anchors
, idx
);
2459 if (cert
&& CFEqual(cert
, anchor
)) {
2471 tpPolicyError("tp_verifyEscrowServiceSigningOpts: invalid anchor for policy");
2472 tpCert
->addStatusCode(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
);
2473 crtn
= CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
2483 * Verify Configuration Profile Signing policy options.
2485 * -- Do basic cert validation (OCSP-based certs)
2486 * -- Chains to the Apple root CA
2487 * -- Leaf has EKU extension with appropriate purpose:
2488 * (1.2.840.113635.100.4.16) if testPolicy is false
2489 * (1.2.840.113635.100.4.17) if testPolicy is true
2491 static CSSM_RETURN
tp_verifyProfileSigningOpts(TPCertGroup
&certGroup
,
2492 const CSSM_DATA
*fieldOpts
,
2493 const iSignCertInfo
*certInfo
, // all certs, size certGroup.numCerts()
2496 unsigned numCerts
= certGroup
.numCerts();
2497 const iSignCertInfo
*isCertInfo
;
2499 CE_ExtendedKeyUsage
*eku
;
2500 CSSM_RETURN crtn
= CSSM_OK
;
2503 isCertInfo
= &certInfo
[0];
2504 tpCert
= certGroup
.certAtIndex(0);
2506 /* Check that EKU extension is present */
2507 if (!isCertInfo
->extendKeyUsage
.present
) {
2508 tpPolicyError("tp_verifyProfileSigningOpts: no extendedKeyUse in leaf");
2509 tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
);
2510 crtn
= CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2514 /* Check that EKU contains appropriate Profile Signing purpose */
2515 eku
= &isCertInfo
->extendKeyUsage
.extnData
->extendedKeyUsage
;
2516 assert(eku
!= NULL
);
2518 for (int ix
=0;ix
<eku
->numPurposes
;ix
++) {
2519 if (tpCompareOids(&eku
->purposes
[ix
], (testPolicy
) ?
2520 &CSSMOID_APPLE_EKU_QA_PROFILE_SIGNING
:
2521 &CSSMOID_APPLE_EKU_PROFILE_SIGNING
)) {
2527 tpPolicyError("tp_verifyProfileSigningOpts: Profile Signing purpose not found");
2528 tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
);
2529 crtn
= CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
2533 /* Check that cert chain is anchored by the Apple Root CA */
2535 tpPolicyError("tp_verifyProfileSigningOpts: numCerts %u", numCerts
);
2536 crtn
= CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
2540 tpCert
= certGroup
.certAtIndex(numCerts
-1);
2541 const CSSM_DATA
*certData
= tpCert
->itemData();
2542 unsigned char digest
[CC_SHA1_DIGEST_LENGTH
];
2543 CC_SHA1(certData
->Data
, (CC_LONG
)certData
->Length
, digest
);
2544 if (memcmp(digest
, kAppleCASHA1
, sizeof(digest
))) {
2545 tpPolicyError("tp_verifyProfileSigningOpts: invalid anchor for policy");
2546 tpCert
->addStatusCode(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
);
2547 crtn
= CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
2557 * RFC2459 says basicConstraints must be flagged critical for
2558 * CA certs, but Verisign doesn't work that way.
2560 #define BASIC_CONSTRAINTS_MUST_BE_CRITICAL 0
2563 * TP iSign spec says Extended Key Usage required for leaf certs,
2564 * but Verisign doesn't work that way.
2566 #define EXTENDED_KEY_USAGE_REQUIRED_FOR_LEAF 0
2569 * TP iSign spec says Subject Alternate Name required for leaf certs,
2570 * but Verisign doesn't work that way.
2572 #define SUBJECT_ALT_NAME_REQUIRED_FOR_LEAF 0
2575 * TP iSign spec originally required KeyUsage for all certs, but
2576 * Verisign doesn't have that in their roots.
2578 #define KEY_USAGE_REQUIRED_FOR_ROOT 0
2581 * RFC 2632, "S/MIME Version 3 Certificate Handling", section
2582 * 4.4.2, says that KeyUsage extensions MUST be flagged critical,
2583 * but Thawte's intermediate cert (common name "Thawte Personal
2584 * Freemail Issuing CA") does not meet this requirement.
2586 #define SMIME_KEY_USAGE_MUST_BE_CRITICAL 0
2589 * Public routine to perform TP verification on a constructed
2591 * Returns CSSM_OK on success.
2592 * Assumes the chain has passed basic subject/issuer verification. First cert of
2593 * incoming certGroup is end-entity (leaf).
2595 * Per-policy details:
2596 * iSign: Assumes that last cert in incoming certGroup is a root cert.
2597 * Also assumes a cert group of more than one cert.
2598 * kTPx509Basic: CertGroup of length one allowed.
2600 CSSM_RETURN
tp_policyVerify(
2603 CSSM_CL_HANDLE clHand
,
2604 CSSM_CSP_HANDLE cspHand
,
2605 TPCertGroup
*certGroup
,
2606 CSSM_BOOL verifiedToRoot
, // last cert is good root
2607 CSSM_BOOL verifiedViaTrustSetting
, // last cert verified via
2609 CSSM_APPLE_TP_ACTION_FLAGS actionFlags
,
2610 const CSSM_DATA
*policyFieldData
, // optional
2611 void *policyOpts
) // future options
2613 iSignCertInfo
*certInfo
= NULL
;
2615 iSignCertInfo
*thisCertInfo
;
2619 CSSM_BOOL cA
= CSSM_FALSE
; // init for compiler warning
2620 bool isLeaf
; // end entity
2621 bool isRoot
; // root cert
2622 CE_ExtendedKeyUsage
*extendUsage
;
2623 CE_AuthorityKeyID
*authorityId
;
2624 CSSM_KEY_PTR pubKey
;
2625 CSSM_RETURN outErr
= CSSM_OK
; // for gross, non-policy errors
2626 CSSM_BOOL policyFail
= CSSM_FALSE
;// generic CSSMERR_TP_VERIFY_ACTION_FAILED
2627 CSSM_RETURN policyError
= CSSM_OK
; // policy-specific failure
2629 /* First, kTPDefault is a nop here */
2630 if(policy
== kTPDefault
) {
2634 if(certGroup
== NULL
) {
2635 return CSSMERR_TP_INVALID_CERTGROUP
;
2637 numCerts
= certGroup
->numCerts();
2639 return CSSMERR_TP_INVALID_CERTGROUP
;
2641 if(policy
== kTPiSign
) {
2642 if(!verifiedToRoot
) {
2643 /* no way, this requires a root cert */
2644 return CSSMERR_TP_VERIFY_ACTION_FAILED
;
2647 /* nope, not for iSign */
2648 return CSSMERR_TP_VERIFY_ACTION_FAILED
;
2652 /* cook up an iSignCertInfo array */
2653 certInfo
= (iSignCertInfo
*)tpCalloc(alloc
, numCerts
, sizeof(iSignCertInfo
));
2654 /* subsequent errors to errOut: */
2656 /* fill it with interesting info from parsed certs */
2657 for(certDex
=0; certDex
<numCerts
; certDex
++) {
2658 if(iSignGetCertInfo(alloc
,
2659 certGroup
->certAtIndex(certDex
),
2660 &certInfo
[certDex
])) {
2661 (certGroup
->certAtIndex(certDex
))->addStatusCode(
2662 CSSMERR_TP_INVALID_CERTIFICATE
);
2663 /* this one is fatal (and can't ignore) */
2664 outErr
= CSSMERR_TP_INVALID_CERTIFICATE
;
2670 * OK, the heart of TP enforcement.
2672 for(certDex
=0; certDex
<numCerts
; certDex
++) {
2673 thisCertInfo
= &certInfo
[certDex
];
2674 TPCertInfo
*thisTpCertInfo
= certGroup
->certAtIndex(certDex
);
2677 * First check for presence of required extensions and
2678 * critical extensions we don't understand.
2680 if(thisCertInfo
->foundUnknownCritical
) {
2681 /* illegal for all policies */
2682 tpPolicyError("tp_policyVerify: critical flag in unknown extension");
2683 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN
)) {
2684 policyFail
= CSSM_TRUE
;
2689 * Check for unsupported key length, per <rdar://6892837>
2691 if((pubKey
=thisTpCertInfo
->pubKey()) != NULL
) {
2692 CSSM_KEYHEADER
*keyHdr
= &pubKey
->KeyHeader
;
2693 if(keyHdr
->AlgorithmId
== CSSM_ALGID_RSA
&& keyHdr
->LogicalKeySizeInBits
< 1024) {
2694 tpPolicyError("tp_policyVerify: RSA key size too small");
2695 if(thisTpCertInfo
->addStatusCode(CSSMERR_CSP_UNSUPPORTED_KEY_SIZE
)) {
2696 policyFail
= CSSM_TRUE
;
2702 * Note it's possible for both of these to be true, for a chain
2703 * of length one (kTPx509Basic, kCrlPolicy only!)
2704 * FIXME: should this code work if the last cert in the chain is NOT a root?
2706 isLeaf
= thisTpCertInfo
->isLeaf();
2707 isRoot
= thisTpCertInfo
->isSelfSigned(true);
2710 * BasicConstraints.cA
2711 * iSign: required in all but leaf and root,
2712 * for which it is optional (with default values of false
2713 * for leaf and true for root).
2714 * all others: always optional, default of false for leaf and
2716 * All: cA must be false for leaf, true for others
2718 if(!thisCertInfo
->basicConstraints
.present
) {
2720 * No basicConstraints present; infer a cA value if appropriate.
2723 /* cool, use default; note that kTPx509Basic with
2724 * certGroup length of one may take this case */
2728 /* cool, use default */
2735 * not present, not leaf, not root....
2736 * ....RFC2459 says this can not be a CA
2741 /* required for iSign in this position */
2742 tpPolicyError("tp_policyVerify: no "
2743 "basicConstraints");
2744 if(thisTpCertInfo
->addStatusCode(
2745 CSSMERR_APPLETP_NO_BASIC_CONSTRAINTS
)) {
2746 policyFail
= CSSM_TRUE
;
2751 } /* inferred a default value */
2753 /* basicConstraints present */
2754 #if BASIC_CONSTRAINTS_MUST_BE_CRITICAL
2755 /* disabled for verisign compatibility */
2756 if(!thisCertInfo
->basicConstraints
.critical
) {
2758 tpPolicyError("tp_policyVerify: basicConstraints marked "
2760 if(thisTpCertInfo
->addStatusCode(CSSMERR_TP_VERIFY_ACTION_FAILED
)) {
2761 policyFail
= CSSM_TRUE
;
2764 #endif /* BASIC_CONSTRAINTS_MUST_BE_CRITICAL */
2766 const CE_BasicConstraints
*bcp
=
2767 &thisCertInfo
->basicConstraints
.extnData
->basicConstraints
;
2771 /* Verify pathLenConstraint if present */
2772 if(!isLeaf
&& // leaf, certDex=0, don't care
2773 cA
&& // p.l.c. only valid for CAs
2774 bcp
->pathLenConstraintPresent
) { // present?
2776 * pathLenConstraint=0 legal for certDex 1 only
2777 * pathLenConstraint=1 legal for certDex {1,2}
2780 if(certDex
> (bcp
->pathLenConstraint
+ 1)) {
2781 tpPolicyError("tp_policyVerify: pathLenConstraint "
2783 if(thisTpCertInfo
->addStatusCode(
2784 CSSMERR_APPLETP_PATH_LEN_CONSTRAINT
)) {
2785 policyFail
= CSSM_TRUE
;
2793 * Special cases to allow a chain of length 1, leaf and root
2794 * both true, and for caller to override the "leaf can't be a CA"
2795 * requirement when a CA cert is explicitly being evaluated as the
2799 !(actionFlags
& CSSM_TP_ACTION_LEAF_IS_CA
)) {
2800 tpPolicyError("tp_policyVerify: cA true for leaf");
2801 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_INVALID_CA
)) {
2802 policyFail
= CSSM_TRUE
;
2806 tpPolicyError("tp_policyVerify: cA false for non-leaf");
2807 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_INVALID_CA
)) {
2808 policyFail
= CSSM_TRUE
;
2813 * Authority Key Identifier optional
2814 * iSign : only allowed in !root.
2815 * If present, must not be critical.
2816 * all others : ignored (though used later for chain verification)
2818 if((policy
== kTPiSign
) && thisCertInfo
->authorityId
.present
) {
2820 tpPolicyError("tp_policyVerify: authorityId in root");
2821 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_INVALID_AUTHORITY_ID
)) {
2822 policyFail
= CSSM_TRUE
;
2825 if(thisCertInfo
->authorityId
.critical
) {
2826 /* illegal per RFC 2459 */
2827 tpPolicyError("tp_policyVerify: authorityId marked "
2829 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_INVALID_AUTHORITY_ID
)) {
2830 policyFail
= CSSM_TRUE
;
2836 * Subject Key Identifier optional
2837 * iSign : can't be critical.
2838 * all others : ignored (though used later for chain verification)
2840 if(thisCertInfo
->subjectId
.present
) {
2841 if((policy
== kTPiSign
) && thisCertInfo
->subjectId
.critical
) {
2842 tpPolicyError("tp_policyVerify: subjectId marked critical");
2843 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_INVALID_SUBJECT_ID
)) {
2844 policyFail
= CSSM_TRUE
;
2850 * Key Usage optional except required as noted
2851 * iSign : required for non-root/non-leaf
2852 * Leaf cert : if present, usage = digitalSignature
2853 * Exception : if leaf, and keyUsage not present,
2854 * netscape-cert-type must be present, with
2855 * Object Signing bit set
2856 * kCrlPolicy : Leaf: usage = CRLSign
2857 * kTP_SMIME : if present, must be critical
2858 * kTP_SWUpdateSign, kTP_ResourceSign, kTP_CodeSigning, kTP_PackageSigning : Leaf :
2859 usage = digitalSignature
2860 * all others : non-leaf : usage = keyCertSign
2863 if(thisCertInfo
->keyUsage
.present
) {
2866 * iSign and *Signing: usage = digitalSignature
2867 * all others : don't care
2868 * Others: usage = keyCertSign
2869 * We only require that one bit to be set, we ignore others.
2874 case kTP_SWUpdateSign
:
2875 case kTP_ResourceSign
:
2876 case kTP_CodeSigning
:
2877 case kTP_PackageSigning
:
2878 expUsage
= CE_KU_DigitalSignature
;
2881 /* if present, this bit must be set */
2882 expUsage
= CE_KU_CRLSign
;
2885 /* accept whatever's there */
2886 expUsage
= thisCertInfo
->keyUsage
.extnData
->keyUsage
;
2891 /* !leaf: this is true for all policies */
2892 expUsage
= CE_KU_KeyCertSign
;
2894 actUsage
= thisCertInfo
->keyUsage
.extnData
->keyUsage
;
2895 if(!(actUsage
& expUsage
)) {
2896 tpPolicyError("tp_policyVerify: bad keyUsage (leaf %s; "
2898 (certDex
== 0) ? "TRUE" : "FALSE", actUsage
);
2899 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE
)) {
2900 policyFail
= CSSM_TRUE
;
2906 * Radar 3523221 renders this whole check obsolete, but I'm leaving
2907 * the code here to document its conspicuous functional absence.
2909 if((policy
== kTP_SMIME
) && !thisCertInfo
->keyUsage
.critical
) {
2911 * Per Radar 3410245, allow this for intermediate certs.
2913 if(SMIME_KEY_USAGE_MUST_BE_CRITICAL
|| isLeaf
|| isRoot
) {
2914 tpPolicyError("tp_policyVerify: key usage, !critical, SMIME");
2915 if(thisTpCertInfo
->addStatusCode(
2916 CSSMERR_APPLETP_SMIME_KEYUSAGE_NOT_CRITICAL
)) {
2917 policyFail
= CSSM_TRUE
;
2923 else if(policy
== kTPiSign
) {
2925 * iSign requires keyUsage present for non root OR
2926 * netscape-cert-type/ObjectSigning for leaf
2928 if(isLeaf
&& thisCertInfo
->netscapeCertType
.present
) {
2929 CE_NetscapeCertType ct
=
2930 thisCertInfo
->netscapeCertType
.extnData
->netscapeCertType
;
2932 if(!(ct
& CE_NCT_ObjSign
)) {
2933 tpPolicyError("tp_policyVerify: netscape-cert-type, "
2935 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE
)) {
2936 policyFail
= CSSM_TRUE
;
2941 tpPolicyError("tp_policyVerify: !isRoot, no keyUsage, "
2942 "!(leaf and netscapeCertType)");
2943 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE
)) {
2944 policyFail
= CSSM_TRUE
;
2950 * RFC 3280, 4.1.2.6, says that an empty subject name can only appear in a
2951 * leaf cert, and only if subjectAltName is present and marked critical.
2953 if(isLeaf
&& thisTpCertInfo
->hasEmptySubjectName()) {
2954 bool badEmptySubject
= false;
2955 if(actionFlags
& CSSM_TP_ACTION_LEAF_IS_CA
) {
2957 * True when evaluating a CA cert as well as when
2958 * evaluating a CRL's cert chain. Note the odd case of a CRL's
2959 * signer having an empty subject matching an empty issuer
2960 * in the CRL. That'll be caught here.
2962 badEmptySubject
= true;
2964 else if(!thisCertInfo
->subjectAltName
.present
|| /* no subjectAltName */
2965 !thisCertInfo
->subjectAltName
.critical
) { /* not critical */
2966 badEmptySubject
= true;
2968 if(badEmptySubject
) {
2969 tpPolicyError("tp_policyVerify: bad empty subject");
2970 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_INVALID_EMPTY_SUBJECT
)) {
2971 policyFail
= CSSM_TRUE
;
2977 * RFC 3739: if this cert has a Qualified Cert Statements extension, and
2978 * it's Critical, make sure we understand all of the extension's statementIds.
2980 if(thisCertInfo
->qualCertStatements
.present
&&
2981 thisCertInfo
->qualCertStatements
.critical
) {
2982 CE_QC_Statements
*qcss
=
2983 &thisCertInfo
->qualCertStatements
.extnData
->qualifiedCertStatements
;
2984 uint32 numQcs
= qcss
->numQCStatements
;
2985 for(unsigned qdex
=0; qdex
<numQcs
; qdex
++) {
2986 CSSM_OID_PTR qid
= &qcss
->qcStatements
[qdex
].statementId
;
2988 for(unsigned kdex
=0; kdex
<NUM_KNOWN_QUAL_CERT_STATEMENTS
; kdex
++) {
2989 if(tpCompareCssmData(qid
, knownQualifiedCertStatements
[kdex
])) {
2995 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_UNKNOWN_QUAL_CERT_STATEMENT
)) {
2996 policyFail
= CSSM_TRUE
;
3001 } /* critical Qualified Cert Statement */
3004 * Certificate Policies extension validation, per section 1.2 of:
3005 * http://iase.disa.mil/pki/dod_cp_v10_final_2_mar_09_signed.pdf
3007 if (tpVerifyCPE(*thisCertInfo
, CSSMOID_PIV_AUTH
, false) ||
3008 tpVerifyCPE(*thisCertInfo
, CSSMOID_PIV_AUTH_2048
, false)) {
3010 * Certificate asserts one of the PIV-Auth Certificate Policy OIDs;
3011 * check the required Key Usage extension for compliance.
3014 * usage = digitalSignature (only; no other bits asserted)
3016 * usage = keyCertSign (required; other bits ignored)
3018 if(thisCertInfo
->keyUsage
.present
) {
3019 actUsage
= thisCertInfo
->keyUsage
.extnData
->keyUsage
;
3021 /* No key usage! Policy fail. */
3024 if(!(actionFlags
& CSSM_TP_ACTION_LEAF_IS_CA
) && (certDex
== 0)) {
3025 expUsage
= CE_KU_DigitalSignature
;
3027 expUsage
= actUsage
| CE_KU_KeyCertSign
;
3029 if(!(actUsage
== expUsage
)) {
3030 tpPolicyError("tp_policyVerify: bad keyUsage for PIV-Auth policy (leaf %s; "
3032 (certDex
== 0) ? "TRUE" : "FALSE", actUsage
);
3033 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE
)) {
3034 policyFail
= CSSM_TRUE
;
3037 } /* Certificate Policies */
3040 } /* for certDex, checking presence of extensions */
3043 * Special case checking for leaf (end entity) cert
3045 * iSign only: Extended key usage, optional for leaf,
3046 * value CSSMOID_ExtendedUseCodeSigning
3048 if((policy
== kTPiSign
) && certInfo
[0].extendKeyUsage
.present
) {
3049 extendUsage
= &certInfo
[0].extendKeyUsage
.extnData
->extendedKeyUsage
;
3050 if(extendUsage
->numPurposes
!= 1) {
3051 tpPolicyError("tp_policyVerify: bad extendUsage->numPurposes "
3053 (int)extendUsage
->numPurposes
);
3054 if((certGroup
->certAtIndex(0))->addStatusCode(
3055 CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
)) {
3056 policyFail
= CSSM_TRUE
;
3059 if(!tpCompareOids(extendUsage
->purposes
,
3060 &CSSMOID_ExtendedUseCodeSigning
)) {
3061 tpPolicyError("tp_policyVerify: bad extendKeyUsage");
3062 if((certGroup
->certAtIndex(0))->addStatusCode(
3063 CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
)) {
3064 policyFail
= CSSM_TRUE
;
3070 * Verify authorityId-->subjectId linkage.
3071 * All optional - skip if needed fields not present.
3072 * Also, always skip last (root) cert.
3074 for(certDex
=0; certDex
<(numCerts
-1); certDex
++) {
3075 if(!certInfo
[certDex
].authorityId
.present
||
3076 !certInfo
[certDex
+1].subjectId
.present
) {
3079 authorityId
= &certInfo
[certDex
].authorityId
.extnData
->authorityKeyID
;
3080 if(!authorityId
->keyIdentifierPresent
) {
3081 /* we only know how to compare keyIdentifier */
3084 if(!tpCompareCssmData(&authorityId
->keyIdentifier
,
3085 &certInfo
[certDex
+1].subjectId
.extnData
->subjectKeyID
)) {
3086 tpPolicyError("tp_policyVerify: bad key ID linkage");
3087 if((certGroup
->certAtIndex(certDex
))->addStatusCode(
3088 CSSMERR_APPLETP_INVALID_ID_LINKAGE
)) {
3089 policyFail
= CSSM_TRUE
;
3095 * Check signature algorithm on all non-root certs,
3096 * reject if known to be untrusted
3098 for(certDex
=0; certDex
<(numCerts
-1); certDex
++) {
3099 if(certInfo
[certDex
].untrustedSigAlg
) {
3100 tpPolicyError("tp_policyVerify: untrusted signature algorithm");
3101 if((certGroup
->certAtIndex(certDex
))->addStatusCode(
3102 CSSMERR_TP_INVALID_CERTIFICATE
)) {
3103 policyFail
= CSSM_TRUE
;
3108 /* specific per-policy checking */
3114 * SSL, EAP, IPSec: optionally verify common name; all are identical
3115 * other than their names.
3116 * FIXME - should this be before or after the root cert test? How can
3117 * we return both errors?
3119 policyError
= tp_verifySslOpts(policy
, *certGroup
, policyFieldData
, certInfo
[0]);
3123 tpDebug("iChat policy");
3126 policyError
= tp_verifySmimeOpts(policy
, *certGroup
, policyFieldData
,
3129 case kTP_SWUpdateSign
:
3130 policyError
= tp_verifySWUpdateSigningOpts(*certGroup
, policyFieldData
, certInfo
);
3132 case kTP_ResourceSign
:
3133 policyError
= tp_verifyResourceSigningOpts(*certGroup
, policyFieldData
, certInfo
);
3135 case kTP_CodeSigning
:
3136 case kTP_PackageSigning
:
3137 policyError
= tp_verifyCodePkgSignOpts(policy
, *certGroup
, policyFieldData
, certInfo
);
3139 case kTP_MacAppStoreRec
:
3140 policyError
= tp_verifyMacAppStoreReceiptOpts(*certGroup
, policyFieldData
, certInfo
);
3142 case kTP_AppleIDSharing
:
3143 policyError
= tp_verifyAppleIDSharingOpts(*certGroup
, policyFieldData
, certInfo
);
3145 case kTP_TimeStamping
:
3146 policyError
= tp_verifyTimeStampingOpts(*certGroup
, policyFieldData
, certInfo
);
3148 case kTP_PassbookSigning
:
3149 policyError
= tp_verifyPassbookSigningOpts(*certGroup
, policyFieldData
, certInfo
);
3151 case kTP_MobileStore
:
3152 policyError
= tp_verifyMobileStoreSigningOpts(*certGroup
, policyFieldData
, certInfo
, false);
3154 case kTP_TestMobileStore
:
3155 policyError
= tp_verifyMobileStoreSigningOpts(*certGroup
, policyFieldData
, certInfo
, true);
3157 case kTP_EscrowService
:
3158 policyError
= tp_verifyEscrowServiceSigningOpts(*certGroup
, policyFieldData
, certInfo
);
3160 case kTP_ProfileSigning
:
3161 policyError
= tp_verifyProfileSigningOpts(*certGroup
, policyFieldData
, certInfo
, false);
3163 case kTP_QAProfileSigning
:
3164 policyError
= tp_verifyProfileSigningOpts(*certGroup
, policyFieldData
, certInfo
, true);
3169 case kTP_PKINIT_Client
:
3175 if(outErr
== CSSM_OK
) {
3176 /* policy-specific error takes precedence here */
3177 if(policyError
!= CSSM_OK
) {
3178 outErr
= policyError
;
3180 else if(policyFail
) {
3181 /* plain vanilla error return from this module */
3182 outErr
= CSSMERR_TP_VERIFY_ACTION_FAILED
;
3186 /* free resources */
3187 for(certDex
=0; certDex
<numCerts
; certDex
++) {
3188 thisCertInfo
= &certInfo
[certDex
];
3189 iSignFreeCertInfo(clHand
, thisCertInfo
);
3191 tpFree(alloc
, certInfo
);
3196 * Obtain policy-specific User Trust parameters
3198 void tp_policyTrustSettingParams(
3200 const CSSM_DATA
*policyData
, // optional
3201 /* returned values - not mallocd */
3202 const char **policyStr
,
3203 uint32
*policyStrLen
,
3204 SecTrustSettingsKeyUsage
*keyUse
)
3206 /* default values */
3208 *keyUse
= kSecTrustSettingsKeyUseAny
;
3210 if((policyData
== NULL
) || (policyData
->Data
== NULL
)) {
3211 /* currently, no further action possible */
3219 if(policyData
->Length
!= sizeof(CSSM_APPLE_TP_SSL_OPTIONS
)) {
3220 /* this error will be caught later */
3223 CSSM_APPLE_TP_SSL_OPTIONS
*sslOpts
=
3224 (CSSM_APPLE_TP_SSL_OPTIONS
*)policyData
->Data
;
3225 *policyStr
= sslOpts
->ServerName
;
3226 *policyStrLen
= sslOpts
->ServerNameLen
;
3227 if(sslOpts
->Flags
& CSSM_APPLE_TP_SSL_CLIENT
) {
3229 * Client signs with its priv key. Server end,
3230 * which (also) verifies the client cert, verifies.
3232 *keyUse
= kSecTrustSettingsKeyUseSignature
;
3235 /* server decrypts */
3236 *keyUse
= kSecTrustSettingsKeyUseEnDecryptKey
;
3244 if(policyData
->Length
!= sizeof(CSSM_APPLE_TP_SMIME_OPTIONS
)) {
3245 /* this error will be caught later */
3248 CSSM_APPLE_TP_SMIME_OPTIONS
*smimeOpts
=
3249 (CSSM_APPLE_TP_SMIME_OPTIONS
*)policyData
->Data
;
3250 *policyStr
= smimeOpts
->SenderEmail
;
3251 *policyStrLen
= smimeOpts
->SenderEmailLen
;
3252 SecTrustSettingsKeyUsage ku
= 0;
3253 CE_KeyUsage smimeKu
= smimeOpts
->IntendedUsage
;
3254 if(smimeKu
& (CE_KU_DigitalSignature
| CE_KU_KeyCertSign
| CE_KU_CRLSign
)) {
3255 ku
|= kSecTrustSettingsKeyUseSignature
;
3257 if(smimeKu
& (CE_KU_KeyEncipherment
| CE_KU_DataEncipherment
)) {
3258 ku
|= kSecTrustSettingsKeyUseEnDecryptKey
;
3265 /* no other options */