2 * Copyright (c) 2000-2014 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>
43 #pragma clang diagnostic push
44 #pragma clang diagnostic ignored "-Wunused-const-variable"
47 * Our private per-extension info. One of these per (understood) extension per
53 CE_Data
*extnData
; // mallocd by CL
54 CSSM_DATA
*valToFree
; // the data we pass to freeField()
58 * Struct to keep track of info pertinent to one cert.
62 /* extensions we're interested in */
63 iSignExtenInfo authorityId
;
64 iSignExtenInfo subjectId
;
65 iSignExtenInfo keyUsage
;
66 iSignExtenInfo extendKeyUsage
;
67 iSignExtenInfo basicConstraints
;
68 iSignExtenInfo netscapeCertType
;
69 iSignExtenInfo subjectAltName
;
70 iSignExtenInfo certPolicies
;
71 iSignExtenInfo qualCertStatements
;
72 iSignExtenInfo nameConstraints
;
73 iSignExtenInfo policyMappings
;
74 iSignExtenInfo policyConstraints
;
75 iSignExtenInfo inhibitAnyPolicy
;
76 iSignExtenInfo certificatePolicies
;
78 /* flag indicating presence of CSSMOID_APPLE_EXTENSION_PROVISIONING_PROFILE_SIGNING */
79 CSSM_BOOL foundProvisioningProfileSigningMarker
;
80 /* flag indicating presence of CSSMOID_APPLE_EXTENSION_PASSBOOK_SIGNING */
81 CSSM_BOOL foundPassbookSigningMarker
;
82 /* flag indicating presence of CSSMOID_APPLE_EXTENSION_SYSINT2_INTERMEDIATE */
83 CSSM_BOOL foundAppleSysInt2Marker
;
84 /* flag indicating presence of CSSMOID_APPLE_EXTENSION_SERVER_AUTHENTICATION */
85 CSSM_BOOL foundAppleServerAuthMarker
;
86 /* flag indicating presence of CSSMOID_APPLE_EXTENSION_ESCROW_SERVICE */
87 CSSM_BOOL foundEscrowServiceMarker
;
88 /* flag indicating presence of CSSMOID_APPLE_EXTENSION_WWDR_INTERMEDIATE */
89 CSSM_BOOL foundAppleWWDRIntMarker
;
90 /* flag indicating presence of a critical extension we don't understand */
91 CSSM_BOOL foundUnknownCritical
;
92 /* flag indicating that this certificate was signed with a known-broken algorithm */
93 CSSM_BOOL untrustedSigAlg
;
98 * The list of Qualified Cert Statement statementIds we understand, even though
99 * we don't actually do anything with them; if these are found in a Qualified
100 * Cert Statement that's critical, we can truthfully say "yes we understand this".
102 static const CSSM_OID_PTR knownQualifiedCertStatements
[] =
104 (const CSSM_OID_PTR
)&CSSMOID_OID_QCS_SYNTAX_V1
,
105 (const CSSM_OID_PTR
)&CSSMOID_OID_QCS_SYNTAX_V2
,
106 (const CSSM_OID_PTR
)&CSSMOID_ETSI_QCS_QC_COMPLIANCE
,
107 (const CSSM_OID_PTR
)&CSSMOID_ETSI_QCS_QC_LIMIT_VALUE
,
108 (const CSSM_OID_PTR
)&CSSMOID_ETSI_QCS_QC_RETENTION
,
109 (const CSSM_OID_PTR
)&CSSMOID_ETSI_QCS_QC_SSCD
111 #define NUM_KNOWN_QUAL_CERT_STATEMENTS (sizeof(knownQualifiedCertStatements) / sizeof(CSSM_OID_PTR))
113 static CSSM_RETURN
tp_verifyMacAppStoreReceiptOpts(TPCertGroup
&certGroup
,
114 const CSSM_DATA
*fieldOpts
, const iSignCertInfo
*certInfo
);
116 static CSSM_RETURN
tp_verifyPassbookSigningOpts(TPCertGroup
&certGroup
,
117 const CSSM_DATA
*fieldOpts
, const iSignCertInfo
*certInfo
);
119 bool certificatePoliciesContainsOID(const CE_CertPolicies
*certPolicies
, const CSSM_OID
*oidToFind
);
121 #define kSecPolicySHA1Size 20
122 static const UInt8 kAppleCASHA1
[kSecPolicySHA1Size
] = {
123 0x61, 0x1E, 0x5B, 0x66, 0x2C, 0x59, 0x3A, 0x08, 0xFF, 0x58,
124 0xD1, 0x4A, 0xE2, 0x24, 0x52, 0xD1, 0x98, 0xDF, 0x6C, 0x60
127 static const UInt8 kMobileRootSHA1
[kSecPolicySHA1Size
] = {
128 0xBD, 0xD6, 0x7C, 0x34, 0xD0, 0xB2, 0x68, 0x5D, 0x31, 0x82,
129 0xCD, 0x32, 0xCB, 0xF4, 0x54, 0x69, 0xA1, 0xF1, 0x6B, 0x09
132 static const UInt8 kAppleCorpCASHA1
[kSecPolicySHA1Size
] = {
133 0xA1, 0x71, 0xDC, 0xDE, 0xE0, 0x8B, 0x1B, 0xAE, 0x30, 0xA1,
134 0xAE, 0x6C, 0xC6, 0xD4, 0x03, 0x3B, 0xFD, 0xEF, 0x91, 0xCE
138 * Certificate policy OIDs
142 #define ANY_POLICY_OID OID_EXTENSION, 0x32, 0x00
143 #define ANY_POLICY_OID_LEN OID_EXTENSION_LENGTH + 2
146 #define INHIBIT_ANY_POLICY_OID OID_EXTENSION, 0x54
147 #define INHIBIT_ANY_POLICY_OID_LEN OID_EXTENSION_LENGTH + 1
149 /* 2.16.840.1.101.2.1 */
150 #define US_DOD_INFOSEC 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01
151 #define US_DOD_INFOSEC_LEN 7
153 /* 2.16.840.1.101.2.1.11.10 */
154 #define PIV_AUTH_OID US_DOD_INFOSEC, 0x0B, 0x0A
155 #define PIV_AUTH_OID_LEN US_DOD_INFOSEC_LEN + 2
157 /* 2.16.840.1.101.2.1.11.20 */
158 #define PIV_AUTH_2048_OID US_DOD_INFOSEC, 0x0B, 0x14
159 #define PIV_AUTH_2048_OID_LEN US_DOD_INFOSEC_LEN + 2
161 static const uint8 OID_ANY_POLICY
[] = {ANY_POLICY_OID
};
162 const CSSM_OID CSSMOID_ANY_POLICY
= {ANY_POLICY_OID_LEN
, (uint8
*)OID_ANY_POLICY
};
163 static const uint8 OID_INHIBIT_ANY_POLICY
[] = {INHIBIT_ANY_POLICY_OID
};
164 const CSSM_OID CSSMOID_INHIBIT_ANY_POLICY
= {INHIBIT_ANY_POLICY_OID_LEN
, (uint8
*)OID_INHIBIT_ANY_POLICY
};
165 static const uint8 OID_PIV_AUTH
[] = {PIV_AUTH_OID
};
166 const CSSM_OID CSSMOID_PIV_AUTH
= {PIV_AUTH_OID_LEN
, (uint8
*)OID_PIV_AUTH
};
167 static const uint8 OID_PIV_AUTH_2048
[] = {PIV_AUTH_2048_OID
};
168 const CSSM_OID CSSMOID_PIV_AUTH_2048
= {PIV_AUTH_2048_OID_LEN
, (uint8
*)OID_PIV_AUTH_2048
};
171 * Setup a single iSignExtenInfo. Called once per known extension
174 static CSSM_RETURN
tpSetupExtension(
177 iSignExtenInfo
*extnInfo
) // which component of certInfo
179 if(extnData
->Length
!= sizeof(CSSM_X509_EXTENSION
)) {
180 tpPolicyError("tpSetupExtension: malformed CSSM_FIELD");
181 return CSSMERR_TP_UNKNOWN_FORMAT
;
183 CSSM_X509_EXTENSION
*cssmExt
= (CSSM_X509_EXTENSION
*)extnData
->Data
;
184 extnInfo
->present
= CSSM_TRUE
;
185 extnInfo
->critical
= cssmExt
->critical
;
186 extnInfo
->extnData
= (CE_Data
*)cssmExt
->value
.parsedValue
;
187 extnInfo
->valToFree
= extnData
;
192 * Fetch a known extension, set up associated iSignExtenInfo if present.
194 static CSSM_RETURN
iSignFetchExtension(
197 const CSSM_OID
*fieldOid
, // which extension to fetch
198 iSignExtenInfo
*extnInfo
) // where the info goes
200 CSSM_DATA_PTR fieldValue
; // mallocd by CL
203 crtn
= tpCert
->fetchField(fieldOid
, &fieldValue
);
207 case CSSMERR_CL_NO_FIELD_VALUES
:
208 /* field not present, OK */
213 return tpSetupExtension(alloc
,
219 * This function performs a check of an extension marked 'critical'
220 * to see if it's one we understand. Returns CSSM_OK if the extension
221 * is acceptable, CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN if unknown.
223 static CSSM_RETURN
iSignVerifyCriticalExtension(
224 CSSM_X509_EXTENSION
*cssmExt
)
226 if (!cssmExt
|| !cssmExt
->extnId
.Data
)
227 return CSSMERR_TP_INVALID_FIELD_POINTER
;
229 if (!cssmExt
->critical
)
232 /* FIXME: remove when policyConstraints NSS template is fixed */
233 if (!memcmp(cssmExt
->extnId
.Data
, CSSMOID_PolicyConstraints
.Data
, CSSMOID_PolicyConstraints
.Length
))
236 if (cssmExt
->extnId
.Length
> APPLE_EXTENSION_OID_LENGTH
&&
237 !memcmp(cssmExt
->extnId
.Data
, CSSMOID_APPLE_EXTENSION
.Data
, APPLE_EXTENSION_OID_LENGTH
)) {
238 /* This extension's OID is under the appleCertificateExtensions arc */
242 return CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN
;
246 * Search for all unknown extensions. If we find one which is flagged critical,
247 * flag certInfo->foundUnknownCritical. Only returns error on gross errors.
249 static CSSM_RETURN
iSignSearchUnknownExtensions(
251 iSignCertInfo
*certInfo
)
254 CSSM_DATA_PTR fieldValue
= NULL
;
255 CSSM_HANDLE searchHand
= CSSM_INVALID_HANDLE
;
256 uint32 numFields
= 0;
258 certInfo
->foundProvisioningProfileSigningMarker
= CSSM_FALSE
;
259 certInfo
->foundPassbookSigningMarker
= CSSM_FALSE
;
260 certInfo
->foundAppleSysInt2Marker
= CSSM_FALSE
;
261 certInfo
->foundAppleWWDRIntMarker
= CSSM_FALSE
;
262 certInfo
->foundEscrowServiceMarker
= CSSM_FALSE
;
264 crtn
= CSSM_CL_CertGetFirstCachedFieldValue(tpCert
->clHand(),
266 &CSSMOID_X509V3CertificateExtensionCStruct
,
272 /* found one, proceed */
274 case CSSMERR_CL_NO_FIELD_VALUES
:
275 /* no unknown extensions present, OK */
281 if(fieldValue
->Length
!= sizeof(CSSM_X509_EXTENSION
)) {
282 tpPolicyError("iSignSearchUnknownExtensions: malformed CSSM_FIELD");
283 return CSSMERR_TP_UNKNOWN_FORMAT
;
286 CSSM_X509_EXTENSION
*cssmExt
= (CSSM_X509_EXTENSION
*)fieldValue
->Data
;
287 if (cssmExt
->extnId
.Length
== APPLE_EXTENSION_CODE_SIGNING_LENGTH
+1 &&
288 !memcmp(cssmExt
->extnId
.Data
, CSSMOID_APPLE_EXTENSION_PASSBOOK_SIGNING
.Data
,
289 APPLE_EXTENSION_CODE_SIGNING_LENGTH
+1)) {
290 /* this is the Passbook Signing extension */
291 certInfo
->foundPassbookSigningMarker
= CSSM_TRUE
;
293 if (cssmExt
->extnId
.Length
== APPLE_EXTENSION_SYSINT2_INTERMEDIATE_LENGTH
&&
294 !memcmp(cssmExt
->extnId
.Data
, CSSMOID_APPLE_EXTENSION_SYSINT2_INTERMEDIATE
.Data
,
295 APPLE_EXTENSION_SYSINT2_INTERMEDIATE_LENGTH
)) {
296 /* this is the Apple System Integration 2 Signing extension */
297 certInfo
->foundAppleSysInt2Marker
= CSSM_TRUE
;
299 if (cssmExt
->extnId
.Length
== APPLE_EXTENSION_ESCROW_SERVICE_LENGTH
&&
300 !memcmp(cssmExt
->extnId
.Data
, CSSMOID_APPLE_EXTENSION_ESCROW_SERVICE
.Data
,
301 APPLE_EXTENSION_ESCROW_SERVICE_LENGTH
)) {
302 /* this is the Escrow Service Signing extension */
303 certInfo
->foundEscrowServiceMarker
= CSSM_TRUE
;
305 if (cssmExt
->extnId
.Length
== APPLE_EXTENSION_PROVISIONING_PROFILE_SIGNING_LENGTH
&&
306 !memcmp(cssmExt
->extnId
.Data
, CSSMOID_APPLE_EXTENSION_PROVISIONING_PROFILE_SIGNING
.Data
,
307 APPLE_EXTENSION_PROVISIONING_PROFILE_SIGNING_LENGTH
)) {
308 /* this is the Provisioning Profile Signing extension */
309 certInfo
->foundProvisioningProfileSigningMarker
= CSSM_TRUE
;
311 if (cssmExt
->extnId
.Length
== APPLE_EXTENSION_WWDR_INTERMEDIATE_LENGTH
&&
312 !memcmp(cssmExt
->extnId
.Data
, CSSMOID_APPLE_EXTENSION_WWDR_INTERMEDIATE
.Data
,
313 APPLE_EXTENSION_WWDR_INTERMEDIATE_LENGTH
)) {
314 /* this is the Apple WWDR extension */
315 certInfo
->foundAppleWWDRIntMarker
= CSSM_TRUE
;
318 if(iSignVerifyCriticalExtension(cssmExt
) != CSSM_OK
) {
319 /* BRRZAPP! Found an unknown extension marked critical */
320 certInfo
->foundUnknownCritical
= CSSM_TRUE
;
323 CSSM_CL_FreeFieldValue(tpCert
->clHand(),
324 &CSSMOID_X509V3CertificateExtensionCStruct
,
328 /* process remaining unknown extensions */
329 for(unsigned i
=1; i
<numFields
; i
++) {
330 crtn
= CSSM_CL_CertGetNextCachedFieldValue(tpCert
->clHand(),
334 /* should never happen */
335 tpPolicyError("searchUnknownExtensions: GetNextCachedFieldValue"
339 if(fieldValue
->Length
!= sizeof(CSSM_X509_EXTENSION
)) {
340 tpPolicyError("iSignSearchUnknownExtensions: "
341 "malformed CSSM_FIELD");
342 crtn
= CSSMERR_TP_UNKNOWN_FORMAT
;
346 CSSM_X509_EXTENSION
*cssmExt
= (CSSM_X509_EXTENSION
*)fieldValue
->Data
;
347 if (cssmExt
->extnId
.Length
== APPLE_EXTENSION_CODE_SIGNING_LENGTH
+1 &&
348 !memcmp(cssmExt
->extnId
.Data
, CSSMOID_APPLE_EXTENSION_PASSBOOK_SIGNING
.Data
,
349 APPLE_EXTENSION_CODE_SIGNING_LENGTH
+1)) {
350 /* this is the Passbook Signing extension */
351 certInfo
->foundPassbookSigningMarker
= CSSM_TRUE
;
353 if (cssmExt
->extnId
.Length
== APPLE_EXTENSION_SYSINT2_INTERMEDIATE_LENGTH
&&
354 !memcmp(cssmExt
->extnId
.Data
, CSSMOID_APPLE_EXTENSION_SYSINT2_INTERMEDIATE
.Data
,
355 APPLE_EXTENSION_SYSINT2_INTERMEDIATE_LENGTH
)) {
356 /* this is the Apple System Integration 2 Signing extension */
357 certInfo
->foundAppleSysInt2Marker
= CSSM_TRUE
;
359 if (cssmExt
->extnId
.Length
== APPLE_EXTENSION_SERVER_AUTHENTICATION_LENGTH
&&
360 !memcmp(cssmExt
->extnId
.Data
, CSSMOID_APPLE_EXTENSION_SERVER_AUTHENTICATION
.Data
,
361 APPLE_EXTENSION_SERVER_AUTHENTICATION_LENGTH
)) {
362 /* this is the Apple Server Authentication extension */
363 certInfo
->foundAppleServerAuthMarker
= CSSM_TRUE
;
365 if (cssmExt
->extnId
.Length
== APPLE_EXTENSION_ESCROW_SERVICE_LENGTH
&&
366 !memcmp(cssmExt
->extnId
.Data
, CSSMOID_APPLE_EXTENSION_ESCROW_SERVICE
.Data
,
367 APPLE_EXTENSION_ESCROW_SERVICE_LENGTH
)) {
368 /* this is the Escrow Service Signing extension */
369 certInfo
->foundEscrowServiceMarker
= CSSM_TRUE
;
371 if (cssmExt
->extnId
.Length
== APPLE_EXTENSION_PROVISIONING_PROFILE_SIGNING_LENGTH
&&
372 !memcmp(cssmExt
->extnId
.Data
, CSSMOID_APPLE_EXTENSION_PROVISIONING_PROFILE_SIGNING
.Data
,
373 APPLE_EXTENSION_PROVISIONING_PROFILE_SIGNING_LENGTH
)) {
374 /* this is the Provisioning Profile Signing extension */
375 certInfo
->foundProvisioningProfileSigningMarker
= CSSM_TRUE
;
377 if (cssmExt
->extnId
.Length
== APPLE_EXTENSION_WWDR_INTERMEDIATE_LENGTH
&&
378 !memcmp(cssmExt
->extnId
.Data
, CSSMOID_APPLE_EXTENSION_WWDR_INTERMEDIATE
.Data
,
379 APPLE_EXTENSION_WWDR_INTERMEDIATE_LENGTH
)) {
380 /* this is the Apple WWDR extension */
381 certInfo
->foundAppleWWDRIntMarker
= CSSM_TRUE
;
384 if(iSignVerifyCriticalExtension(cssmExt
) != CSSM_OK
) {
385 /* BRRZAPP! Found an unknown extension marked critical */
386 certInfo
->foundUnknownCritical
= CSSM_TRUE
;
389 CSSM_CL_FreeFieldValue(tpCert
->clHand(),
390 &CSSMOID_X509V3CertificateExtensionCStruct
,
393 } /* for additional fields */
397 CSSM_CL_FreeFieldValue(tpCert
->clHand(),
398 &CSSMOID_X509V3CertificateExtensionCStruct
,
401 if(searchHand
!= CSSM_INVALID_HANDLE
) {
402 CSSM_CL_CertAbortQuery(tpCert
->clHand(), searchHand
);
408 * Check the signature algorithm. If it's known to be untrusted,
409 * flag certInfo->untrustedSigAlg.
411 static void iSignCheckSignatureAlgorithm(
413 iSignCertInfo
*certInfo
)
415 CSSM_X509_ALGORITHM_IDENTIFIER
*algId
= NULL
;
416 CSSM_DATA_PTR valueToFree
= NULL
;
418 algId
= tp_CertGetAlgId(tpCert
, &valueToFree
);
420 tpCompareCssmData(&algId
->algorithm
, &CSSMOID_MD2
) ||
421 tpCompareCssmData(&algId
->algorithm
, &CSSMOID_MD2WithRSA
) ||
422 tpCompareCssmData(&algId
->algorithm
, &CSSMOID_MD5
) ||
423 tpCompareCssmData(&algId
->algorithm
, &CSSMOID_MD5WithRSA
) ) {
424 certInfo
->untrustedSigAlg
= CSSM_TRUE
;
426 certInfo
->untrustedSigAlg
= CSSM_FALSE
;
430 tp_CertFreeAlgId(tpCert
->clHand(), valueToFree
);
435 * Given a TPCertInfo, fetch the associated iSignCertInfo fields.
436 * Returns CSSM_FAIL on error.
438 static CSSM_RETURN
iSignGetCertInfo(
441 iSignCertInfo
*certInfo
)
445 /* first grind thru the extensions we're interested in */
446 crtn
= iSignFetchExtension(alloc
,
448 &CSSMOID_AuthorityKeyIdentifier
,
449 &certInfo
->authorityId
);
453 crtn
= iSignFetchExtension(alloc
,
455 &CSSMOID_SubjectKeyIdentifier
,
456 &certInfo
->subjectId
);
460 crtn
= iSignFetchExtension(alloc
,
463 &certInfo
->keyUsage
);
467 crtn
= iSignFetchExtension(alloc
,
469 &CSSMOID_ExtendedKeyUsage
,
470 &certInfo
->extendKeyUsage
);
474 crtn
= iSignFetchExtension(alloc
,
476 &CSSMOID_BasicConstraints
,
477 &certInfo
->basicConstraints
);
481 crtn
= iSignFetchExtension(alloc
,
483 &CSSMOID_NetscapeCertType
,
484 &certInfo
->netscapeCertType
);
488 crtn
= iSignFetchExtension(alloc
,
490 &CSSMOID_SubjectAltName
,
491 &certInfo
->subjectAltName
);
495 crtn
= iSignFetchExtension(alloc
,
497 &CSSMOID_CertificatePolicies
,
498 &certInfo
->certPolicies
);
502 crtn
= iSignFetchExtension(alloc
,
504 &CSSMOID_QC_Statements
,
505 &certInfo
->qualCertStatements
);
509 crtn
= iSignFetchExtension(alloc
,
511 &CSSMOID_NameConstraints
,
512 &certInfo
->nameConstraints
);
516 crtn
= iSignFetchExtension(alloc
,
518 &CSSMOID_PolicyMappings
,
519 &certInfo
->policyMappings
);
523 crtn
= iSignFetchExtension(alloc
,
525 &CSSMOID_PolicyConstraints
,
526 &certInfo
->policyConstraints
);
530 crtn
= iSignFetchExtension(alloc
,
532 &CSSMOID_InhibitAnyPolicy
,
533 &certInfo
->inhibitAnyPolicy
);
537 crtn
= iSignFetchExtension(alloc
,
539 &CSSMOID_CertificatePolicies
,
540 &certInfo
->certificatePolicies
);
545 /* check signature algorithm field */
546 iSignCheckSignatureAlgorithm(tpCert
, certInfo
);
548 /* now look for extensions we don't understand - the only thing we're interested
549 * in is the critical flag. */
550 return iSignSearchUnknownExtensions(tpCert
, certInfo
);
554 * Free (via CL) the fields allocated in iSignGetCertInfo().
556 static void iSignFreeCertInfo(
557 CSSM_CL_HANDLE clHand
,
558 iSignCertInfo
*certInfo
)
560 if(certInfo
->authorityId
.present
) {
561 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_AuthorityKeyIdentifier
,
562 certInfo
->authorityId
.valToFree
);
564 if(certInfo
->subjectId
.present
) {
565 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_SubjectKeyIdentifier
,
566 certInfo
->subjectId
.valToFree
);
568 if(certInfo
->keyUsage
.present
) {
569 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_KeyUsage
,
570 certInfo
->keyUsage
.valToFree
);
572 if(certInfo
->extendKeyUsage
.present
) {
573 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_ExtendedKeyUsage
,
574 certInfo
->extendKeyUsage
.valToFree
);
576 if(certInfo
->basicConstraints
.present
) {
577 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_BasicConstraints
,
578 certInfo
->basicConstraints
.valToFree
);
580 if(certInfo
->netscapeCertType
.present
) {
581 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_NetscapeCertType
,
582 certInfo
->netscapeCertType
.valToFree
);
584 if(certInfo
->subjectAltName
.present
) {
585 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_SubjectAltName
,
586 certInfo
->subjectAltName
.valToFree
);
588 if(certInfo
->certPolicies
.present
) {
589 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_CertificatePolicies
,
590 certInfo
->certPolicies
.valToFree
);
592 // if(certInfo->policyConstraints.present) {
593 // CSSM_CL_FreeFieldValue(clHand, &CSSMOID_PolicyConstraints,
594 // certInfo->policyConstraints.valToFree);
596 if(certInfo
->qualCertStatements
.present
) {
597 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_QC_Statements
,
598 certInfo
->qualCertStatements
.valToFree
);
600 if(certInfo
->certificatePolicies
.present
) {
601 CSSM_CL_FreeFieldValue(clHand
, &CSSMOID_CertificatePolicies
,
602 certInfo
->certificatePolicies
.valToFree
);
607 * See if cert's Subject.{commonName,EmailAddress} matches caller-specified
608 * string. Returns CSSM_TRUE if match, else returns CSSM_FALSE.
609 * Also indicates whether *any* of the specified fields were found, regardless
613 SN_CommonName
, // CSSMOID_CommonName, host name format
614 SN_Email
, // CSSMOID_EmailAddress
615 SN_UserID
, // CSSMOID_UserID
616 SN_OrgUnit
// CSSMOID_OrganizationalUnitName
617 } SubjSubjNameSearchType
;
619 static CSSM_BOOL
tpCompareSubjectName(
621 SubjSubjNameSearchType searchType
,
622 bool normalizeAll
, // for SN_Email case: lower-case all of
623 // the cert's value, not just the portion
625 const char *callerStr
, // already tpToLower'd
629 char *certName
= NULL
; // from cert's subject name
630 uint32 certNameLen
= 0;
631 CSSM_DATA_PTR subjNameData
= NULL
;
633 CSSM_BOOL ourRtn
= CSSM_FALSE
;
634 const CSSM_OID
*oidSrch
;
636 const unsigned char x500_userid_oid
[] = { 0x09,0x92,0x26,0x89,0x93,0xF2,0x2C,0x64,0x01,0x01 };
637 CSSM_OID X500_UserID_OID
= { sizeof(x500_userid_oid
), (uint8
*)x500_userid_oid
};
642 oidSrch
= &CSSMOID_CommonName
;
645 oidSrch
= &CSSMOID_EmailAddress
;
648 oidSrch
= &X500_UserID_OID
;
651 oidSrch
= &CSSMOID_OrganizationalUnitName
;
657 crtn
= cert
.fetchField(&CSSMOID_X509V1SubjectNameCStruct
, &subjNameData
);
659 /* should never happen, we shouldn't be here if there is no subject */
660 tpPolicyError("tpCompareSubjectName: error retrieving subject name");
663 CSSM_X509_NAME_PTR x509name
= (CSSM_X509_NAME_PTR
)subjNameData
->Data
;
664 if((x509name
== NULL
) || (subjNameData
->Length
!= sizeof(CSSM_X509_NAME
))) {
665 tpPolicyError("tpCompareSubjectName: malformed CSSM_X509_NAME");
666 cert
.freeField(&CSSMOID_X509V1SubjectNameCStruct
, subjNameData
);
670 /* Now grunge thru the X509 name looking for a common name */
671 CSSM_X509_TYPE_VALUE_PAIR
*ptvp
;
672 CSSM_X509_RDN_PTR rdnp
;
676 for(rdnDex
=0; rdnDex
<x509name
->numberOfRDNs
; rdnDex
++) {
677 rdnp
= &x509name
->RelativeDistinguishedName
[rdnDex
];
678 for(pairDex
=0; pairDex
<rdnp
->numberOfPairs
; pairDex
++) {
679 ptvp
= &rdnp
->AttributeTypeAndValue
[pairDex
];
680 if(tpCompareOids(&ptvp
->type
, oidSrch
)) {
682 certName
= (char *)ptvp
->value
.Data
;
683 certNameLen
= (uint32
)ptvp
->value
.Length
;
687 /* handle odd encodings that we need to convert to 8-bit */
688 CFStringBuiltInEncodings encoding
= kCFStringEncodingUnicode
;
689 CFDataRef cfd
= NULL
;
690 bool doConvert
= false;
691 switch(ptvp
->valueType
) {
692 case BER_TAG_T61_STRING
:
694 encoding
= kCFStringEncodingISOLatin1
;
697 case BER_TAG_PKIX_BMP_STRING
:
698 encoding
= kCFStringEncodingUnicode
;
702 * All others - either take as is, or let it fail due to
703 * illegal/incomprehensible format
709 /* raw data ==> CFString */
710 cfd
= CFDataCreate(NULL
, (UInt8
*)certName
, certNameLen
);
712 /* try next component */
715 CFStringRef cfStr
= CFStringCreateFromExternalRepresentation(
716 NULL
, cfd
, encoding
);
719 tpPolicyError("tpCompareSubjectName: bad str (1)");
723 /* CFString ==> straight ASCII */
724 cfd
= CFStringCreateExternalRepresentation(NULL
,
725 cfStr
, kCFStringEncodingASCII
, 0);
728 tpPolicyError("tpCompareSubjectName: bad str (2)");
731 certNameLen
= (uint32
)CFDataGetLength(cfd
);
732 certName
= (char *)CFDataGetBytePtr(cfd
);
734 ourRtn
= tpCompareHostNames(callerStr
, callerStrLen
,
735 certName
, certNameLen
);
743 ourRtn
= tpCompareEmailAddr(callerStr
, callerStrLen
,
744 certName
, certNameLen
, normalizeAll
);
748 /* exact match only here, for now */
749 ourRtn
= ((callerStrLen
== certNameLen
) &&
750 !memcmp(callerStr
, certName
, certNameLen
)) ?
751 CSSM_TRUE
: CSSM_FALSE
;
758 /* else keep going, maybe there's another common name */
765 cert
.freeField(&CSSMOID_X509V1SubjectNameCStruct
, subjNameData
);
770 * Compare ASCII form of an IP address to a CSSM_DATA containing
771 * the IP address's numeric components. Returns true on match.
773 static CSSM_BOOL
tpCompIpAddrStr(
776 const CSSM_DATA
*numeric
)
778 const char *cp
= str
;
782 if((numeric
== NULL
) || (numeric
->Length
== 0) || (str
== NULL
)) {
785 if(cp
[strLen
- 1] == '\0') {
786 /* ignore NULL terminator */
789 for(unsigned dex
=0; dex
<numeric
->Length
; dex
++) {
790 /* cp points to start of current string digit */
792 const char *lastChar
= cp
+ strLen
;
794 for( ; nextDot
<lastChar
; nextDot
++) {
795 if(*nextDot
== '.') {
799 if(nextDot
== lastChar
) {
800 /* legal and required on last digit */
801 if(dex
!= (numeric
->Length
- 1)) {
805 else if(dex
== (numeric
->Length
- 1)) {
808 ptrdiff_t digLen
= nextDot
- cp
;
809 if(digLen
>= sizeof(buf
)) {
813 memmove(buf
, cp
, digLen
);
815 /* incr digLen to include the next dot */
819 int digVal
= atoi(buf
);
820 if(digVal
!= numeric
->Data
[dex
]) {
828 * See if cert's subjectAltName contains an element matching caller-specified
829 * string, hostname, in the following forms:
831 * SAN_HostName : dnsName, iPAddress
832 * SAN_Email : RFC822Name
834 * Returns CSSM_TRUE if match, else returns CSSM_FALSE.
836 * Also indicates whether or not a dnsName (search type HostName) or
837 * RFC822Name (search type SAM_Email) was found, regardless of result
840 * The appStr/appStrLen args are optional - if NULL/0, only the
841 * search for dnsName/RFC822Name is done.
846 } SubjAltNameSearchType
;
848 static CSSM_BOOL
tpCompareSubjectAltName(
849 const iSignExtenInfo
&subjAltNameInfo
,
850 const char *appStr
, // caller has lower-cased as appropriate
852 SubjAltNameSearchType searchType
,
853 bool normalizeAll
, // for SAN_Email case: lower-case all of
854 // the cert's value, not just the portion
856 bool &dnsNameFound
, // RETURNED, SAN_HostName case
857 bool &emailFound
) // RETURNED, SAN_Email case
859 dnsNameFound
= false;
861 if(!subjAltNameInfo
.present
) {
862 /* common failure, no subjectAltName found */
866 CE_GeneralNames
*names
= &subjAltNameInfo
.extnData
->subjectAltName
;
867 CSSM_BOOL ourRtn
= CSSM_FALSE
;
871 /* Search thru the CE_GeneralNames looking for the appropriate attribute */
872 for(unsigned dex
=0; dex
<names
->numNames
; dex
++) {
873 CE_GeneralName
*name
= &names
->generalName
[dex
];
876 switch(name
->nameType
) {
879 /* nothing to do here */
882 ourRtn
= tpCompIpAddrStr(appStr
, appStrLen
, &name
->name
);
886 if(name
->berEncoded
) {
887 tpErrorLog("tpCompareSubjectAltName: malformed "
888 "CE_GeneralName (1)\n");
891 certName
= (char *)name
->name
.Data
;
892 if(certName
== NULL
) {
893 tpErrorLog("tpCompareSubjectAltName: malformed "
894 "CE_GeneralName (2)\n");
897 certNameLen
= (uint32
)(name
->name
.Length
);
900 /* skip if caller passed in NULL */
901 ourRtn
= tpCompareHostNames(appStr
, appStrLen
,
902 certName
, certNameLen
);
907 /* not interested, proceed to next name */
910 break; /* from case HostName */
913 if(name
->nameType
!= GNT_RFC822Name
) {
917 certName
= (char *)name
->name
.Data
;
918 if(certName
== NULL
) {
919 tpErrorLog("tpCompareSubjectAltName: malformed "
923 certNameLen
= (uint32
)(name
->name
.Length
);
926 ourRtn
= tpCompareEmailAddr(appStr
, appStrLen
, certName
,
927 certNameLen
, normalizeAll
);
939 /* is host name in the form of a.b.c.d, where a,b,c, and d are digits? */
940 static CSSM_BOOL
tpIsNumeric(
941 const char *hostName
,
942 unsigned hostNameLen
)
944 if(hostName
[hostNameLen
- 1] == '\0') {
945 /* ignore NULL terminator */
948 for(unsigned i
=0; i
<hostNameLen
; i
++) {
949 char c
= *hostName
++;
961 * Convert a typed string represented by a CSSM_X509_TYPE_VALUE_PAIR to a
962 * CFStringRef. Caller owns and must release the result. NULL return means
963 * unconvertible input "string".
965 static CFStringRef CF_RETURNS_RETAINED
tpTvpToCfString(
966 const CSSM_X509_TYPE_VALUE_PAIR
*tvp
)
968 CFStringBuiltInEncodings encoding
;
969 switch(tvp
->valueType
) {
970 case BER_TAG_T61_STRING
:
972 encoding
= kCFStringEncodingISOLatin1
;
974 case BER_TAG_PKIX_BMP_STRING
:
975 encoding
= kCFStringEncodingUnicode
;
977 case BER_TAG_PRINTABLE_STRING
:
978 case BER_TAG_IA5_STRING
:
979 case BER_TAG_PKIX_UTF8_STRING
:
980 encoding
= kCFStringEncodingUTF8
;
986 /* raw data ==> CFString */
987 CFDataRef cfd
= CFDataCreate(NULL
, tvp
->value
.Data
, tvp
->value
.Length
);
991 CFStringRef cfStr
= CFStringCreateFromExternalRepresentation(NULL
, cfd
, encoding
);
997 * Compare a CFString and a string represented by a CSSM_X509_TYPE_VALUE_PAIR.
998 * Returns CSSM_TRUE if they are equal.
1000 static bool tpCompareTvpToCfString(
1001 const CSSM_X509_TYPE_VALUE_PAIR
*tvp
,
1003 CFOptionFlags flags
) // e.g., kCFCompareCaseInsensitive
1005 CFStringRef cfStr
= tpTvpToCfString(tvp
);
1009 CFComparisonResult res
= CFStringCompare(refStr
, cfStr
, flags
);
1011 if(res
== kCFCompareEqualTo
) {
1020 * Given one iSignCertInfo, determine whether or not the specified
1021 * EKU OID, or - optionally - CSSMOID_ExtendedKeyUsageAny - is present.
1022 * Returns true if so, else false.
1024 static bool tpVerifyEKU(
1025 const iSignCertInfo
&certInfo
,
1026 const CSSM_OID
&ekuOid
,
1027 bool ekuAnyOK
) // if true, CSSMOID_ExtendedKeyUsageAny counts as "found"
1029 if(!certInfo
.extendKeyUsage
.present
) {
1032 CE_ExtendedKeyUsage
*eku
= &certInfo
.extendKeyUsage
.extnData
->extendedKeyUsage
;
1033 assert(eku
!= NULL
);
1035 for(unsigned i
=0; i
<eku
->numPurposes
; i
++) {
1036 const CSSM_OID
*foundEku
= &eku
->purposes
[i
];
1037 if(tpCompareOids(foundEku
, &ekuOid
)) {
1040 if(ekuAnyOK
&& tpCompareOids(foundEku
, &CSSMOID_ExtendedKeyUsageAny
)) {
1048 * Given one iSignCertInfo, determine whether or not the specified
1049 * Certificate Policy OID, or - optionally - CSSMOID_ANY_POLICY - is present.
1050 * Returns true if so, else false.
1052 static bool tpVerifyCPE(
1053 const iSignCertInfo
&certInfo
,
1054 const CSSM_OID
&cpOid
,
1055 bool anyPolicyOK
) // if true, CSSMOID_ANY_POLICY counts as "found"
1057 if(!certInfo
.certPolicies
.present
) {
1060 CE_CertPolicies
*cp
= &certInfo
.certPolicies
.extnData
->certPolicies
;
1063 for(unsigned i
=0; i
<cp
->numPolicies
; i
++) {
1064 const CE_PolicyInformation
*foundPolicy
= &cp
->policies
[i
];
1065 if(tpCompareOids(&foundPolicy
->certPolicyId
, &cpOid
)) {
1068 if(anyPolicyOK
&& tpCompareOids(&foundPolicy
->certPolicyId
, &CSSMOID_ANY_POLICY
)) {
1076 * Verify iChat handle. We search for a matching (case-insensitive) string
1079 * -- name component ("dmitch") from subject name's CommonName
1081 * -- domain name from subject name's organizationalUnit
1083 * Plus we require an Organization component of "Apple Computer, Inc." or "Apple Inc."
1085 static bool tpCompareIChatHandleName(
1087 const char *iChatHandle
, // UTF8
1088 uint32 iChatHandleLen
)
1090 CSSM_DATA_PTR subjNameData
= NULL
; // from fetchField
1092 bool ourRtn
= false;
1093 CSSM_X509_NAME_PTR x509name
;
1094 CSSM_X509_TYPE_VALUE_PAIR
*ptvp
;
1095 CSSM_X509_RDN_PTR rdnp
;
1099 /* search until all of these are true */
1100 CSSM_BOOL commonNameMatch
= CSSM_FALSE
; // name before '@'
1101 CSSM_BOOL orgUnitMatch
= CSSM_FALSE
; // domain after '@
1102 CSSM_BOOL orgMatch
= CSSM_FALSE
; // Apple Computer, Inc. (or Apple Inc.)
1105 * incoming UTF8 handle ==> two components.
1106 * First convert to CFString.
1108 if(iChatHandle
[iChatHandleLen
- 1] == '\0') {
1109 /* avoid NULL when creating CFStrings */
1112 CFDataRef cfd
= CFDataCreate(NULL
, (const UInt8
*)iChatHandle
, iChatHandleLen
);
1116 CFStringRef handleStr
= CFStringCreateFromExternalRepresentation(NULL
, cfd
,
1117 kCFStringEncodingUTF8
);
1119 if(handleStr
== NULL
) {
1120 tpPolicyError("tpCompareIChatHandleName: bad incoming handle (1)");
1125 * Find the '@' delimiter
1128 whereIsAt
= CFStringFind(handleStr
, CFSTR("@"), 0);
1129 if(whereIsAt
.length
== 0) {
1130 tpPolicyError("tpCompareIChatHandleName: bad incoming handle: no @");
1131 CFRelease(handleStr
);
1136 * Two components, before and after delimiter
1138 CFRange r
= {0, whereIsAt
.location
};
1139 CFStringRef iChatName
= CFStringCreateWithSubstring(NULL
, handleStr
, r
);
1140 if(iChatName
== NULL
) {
1141 tpPolicyError("tpCompareIChatHandleName: bad incoming handle (2)");
1142 CFRelease(handleStr
);
1145 r
.location
= whereIsAt
.location
+ 1; // after the '@'
1146 r
.length
= CFStringGetLength(handleStr
) - r
.location
;
1147 CFStringRef iChatDomain
= CFStringCreateWithSubstring(NULL
, handleStr
, r
);
1148 CFRelease(handleStr
);
1149 if(iChatDomain
== NULL
) {
1150 tpPolicyError("tpCompareIChatHandleName: bad incoming handle (3)");
1151 CFRelease(iChatName
);
1154 /* subsequent errors to errOut: */
1156 /* get subject name in CSSM form, all subsequent ops work on that */
1157 crtn
= cert
.fetchField(&CSSMOID_X509V1SubjectNameCStruct
, &subjNameData
);
1159 /* should never happen, we shouldn't be here if there is no subject */
1160 tpPolicyError("tpCompareIChatHandleName: error retrieving subject name");
1164 x509name
= (CSSM_X509_NAME_PTR
)subjNameData
->Data
;
1165 if((x509name
== NULL
) || (subjNameData
->Length
!= sizeof(CSSM_X509_NAME
))) {
1166 tpPolicyError("tpCompareIChatHandleName: malformed CSSM_X509_NAME");
1170 /* Now grunge thru the X509 name looking for three fields */
1172 for(rdnDex
=0; rdnDex
<x509name
->numberOfRDNs
; rdnDex
++) {
1173 rdnp
= &x509name
->RelativeDistinguishedName
[rdnDex
];
1174 for(pairDex
=0; pairDex
<rdnp
->numberOfPairs
; pairDex
++) {
1175 ptvp
= &rdnp
->AttributeTypeAndValue
[pairDex
];
1176 if(!commonNameMatch
&&
1177 tpCompareOids(&ptvp
->type
, &CSSMOID_CommonName
) &&
1178 tpCompareTvpToCfString(ptvp
, iChatName
, kCFCompareCaseInsensitive
)) {
1179 commonNameMatch
= CSSM_TRUE
;
1183 tpCompareOids(&ptvp
->type
, &CSSMOID_OrganizationalUnitName
) &&
1184 tpCompareTvpToCfString(ptvp
, iChatDomain
, kCFCompareCaseInsensitive
)) {
1185 orgUnitMatch
= CSSM_TRUE
;
1189 tpCompareOids(&ptvp
->type
, &CSSMOID_OrganizationName
) &&
1190 /* this one is case sensitive */
1191 (tpCompareTvpToCfString(ptvp
, CFSTR("Apple Computer, Inc."), 0) ||
1192 tpCompareTvpToCfString(ptvp
, CFSTR("Apple Inc."), 0))) {
1193 orgMatch
= CSSM_TRUE
;
1196 if(commonNameMatch
&& orgUnitMatch
&& orgMatch
) {
1204 cert
.freeField(&CSSMOID_X509V1SubjectNameCStruct
, subjNameData
);
1205 CFRelease(iChatName
);
1206 CFRelease(iChatDomain
);
1211 * Verify SSL options. Currently this just consists of matching the
1212 * leaf cert's subject common name against the caller's (optional)
1215 static CSSM_RETURN
tp_verifySslOpts(
1217 TPCertGroup
&certGroup
,
1218 const CSSM_DATA
*sslFieldOpts
,
1219 const iSignCertInfo
*certInfo
) // all certs, size certGroup.numCerts()
1221 const iSignCertInfo
&leafCertInfo
= certInfo
[0];
1222 CSSM_APPLE_TP_SSL_OPTIONS
*sslOpts
= NULL
;
1223 unsigned hostNameLen
= 0;
1224 const char *serverName
= NULL
;
1225 TPCertInfo
*leaf
= certGroup
.certAtIndex(0);
1226 assert(leaf
!= NULL
);
1228 /* CSSM_APPLE_TP_SSL_OPTIONS is optional */
1229 if((sslFieldOpts
!= NULL
) && (sslFieldOpts
->Data
!= NULL
)) {
1230 sslOpts
= (CSSM_APPLE_TP_SSL_OPTIONS
*)sslFieldOpts
->Data
;
1231 switch(sslOpts
->Version
) {
1232 case CSSM_APPLE_TP_SSL_OPTS_VERSION
:
1233 if(sslFieldOpts
->Length
!= sizeof(CSSM_APPLE_TP_SSL_OPTIONS
)) {
1234 return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
1237 /* handle backwards compatibility here if necessary */
1239 return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
1241 hostNameLen
= sslOpts
->ServerNameLen
;
1242 serverName
= sslOpts
->ServerName
;
1245 /* host name check is optional */
1246 if(hostNameLen
!= 0) {
1247 if(serverName
== NULL
) {
1248 return CSSMERR_TP_INVALID_POINTER
;
1251 /* convert caller's hostname string to lower case */
1252 char *hostName
= (char *)certGroup
.alloc().malloc(hostNameLen
);
1253 memmove(hostName
, serverName
, hostNameLen
);
1254 tpToLower(hostName
, hostNameLen
);
1256 CSSM_BOOL match
= CSSM_FALSE
;
1258 /* First check subjectAltName... */
1259 bool dnsNameFound
= false;
1261 match
= tpCompareSubjectAltName(leafCertInfo
.subjectAltName
,
1262 hostName
, hostNameLen
,
1263 SAN_HostName
, false, dnsNameFound
, dummy
);
1266 * Then common name, if
1267 * -- no match from subjectAltName, AND
1268 * -- dnsName was NOT found, AND
1269 * -- hostName is not strictly numeric form (1.2.3.4)
1271 if(!match
&& !dnsNameFound
&& !tpIsNumeric(hostName
, hostNameLen
)) {
1273 match
= tpCompareSubjectName(*leaf
, SN_CommonName
, false, hostName
, hostNameLen
,
1278 * Limit allowed domains for specific anchors
1280 CSSM_BOOL domainMatch
= CSSM_TRUE
;
1282 TPCertInfo
*tpCert
= certGroup
.lastCert();
1284 const CSSM_DATA
*certData
= tpCert
->itemData();
1285 unsigned char digest
[CC_SHA1_DIGEST_LENGTH
];
1286 CC_SHA1(certData
->Data
, (CC_LONG
)certData
->Length
, digest
);
1287 if (!memcmp(digest
, kAppleCorpCASHA1
, sizeof(digest
))) {
1288 const char *dnlist
[] = { "apple.com", "icloud.com" };
1289 unsigned int idx
, dncount
=2;
1290 domainMatch
= CSSM_FALSE
;
1291 for(idx
=0;idx
<dncount
;idx
++) {
1292 uint32 len
=(uint32
)strlen(dnlist
[idx
]);
1293 char *domainName
=(char*)certGroup
.alloc().malloc(len
);
1294 memmove(domainName
, (char*)dnlist
[idx
], len
);
1295 if(tpCompareDomainSuffix(hostName
, hostNameLen
,
1297 domainMatch
= CSSM_TRUE
;
1299 certGroup
.alloc().free(domainName
);
1308 certGroup
.alloc().free(hostName
);
1310 if(leaf
->addStatusCode(CSSMERR_APPLETP_HOSTNAME_MISMATCH
)) {
1311 return CSSMERR_APPLETP_HOSTNAME_MISMATCH
;
1315 if(leaf
->addStatusCode(CSSMERR_APPLETP_CA_PIN_MISMATCH
)) {
1316 return CSSMERR_APPLETP_CA_PIN_MISMATCH
;
1322 * Ensure that, if an extendedKeyUsage extension is present in the
1323 * leaf, that either anyExtendedKeyUsage or the appropriate
1324 * CSSMOID_{Server,Client}Auth, or a SeverGatedCrypto usage is present.
1326 const iSignExtenInfo
&ekuInfo
= leafCertInfo
.extendKeyUsage
;
1327 if(ekuInfo
.present
) {
1328 bool foundGoodEku
= false;
1329 bool isServer
= true;
1330 CE_ExtendedKeyUsage
*eku
= (CE_ExtendedKeyUsage
*)ekuInfo
.extnData
;
1331 assert(eku
!= NULL
);
1334 * Determine appropriate extended key usage; default is SSL server
1336 const CSSM_OID
*extUse
= &CSSMOID_ServerAuth
;
1337 if((sslOpts
!= NULL
) && /* optional, default server side */
1338 (sslOpts
->Version
> 0) && /* this was added in struct version 1 */
1339 (sslOpts
->Flags
& CSSM_APPLE_TP_SSL_CLIENT
)) {
1340 extUse
= &CSSMOID_ClientAuth
;
1344 /* search for that one or for "any" indicator */
1345 for(unsigned i
=0; i
<eku
->numPurposes
; i
++) {
1346 const CSSM_OID
*purpose
= &eku
->purposes
[i
];
1347 if(tpCompareOids(purpose
, extUse
)) {
1348 foundGoodEku
= true;
1351 if(tpCompareOids(purpose
, &CSSMOID_ExtendedKeyUsageAny
)) {
1352 foundGoodEku
= true;
1355 if((policy
== kTP_IPSec
) && (tpCompareOids(purpose
, &CSSMOID_EKU_IPSec
))) {
1356 foundGoodEku
= true;
1360 /* server gated crypto: server side only */
1361 if(tpCompareOids(purpose
, &CSSMOID_NetscapeSGC
)) {
1362 foundGoodEku
= true;
1365 if(tpCompareOids(purpose
, &CSSMOID_MicrosoftSGC
)) {
1366 foundGoodEku
= true;
1372 if(leaf
->addStatusCode(CSSMERR_APPLETP_SSL_BAD_EXT_KEY_USE
)) {
1373 return CSSMERR_TP_VERIFY_ACTION_FAILED
;
1379 * Check for additional options flag (2nd lowest bit set) which indicates
1380 * we must be issued by an Apple intermediate with a particular extension.
1381 * (This flag is set by SecPolicyCreateAppleSSLService in SecPolicy.cpp.)
1383 if((sslOpts
!= NULL
) &&
1384 (sslOpts
->Version
> 0) && /* this was added in struct version 1 */
1385 (sslOpts
->Flags
& 0x00000002)) {
1387 if (certGroup
.numCerts() > 1) {
1388 const iSignCertInfo
*isCertInfo
= &certInfo
[1];
1389 if (!(isCertInfo
->foundAppleServerAuthMarker
== CSSM_TRUE
)) {
1390 TPCertInfo
*tpCert
= certGroup
.certAtIndex(1);
1391 tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
);
1392 return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
1396 /* we only have the leaf? */
1397 if(leaf
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
)) {
1398 return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
1406 * Verify SMIME and iChat options.
1407 * This deals with both S/MIME and iChat policies; within the iChat domain it
1408 * deals with Apple-specific .mac certs as well as what we call "generic AIM"
1409 * certs, as used in the Windows AIM client.
1411 #define CE_CIPHER_MASK (~(CE_KU_EncipherOnly | CE_KU_DecipherOnly))
1413 static CSSM_RETURN
tp_verifySmimeOpts(
1415 TPCertGroup
&certGroup
,
1416 const CSSM_DATA
*smimeFieldOpts
,
1417 const iSignCertInfo
*certInfo
) // all certs, size certGroup.numCerts()
1419 const iSignCertInfo
&leafCertInfo
= certInfo
[0];
1420 bool iChat
= (policy
== kTP_iChat
) ? true : false;
1422 * The CSSM_APPLE_TP_SMIME_OPTIONS pointer is optional as is everything in it.
1424 CSSM_APPLE_TP_SMIME_OPTIONS
*smimeOpts
= NULL
;
1425 if(smimeFieldOpts
!= NULL
) {
1426 smimeOpts
= (CSSM_APPLE_TP_SMIME_OPTIONS
*)smimeFieldOpts
->Data
;
1428 if(smimeOpts
!= NULL
) {
1429 switch(smimeOpts
->Version
) {
1430 case CSSM_APPLE_TP_SMIME_OPTS_VERSION
:
1431 if(smimeFieldOpts
->Length
!=
1432 sizeof(CSSM_APPLE_TP_SMIME_OPTIONS
)) {
1433 return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
1436 /* handle backwards compatibility here if necessary */
1438 return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
1442 TPCertInfo
*leaf
= certGroup
.certAtIndex(0);
1443 assert(leaf
!= NULL
);
1445 /* Verify optional email address, a.k.a. handle for iChat policy */
1446 unsigned emailLen
= 0;
1447 if(smimeOpts
!= NULL
) {
1448 emailLen
= smimeOpts
->SenderEmailLen
;
1452 bool emailFoundInSAN
= false;
1453 bool iChatHandleFound
= false; /* indicates a genuine Apple iChat cert */
1454 bool emailFoundInDN
= false;
1456 if(smimeOpts
->SenderEmail
== NULL
) {
1457 return CSSMERR_TP_INVALID_POINTER
;
1460 /* iChat - first try the Apple custom format */
1462 iChatHandleFound
= tpCompareIChatHandleName(*leaf
, smimeOpts
->SenderEmail
,
1464 if(iChatHandleFound
) {
1472 * normalize caller's email string
1473 * SMIME - lowercase only the portion after '@'
1474 * iChat - lowercase all of it
1476 char *email
= (char *)certGroup
.alloc().malloc(emailLen
);
1477 memmove(email
, smimeOpts
->SenderEmail
, emailLen
);
1478 tpNormalizeAddrSpec(email
, emailLen
, iChat
);
1482 * First check subjectAltName. The emailFound bool indicates
1483 * that *some* email address was found, regardless of a match
1487 match
= tpCompareSubjectAltName(leafCertInfo
.subjectAltName
,
1489 SAN_Email
, iChat
, dummy
, emailFoundInSAN
);
1492 * Then subject DN, CSSMOID_EmailAddress, if no match from
1493 * subjectAltName. In this case the whole email address is
1494 * case insensitive (RFC 3280, section 4.1.2.6), so
1498 tpNormalizeAddrSpec(email
, emailLen
, true);
1499 match
= tpCompareSubjectName(*leaf
, SN_Email
, true, email
, emailLen
,
1502 certGroup
.alloc().free(email
);
1505 * Error here if no match found but there was indeed *some*
1506 * email address in the cert.
1508 if(!match
&& (emailFoundInSAN
|| emailFoundInDN
)) {
1509 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND
)) {
1510 tpPolicyError("SMIME email addrs in cert but no match");
1511 return CSSMERR_APPLETP_SMIME_EMAIL_ADDRS_NOT_FOUND
;
1517 * iChat only: error if app specified email address but there was
1520 if(iChat
&& !emailFoundInSAN
&& !emailFoundInDN
&& !iChatHandleFound
) {
1521 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_NO_EMAIL_ADDRS
)) {
1522 tpPolicyError("iChat: no email address or handle in cert");
1523 return CSSMERR_APPLETP_SMIME_NO_EMAIL_ADDRS
;
1529 * Going by the letter of the law, here's what RFC 2632 has to say
1530 * about the legality of an empty Subject Name:
1532 * ...the subject DN in a user's (i.e. end-entity) certificate MAY
1533 * be an empty SEQUENCE in which case the subjectAltName extension
1534 * will include the subject's identifier and MUST be marked as
1537 * OK, first examine the leaf cert's subject name.
1540 CSSM_DATA_PTR subjNameData
= NULL
;
1541 const iSignExtenInfo
&kuInfo
= leafCertInfo
.keyUsage
;
1542 const iSignExtenInfo
&ekuInfo
= leafCertInfo
.extendKeyUsage
;
1543 const CSSM_X509_NAME
*x509Name
= NULL
;
1546 /* empty subject name processing is S/MIME only */
1550 crtn
= leaf
->fetchField(&CSSMOID_X509V1SubjectNameCStruct
, &subjNameData
);
1552 /* This should really never happen */
1553 tpPolicyError("SMIME policy: error fetching subjectName");
1554 leaf
->addStatusCode(CSSMERR_TP_INVALID_CERTIFICATE
);
1555 return CSSMERR_TP_INVALID_CERTIFICATE
;
1557 /* must do a leaf->freeField(&CSSMOID_X509V1SubjectNameCStruct on exit */
1559 x509Name
= (const CSSM_X509_NAME
*)subjNameData
->Data
;
1560 if(x509Name
->numberOfRDNs
== 0) {
1562 * Empty subject name. If we haven't already seen a valid
1563 * email address in the subject alternate name (by looking
1564 * for a specific address specified by app), try to find
1567 if(!emailFoundInSAN
&& // haven't found one, and
1568 (emailLen
== 0)) { // didn't even look yet
1570 tpCompareSubjectAltName(leafCertInfo
.subjectAltName
,
1571 NULL
, 0, // email, emailLen,
1572 SAN_Email
, false, dummy
,
1573 emailFoundInSAN
); // the variable we're updating
1575 if(!emailFoundInSAN
) {
1576 tpPolicyError("SMIME policy fail: empty subject name and "
1577 "no Email Addrs in SubjectAltName");
1578 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_NO_EMAIL_ADDRS
)) {
1579 leaf
->freeField(&CSSMOID_X509V1SubjectNameCStruct
, subjNameData
);
1580 return CSSMERR_TP_VERIFY_ACTION_FAILED
;
1583 /* have to skip the next block */
1589 * One more thing: this leaf must indeed have a subjAltName
1590 * extension and it must be critical. We would not have gotten this
1591 * far if the subjAltName extension was not actually present....
1593 assert(leafCertInfo
.subjectAltName
.present
);
1594 if(!leafCertInfo
.subjectAltName
.critical
) {
1595 tpPolicyError("SMIME policy fail: empty subject name and "
1596 "no Email Addrs in SubjectAltName");
1597 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_SUBJ_ALT_NAME_NOT_CRIT
)) {
1598 leaf
->freeField(&CSSMOID_X509V1SubjectNameCStruct
, subjNameData
);
1599 return CSSMERR_TP_VERIFY_ACTION_FAILED
;
1604 leaf
->freeField(&CSSMOID_X509V1SubjectNameCStruct
, subjNameData
);
1607 * Enforce the usage of the key associated with the leaf cert.
1608 * Cert's KeyUsage must be a superset of what the app is trying to do.
1609 * Note the {en,de}cipherOnly flags are handled separately....
1611 if(kuInfo
.present
&& (smimeOpts
!= NULL
)) {
1612 CE_KeyUsage certKu
= *((CE_KeyUsage
*)kuInfo
.extnData
);
1613 CE_KeyUsage appKu
= smimeOpts
->IntendedUsage
;
1614 CE_KeyUsage intersection
= certKu
& appKu
;
1615 if((intersection
& CE_CIPHER_MASK
) != (appKu
& CE_CIPHER_MASK
)) {
1616 tpPolicyError("SMIME KeyUsage err: appKu 0x%x certKu 0x%x",
1618 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_KEY_USE
)) {
1619 return CSSMERR_TP_VERIFY_ACTION_FAILED
;
1623 /* Now the en/de cipher only bits - for keyAgreement only */
1624 if(appKu
& CE_KU_KeyAgreement
) {
1626 * 1. App wants to use this for key agreement; it must
1627 * say what it wants to do with the derived key.
1628 * In this context, the app's XXXonly bit means that
1629 * it wants to use the key for that op - not necessarliy
1632 if((appKu
& (CE_KU_EncipherOnly
| CE_KU_DecipherOnly
)) == 0) {
1633 tpPolicyError("SMIME KeyUsage err: KeyAgreement with "
1634 "no Encipher or Decipher");
1635 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_KEY_USE
)) {
1636 return CSSMERR_TP_VERIFY_ACTION_FAILED
;
1641 * 2. If cert restricts to encipher only make sure the
1642 * app isn't trying to decipher.
1644 if((certKu
& CE_KU_EncipherOnly
) &&
1645 (appKu
& CE_KU_DecipherOnly
)) {
1646 tpPolicyError("SMIME KeyUsage err: cert EncipherOnly, "
1647 "app wants to decipher");
1648 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_KEY_USE
)) {
1649 return CSSMERR_TP_VERIFY_ACTION_FAILED
;
1654 * 3. If cert restricts to decipher only make sure the
1655 * app isn't trying to encipher.
1657 if((certKu
& CE_KU_DecipherOnly
) &&
1658 (appKu
& CE_KU_EncipherOnly
)) {
1659 tpPolicyError("SMIME KeyUsage err: cert DecipherOnly, "
1660 "app wants to encipher");
1661 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_KEY_USE
)) {
1662 return CSSMERR_TP_VERIFY_ACTION_FAILED
;
1669 * Extended Key Use verification, which is different for the two policies.
1672 if(iChat
&& !ekuInfo
.present
) {
1674 * iChat: whether generic AIM cert or Apple .mac/iChat cert, we must have an
1675 * extended key use extension.
1677 tpPolicyError("iChat: No extended Key Use");
1678 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
)) {
1679 return CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
;
1683 if(!iChatHandleFound
) {
1685 * S/MIME and generic AIM certs when evaluating iChat policy.
1686 * Look for either emailProtection or anyExtendedKeyUsage usages.
1688 * S/MIME : the whole extension is optional.
1689 * iChat : extension must be there (which we've already covered, above)
1690 * and we must find one of those extensions.
1692 if(ekuInfo
.present
) {
1693 bool foundGoodEku
= false;
1694 CE_ExtendedKeyUsage
*eku
= (CE_ExtendedKeyUsage
*)ekuInfo
.extnData
;
1695 assert(eku
!= NULL
);
1696 for(unsigned i
=0; i
<eku
->numPurposes
; i
++) {
1697 if(tpCompareOids(&eku
->purposes
[i
], &CSSMOID_EmailProtection
)) {
1698 foundGoodEku
= true;
1701 if(tpCompareOids(&eku
->purposes
[i
], &CSSMOID_ExtendedKeyUsageAny
)) {
1702 foundGoodEku
= true;
1707 tpPolicyError("iChat/SMIME: No appropriate extended Key Use");
1708 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
)) {
1709 return CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
;
1716 * Apple iChat cert. Look for anyExtendedKeyUsage, iChatSigning,
1717 * ichatEncrypting - the latter of two which can optionally be
1720 assert(iChat
); /* or we could not have even looked for an iChat style handle */
1721 assert(ekuInfo
.present
); /* checked above */
1722 bool foundAnyEku
= false;
1723 bool foundIChatSign
= false;
1724 bool foundISignEncrypt
= false;
1725 CE_ExtendedKeyUsage
*eku
= (CE_ExtendedKeyUsage
*)ekuInfo
.extnData
;
1726 assert(eku
!= NULL
);
1728 for(unsigned i
=0; i
<eku
->numPurposes
; i
++) {
1729 if(tpCompareOids(&eku
->purposes
[i
],
1730 &CSSMOID_APPLE_EKU_ICHAT_SIGNING
)) {
1731 foundIChatSign
= true;
1733 else if(tpCompareOids(&eku
->purposes
[i
],
1734 &CSSMOID_APPLE_EKU_ICHAT_ENCRYPTION
)) {
1735 foundISignEncrypt
= true;
1737 else if(tpCompareOids(&eku
->purposes
[i
], &CSSMOID_ExtendedKeyUsageAny
)) {
1742 if(!foundAnyEku
&& !foundISignEncrypt
&& !foundIChatSign
) {
1743 /* No go - no acceptable uses found */
1744 tpPolicyError("iChat: No valid extended Key Uses found");
1745 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
)) {
1746 return CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
;
1750 /* check for specifically required uses */
1751 if((smimeOpts
!= NULL
) && (smimeOpts
->IntendedUsage
!= 0)) {
1752 if(smimeOpts
->IntendedUsage
& CE_KU_DigitalSignature
) {
1753 if(!foundIChatSign
) {
1754 tpPolicyError("iChat: ICHAT_SIGNING required, but missing");
1755 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
)) {
1756 return CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
;
1760 if(smimeOpts
->IntendedUsage
& CE_KU_DataEncipherment
) {
1761 if(!foundISignEncrypt
) {
1762 tpPolicyError("iChat: ICHAT_ENCRYPT required, but missing");
1763 if(leaf
->addStatusCode(CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
)) {
1764 return CSSMERR_APPLETP_SMIME_BAD_EXT_KEY_USE
;
1768 } /* checking IntendedUsage */
1769 } /* iChat cert format */
1775 * Verify Apple SW Update signing (was Apple Code Signing, pre-Leopard) options.
1777 * -- Must have one intermediate cert
1778 * -- intermediate must have basic constraints with path length 0
1779 * -- intermediate has CSSMOID_APPLE_EKU_CODE_SIGNING EKU
1780 * -- leaf cert has either CODE_SIGNING or CODE_SIGN_DEVELOPMENT EKU (the latter of
1781 * which triggers a CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT error)
1783 static CSSM_RETURN
tp_verifySWUpdateSigningOpts(
1784 TPCertGroup
&certGroup
,
1785 const CSSM_DATA
*fieldOpts
, // currently unused
1786 const iSignCertInfo
*certInfo
) // all certs, size certGroup.numCerts()
1788 unsigned numCerts
= certGroup
.numCerts();
1789 const iSignCertInfo
*isCertInfo
;
1791 // const CE_BasicConstraints *bc; // currently unused
1792 CE_ExtendedKeyUsage
*eku
;
1793 CSSM_RETURN crtn
= CSSM_OK
;
1796 if(!certGroup
.isAllowedError(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
)) {
1797 tpPolicyError("tp_verifySWUpdateSigningOpts: numCerts %u", numCerts
);
1798 return CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
1800 else if(numCerts
< 3) {
1801 /* this error allowed, but no intermediate...check leaf */
1806 /* verify intermediate cert */
1807 isCertInfo
= &certInfo
[1];
1808 tpCert
= certGroup
.certAtIndex(1);
1810 if(!isCertInfo
->basicConstraints
.present
) {
1811 tpPolicyError("tp_verifySWUpdateSigningOpts: no basicConstraints in intermediate");
1812 if(tpCert
->addStatusCode(CSSMERR_APPLETP_CS_NO_BASIC_CONSTRAINTS
)) {
1813 return CSSMERR_APPLETP_CS_NO_BASIC_CONSTRAINTS
;
1817 /* ExtendedKeyUse required, one legal value */
1818 if(!isCertInfo
->extendKeyUsage
.present
) {
1819 tpPolicyError("tp_verifySWUpdateSigningOpts: no extendedKeyUse in intermediate");
1820 if(tpCert
->addStatusCode(CSSMERR_APPLETP_CS_NO_EXTENDED_KEY_USAGE
)) {
1821 return CSSMERR_APPLETP_CS_NO_EXTENDED_KEY_USAGE
;
1828 eku
= &isCertInfo
->extendKeyUsage
.extnData
->extendedKeyUsage
;
1829 assert(eku
!= NULL
);
1830 if(eku
->numPurposes
!= 1) {
1831 tpPolicyError("tp_verifySWUpdateSigningOpts: bad eku->numPurposes in intermediate (%lu)",
1832 (unsigned long)eku
->numPurposes
);
1833 if(tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
)) {
1834 return CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
1836 else if(eku
->numPurposes
== 0) {
1837 /* ignore that error but no EKU - skip EKU check */
1840 /* else ignore error and we have an intermediate EKU; proceed */
1843 if(!tpCompareOids(&eku
->purposes
[0], &CSSMOID_APPLE_EKU_CODE_SIGNING
)) {
1844 tpPolicyError("tp_verifySWUpdateSigningOpts: bad EKU");
1845 if(tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
)) {
1846 crtn
= CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
1852 /* verify leaf cert */
1853 isCertInfo
= &certInfo
[0];
1854 tpCert
= certGroup
.certAtIndex(0);
1855 if(!isCertInfo
->extendKeyUsage
.present
) {
1856 tpPolicyError("tp_verifySWUpdateSigningOpts: no extendedKeyUse in leaf");
1857 if(tpCert
->addStatusCode(CSSMERR_APPLETP_CS_NO_EXTENDED_KEY_USAGE
)) {
1858 return crtn
? crtn
: CSSMERR_APPLETP_CS_NO_EXTENDED_KEY_USAGE
;
1861 /* have to skip remainder */
1866 eku
= &isCertInfo
->extendKeyUsage
.extnData
->extendedKeyUsage
;
1867 assert(eku
!= NULL
);
1868 if(eku
->numPurposes
!= 1) {
1869 tpPolicyError("tp_verifySWUpdateSigningOpts: bad eku->numPurposes (%lu)",
1870 (unsigned long)eku
->numPurposes
);
1871 if(tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
)) {
1872 if(crtn
== CSSM_OK
) {
1873 crtn
= CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
1878 if(!tpCompareOids(&eku
->purposes
[0], &CSSMOID_APPLE_EKU_CODE_SIGNING
)) {
1879 if(tpCompareOids(&eku
->purposes
[0], &CSSMOID_APPLE_EKU_CODE_SIGNING_DEV
)) {
1880 tpPolicyError("tp_verifySWUpdateSigningOpts: DEVELOPMENT cert");
1881 if(tpCert
->addStatusCode(CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT
)) {
1882 if(crtn
== CSSM_OK
) {
1883 crtn
= CSSMERR_APPLETP_CODE_SIGN_DEVELOPMENT
;
1888 tpPolicyError("tp_verifySWUpdateSigningOpts: bad EKU in leaf");
1889 if(tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
)) {
1890 if(crtn
== CSSM_OK
) {
1891 crtn
= CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
1901 * Verify Apple Resource Signing options.
1903 * -- leaf cert must have CSSMOID_APPLE_EKU_RESOURCE_SIGNING EKU
1904 * -- chain length must be >= 2
1905 * -- mainline code already verified that leaf KeyUsage = digitalSignature (only)
1907 static CSSM_RETURN
tp_verifyResourceSigningOpts(
1908 TPCertGroup
&certGroup
,
1909 const CSSM_DATA
*fieldOpts
, // currently unused
1910 const iSignCertInfo
*certInfo
) // all certs, size certGroup.numCerts()
1912 unsigned numCerts
= certGroup
.numCerts();
1914 if(!certGroup
.isAllowedError(CSSMERR_APPLETP_RS_BAD_CERT_CHAIN_LENGTH
)) {
1915 tpPolicyError("tp_verifyResourceSigningOpts: numCerts %u", numCerts
);
1916 return CSSMERR_APPLETP_RS_BAD_CERT_CHAIN_LENGTH
;
1919 const iSignCertInfo
&leafCert
= certInfo
[0];
1920 TPCertInfo
*leaf
= certGroup
.certAtIndex(0);
1922 /* leaf ExtendedKeyUse required, one legal value */
1923 if(!tpVerifyEKU(leafCert
, CSSMOID_APPLE_EKU_RESOURCE_SIGNING
, false)) {
1924 tpPolicyError("tp_verifyResourceSigningOpts: no RESOURCE_SIGNING EKU");
1925 if(leaf
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
)) {
1926 return CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
1934 * Common code for Apple Code Signing and Apple Package Signing.
1935 * For now we just require an RFC3280-style CodeSigning EKU in the leaf
1936 * for both policies.
1938 static CSSM_RETURN
tp_verifyCodePkgSignOpts(
1940 TPCertGroup
&certGroup
,
1941 const CSSM_DATA
*fieldOpts
, // currently unused
1942 const iSignCertInfo
*certInfo
) // all certs, size certGroup.numCerts()
1944 const iSignCertInfo
&leafCert
= certInfo
[0];
1946 /* leaf ExtendedKeyUse required, one legal value */
1947 if(!tpVerifyEKU(leafCert
, CSSMOID_ExtendedUseCodeSigning
, false)) {
1948 TPCertInfo
*leaf
= certGroup
.certAtIndex(0);
1949 tpPolicyError("tp_verifyCodePkgSignOpts: no CodeSigning EKU");
1950 if(leaf
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
)) {
1951 return CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
1960 * Verify MacAppStore receipt verification policy options.
1962 * -- Must have one intermediate cert
1963 * -- intermediate must be the FairPlay intermediate
1964 * -- leaf cert has the CSSMOID_APPLE_EXTENSION_MACAPPSTORE_RECEIPT marker extension
1966 static CSSM_RETURN
tp_verifyMacAppStoreReceiptOpts(
1967 TPCertGroup
&certGroup
,
1968 const CSSM_DATA
*fieldOpts
, // currently unused
1969 const iSignCertInfo
*certInfo
) // all certs, size certGroup.numCerts()
1971 unsigned numCerts
= certGroup
.numCerts();
1974 if (!certGroup
.isAllowedError(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
))
1976 tpPolicyError("tp_verifyMacAppStoreReceiptOpts: numCerts %u", numCerts
);
1977 return CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
1981 const iSignCertInfo
*isCertInfo
;
1984 /* verify intermediate cert */
1985 isCertInfo
= &certInfo
[1];
1986 tpCert
= certGroup
.certAtIndex(1);
1988 if (!isCertInfo
->basicConstraints
.present
)
1990 tpPolicyError("tp_verifyMacAppStoreReceiptOpts: no basicConstraints in intermediate");
1991 if (tpCert
->addStatusCode(CSSMERR_APPLETP_CS_NO_BASIC_CONSTRAINTS
))
1992 return CSSMERR_APPLETP_CS_NO_BASIC_CONSTRAINTS
;
1995 // Now check the leaf
1996 isCertInfo
= &certInfo
[0];
1997 tpCert
= certGroup
.certAtIndex(0);
1998 if (certInfo
->certificatePolicies
.present
)
2000 // syslog(LOG_ERR, "tp_verifyMacAppStoreReceiptOpts: found certificatePolicies");
2001 const CE_CertPolicies
*certPolicies
=
2002 &isCertInfo
->certificatePolicies
.extnData
->certPolicies
;
2003 if (!certificatePoliciesContainsOID(certPolicies
, &CSSMOID_MACAPPSTORE_RECEIPT_CERT_POLICY
))
2004 if (tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
))
2005 return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2009 // syslog(LOG_ERR, "tp_verifyMacAppStoreReceiptOpts: no certificatePolicies present"); // DEBUG
2010 tpPolicyError("tp_verifyMacAppStoreReceiptOpts: no certificatePolicies present in leaf");
2011 if (tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
))
2012 return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2018 bool certificatePoliciesContainsOID(const CE_CertPolicies
*certPolicies
, const CSSM_OID
*oidToFind
)
2020 // returns true if the given OID is present in the cert policies
2022 if (!certPolicies
|| !oidToFind
)
2025 const uint32 maxIndex
= 100; // sanity check
2026 for (uint32 policyIndex
= 0; policyIndex
< certPolicies
->numPolicies
&& policyIndex
< maxIndex
; policyIndex
++)
2028 CE_PolicyInformation
*certPolicyInfo
= &certPolicies
->policies
[policyIndex
];
2029 CSSM_OID_PTR oid
= &certPolicyInfo
->certPolicyId
;
2030 if (oid
&& tpCompareOids(oid
, oidToFind
)) // found it
2038 * Verify Time Stamping (RFC3161) policy options.
2040 * -- Leaf must contain Extended Key Usage (EKU), marked critical
2041 * -- The EKU must contain the id-kp-timeStamping purpose and no other
2043 static CSSM_RETURN
tp_verifyTimeStampingOpts(TPCertGroup
&certGroup
,
2044 const CSSM_DATA
*fieldOpts
, // currently unused
2045 const iSignCertInfo
*certInfo
) // all certs, size certGroup.numCerts()
2047 //unsigned numCerts = certGroup.numCerts();
2048 const iSignCertInfo
*isCertInfo
;
2050 CE_ExtendedKeyUsage
*eku
;
2052 isCertInfo
= &certInfo
[0];
2053 tpCert
= certGroup
.certAtIndex(0);
2055 if (!isCertInfo
->extendKeyUsage
.present
)
2057 tpPolicyError("tp_verifyTimeStampingOpts: no extendedKeyUse in leaf");
2058 tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
);
2059 return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2062 if(!isCertInfo
->extendKeyUsage
.critical
)
2064 tpPolicyError("tp_verifyTimeStampingOpts: extended key usage !critical");
2065 tpCert
->addStatusCode(CSSMERR_APPLETP_EXT_KEYUSAGE_NOT_CRITICAL
);
2066 return CSSMERR_APPLETP_EXT_KEYUSAGE_NOT_CRITICAL
;
2069 eku
= &isCertInfo
->extendKeyUsage
.extnData
->extendedKeyUsage
;
2070 assert(eku
!= NULL
);
2072 if(eku
->numPurposes
!= 1)
2074 tpPolicyError("tp_verifyTimeStampingOpts: bad eku->numPurposes (%lu)",
2075 (unsigned long)eku
->numPurposes
);
2076 tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
);
2077 return CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
2080 if(!tpCompareOids(&eku
->purposes
[0], &CSSMOID_TimeStamping
))
2082 tpPolicyError("tp_verifyTimeStampingOpts: TimeStamping purpose not found");
2083 tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
);
2084 return CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
2091 * Verify Passbook Signing policy options.
2093 * -- Do basic cert validation (OCSP-based certs)
2094 * -- Chains to the Apple root CA
2095 * -- Has custom marker extension (1.2.840.113635.100.6.1.16)
2096 * (CSSMOID_APPLE_EXTENSION_PASSBOOK_SIGNING)
2097 * -- EKU contains Passbook Signing purpose (1.2.840.113635.100.4.14)
2098 * (CSSMOID_APPLE_EKU_PASSBOOK_SIGNING)
2099 * -- UID field of Subject must contain provided card signer string
2100 * -- OU field of Subject must contain provided team identifier string
2102 static CSSM_RETURN
tp_verifyPassbookSigningOpts(TPCertGroup
&certGroup
,
2103 const CSSM_DATA
*fieldOpts
,
2104 const iSignCertInfo
*certInfo
) // all certs, size certGroup.numCerts()
2106 unsigned numCerts
= certGroup
.numCerts();
2107 const iSignCertInfo
*isCertInfo
;
2109 CE_ExtendedKeyUsage
*eku
;
2110 CSSM_RETURN crtn
= CSSM_OK
;
2111 unsigned int nameLen
= 0;
2112 const char *name
= NULL
;
2113 char *p
, *signerName
= NULL
, *teamIdentifier
= NULL
;
2116 isCertInfo
= &certInfo
[0];
2117 tpCert
= certGroup
.certAtIndex(0);
2119 /* The CSSM_APPLE_TP_SMIME_OPTIONS pointer is required. */
2120 if (!fieldOpts
|| !fieldOpts
->Data
)
2121 return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
2123 CSSM_APPLE_TP_SMIME_OPTIONS
*opts
= (CSSM_APPLE_TP_SMIME_OPTIONS
*)fieldOpts
->Data
;
2124 switch (opts
->Version
)
2126 case CSSM_APPLE_TP_SMIME_OPTS_VERSION
:
2127 if (fieldOpts
->Length
!= sizeof(CSSM_APPLE_TP_SMIME_OPTIONS
))
2128 return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
2130 /* handle backwards compatibility here if necessary */
2132 return CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
2134 nameLen
= opts
->SenderEmailLen
;
2135 name
= opts
->SenderEmail
;
2136 if (!name
|| !nameLen
)
2137 return CSSMERR_APPLETP_IDENTIFIER_MISSING
;
2140 /* Split the provided name into signer name and team identifier
2141 * (allocates memory, which must be freed at end) */
2142 signerName
= (char *)certGroup
.alloc().malloc(nameLen
);
2143 teamIdentifier
= (char *)certGroup
.alloc().malloc(nameLen
);
2144 memmove(signerName
, name
, nameLen
);
2145 teamIdentifier
[0] = '\0';
2146 if ((p
= strchr(signerName
, '\t')) != NULL
) {
2148 memmove(teamIdentifier
, p
, strlen(p
)+1);
2151 /* Check signer name in UID field */
2152 if (CSSM_FALSE
== tpCompareSubjectName(*tpCert
,
2153 SN_UserID
, false, signerName
, (unsigned int)strlen(signerName
), found
)) {
2154 tpPolicyError("tp_verifyPassbookSigningOpts: signer name not in subject UID field");
2155 tpCert
->addStatusCode(CSSMERR_APPLETP_IDENTIFIER_MISSING
);
2156 crtn
= CSSMERR_APPLETP_IDENTIFIER_MISSING
;
2160 /* Check team identifier in OU field */
2161 if (CSSM_FALSE
== tpCompareSubjectName(*tpCert
,
2162 SN_OrgUnit
, false, teamIdentifier
, (unsigned int)strlen(teamIdentifier
), found
)) {
2163 tpPolicyError("tp_verifyPassbookSigningOpts: team identifier not in subject OU field");
2164 tpCert
->addStatusCode(CSSMERR_APPLETP_IDENTIFIER_MISSING
);
2165 crtn
= CSSMERR_APPLETP_IDENTIFIER_MISSING
;
2169 /* Check that EKU extension is present */
2170 if (!isCertInfo
->extendKeyUsage
.present
) {
2171 tpPolicyError("tp_verifyPassbookSigningOpts: no extendedKeyUse in leaf");
2172 tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
);
2173 crtn
= CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2177 /* Check that EKU contains Passbook Signing purpose */
2178 eku
= &isCertInfo
->extendKeyUsage
.extnData
->extendedKeyUsage
;
2179 assert(eku
!= NULL
);
2181 for (int ix
=0;ix
<eku
->numPurposes
;ix
++) {
2182 if (tpCompareOids(&eku
->purposes
[ix
], &CSSMOID_APPLE_EKU_PASSBOOK_SIGNING
)) {
2188 tpPolicyError("tp_verifyPassbookSigningOpts: Passbook Signing purpose not found");
2189 tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
);
2190 crtn
= CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
2194 /* Check that Passbook Signing marker extension is present */
2195 if (!(isCertInfo
->foundPassbookSigningMarker
== CSSM_TRUE
)) {
2196 tpPolicyError("tp_verifyPassbookSigningOpts: no Passbook Signing extension in leaf");
2197 tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
);
2198 crtn
= CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2202 /* Check that cert chain is anchored by the Apple Root CA */
2204 tpPolicyError("tp_verifyPassbookSigningOpts: numCerts %u", numCerts
);
2205 crtn
= CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
2209 tpCert
= certGroup
.certAtIndex(numCerts
-1);
2210 const CSSM_DATA
*certData
= tpCert
->itemData();
2211 unsigned char digest
[CC_SHA1_DIGEST_LENGTH
];
2212 CC_SHA1(certData
->Data
, (CC_LONG
)certData
->Length
, digest
);
2213 if (memcmp(digest
, kAppleCASHA1
, sizeof(digest
))) {
2214 tpPolicyError("tp_verifyPassbookSigningOpts: invalid anchor for policy");
2215 tpCert
->addStatusCode(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
);
2216 crtn
= CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
2223 certGroup
.alloc().free(signerName
);
2225 certGroup
.alloc().free(teamIdentifier
);
2231 * Verify Mobile Store policy options.
2233 * -- Do basic cert validation.
2234 * -- Chain length must be exactly 3.
2235 * -- Must chain to known Mobile Store root.
2236 * -- Intermediate must have CSSMOID_APPLE_EXTENSION_SYSINT2_INTERMEDIATE marker
2237 * (1.2.840.113635.100.6.2.10)
2238 * -- Key usage in leaf certificate must be Digital Signature.
2239 * -- Leaf has certificatePolicies extension with appropriate policy:
2240 * (1.2.840.113635.100.5.12) if testPolicy is false
2241 * (1.2.840.113635.100.5.12.1) if testPolicy is true
2243 static CSSM_RETURN
tp_verifyMobileStoreSigningOpts(TPCertGroup
&certGroup
,
2244 const CSSM_DATA
*fieldOpts
,
2245 const iSignCertInfo
*certInfo
, // all certs, size certGroup.numCerts()
2248 unsigned numCerts
= certGroup
.numCerts();
2249 const iSignCertInfo
*isCertInfo
;
2252 CSSM_RETURN crtn
= CSSM_OK
;
2254 isCertInfo
= &certInfo
[0];
2255 tpCert
= certGroup
.certAtIndex(0);
2257 /* Check that KU extension is present */
2258 if (!isCertInfo
->keyUsage
.present
) {
2259 tpPolicyError("tp_verifyMobileStoreSigningOpts: no keyUsage in leaf");
2260 tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
);
2261 crtn
= CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2265 /* Check that KU contains Digital Signature usage */
2266 ku
= isCertInfo
->keyUsage
.extnData
->keyUsage
;
2267 if (!(ku
& CE_KU_DigitalSignature
)) {
2268 tpPolicyError("tp_verifyMobileStoreSigningOpts: DigitalSignature usage not found");
2269 tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE
);
2270 crtn
= CSSMERR_APPLETP_INVALID_KEY_USAGE
;
2274 /* Check that Mobile Store Signing certicate policy is present in leaf */
2275 if (isCertInfo
->certificatePolicies
.present
)
2277 const CE_CertPolicies
*certPolicies
=
2278 &isCertInfo
->certificatePolicies
.extnData
->certPolicies
;
2279 const CSSM_OID
*policyOID
= (testPolicy
) ?
2280 &CSSMOID_TEST_MOBILE_STORE_SIGNING_POLICY
:
2281 &CSSMOID_MOBILE_STORE_SIGNING_POLICY
;
2282 if (!certificatePoliciesContainsOID(certPolicies
, policyOID
))
2283 if (tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
))
2284 return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2288 tpPolicyError("tp_verifyMobileStoreSigningOpts: no certificatePolicies present in leaf");
2289 if (tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
))
2290 return CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2293 /* Check that cert chain length is 3 */
2294 if (numCerts
!= 3) {
2295 tpPolicyError("tp_verifyMobileStoreSigningOpts: numCerts %u", numCerts
);
2296 crtn
= CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
2300 /* Check that cert chain is anchored by a known root */
2302 tpCert
= certGroup
.certAtIndex(numCerts
-1);
2303 const CSSM_DATA
*certData
= tpCert
->itemData();
2304 unsigned char digest
[CC_SHA1_DIGEST_LENGTH
];
2305 CC_SHA1(certData
->Data
, (CC_LONG
)certData
->Length
, digest
);
2306 if (memcmp(digest
, kMobileRootSHA1
, sizeof(digest
))) {
2307 tpPolicyError("tp_verifyMobileStoreSigningOpts: invalid anchor for policy");
2308 tpCert
->addStatusCode(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
);
2309 crtn
= CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
2314 /* Check that Apple System Integration 2 marker extension is present in intermediate */
2315 isCertInfo
= &certInfo
[1];
2316 tpCert
= certGroup
.certAtIndex(1);
2317 if (!(isCertInfo
->foundAppleSysInt2Marker
== CSSM_TRUE
)) {
2318 tpPolicyError("tp_verifyMobileStoreSigningOpts: intermediate marker extension not found");
2319 tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
);
2320 crtn
= CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2329 * Verify Provisioning Profile Signing policy options.
2331 * -- Do basic cert validation (OCSP-based certs)
2332 * -- Chains to the Apple root CA
2333 * -- Leaf has Provisioning Profile marker OID (1.2.840.113635.100.4.11)
2334 * -- Intermediate has WWDR marker OID (1.2.840.113635.100.6.2.1)
2336 static CSSM_RETURN
tp_verifyProvisioningProfileSigningOpts(TPCertGroup
&certGroup
,
2337 const CSSM_DATA
*fieldOpts
,
2338 const iSignCertInfo
*certInfo
) // all certs, size certGroup.numCerts()
2340 unsigned numCerts
= certGroup
.numCerts();
2341 const iSignCertInfo
*isCertInfo
;
2343 CSSM_RETURN crtn
= CSSM_OK
;
2345 isCertInfo
= &certInfo
[0];
2346 tpCert
= certGroup
.certAtIndex(0);
2348 /* Check that cert chain is anchored by the Apple Root CA */
2350 tpPolicyError("tp_verifyProvisioningProfileSigningOpts: numCerts %u", numCerts
);
2351 crtn
= CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
2355 tpCert
= certGroup
.certAtIndex(numCerts
-1);
2356 const CSSM_DATA
*certData
= tpCert
->itemData();
2357 unsigned char digest
[CC_SHA1_DIGEST_LENGTH
];
2358 CC_SHA1(certData
->Data
, (CC_LONG
)certData
->Length
, digest
);
2359 if (memcmp(digest
, kAppleCASHA1
, sizeof(digest
))) {
2360 tpPolicyError("tp_verifyProvisioningProfileSigningOpts: invalid anchor for policy");
2361 tpCert
->addStatusCode(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
);
2362 crtn
= CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
2367 /* Check that Provisioning Profile Signing marker extension is present */
2368 if (!(isCertInfo
->foundProvisioningProfileSigningMarker
== CSSM_TRUE
)) {
2369 tpPolicyError("tp_verifyProvisioningProfileSigningOpts: no Provisioning Profile Signing extension in leaf");
2370 tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
);
2371 crtn
= CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2375 /* Check that Apple WWDR marker extension is present in intermediate */
2376 isCertInfo
= &certInfo
[1];
2377 tpCert
= certGroup
.certAtIndex(1);
2378 if (!(isCertInfo
->foundAppleWWDRIntMarker
== CSSM_TRUE
)) {
2379 tpPolicyError("tp_verifyProvisioningProfileSigningOpts: intermediate marker extension not found");
2380 tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
);
2381 crtn
= CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2391 * Verify Configuration Profile Signing policy options.
2393 * -- Do basic cert validation (OCSP-based certs)
2394 * -- Chains to the Apple root CA
2395 * -- Leaf has EKU extension with appropriate purpose:
2396 * (1.2.840.113635.100.4.16) if testPolicy is false
2397 * (1.2.840.113635.100.4.17) if testPolicy is true
2399 static CSSM_RETURN
tp_verifyProfileSigningOpts(TPCertGroup
&certGroup
,
2400 const CSSM_DATA
*fieldOpts
,
2401 const iSignCertInfo
*certInfo
, // all certs, size certGroup.numCerts()
2404 unsigned numCerts
= certGroup
.numCerts();
2405 const iSignCertInfo
*isCertInfo
;
2407 CE_ExtendedKeyUsage
*eku
;
2408 CSSM_RETURN crtn
= CSSM_OK
;
2411 isCertInfo
= &certInfo
[0];
2412 tpCert
= certGroup
.certAtIndex(0);
2414 /* Check that EKU extension is present */
2415 if (!isCertInfo
->extendKeyUsage
.present
) {
2416 tpPolicyError("tp_verifyProfileSigningOpts: no extendedKeyUse in leaf");
2417 tpCert
->addStatusCode(CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
);
2418 crtn
= CSSMERR_APPLETP_MISSING_REQUIRED_EXTENSION
;
2422 /* Check that EKU contains appropriate Profile Signing purpose */
2423 eku
= &isCertInfo
->extendKeyUsage
.extnData
->extendedKeyUsage
;
2424 assert(eku
!= NULL
);
2426 for (int ix
=0;ix
<eku
->numPurposes
;ix
++) {
2427 if (tpCompareOids(&eku
->purposes
[ix
], (testPolicy
) ?
2428 &CSSMOID_APPLE_EKU_QA_PROFILE_SIGNING
:
2429 &CSSMOID_APPLE_EKU_PROFILE_SIGNING
)) {
2435 tpPolicyError("tp_verifyProfileSigningOpts: Profile Signing purpose not found");
2436 tpCert
->addStatusCode(CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
);
2437 crtn
= CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
;
2441 /* Check that cert chain is anchored by the Apple Root CA */
2443 tpPolicyError("tp_verifyProfileSigningOpts: numCerts %u", numCerts
);
2444 crtn
= CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
2448 tpCert
= certGroup
.certAtIndex(numCerts
-1);
2449 const CSSM_DATA
*certData
= tpCert
->itemData();
2450 unsigned char digest
[CC_SHA1_DIGEST_LENGTH
];
2451 CC_SHA1(certData
->Data
, (CC_LONG
)certData
->Length
, digest
);
2452 if (memcmp(digest
, kAppleCASHA1
, sizeof(digest
))) {
2453 tpPolicyError("tp_verifyProfileSigningOpts: invalid anchor for policy");
2454 tpCert
->addStatusCode(CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
);
2455 crtn
= CSSMERR_APPLETP_CS_BAD_CERT_CHAIN_LENGTH
;
2465 * RFC2459 says basicConstraints must be flagged critical for
2466 * CA certs, but Verisign doesn't work that way.
2468 #define BASIC_CONSTRAINTS_MUST_BE_CRITICAL 0
2471 * TP iSign spec says Extended Key Usage required for leaf certs,
2472 * but Verisign doesn't work that way.
2474 #define EXTENDED_KEY_USAGE_REQUIRED_FOR_LEAF 0
2477 * TP iSign spec says Subject Alternate Name required for leaf certs,
2478 * but Verisign doesn't work that way.
2480 #define SUBJECT_ALT_NAME_REQUIRED_FOR_LEAF 0
2483 * TP iSign spec originally required KeyUsage for all certs, but
2484 * Verisign doesn't have that in their roots.
2486 #define KEY_USAGE_REQUIRED_FOR_ROOT 0
2489 * RFC 2632, "S/MIME Version 3 Certificate Handling", section
2490 * 4.4.2, says that KeyUsage extensions MUST be flagged critical,
2491 * but Thawte's intermediate cert (common name "Thawte Personal
2492 * Freemail Issuing CA") does not meet this requirement.
2494 #define SMIME_KEY_USAGE_MUST_BE_CRITICAL 0
2497 * Public routine to perform TP verification on a constructed
2499 * Returns CSSM_OK on success.
2500 * Assumes the chain has passed basic subject/issuer verification. First cert of
2501 * incoming certGroup is end-entity (leaf).
2503 * Per-policy details:
2504 * iSign: Assumes that last cert in incoming certGroup is a root cert.
2505 * Also assumes a cert group of more than one cert.
2506 * kTPx509Basic: CertGroup of length one allowed.
2508 CSSM_RETURN
tp_policyVerify(
2511 CSSM_CL_HANDLE clHand
,
2512 CSSM_CSP_HANDLE cspHand
,
2513 TPCertGroup
*certGroup
,
2514 CSSM_BOOL verifiedToRoot
, // last cert is good root
2515 CSSM_BOOL verifiedViaTrustSetting
, // last cert verified via
2517 CSSM_APPLE_TP_ACTION_FLAGS actionFlags
,
2518 const CSSM_DATA
*policyFieldData
, // optional
2519 void *policyOpts
) // future options
2521 iSignCertInfo
*certInfo
= NULL
;
2523 iSignCertInfo
*thisCertInfo
;
2527 CSSM_BOOL cA
= CSSM_FALSE
; // init for compiler warning
2528 bool isLeaf
; // end entity
2529 bool isRoot
; // root cert
2530 CE_ExtendedKeyUsage
*extendUsage
;
2531 CE_AuthorityKeyID
*authorityId
;
2532 CSSM_KEY_PTR pubKey
;
2533 CSSM_RETURN outErr
= CSSM_OK
; // for gross, non-policy errors
2534 CSSM_BOOL policyFail
= CSSM_FALSE
;// generic CSSMERR_TP_VERIFY_ACTION_FAILED
2535 CSSM_RETURN policyError
= CSSM_OK
; // policy-specific failure
2537 /* First, kTPDefault is a nop here */
2538 if(policy
== kTPDefault
) {
2542 if(certGroup
== NULL
) {
2543 return CSSMERR_TP_INVALID_CERTGROUP
;
2545 numCerts
= certGroup
->numCerts();
2547 return CSSMERR_TP_INVALID_CERTGROUP
;
2549 if(policy
== kTPiSign
) {
2550 if(!verifiedToRoot
) {
2551 /* no way, this requires a root cert */
2552 return CSSMERR_TP_VERIFY_ACTION_FAILED
;
2555 /* nope, not for iSign */
2556 return CSSMERR_TP_VERIFY_ACTION_FAILED
;
2560 /* cook up an iSignCertInfo array */
2561 certInfo
= (iSignCertInfo
*)tpCalloc(alloc
, numCerts
, sizeof(iSignCertInfo
));
2562 /* subsequent errors to errOut: */
2564 /* fill it with interesting info from parsed certs */
2565 for(certDex
=0; certDex
<numCerts
; certDex
++) {
2566 if(iSignGetCertInfo(alloc
,
2567 certGroup
->certAtIndex(certDex
),
2568 &certInfo
[certDex
])) {
2569 (certGroup
->certAtIndex(certDex
))->addStatusCode(
2570 CSSMERR_TP_INVALID_CERTIFICATE
);
2571 /* this one is fatal (and can't ignore) */
2572 outErr
= CSSMERR_TP_INVALID_CERTIFICATE
;
2578 * OK, the heart of TP enforcement.
2580 for(certDex
=0; certDex
<numCerts
; certDex
++) {
2581 thisCertInfo
= &certInfo
[certDex
];
2582 TPCertInfo
*thisTpCertInfo
= certGroup
->certAtIndex(certDex
);
2585 * First check for presence of required extensions and
2586 * critical extensions we don't understand.
2588 if(thisCertInfo
->foundUnknownCritical
) {
2589 /* illegal for all policies */
2590 tpPolicyError("tp_policyVerify: critical flag in unknown extension");
2591 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_UNKNOWN_CRITICAL_EXTEN
)) {
2592 policyFail
= CSSM_TRUE
;
2597 * Check for unsupported key length, per <rdar://6892837>
2599 if((pubKey
=thisTpCertInfo
->pubKey()) != NULL
) {
2600 CSSM_KEYHEADER
*keyHdr
= &pubKey
->KeyHeader
;
2601 if(keyHdr
->AlgorithmId
== CSSM_ALGID_RSA
&& keyHdr
->LogicalKeySizeInBits
< 1024) {
2602 tpPolicyError("tp_policyVerify: RSA key size too small");
2603 if(thisTpCertInfo
->addStatusCode(CSSMERR_CSP_UNSUPPORTED_KEY_SIZE
)) {
2604 policyFail
= CSSM_TRUE
;
2610 * Note it's possible for both of these to be true, for a chain
2611 * of length one (kTPx509Basic, kCrlPolicy only!)
2612 * FIXME: should this code work if the last cert in the chain is NOT a root?
2614 isLeaf
= thisTpCertInfo
->isLeaf();
2615 isRoot
= thisTpCertInfo
->isSelfSigned(true);
2618 * BasicConstraints.cA
2619 * iSign: required in all but leaf and root,
2620 * for which it is optional (with default values of false
2621 * for leaf and true for root).
2622 * all others: always optional, default of false for leaf and
2624 * All: cA must be false for leaf, true for others
2626 if(!thisCertInfo
->basicConstraints
.present
) {
2628 * No basicConstraints present; infer a cA value if appropriate.
2631 /* cool, use default; note that kTPx509Basic with
2632 * certGroup length of one may take this case */
2636 /* cool, use default */
2643 * not present, not leaf, not root....
2644 * ....RFC2459 says this can not be a CA
2649 /* required for iSign in this position */
2650 tpPolicyError("tp_policyVerify: no "
2651 "basicConstraints");
2652 if(thisTpCertInfo
->addStatusCode(
2653 CSSMERR_APPLETP_NO_BASIC_CONSTRAINTS
)) {
2654 policyFail
= CSSM_TRUE
;
2659 } /* inferred a default value */
2661 /* basicConstraints present */
2662 #if BASIC_CONSTRAINTS_MUST_BE_CRITICAL
2663 /* disabled for verisign compatibility */
2664 if(!thisCertInfo
->basicConstraints
.critical
) {
2666 tpPolicyError("tp_policyVerify: basicConstraints marked "
2668 if(thisTpCertInfo
->addStatusCode(CSSMERR_TP_VERIFY_ACTION_FAILED
)) {
2669 policyFail
= CSSM_TRUE
;
2672 #endif /* BASIC_CONSTRAINTS_MUST_BE_CRITICAL */
2674 const CE_BasicConstraints
*bcp
=
2675 &thisCertInfo
->basicConstraints
.extnData
->basicConstraints
;
2679 /* Verify pathLenConstraint if present */
2680 if(!isLeaf
&& // leaf, certDex=0, don't care
2681 cA
&& // p.l.c. only valid for CAs
2682 bcp
->pathLenConstraintPresent
) { // present?
2684 * pathLenConstraint=0 legal for certDex 1 only
2685 * pathLenConstraint=1 legal for certDex {1,2}
2688 if(certDex
> (bcp
->pathLenConstraint
+ 1)) {
2689 tpPolicyError("tp_policyVerify: pathLenConstraint "
2691 if(thisTpCertInfo
->addStatusCode(
2692 CSSMERR_APPLETP_PATH_LEN_CONSTRAINT
)) {
2693 policyFail
= CSSM_TRUE
;
2701 * Special cases to allow a chain of length 1, leaf and root
2702 * both true, and for caller to override the "leaf can't be a CA"
2703 * requirement when a CA cert is explicitly being evaluated as the
2707 !(actionFlags
& CSSM_TP_ACTION_LEAF_IS_CA
)) {
2708 tpPolicyError("tp_policyVerify: cA true for leaf");
2709 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_INVALID_CA
)) {
2710 policyFail
= CSSM_TRUE
;
2714 tpPolicyError("tp_policyVerify: cA false for non-leaf");
2715 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_INVALID_CA
)) {
2716 policyFail
= CSSM_TRUE
;
2721 * Authority Key Identifier optional
2722 * iSign : only allowed in !root.
2723 * If present, must not be critical.
2724 * all others : ignored (though used later for chain verification)
2726 if((policy
== kTPiSign
) && thisCertInfo
->authorityId
.present
) {
2728 tpPolicyError("tp_policyVerify: authorityId in root");
2729 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_INVALID_AUTHORITY_ID
)) {
2730 policyFail
= CSSM_TRUE
;
2733 if(thisCertInfo
->authorityId
.critical
) {
2734 /* illegal per RFC 2459 */
2735 tpPolicyError("tp_policyVerify: authorityId marked "
2737 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_INVALID_AUTHORITY_ID
)) {
2738 policyFail
= CSSM_TRUE
;
2744 * Subject Key Identifier optional
2745 * iSign : can't be critical.
2746 * all others : ignored (though used later for chain verification)
2748 if(thisCertInfo
->subjectId
.present
) {
2749 if((policy
== kTPiSign
) && thisCertInfo
->subjectId
.critical
) {
2750 tpPolicyError("tp_policyVerify: subjectId marked critical");
2751 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_INVALID_SUBJECT_ID
)) {
2752 policyFail
= CSSM_TRUE
;
2758 * Key Usage optional except required as noted
2759 * iSign : required for non-root/non-leaf
2760 * Leaf cert : if present, usage = digitalSignature
2761 * Exception : if leaf, and keyUsage not present,
2762 * netscape-cert-type must be present, with
2763 * Object Signing bit set
2764 * kCrlPolicy : Leaf: usage = CRLSign
2765 * kTP_SMIME : if present, must be critical
2766 * kTP_SWUpdateSign, kTP_ResourceSign, kTP_CodeSigning, kTP_PackageSigning : Leaf :
2767 usage = digitalSignature
2768 * all others : non-leaf : usage = keyCertSign
2771 if(thisCertInfo
->keyUsage
.present
) {
2774 * iSign and *Signing: usage = digitalSignature
2775 * all others : don't care
2776 * Others: usage = keyCertSign
2777 * We only require that one bit to be set, we ignore others.
2782 case kTP_SWUpdateSign
:
2783 case kTP_ResourceSign
:
2784 case kTP_CodeSigning
:
2785 case kTP_PackageSigning
:
2786 expUsage
= CE_KU_DigitalSignature
;
2789 /* if present, this bit must be set */
2790 expUsage
= CE_KU_CRLSign
;
2793 /* accept whatever's there */
2794 expUsage
= thisCertInfo
->keyUsage
.extnData
->keyUsage
;
2799 /* !leaf: this is true for all policies */
2800 expUsage
= CE_KU_KeyCertSign
;
2802 actUsage
= thisCertInfo
->keyUsage
.extnData
->keyUsage
;
2803 if(!(actUsage
& expUsage
)) {
2804 tpPolicyError("tp_policyVerify: bad keyUsage (leaf %s; "
2806 (certDex
== 0) ? "TRUE" : "FALSE", actUsage
);
2807 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE
)) {
2808 policyFail
= CSSM_TRUE
;
2814 * Radar 3523221 renders this whole check obsolete, but I'm leaving
2815 * the code here to document its conspicuous functional absence.
2817 if((policy
== kTP_SMIME
) && !thisCertInfo
->keyUsage
.critical
) {
2819 * Per Radar 3410245, allow this for intermediate certs.
2821 if(SMIME_KEY_USAGE_MUST_BE_CRITICAL
|| isLeaf
|| isRoot
) {
2822 tpPolicyError("tp_policyVerify: key usage, !critical, SMIME");
2823 if(thisTpCertInfo
->addStatusCode(
2824 CSSMERR_APPLETP_SMIME_KEYUSAGE_NOT_CRITICAL
)) {
2825 policyFail
= CSSM_TRUE
;
2831 else if(policy
== kTPiSign
) {
2833 * iSign requires keyUsage present for non root OR
2834 * netscape-cert-type/ObjectSigning for leaf
2836 if(isLeaf
&& thisCertInfo
->netscapeCertType
.present
) {
2837 CE_NetscapeCertType ct
=
2838 thisCertInfo
->netscapeCertType
.extnData
->netscapeCertType
;
2840 if(!(ct
& CE_NCT_ObjSign
)) {
2841 tpPolicyError("tp_policyVerify: netscape-cert-type, "
2843 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE
)) {
2844 policyFail
= CSSM_TRUE
;
2849 tpPolicyError("tp_policyVerify: !isRoot, no keyUsage, "
2850 "!(leaf and netscapeCertType)");
2851 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE
)) {
2852 policyFail
= CSSM_TRUE
;
2858 * RFC 3280, 4.1.2.6, says that an empty subject name can only appear in a
2859 * leaf cert, and only if subjectAltName is present and marked critical.
2861 if(isLeaf
&& thisTpCertInfo
->hasEmptySubjectName()) {
2862 bool badEmptySubject
= false;
2863 if(actionFlags
& CSSM_TP_ACTION_LEAF_IS_CA
) {
2865 * True when evaluating a CA cert as well as when
2866 * evaluating a CRL's cert chain. Note the odd case of a CRL's
2867 * signer having an empty subject matching an empty issuer
2868 * in the CRL. That'll be caught here.
2870 badEmptySubject
= true;
2872 else if(!thisCertInfo
->subjectAltName
.present
|| /* no subjectAltName */
2873 !thisCertInfo
->subjectAltName
.critical
) { /* not critical */
2874 badEmptySubject
= true;
2876 if(badEmptySubject
) {
2877 tpPolicyError("tp_policyVerify: bad empty subject");
2878 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_INVALID_EMPTY_SUBJECT
)) {
2879 policyFail
= CSSM_TRUE
;
2885 * RFC 3739: if this cert has a Qualified Cert Statements extension, and
2886 * it's Critical, make sure we understand all of the extension's statementIds.
2888 if(thisCertInfo
->qualCertStatements
.present
&&
2889 thisCertInfo
->qualCertStatements
.critical
) {
2890 CE_QC_Statements
*qcss
=
2891 &thisCertInfo
->qualCertStatements
.extnData
->qualifiedCertStatements
;
2892 uint32 numQcs
= qcss
->numQCStatements
;
2893 for(unsigned qdex
=0; qdex
<numQcs
; qdex
++) {
2894 CSSM_OID_PTR qid
= &qcss
->qcStatements
[qdex
].statementId
;
2896 for(unsigned kdex
=0; kdex
<NUM_KNOWN_QUAL_CERT_STATEMENTS
; kdex
++) {
2897 if(tpCompareCssmData(qid
, knownQualifiedCertStatements
[kdex
])) {
2903 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_UNKNOWN_QUAL_CERT_STATEMENT
)) {
2904 policyFail
= CSSM_TRUE
;
2909 } /* critical Qualified Cert Statement */
2912 * Certificate Policies extension validation, per section 1.2 of:
2913 * http://iase.disa.mil/pki/dod_cp_v10_final_2_mar_09_signed.pdf
2915 if (tpVerifyCPE(*thisCertInfo
, CSSMOID_PIV_AUTH
, false) ||
2916 tpVerifyCPE(*thisCertInfo
, CSSMOID_PIV_AUTH_2048
, false)) {
2918 * Certificate asserts one of the PIV-Auth Certificate Policy OIDs;
2919 * check the required Key Usage extension for compliance.
2922 * usage = digitalSignature (only; no other bits asserted)
2924 * usage = keyCertSign (required; other bits ignored)
2926 if(thisCertInfo
->keyUsage
.present
) {
2927 actUsage
= thisCertInfo
->keyUsage
.extnData
->keyUsage
;
2929 /* No key usage! Policy fail. */
2932 if(!(actionFlags
& CSSM_TP_ACTION_LEAF_IS_CA
) && (certDex
== 0)) {
2933 expUsage
= CE_KU_DigitalSignature
;
2935 expUsage
= actUsage
| CE_KU_KeyCertSign
;
2937 if(!(actUsage
== expUsage
)) {
2938 tpPolicyError("tp_policyVerify: bad keyUsage for PIV-Auth policy (leaf %s; "
2940 (certDex
== 0) ? "TRUE" : "FALSE", actUsage
);
2941 if(thisTpCertInfo
->addStatusCode(CSSMERR_APPLETP_INVALID_KEY_USAGE
)) {
2942 policyFail
= CSSM_TRUE
;
2945 } /* Certificate Policies */
2948 } /* for certDex, checking presence of extensions */
2951 * Special case checking for leaf (end entity) cert
2953 * iSign only: Extended key usage, optional for leaf,
2954 * value CSSMOID_ExtendedUseCodeSigning
2956 if((policy
== kTPiSign
) && certInfo
[0].extendKeyUsage
.present
) {
2957 extendUsage
= &certInfo
[0].extendKeyUsage
.extnData
->extendedKeyUsage
;
2958 if(extendUsage
->numPurposes
!= 1) {
2959 tpPolicyError("tp_policyVerify: bad extendUsage->numPurposes "
2961 (int)extendUsage
->numPurposes
);
2962 if((certGroup
->certAtIndex(0))->addStatusCode(
2963 CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
)) {
2964 policyFail
= CSSM_TRUE
;
2967 if(!tpCompareOids(extendUsage
->purposes
,
2968 &CSSMOID_ExtendedUseCodeSigning
)) {
2969 tpPolicyError("tp_policyVerify: bad extendKeyUsage");
2970 if((certGroup
->certAtIndex(0))->addStatusCode(
2971 CSSMERR_APPLETP_INVALID_EXTENDED_KEY_USAGE
)) {
2972 policyFail
= CSSM_TRUE
;
2978 * Verify authorityId-->subjectId linkage.
2979 * All optional - skip if needed fields not present.
2980 * Also, always skip last (root) cert.
2982 for(certDex
=0; certDex
<(numCerts
-1); certDex
++) {
2983 if(!certInfo
[certDex
].authorityId
.present
||
2984 !certInfo
[certDex
+1].subjectId
.present
) {
2987 authorityId
= &certInfo
[certDex
].authorityId
.extnData
->authorityKeyID
;
2988 if(!authorityId
->keyIdentifierPresent
) {
2989 /* we only know how to compare keyIdentifier */
2992 if(!tpCompareCssmData(&authorityId
->keyIdentifier
,
2993 &certInfo
[certDex
+1].subjectId
.extnData
->subjectKeyID
)) {
2994 tpPolicyError("tp_policyVerify: bad key ID linkage");
2995 if((certGroup
->certAtIndex(certDex
))->addStatusCode(
2996 CSSMERR_APPLETP_INVALID_ID_LINKAGE
)) {
2997 policyFail
= CSSM_TRUE
;
3003 * Check signature algorithm on all non-root certs,
3004 * reject if known to be untrusted
3006 for(certDex
=0; certDex
<(numCerts
-1); certDex
++) {
3007 if(certInfo
[certDex
].untrustedSigAlg
) {
3008 tpPolicyError("tp_policyVerify: untrusted signature algorithm");
3009 if((certGroup
->certAtIndex(certDex
))->addStatusCode(
3010 CSSMERR_TP_INVALID_CERTIFICATE
)) {
3011 policyFail
= CSSM_TRUE
;
3016 /* specific per-policy checking */
3022 * SSL, EAP, IPSec: optionally verify common name; all are identical
3023 * other than their names.
3024 * FIXME - should this be before or after the root cert test? How can
3025 * we return both errors?
3027 policyError
= tp_verifySslOpts(policy
, *certGroup
, policyFieldData
, certInfo
);
3031 tpDebug("iChat policy");
3034 policyError
= tp_verifySmimeOpts(policy
, *certGroup
, policyFieldData
, certInfo
);
3036 case kTP_SWUpdateSign
:
3037 policyError
= tp_verifySWUpdateSigningOpts(*certGroup
, policyFieldData
, certInfo
);
3039 case kTP_ResourceSign
:
3040 policyError
= tp_verifyResourceSigningOpts(*certGroup
, policyFieldData
, certInfo
);
3042 case kTP_CodeSigning
:
3043 case kTP_PackageSigning
:
3044 policyError
= tp_verifyCodePkgSignOpts(policy
, *certGroup
, policyFieldData
, certInfo
);
3046 case kTP_MacAppStoreRec
:
3047 policyError
= tp_verifyMacAppStoreReceiptOpts(*certGroup
, policyFieldData
, certInfo
);
3049 case kTP_AppleIDSharing
:
3050 /* As of macOS 10.12, this code path should be unused. Until we can remove this
3051 * module entirely, ensure that no Apple ID evaluations take this path. [10119995] */
3052 tpPolicyError("tp_policyVerify: unexpected attempt to use legacy kTP_AppleIDSharing");
3053 policyFail
= CSSM_TRUE
;
3055 case kTP_TimeStamping
:
3056 policyError
= tp_verifyTimeStampingOpts(*certGroup
, policyFieldData
, certInfo
);
3058 case kTP_PassbookSigning
:
3059 policyError
= tp_verifyPassbookSigningOpts(*certGroup
, policyFieldData
, certInfo
);
3061 case kTP_MobileStore
:
3062 policyError
= tp_verifyMobileStoreSigningOpts(*certGroup
, policyFieldData
, certInfo
, false);
3064 case kTP_TestMobileStore
:
3065 policyError
= tp_verifyMobileStoreSigningOpts(*certGroup
, policyFieldData
, certInfo
, true);
3067 case kTP_EscrowService
:
3068 policyFail
= CSSM_TRUE
;
3070 case kTP_ProfileSigning
:
3071 policyError
= tp_verifyProfileSigningOpts(*certGroup
, policyFieldData
, certInfo
, false);
3073 case kTP_QAProfileSigning
:
3074 policyError
= tp_verifyProfileSigningOpts(*certGroup
, policyFieldData
, certInfo
, true);
3076 case kTP_PCSEscrowService
:
3077 policyFail
= CSSM_TRUE
;
3079 case kTP_ProvisioningProfileSigning
:
3080 policyError
= tp_verifyProvisioningProfileSigningOpts(*certGroup
, policyFieldData
, certInfo
);
3085 case kTP_PKINIT_Client
:
3091 if(outErr
== CSSM_OK
) {
3092 /* policy-specific error takes precedence here */
3093 if(policyError
!= CSSM_OK
) {
3094 outErr
= policyError
;
3096 else if(policyFail
) {
3097 /* plain vanilla error return from this module */
3098 outErr
= CSSMERR_TP_VERIFY_ACTION_FAILED
;
3102 /* free resources */
3103 for(certDex
=0; certDex
<numCerts
; certDex
++) {
3104 thisCertInfo
= &certInfo
[certDex
];
3105 iSignFreeCertInfo(clHand
, thisCertInfo
);
3107 tpFree(alloc
, certInfo
);
3112 * Obtain policy-specific User Trust parameters
3114 void tp_policyTrustSettingParams(
3116 const CSSM_DATA
*policyData
, // optional
3117 /* returned values - not mallocd */
3118 const char **policyStr
,
3119 uint32
*policyStrLen
,
3120 SecTrustSettingsKeyUsage
*keyUse
)
3122 /* default values */
3124 *keyUse
= kSecTrustSettingsKeyUseAny
;
3126 if((policyData
== NULL
) || (policyData
->Data
== NULL
)) {
3127 /* currently, no further action possible */
3135 if(policyData
->Length
!= sizeof(CSSM_APPLE_TP_SSL_OPTIONS
)) {
3136 /* this error will be caught later */
3139 CSSM_APPLE_TP_SSL_OPTIONS
*sslOpts
=
3140 (CSSM_APPLE_TP_SSL_OPTIONS
*)policyData
->Data
;
3141 *policyStr
= sslOpts
->ServerName
;
3142 *policyStrLen
= sslOpts
->ServerNameLen
;
3143 if(sslOpts
->Flags
& CSSM_APPLE_TP_SSL_CLIENT
) {
3145 * Client signs with its priv key. Server end,
3146 * which (also) verifies the client cert, verifies.
3148 *keyUse
= kSecTrustSettingsKeyUseSignature
;
3151 /* server decrypts */
3152 *keyUse
= kSecTrustSettingsKeyUseEnDecryptKey
;
3160 if(policyData
->Length
!= sizeof(CSSM_APPLE_TP_SMIME_OPTIONS
)) {
3161 /* this error will be caught later */
3164 CSSM_APPLE_TP_SMIME_OPTIONS
*smimeOpts
=
3165 (CSSM_APPLE_TP_SMIME_OPTIONS
*)policyData
->Data
;
3166 *policyStr
= smimeOpts
->SenderEmail
;
3167 *policyStrLen
= smimeOpts
->SenderEmailLen
;
3168 SecTrustSettingsKeyUsage ku
= 0;
3169 CE_KeyUsage smimeKu
= smimeOpts
->IntendedUsage
;
3170 if(smimeKu
& (CE_KU_DigitalSignature
| CE_KU_KeyCertSign
| CE_KU_CRLSign
)) {
3171 ku
|= kSecTrustSettingsKeyUseSignature
;
3173 if(smimeKu
& (CE_KU_KeyEncipherment
| CE_KU_DataEncipherment
)) {
3174 ku
|= kSecTrustSettingsKeyUseEnDecryptKey
;
3181 /* no other options */
3186 #pragma clang diagnostic pop