]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
1 | /* Copyright (c) 2006 Apple Computer, Inc. |
2 | * | |
3 | * certSerialEncodeTest.cpp | |
4 | * | |
5 | * Verify proper encoding of unsigned integer as a DER_encoded signed integer. | |
6 | * Verifies Radar 4471281. | |
7 | * | |
8 | */ | |
9 | ||
10 | #include <utilLib/common.h> | |
11 | #include <utilLib/cspwrap.h> | |
12 | #include <security_cdsa_utils/cuFileIo.h> | |
13 | #include <clAppUtils/clutils.h> | |
14 | #include <stdlib.h> | |
15 | #include <stdio.h> | |
16 | #include <string.h> | |
17 | #include <Security/cssm.h> | |
18 | #include <Security/x509defs.h> | |
19 | #include <Security/oidsattr.h> | |
20 | #include <Security/oidscert.h> | |
21 | #include <Security/oidsalg.h> | |
22 | #include <Security/certextensions.h> | |
23 | #include <Security/cssmapple.h> | |
24 | #include <string.h> | |
25 | ||
26 | #define SUBJ_KEY_LABEL "subjectKey" | |
27 | #define ROOT_KEY_LABEL "rootKey" | |
28 | /* default key and signature algorithm */ | |
29 | #define SIG_ALG_DEFAULT CSSM_ALGID_SHA1WithRSA | |
30 | #define SIG_OID_DEFAULT CSSMOID_SHA1WithRSA | |
31 | #define KEY_ALG_DEFAULT CSSM_ALGID_RSA | |
32 | ||
33 | /* for write certs/keys option */ | |
34 | #define ROOT_CERT_FILE_NAME "ssRootCert.cer" | |
35 | #define SUBJ_CERT_FILE_NAME "ssSubjCert.cer" | |
36 | ||
37 | /* public key in ref form, TP supports this as of 1/30/02 */ | |
38 | #define PUB_KEY_IS_REF CSSM_TRUE | |
39 | ||
40 | static void usage(char **argv) | |
41 | { | |
42 | printf("Usage: %s [options]\n", argv[0]); | |
43 | printf("Options:\n"); | |
44 | printf(" w[rite certs]\n"); | |
45 | printf(" p(ause for MallocDebug)\n"); | |
46 | printf(" q(uiet)\n"); | |
47 | exit(1); | |
48 | } | |
49 | ||
50 | /* | |
51 | * RDN components | |
52 | */ | |
53 | static CSSM_APPLE_TP_NAME_OID rootRdn[] = | |
54 | { | |
55 | { "Apple Computer", &CSSMOID_OrganizationName }, | |
56 | { "The Big Cheesy Debug Root", &CSSMOID_CommonName } | |
57 | }; | |
58 | #define NUM_ROOT_NAMES (sizeof(rootRdn) / sizeof(CSSM_APPLE_TP_NAME_OID)) | |
59 | ||
60 | /* test cases */ | |
61 | typedef struct { | |
62 | uint32 serialIn; /* --> CSSM_TP_SubmitCredRequest */ | |
63 | CSSM_SIZE expectLen; | |
64 | const uint8 *expect; | |
65 | } SerialNumber; | |
66 | ||
67 | /* 0x7f */ | |
68 | static const uint8 sn0_Data[1] = {0x7f}; | |
69 | static const SerialNumber sn0 = {0x7f, 1, sn0_Data }; | |
70 | ||
71 | /* 0x80 */ | |
72 | static const uint8 sn1_Data[2] = {0x00, 0x80}; | |
73 | static const SerialNumber sn1 = {0x80, 2, sn1_Data }; | |
74 | ||
75 | /* 0x7ff */ | |
76 | static const uint8 sn2_Data[2] = {0x07, 0xff}; | |
77 | static const SerialNumber sn2 = {0x7ff, 2, sn2_Data }; | |
78 | ||
79 | /* 0x80ff */ | |
80 | static const uint8 sn3_Data[3] = {0x00, 0x80, 0xff}; | |
81 | static const SerialNumber sn3 = {0x80ff, 3, sn3_Data }; | |
82 | ||
83 | /* 0xfffffff */ | |
84 | static const uint8 sn4_Data[4] = {0x0f, 0xff, 0xff, 0xff}; | |
85 | static const SerialNumber sn4 = {0xfffffff, 4, sn4_Data }; | |
86 | ||
87 | /* 0x0fffffff */ | |
88 | static const uint8 sn5_Data[4] = {0x0f, 0xff, 0xff, 0xff}; | |
89 | static const SerialNumber sn5 = {0x0fffffff, 4, sn5_Data }; | |
90 | ||
91 | /* 0x80000000 */ | |
92 | static const uint8 sn6_Data[5] = {0x00, 0x80, 0x00, 0x00, 0x00}; | |
93 | static const SerialNumber sn6 = {0x80000000, 5, sn6_Data }; | |
94 | ||
95 | static const SerialNumber *serialNumbers[] = { | |
96 | &sn0, &sn1, &sn2, &sn3, &sn4, &sn5, &sn6 | |
97 | }; | |
98 | #define NUM_SERIAL_NUMS (sizeof(serialNumbers) / sizeof(serialNumbers[0])) | |
99 | ||
100 | static int doTest( | |
101 | CSSM_CL_HANDLE clHand, // CL handle | |
102 | CSSM_CSP_HANDLE cspHand, // CSP handle | |
103 | CSSM_TP_HANDLE tpHand, // TP handle | |
104 | CSSM_KEY_PTR subjPubKey, | |
105 | CSSM_KEY_PTR signerPrivKey, | |
106 | uint32 serialNumIn, | |
107 | CSSM_SIZE serialNumExpLen, | |
108 | const uint8 *serialNumExp, | |
109 | CSSM_BOOL quiet, | |
110 | CSSM_BOOL writeBlobs) | |
111 | { | |
112 | CSSM_DATA refId; // mallocd by CSSM_TP_SubmitCredRequest | |
113 | CSSM_APPLE_TP_CERT_REQUEST certReq; | |
114 | CSSM_TP_REQUEST_SET reqSet; | |
115 | sint32 estTime; | |
116 | CSSM_BOOL confirmRequired; | |
117 | CSSM_TP_RESULT_SET_PTR resultSet; | |
118 | CSSM_ENCODED_CERT *encCert; | |
119 | CSSM_TP_CALLERAUTH_CONTEXT CallerAuthContext; | |
120 | CSSM_FIELD policyId; | |
121 | CSSM_RETURN crtn; | |
122 | CSSM_DATA *signedRootCert; | |
123 | int ourRtn = 0; | |
124 | CSSM_DATA_PTR foundSerial = NULL; | |
125 | CSSM_HANDLE resultHand = 0; | |
126 | uint32 numFields; | |
127 | ||
128 | /* certReq for root */ | |
129 | memset(&certReq, 0, sizeof(CSSM_APPLE_TP_CERT_REQUEST)); | |
130 | certReq.cspHand = cspHand; | |
131 | certReq.clHand = clHand; | |
132 | certReq.serialNumber = serialNumIn; | |
133 | certReq.numSubjectNames = NUM_ROOT_NAMES; | |
134 | certReq.subjectNames = rootRdn; | |
135 | certReq.numIssuerNames = 0; | |
136 | certReq.issuerNames = NULL; | |
137 | certReq.certPublicKey = subjPubKey; | |
138 | certReq.issuerPrivateKey = signerPrivKey; | |
139 | certReq.signatureAlg = CSSM_ALGID_SHA1WithRSA; | |
140 | certReq.signatureOid = CSSMOID_SHA1WithRSA; | |
141 | certReq.notBefore = 0; // now | |
142 | certReq.notAfter = 10000; // seconds from now | |
143 | certReq.numExtensions = 0; | |
144 | certReq.extensions = NULL; | |
145 | ||
146 | reqSet.NumberOfRequests = 1; | |
147 | reqSet.Requests = &certReq; | |
148 | ||
149 | /* a big CSSM_TP_CALLERAUTH_CONTEXT just to specify an OID */ | |
150 | memset(&CallerAuthContext, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT)); | |
151 | memset(&policyId, 0, sizeof(CSSM_FIELD)); | |
152 | policyId.FieldOid = CSSMOID_APPLE_TP_LOCAL_CERT_GEN; | |
153 | CallerAuthContext.Policy.NumberOfPolicyIds = 1; | |
154 | CallerAuthContext.Policy.PolicyIds = &policyId; | |
155 | ||
156 | /* generate root cert */ | |
157 | if(!quiet) { | |
158 | printf("Creating root cert...\n"); | |
159 | } | |
160 | crtn = CSSM_TP_SubmitCredRequest(tpHand, | |
161 | NULL, // PreferredAuthority | |
162 | CSSM_TP_AUTHORITY_REQUEST_CERTISSUE, | |
163 | &reqSet, | |
164 | &CallerAuthContext, | |
165 | &estTime, | |
166 | &refId); | |
167 | if(crtn) { | |
168 | printError("CSSM_TP_SubmitCredRequest", crtn); | |
169 | ourRtn = -1; | |
170 | goto errOut; | |
171 | } | |
172 | crtn = CSSM_TP_RetrieveCredResult(tpHand, | |
173 | &refId, | |
174 | NULL, // CallerAuthCredentials | |
175 | &estTime, | |
176 | &confirmRequired, | |
177 | &resultSet); | |
178 | if(crtn) { | |
179 | printError("CSSM_TP_RetrieveCredResult", crtn); | |
180 | ourRtn = -1; | |
181 | goto errOut; | |
182 | } | |
183 | if(resultSet == NULL) { | |
184 | printf("***CSSM_TP_RetrieveCredResult returned NULL result set.\n"); | |
185 | ourRtn = -1; | |
186 | goto errOut; | |
187 | } | |
188 | encCert = (CSSM_ENCODED_CERT *)resultSet->Results; | |
189 | signedRootCert = &encCert->CertBlob; | |
190 | if(writeBlobs) { | |
191 | writeFile(ROOT_CERT_FILE_NAME, signedRootCert->Data, signedRootCert->Length); | |
192 | printf("...wrote %lu bytes to %s\n", signedRootCert->Length, | |
193 | ROOT_CERT_FILE_NAME); | |
194 | } | |
195 | ||
196 | /* make sure it self-verifies */ | |
197 | crtn = CSSM_CL_CertVerify(clHand, 0 /* CCHandle */, | |
198 | signedRootCert, signedRootCert, | |
199 | NULL, 0); | |
200 | if(crtn) { | |
201 | cssmPerror("CSSM_CL_CertVerify", crtn); | |
202 | printf("***Created cert does not self-verify\n"); | |
203 | ourRtn = -1; | |
204 | goto errOut; | |
205 | } | |
206 | ||
207 | /* extract the field we're interested in verifying */ | |
208 | crtn = CSSM_CL_CertGetFirstFieldValue(clHand, signedRootCert, | |
209 | &CSSMOID_X509V1SerialNumber, &resultHand, &numFields, &foundSerial); | |
210 | if(crtn) { | |
211 | cssmPerror("CSSM_CL_CertGetFirstFieldValue(serialNumber)", crtn); | |
212 | printf("***Can't obtain serial number\n"); | |
213 | ourRtn = -1; | |
214 | goto errOut; | |
215 | } | |
216 | CSSM_CL_CertAbortQuery(clHand, resultHand); | |
217 | if(foundSerial->Length != serialNumExpLen) { | |
218 | printf("***expected serialNumber len 0x%lu, got 0x%lu\n", | |
219 | (unsigned long)serialNumExpLen, (unsigned long)foundSerial->Length); | |
220 | ourRtn = -1; | |
221 | goto errOut; | |
222 | } | |
223 | for(unsigned dex=0; dex<serialNumExpLen; dex++) { | |
224 | if(foundSerial->Data[dex] != serialNumExp[dex]) { | |
225 | printf("***SerialNumber mismatch at index %u: exp %02X got %02X\n", | |
226 | dex, (unsigned)serialNumExp[dex], | |
227 | (unsigned)foundSerial->Data[dex]); | |
228 | ourRtn = -1; | |
229 | } | |
230 | } | |
231 | /* free retrieved serial number and the result set itself */ | |
232 | CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1SerialNumber, foundSerial); | |
233 | CSSM_FREE(signedRootCert->Data); | |
234 | CSSM_FREE(encCert); | |
235 | CSSM_FREE(resultSet); | |
236 | /* Per the spec, this is supposed to be Opaque to us and the TP is supposed to free | |
237 | * it when it goes out of scope...but libsecurity_keychains's | |
238 | * CertificateRequest::submitDotMac() frees this...that would have to change | |
239 | * in order for the TP to free this properly. Someday maybe. No big deal. | |
240 | */ | |
241 | CSSM_FREE(refId.Data); | |
242 | errOut: | |
243 | return ourRtn; | |
244 | } | |
245 | ||
246 | int main(int argc, char **argv) | |
247 | { | |
248 | CSSM_CL_HANDLE clHand; // CL handle | |
249 | CSSM_CSP_HANDLE cspHand; // CSP handle | |
250 | CSSM_TP_HANDLE tpHand; // TP handle | |
251 | CSSM_KEY rootPubKey; // root's RSA public key blob | |
252 | CSSM_KEY rootPrivKey; // root's RSA private key - ref format | |
253 | CSSM_RETURN crtn; | |
254 | int arg; | |
255 | unsigned dex; | |
256 | int ourRtn = 0; | |
257 | uint32 keySizeInBits = 512; | |
258 | CSSM_BOOL doPause = CSSM_FALSE; | |
259 | ||
260 | /* user-spec'd variables */ | |
261 | CSSM_BOOL writeBlobs = CSSM_FALSE; | |
262 | CSSM_BOOL quiet = CSSM_FALSE; | |
263 | ||
264 | for(arg=1; arg<argc; arg++) { | |
265 | switch(argv[arg][0]) { | |
266 | case 'w': | |
267 | writeBlobs = CSSM_TRUE; | |
268 | break; | |
269 | case 'q': | |
270 | quiet = CSSM_TRUE; | |
271 | break; | |
272 | case 'p': | |
273 | doPause = CSSM_TRUE; | |
274 | break; | |
275 | default: | |
276 | usage(argv); | |
277 | } | |
278 | } | |
279 | ||
280 | testStartBanner("certSerialEncodeTest", argc, argv); | |
281 | ||
282 | ||
283 | /* connect to CL, TP, and CSP */ | |
284 | clHand = clStartup(); | |
285 | if(clHand == 0) { | |
286 | return -1; | |
287 | } | |
288 | tpHand = tpStartup(); | |
289 | if(tpHand == 0) { | |
290 | return -1; | |
291 | } | |
292 | cspHand = cspStartup(); | |
293 | if(cspHand == 0) { | |
294 | return -1; | |
295 | } | |
296 | ||
297 | /* cook up key pair for self-signed cert */ | |
298 | crtn = cspGenKeyPair(cspHand, | |
299 | CSSM_ALGID_RSA, | |
300 | ROOT_KEY_LABEL, | |
301 | strlen(ROOT_KEY_LABEL), | |
302 | keySizeInBits, | |
303 | &rootPubKey, | |
304 | CSSM_FALSE, // pubIsRef - should work both ways, but not yet | |
305 | CSSM_KEYUSE_VERIFY, | |
306 | CSSM_KEYBLOB_RAW_FORMAT_NONE, | |
307 | &rootPrivKey, | |
308 | writeBlobs ? CSSM_FALSE : CSSM_TRUE, // privIsRef | |
309 | CSSM_KEYUSE_SIGN, | |
310 | CSSM_KEYBLOB_RAW_FORMAT_NONE, | |
311 | CSSM_FALSE); | |
312 | if(crtn) { | |
313 | ourRtn = -1; | |
314 | goto abort; | |
315 | } | |
316 | ||
317 | for(dex=0; dex<NUM_SERIAL_NUMS; dex++) { | |
318 | const SerialNumber *sn = serialNumbers[dex]; | |
319 | if(!quiet) { | |
320 | printf("...testing serial number 0x%lx\n", (unsigned long)sn->serialIn); | |
321 | } | |
322 | ourRtn = doTest(clHand, cspHand, tpHand, | |
323 | &rootPubKey, &rootPrivKey, | |
324 | sn->serialIn, sn->expectLen, sn->expect, | |
325 | quiet, writeBlobs); | |
326 | if(ourRtn) { | |
327 | break; | |
328 | } | |
329 | if(doPause) { | |
330 | fpurge(stdin); | |
331 | printf("Pausing for MallocDebug. a to abort, anything else to continue: "); | |
332 | if(getchar() == 'a') { | |
333 | break; | |
334 | } | |
335 | } | |
336 | } | |
337 | ||
338 | cspFreeKey(cspHand, &rootPubKey); | |
339 | cspFreeKey(cspHand, &rootPrivKey); | |
340 | ||
341 | abort: | |
342 | if(cspHand != 0) { | |
343 | CSSM_ModuleDetach(cspHand); | |
344 | } | |
345 | if(clHand != 0) { | |
346 | CSSM_ModuleDetach(clHand); | |
347 | } | |
348 | if(tpHand != 0) { | |
349 | CSSM_ModuleDetach(tpHand); | |
350 | } | |
351 | ||
352 | if((ourRtn == 0) && !quiet) { | |
353 | printf("certSerialEncodeTest test succeeded\n"); | |
354 | } | |
355 | return ourRtn; | |
356 | } | |
357 | ||
358 |