2 * Copyright (c) 2003-2004,2006,2009-2019 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
23 * trusted_cert_utils.c
26 #include "trusted_cert_utils.h"
27 #include "trusted_cert_ssl.h"
28 #include "SecBase64.h"
29 #include <Security/SecCertificatePriv.h>
30 #include <Security/SecPolicyPriv.h>
31 #include <Security/SecBasePriv.h>
32 #include <Security/SecTrustSettings.h>
33 #include <Security/cssmapple.h>
34 #include <Security/oidsalg.h>
35 #include <utilities/fileIo.h>
36 #include <utilities/SecCFRelease.h>
37 #include <security_cdsa_utils/cuPem.h>
39 static int indentSize
= 0;
40 void indentIncr(void) { indentSize
+= 3; }
41 void indentDecr(void) { indentSize
-= 3; }
50 for (dex
=0; dex
<indentSize
; dex
++) {
60 bool doEllipsis
= false;
66 for(dex
=0; dex
<len
; dex
++) {
82 const unsigned char *buf
,
86 bool doEllipsis
= false;
92 for(dex
=0; dex
<len
; dex
++) {
93 printf("%02X ", *buf
++);
100 /* print the contents of a CFString */
108 CFDataRef strData
= CFStringCreateExternalRepresentation(NULL
, cfstr
,
109 kCFStringEncodingUTF8
, true);
112 if(strData
== NULL
) {
113 printf("<<string decode error>>");
116 const char *cp
= (const char *)CFDataGetBytePtr(strData
);
117 CFIndex len
= CFDataGetLength(strData
);
118 for(dex
=0; dex
<len
; dex
++) {
119 if (*cp
== '\n' || *cp
== '\r') {
120 printf("\n"); /* handle line breaks */
129 /* print a CFDateRef */
130 static const char *months
[12] = {
131 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
132 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
138 CFAbsoluteTime absTime
= CFDateGetAbsoluteTime(dateRef
);
140 printf("<<Malformed CFDateRef>>\n");
143 CFGregorianDate gregDate
= CFAbsoluteTimeGetGregorianDate(absTime
, NULL
);
144 const char *month
= "Unknown";
145 if((gregDate
.month
> 12) || (gregDate
.month
<= 0)) {
146 printf("Huh? GregDate.month > 11. These amps only GO to 11.\n");
149 month
= months
[gregDate
.month
- 1];
151 printf("%s %d, %d %02d:%02d",
152 month
, gregDate
.day
, (int)gregDate
.year
, gregDate
.hour
, gregDate
.minute
);
155 /* print a CFNumber */
160 if(!CFNumberGetValue(cfNum
, kCFNumberSInt32Type
, &s
)) {
161 printf("***CFNumber overflow***");
164 printf("%d", (int)s
);
167 /* print a CFNumber as a SecTrustSettingsResult */
168 void printResultType(
172 if(!CFNumberGetValue(cfNum
, kCFNumberSInt32Type
, &n
)) {
173 printf("***CFNumber overflow***");
179 case kSecTrustSettingsResultInvalid
: s
= "kSecTrustSettingsResultInvalid"; break;
180 case kSecTrustSettingsResultTrustRoot
: s
= "kSecTrustSettingsResultTrustRoot"; break;
181 case kSecTrustSettingsResultTrustAsRoot
: s
= "kSecTrustSettingsResultTrustAsRoot"; break;
182 case kSecTrustSettingsResultDeny
: s
= "kSecTrustSettingsResultDeny"; break;
183 case kSecTrustSettingsResultUnspecified
: s
= "kSecTrustSettingsResultUnspecified"; break;
185 sprintf(bogus
, "Unknown SecTrustSettingsResult (%d)", (int)n
);
192 /* print a CFNumber as SecTrustSettingsKeyUsage */
197 if(!CFNumberGetValue(cfNum
, kCFNumberSInt32Type
, &s
)) {
198 printf("***CFNumber overflow***");
201 uint32 n
= (uint32
)s
;
202 if(n
== kSecTrustSettingsKeyUseAny
) {
211 if(n
& kSecTrustSettingsKeyUseSignature
) {
212 printf("Signature ");
214 if(n
& kSecTrustSettingsKeyUseEnDecryptData
) {
215 printf("EnDecryptData ");
217 if(n
& kSecTrustSettingsKeyUseEnDecryptKey
) {
218 printf("EnDecryptKey ");
220 if(n
& kSecTrustSettingsKeyUseSignCert
) {
223 if(n
& kSecTrustSettingsKeyUseSignRevocation
) {
224 printf("SignRevocation ");
226 if(n
& kSecTrustSettingsKeyUseKeyExchange
) {
227 printf("KeyExchange ");
232 /* print a CFNumber as CSSM_RETURN string */
237 if(!CFNumberGetValue(cfNum
, kCFNumberSInt32Type
, &s
)) {
238 printf("***CFNumber overflow***");
241 printf("%s", cssmErrorString((CSSM_RETURN
)s
));
244 /* convert an OID to a SecPolicyRef */
245 SecPolicyRef
oidToPolicy(
249 SecPolicyRef policyRef
= NULL
;
251 ortn
= SecPolicyCopy(CSSM_CERT_X_509v3
, oid
, &policyRef
);
253 cssmPerror("SecPolicyCopy", ortn
);
264 static OidString oidStrings
[] =
266 { &CSSMOID_APPLE_ISIGN
, "iSign" },
267 { &CSSMOID_APPLE_X509_BASIC
, "Apple X509 Basic" },
268 { &CSSMOID_APPLE_TP_SSL
, "SSL" },
269 { &CSSMOID_APPLE_TP_SMIME
, "SMIME" },
270 { &CSSMOID_APPLE_TP_EAP
, "EAP" },
271 { &CSSMOID_APPLE_TP_SW_UPDATE_SIGNING
, "SW Update Signing" },
272 { &CSSMOID_APPLE_TP_IP_SEC
, "IPSec" },
273 { &CSSMOID_APPLE_TP_ICHAT
, "iChat" },
274 { &CSSMOID_APPLE_TP_RESOURCE_SIGN
, "Resource Signing" },
275 { &CSSMOID_APPLE_TP_PKINIT_CLIENT
, "PKINIT Client" },
276 { &CSSMOID_APPLE_TP_PKINIT_SERVER
, "PKINIT Server" },
277 { &CSSMOID_APPLE_TP_CODE_SIGNING
, "Code Signing" },
278 { &CSSMOID_APPLE_TP_PACKAGE_SIGNING
, "Package Signing" },
279 { &CSSMOID_APPLE_TP_MACAPPSTORE_RECEIPT
, "Mac App Store" },
280 { &CSSMOID_APPLE_TP_APPLEID_SHARING
, "AppleID Sharing" }
282 #define NUM_OID_STRINGS (sizeof(oidStrings) / sizeof(oidStrings[0]))
284 /* convert a policy string to a SecPolicyRef */
285 SecPolicyRef
oidStringToPolicy(
288 /* OID string to an OID pointer */
289 const CSSM_OID
*oid
= NULL
;
292 for(dex
=0; dex
<NUM_OID_STRINGS
; dex
++) {
293 OidString
*os
= &oidStrings
[dex
];
294 if(!strcmp(oidStr
, os
->oidStr
)) {
303 /* OID to SecPolicyRef */
304 return oidToPolicy(oid
);
307 /* CSSM_OID --> OID string */
308 const char *oidToOidString(
312 static char unknownOidString
[200];
314 for(dex
=0; dex
<NUM_OID_STRINGS
; dex
++) {
315 OidString
*os
= &oidStrings
[dex
];
316 if(compareOids(oid
, os
->oid
)) {
320 sprintf(unknownOidString
, "Unknown OID length %ld, value { ", oid
->Length
);
321 for(dex
=0; dex
<oid
->Length
; dex
++) {
323 sprintf(tmp
, "%02X ", oid
->Data
[dex
]);
324 strcat(unknownOidString
, tmp
);
326 strcat(unknownOidString
, " }");
327 return unknownOidString
;
330 /* compare OIDs; returns 1 if identical, else returns 0 */
332 const CSSM_OID
*oid1
,
333 const CSSM_OID
*oid2
)
335 if((oid1
== NULL
) || (oid2
== NULL
)) {
338 if(oid1
->Length
!= oid2
->Length
) {
341 if(memcmp(oid1
->Data
, oid2
->Data
, oid1
->Length
)) {
347 /* app path string to SecTrustedApplicationRef */
348 SecTrustedApplicationRef
appPathToAppRef(
351 SecTrustedApplicationRef appRef
= NULL
;
354 if(appPath
== NULL
) {
357 ortn
= SecTrustedApplicationCreateFromPath(appPath
, &appRef
);
359 cssmPerror("SecTrustedApplicationCreateFromPath", ortn
);
366 const char *fileName
,
367 SecCertificateRef
*certRef
)
369 unsigned char *cp
= NULL
;
373 unsigned char *decoded
= NULL
;
374 unsigned decodedLen
= 0;
376 if(readFileSizet(fileName
, &cp
, &len
)) {
377 printf("***Error reading file %s\n", fileName
);
380 if(isPem(cp
, (unsigned) len
)) {
381 if(pemDecode(cp
, (unsigned) len
, &decoded
, &decodedLen
)) {
382 fprintf(stderr
, "Error decoding cert file %s\n", fileName
);
385 certData
.Length
= decodedLen
;
386 certData
.Data
= decoded
;
389 certData
.Length
= len
;
392 ortn
= SecCertificateCreateFromData(&certData
,
393 CSSM_CERT_X_509v3
, CSSM_CERT_ENCODING_DER
, certRef
);
399 cssmPerror("SecCertificateCreateFromData", ortn
);
405 /* policy string --> CSSM_OID */
406 const CSSM_OID
*policyStringToOid(
410 if(!policy
|| !useTLS
) {
413 if(!strcmp(policy
, "ssl")) {
415 return &CSSMOID_APPLE_TP_SSL
;
417 else if(!strcmp(policy
, "smime")) {
418 return &CSSMOID_APPLE_TP_SMIME
;
420 else if(!strcmp(policy
, "codeSign")) {
421 return &CSSMOID_APPLE_TP_CODE_SIGNING
;
423 else if(!strcmp(policy
, "IPSec")) {
425 return &CSSMOID_APPLE_TP_IP_SEC
;
427 else if(!strcmp(policy
, "basic")) {
428 return &CSSMOID_APPLE_X509_BASIC
;
430 else if(!strcmp(policy
, "swUpdate")) {
431 return &CSSMOID_APPLE_TP_SW_UPDATE_SIGNING
;
433 else if(!strcmp(policy
, "pkgSign")) {
434 return &CSSMOID_APPLE_TP_PACKAGE_SIGNING
;
436 else if(!strcmp(policy
, "eap")) {
438 return &CSSMOID_APPLE_TP_EAP
;
440 else if(!strcmp(policy
, "macappstore")) {
441 return &CSSMOID_APPLE_TP_MACAPPSTORE_RECEIPT
;
443 else if(!strcmp(policy
, "appleID")) {
444 return &CSSMOID_APPLE_TP_APPLEID_SHARING
;
446 else if(!strcmp(policy
, "timestamping")) {
447 return &CSSMOID_APPLE_TP_TIMESTAMPING
;
450 fprintf(stderr
, "***unknown policy spec (%s)\n", policy
);
455 CFOptionFlags
revCheckOptionStringToFlags(
456 const char *revCheckOption
)
458 CFOptionFlags result
= 0;
459 if(revCheckOption
== NULL
) {
462 else if(!strcmp(revCheckOption
, "ocsp")) {
463 result
|= kSecRevocationOCSPMethod
;
465 else if(!strcmp(revCheckOption
, "crl")) {
466 result
|= kSecRevocationCRLMethod
;
468 else if(!strcmp(revCheckOption
, "require")) {
469 result
|= kSecRevocationRequirePositiveResponse
;
471 else if(!strcmp(revCheckOption
, "offline")) {
472 result
|= kSecRevocationNetworkAccessDisabled
;
474 else if(!strcmp(revCheckOption
, "online")) {
475 result
|= kSecRevocationOnlineCheck
;
480 static size_t print_buffer_pem(FILE *stream
,
481 const char *pem_name
, size_t length
, const uint8_t *bytes
)
483 size_t pem_name_len
= strlen(pem_name
);
484 size_t b64_len
= SecBase64Encode2(NULL
, length
, NULL
, 0,
485 kSecB64_F_LINE_LEN_USE_PARAM
, 64, NULL
);
486 char *buffer
= malloc(33 + 2 * pem_name_len
+ b64_len
);
488 p
+= sprintf(buffer
, "-----BEGIN %s-----\n", pem_name
);
489 SecBase64Result result
;
490 p
+= SecBase64Encode2(bytes
, length
, p
, b64_len
,\
491 kSecB64_F_LINE_LEN_USE_PARAM
, 64, &result
);
496 p
+= sprintf(p
, "\n-----END %s-----\n", pem_name
);
497 size_t res
= fwrite(buffer
, 1, p
- buffer
, stream
);
499 bzero(buffer
, p
- buffer
);
504 void printCertLabel(SecCertificateRef certRef
)
506 CFStringRef label
= SecCertificateCopySubjectSummary(certRef
);
508 CFReleaseSafe(label
);
511 void printCertDescription(SecCertificateRef certRef
)
513 CFStringRef description
= CFCopyDescription((CFTypeRef
)certRef
);
514 printCfStr(description
);
515 CFReleaseSafe(description
);
518 void printCertText(SecCertificateRef certRef
)
520 CFStringRef certStr
= CopyCertificateTextRepresentation(certRef
);
524 CFReleaseSafe(certStr
);
527 void printCertChain(SecTrustRef trustRef
, bool printPem
, bool printText
)
529 CFIndex idx
, count
= SecTrustGetCertificateCount(trustRef
);
530 for (idx
= 0; idx
< count
; idx
++) {
531 SecCertificateRef cert
= SecTrustGetCertificateAtIndex(trustRef
, idx
);
532 fprintf(stdout
, " %ld: ", idx
);
533 printCertLabel(cert
);
534 fprintf(stdout
, "\n ");
535 if (!cert
) { continue; }
536 printCertDescription(cert
);
537 fprintf(stdout
, "\n");
542 print_buffer_pem(stdout
, "CERTIFICATE",
543 SecCertificateGetLength(cert
),
544 SecCertificateGetBytePtr(cert
));