]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/certChain/certChain.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / certChain / certChain.cpp
1 /*
2 * Given a cert, produce a complete ordered cert chain back to a root.
3 * Intermediate certs can be in any user keychain.
4 */
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <security_cdsa_utils/cuFileIo.h> /* private */
8 #include <security_cdsa_utils/cuPrintCert.h> /* private */
9 #include <Security/Security.h>
10 #include <Security/SecTrustPriv.h> /* private */
11
12 static void usage(char **argv)
13 {
14 printf("Usage:\n");
15 printf(" %s certFileName [d(isable intermediates) [f filebase] [n(o cert dump)]\n", argv[0]);
16 exit(1);
17 }
18
19 int main(int argc, char **argv)
20 {
21 unsigned char *certData = NULL; // subject cert, raw data
22 unsigned certDataLen = 0;
23 OSStatus ortn;
24 SecTrustRef secTrust = NULL;
25 CFMutableArrayRef subjCerts = NULL;
26 SecPolicyRef policy = NULL;
27 SecPolicySearchRef policySearch = NULL;
28 SecTrustResultType secTrustResult;
29 CSSM_RETURN crtn = CSSM_OK;
30 CSSM_TP_APPLE_EVIDENCE_INFO *dummyEv; // not used
31 CFArrayRef certChain = NULL; // constructed chain
32 CFIndex numCerts;
33 bool disableLocalIntermediates = false;
34 char *fileBase = NULL;
35 bool enableCertDump = true;
36
37 if(argc < 2) {
38 usage(argv);
39 }
40 if(readFile(argv[1], &certData, &certDataLen)) {
41 printf("***Error reading cert from %s. Aborting.\n", argv[1]);
42 exit(1);
43 }
44 for(int arg=2; arg<argc; arg++) {
45 char *argp = argv[arg];
46 switch(argp[0]) {
47 case 'd':
48 disableLocalIntermediates = true;
49 break;
50 case 'n':
51 enableCertDump = false;
52 break;
53 case 'f':
54 arg++;
55 if(arg == argc) {
56 usage(argv);
57 }
58 fileBase = argv[arg];
59 break;
60 default:
61 usage(argv);
62 }
63 }
64
65 /* SecCertificateRef form of subject cert */
66 SecCertificateRef certRef = NULL;
67 CSSM_DATA cdata = {(uint32)certDataLen, (uint8 *)certData};
68 ortn = SecCertificateCreateFromData(&cdata,
69 CSSM_CERT_X_509v3,
70 CSSM_CERT_ENCODING_DER,
71 &certRef);
72 if(ortn) {
73 cssmPerror("SecCertificateCreateFromData", ortn);
74 goto errOut;
75 }
76
77 /* make a one-element array */
78 subjCerts = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
79 CFArraySetValueAtIndex(subjCerts, 0, certRef);
80
81 /* the array owns the subject cert ref now */
82 CFRelease(certRef);
83
84 /* Get a SecPolicyRef for generic X509 cert chain verification */
85 ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
86 &CSSMOID_APPLE_X509_BASIC,
87 NULL, // value
88 &policySearch);
89 if(ortn) {
90 cssmPerror("SecPolicySearchCreate", ortn);
91 goto errOut;
92 }
93 ortn = SecPolicySearchCopyNext(policySearch, &policy);
94 if(ortn) {
95 cssmPerror("SecPolicySearchCopyNext", ortn);
96 goto errOut;
97 }
98
99 /* build a SecTrustRef for specified policy and certs */
100 ortn = SecTrustCreateWithCertificates(subjCerts,
101 policy, &secTrust);
102 if(ortn) {
103 cssmPerror("SecTrustCreateWithCertificates", ortn);
104 goto errOut;
105 }
106
107 if(disableLocalIntermediates) {
108 /*
109 * Avoid searching user keychains for intermediate certs
110 * by specifying an empty array of keychains
111 */
112 CFMutableArrayRef kcList;
113 kcList = CFArrayCreateMutable(NULL, 0, NULL);
114 if(kcList == NULL) {
115 printf("***CFArrayCreateMutable error\n");
116 ortn = -1;
117 goto errOut;
118 }
119 ortn = SecTrustSetKeychains(secTrust, kcList);
120 if(ortn) {
121 cssmPerror("SecTrustSetKeychains", ortn);
122 goto errOut;
123 }
124 CFRelease(kcList);
125 }
126
127 /* evaluate: GO */
128 ortn = SecTrustEvaluate(secTrust, &secTrustResult);
129 if(ortn) {
130 cssmPerror("SecTrustEvaluate", ortn);
131 goto errOut;
132 }
133 switch(secTrustResult) {
134 case kSecTrustResultUnspecified:
135 /* cert chain valid, no special UserTrust assignments */
136 case kSecTrustResultProceed:
137 /* cert chain valid AND user explicitly trusts this */
138 break;
139 case kSecTrustResultDeny:
140 case kSecTrustResultConfirm:
141 /*
142 * Cert chain may well have verified OK, but user has flagged
143 * one of these certs as untrustable.
144 */
145 printf("***User specified that a cert in this chain is untrusted.\n");
146 goto errOut;
147
148 default:
149 {
150 /* private SPI to get low-level CSSM error */
151 OSStatus osCrtn;
152 ortn = SecTrustGetCssmResultCode(secTrust, (OSStatus *)&crtn);
153 if(ortn) {
154 cssmPerror("SecTrustEvaluate", ortn);
155 goto errOut;
156 }
157 }
158 }
159 if(crtn) {
160 /* get some detailed error info */
161 switch(crtn) {
162 case CSSMERR_TP_INVALID_ANCHOR_CERT:
163 printf("***Verified to unknown anchor cert\n");
164 break;
165 case CSSMERR_TP_NOT_TRUSTED:
166 printf("***Can not verify to a root cert \n");
167 break;
168 case CSSMERR_TP_CERT_EXPIRED:
169 printf("***A cert in this chain has expired\n");
170 break;
171 case CSSMERR_TP_CERT_NOT_VALID_YET:
172 printf("***A cert in this chain is not yet valid\n");
173 break;
174 default:
175 printf("Other error from SecTrustEvaluate\n");
176 cssmPerror("SecTrustEvaluate", crtn);
177 break;
178 }
179 } /* SecTrustEvaluate error */
180
181 /* get resulting constructed cert chain */
182 ortn = SecTrustGetResult(secTrust, &secTrustResult, &certChain, &dummyEv);
183 if(ortn) {
184 cssmPerror("SecTrustEvaluate", ortn);
185 goto errOut;
186 }
187
188 /* display the results */
189 numCerts = CFArrayGetCount(certChain);
190 printf("Number of certs in constructed cert chain = %d\n", (int)numCerts);
191 if(enableCertDump) {
192 for(unsigned i=0; i<numCerts; i++) {
193 CSSM_DATA cd;
194 certRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, i);
195 ortn = SecCertificateGetData(certRef, &cd);
196 if(ortn) {
197 printf("***SecCertificateGetData returned %d\n", (int)ortn);
198 continue;
199 }
200 printf("\n================== Cert %d ===================\n\n", i);
201 printCert(cd.Data, cd.Length, CSSM_FALSE);
202 printf("\n=============== End of Cert %d ===============\n", i);
203
204 if((fileBase != NULL) & (i > 0)) {
205 char fname[200];
206 sprintf(fname, "%s_%u", fileBase, i);
207 if(writeFile(fname, cd.Data, cd.Length)) {
208 printf("***Error writing to %s\n", fname);
209 }
210 else {
211 printf("...write %lu bytes to %s\n", cd.Length, fname);
212 }
213 }
214 }
215 }
216 errOut:
217 if(certData) {
218 /* mallocds by readFile() */
219 free(certData);
220 }
221 if(secTrust) {
222 CFRelease(secTrust);
223 }
224 if(subjCerts) {
225 CFRelease(subjCerts);
226 }
227 if(policy) {
228 CFRelease(policy);
229 }
230 if(policySearch) {
231 CFRelease(policySearch);
232 }
233 return (int)ortn;
234 }