]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
1 | /* |
2 | * pubKeyTool.cpp - calculate public key hash of arbitrary keys and certs; derive | |
3 | * public key from a private key or a cert. | |
4 | */ | |
5 | ||
6 | #include <stdlib.h> | |
7 | #include <strings.h> | |
8 | #include <stdio.h> | |
9 | #include <unistd.h> | |
10 | #include <Security/Security.h> | |
11 | #include <security_cdsa_utils/cuFileIo.h> | |
12 | #include <security_cdsa_utils/cuCdsaUtils.h> | |
13 | #include "cspwrap.h" | |
14 | #include "common.h" | |
15 | ||
16 | static void usage(char **argv) | |
17 | { | |
18 | printf("usage: %s [options]\n", argv[0]); | |
19 | printf("Options:\n"); | |
20 | printf(" -k priv_key_file -- private key file to read\n"); | |
21 | printf(" -b pub_key_file -- public key file to read\n"); | |
22 | printf(" -c cert_file -- cert file to read\n"); | |
23 | printf(" -d -- print public key digest\n"); | |
24 | printf(" -o out_file -- write public key to out_file\n"); | |
25 | printf(" -f pkcs1|pkcs8|x509 -- input key format\n"); | |
26 | printf(" -- default is PKCS8 for private key, PKCS1 for" | |
27 | " public\n"); | |
28 | printf(" -K keychain -- import pub key to this keychain; workaround " | |
29 | "for Radar 4191851)\n"); | |
30 | exit(1); | |
31 | } | |
32 | ||
33 | /* Convert raw key blob into a respectable CSSM_KEY. */ | |
34 | static CSSM_RETURN inferCssmKey( | |
35 | const CSSM_DATA &keyBlob, | |
36 | bool isPrivKey, | |
37 | CSSM_KEYBLOB_FORMAT keyForm, | |
38 | CSSM_CSP_HANDLE cspHand, | |
39 | CSSM_KEY &outKey) | |
40 | { | |
41 | memset(&outKey, 0, sizeof(CSSM_KEY)); | |
42 | outKey.KeyData = keyBlob; | |
43 | CSSM_KEYHEADER &hdr = outKey.KeyHeader; | |
44 | hdr.HeaderVersion = CSSM_KEYHEADER_VERSION; | |
45 | /* CspId blank */ | |
46 | hdr.BlobType = CSSM_KEYBLOB_RAW; | |
47 | hdr.AlgorithmId = CSSM_ALGID_RSA; | |
48 | hdr.KeyAttr = CSSM_KEYATTR_EXTRACTABLE; | |
49 | hdr.Format = keyForm; | |
50 | hdr.KeyClass = isPrivKey ? CSSM_KEYCLASS_PRIVATE_KEY : CSSM_KEYCLASS_PUBLIC_KEY; | |
51 | hdr.KeyUsage = CSSM_KEYUSE_ANY; | |
52 | hdr.WrapAlgorithmId = CSSM_ALGID_NONE; | |
53 | hdr.WrapMode = CSSM_ALGMODE_NONE; | |
54 | /* | |
55 | * LogicalKeySizeInBits - ask the CSP | |
56 | */ | |
57 | CSSM_KEY_SIZE keySize; | |
58 | CSSM_RETURN crtn; | |
59 | crtn = CSSM_QueryKeySizeInBits(cspHand, CSSM_INVALID_HANDLE, &outKey, | |
60 | &keySize); | |
61 | if(crtn) { | |
62 | cssmPerror("CSSM_QueryKeySizeInBits", crtn); | |
63 | return crtn; | |
64 | } | |
65 | hdr.LogicalKeySizeInBits = keySize.LogicalKeySizeInBits; | |
66 | return CSSM_OK; | |
67 | } | |
68 | ||
69 | /* | |
70 | * Given any key in either blob or reference format, | |
71 | * obtain the associated public key's SHA-1 hash. | |
72 | */ | |
73 | static CSSM_RETURN keyDigest( | |
74 | CSSM_CSP_HANDLE cspHand, | |
75 | const CSSM_KEY *key, | |
76 | CSSM_DATA_PTR *hashData) /* struct and contents cuAppMalloc'd and RETURNED */ | |
77 | { | |
78 | CSSM_CC_HANDLE ccHand; | |
79 | CSSM_RETURN crtn; | |
80 | CSSM_DATA_PTR dp; | |
81 | ||
82 | *hashData = NULL; | |
83 | ||
84 | /* validate input params */ | |
85 | if((key == NULL) || | |
86 | (hashData == NULL)) { | |
87 | printf("keyHash: bogus args\n"); | |
88 | return CSSMERR_CSSM_INTERNAL_ERROR; | |
89 | } | |
90 | ||
91 | /* cook up a context for a passthrough op */ | |
92 | crtn = CSSM_CSP_CreatePassThroughContext(cspHand, | |
93 | key, | |
94 | &ccHand); | |
95 | if(ccHand == 0) { | |
96 | cssmPerror("CSSM_CSP_CreatePassThroughContext", crtn); | |
97 | return crtn; | |
98 | } | |
99 | ||
100 | /* now it's up to the CSP */ | |
101 | crtn = CSSM_CSP_PassThrough(ccHand, | |
102 | CSSM_APPLECSP_KEYDIGEST, | |
103 | NULL, | |
104 | (void **)&dp); | |
105 | if(crtn) { | |
106 | cssmPerror("CSSM_CSP_PassThrough(KEYDIGEST)", crtn); | |
107 | } | |
108 | else { | |
109 | *hashData = dp; | |
110 | crtn = CSSM_OK; | |
111 | } | |
112 | CSSM_DeleteContext(ccHand); | |
113 | return crtn; | |
114 | } | |
115 | ||
116 | /* | |
117 | * Here's a tricky one. Given a private key, obtain the correspoding public key. | |
118 | * This uses a private key blob format that's used internally in the CSP | |
119 | * to generate key digests. | |
120 | */ | |
121 | ||
122 | /* | |
123 | * this magic const copied from BinaryKey.h | |
124 | */ | |
125 | #define CSSM_KEYBLOB_RAW_FORMAT_DIGEST \ | |
126 | (CSSM_KEYBLOB_RAW_FORMAT_VENDOR_DEFINED + 0x12345) | |
127 | ||
128 | static CSSM_RETURN pubKeyFromPrivKey( | |
129 | CSSM_CSP_HANDLE cspHand, | |
130 | const CSSM_KEY *privKey, // assumed to be raw format | |
131 | CSSM_KEY *pubKey) | |
132 | { | |
133 | /* first convert to reference key */ | |
134 | CSSM_KEY refKey; | |
135 | CSSM_RETURN crtn; | |
136 | crtn = cspRawKeyToRef(cspHand, privKey, &refKey); | |
137 | if(crtn) { | |
138 | return crtn; | |
139 | } | |
140 | ||
141 | /* now a NULL wrap with the magic format attribute */ | |
142 | CSSM_CC_HANDLE ccHand; | |
143 | CSSM_ACCESS_CREDENTIALS creds; | |
144 | CSSM_DATA descData = {0, 0}; | |
145 | ||
146 | crtn = CSSM_CSP_CreateSymmetricContext(cspHand, | |
147 | CSSM_ALGID_NONE, | |
148 | CSSM_ALGMODE_NONE, | |
149 | NULL, // passPhrase, | |
150 | NULL, // key | |
151 | NULL, // initVector, | |
152 | CSSM_PADDING_NONE, | |
153 | NULL, // Reserved | |
154 | &ccHand); | |
155 | if(crtn) { | |
156 | cssmPerror("CSSM_CSP_CreateSymmetricContext", crtn); | |
157 | return crtn; | |
158 | } | |
159 | crtn = AddContextAttribute(ccHand, | |
160 | /* | |
161 | * The output of the WrapKey is a private key as far as the CSP is | |
162 | * concerned, at the level that this attribute is used anyway.... | |
163 | */ | |
164 | CSSM_ATTRIBUTE_PRIVATE_KEY_FORMAT, | |
165 | sizeof(uint32), | |
166 | CAT_Uint32, | |
167 | NULL, | |
168 | CSSM_KEYBLOB_RAW_FORMAT_DIGEST); | |
169 | if(crtn) { | |
170 | cssmPerror("CSSM_CSP_CreateSymmetricContext", crtn); | |
171 | goto errOut; | |
172 | } | |
173 | memset(pubKey, 0, sizeof(CSSM_KEY)); | |
174 | memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); | |
175 | crtn = CSSM_WrapKey(ccHand, | |
176 | &creds, | |
177 | &refKey, | |
178 | &descData, | |
179 | pubKey); | |
180 | if(crtn) { | |
181 | cssmPerror("CSSM_WrapKey", crtn); | |
182 | goto errOut; | |
183 | } | |
184 | ||
185 | /* now: presto chango - don't do this at home! */ | |
186 | pubKey->KeyHeader.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY; | |
187 | errOut: | |
188 | CSSM_FreeKey(cspHand, NULL, &refKey, CSSM_FALSE); | |
189 | CSSM_DeleteContext(ccHand); | |
190 | return crtn; | |
191 | } | |
192 | ||
193 | /* | |
194 | * Import a key into a DLDB. | |
195 | */ | |
196 | static CSSM_RETURN importToDlDb( | |
197 | CSSM_CSP_HANDLE cspHand, | |
198 | CSSM_DL_DB_HANDLE_PTR dlDbHand, | |
199 | const CSSM_KEY *rawPubKey, | |
200 | CSSM_DATA_PTR labelData, | |
201 | CSSM_KEY_PTR importedKey) | |
202 | { | |
203 | CSSM_CC_HANDLE ccHand = 0; | |
204 | CSSM_RETURN crtn; | |
205 | uint32 keyAttr; | |
206 | CSSM_ACCESS_CREDENTIALS creds; | |
207 | CSSM_CONTEXT_ATTRIBUTE newAttr; | |
208 | CSSM_DATA descData = {0, 0}; | |
209 | ||
210 | memset(importedKey, 0, sizeof(CSSM_KEY)); | |
211 | memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS)); | |
212 | crtn = CSSM_CSP_CreateSymmetricContext(cspHand, | |
213 | CSSM_ALGID_NONE, | |
214 | CSSM_ALGMODE_NONE, | |
215 | &creds, | |
216 | NULL, // unwrappingKey | |
217 | NULL, // initVector | |
218 | CSSM_PADDING_NONE, | |
219 | 0, // Params | |
220 | &ccHand); | |
221 | if(crtn) { | |
222 | cssmPerror("CSSM_CSP_CreateSymmetricContext", crtn); | |
223 | return crtn; | |
224 | } | |
225 | keyAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_PERMANENT; | |
226 | ||
227 | /* Add DLDB to context */ | |
228 | newAttr.AttributeType = CSSM_ATTRIBUTE_DL_DB_HANDLE; | |
229 | newAttr.AttributeLength = sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE); | |
230 | newAttr.Attribute.Data = (CSSM_DATA_PTR)dlDbHand; | |
231 | crtn = CSSM_UpdateContextAttributes(ccHand, 1, &newAttr); | |
232 | if(crtn) { | |
233 | cssmPerror("CSSM_UpdateContextAttributes", crtn); | |
234 | goto errOut; | |
235 | } | |
236 | ||
237 | /* import */ | |
238 | crtn = CSSM_UnwrapKey(ccHand, | |
239 | NULL, // PublicKey | |
240 | rawPubKey, | |
241 | CSSM_KEYUSE_ANY, | |
242 | keyAttr, | |
243 | labelData, | |
244 | NULL, // CredAndAclEntry | |
245 | importedKey, | |
246 | &descData); // required | |
247 | if(crtn) { | |
248 | cssmPerror("CSSM_UnwrapKey", crtn); | |
249 | } | |
250 | errOut: | |
251 | if(ccHand) { | |
252 | CSSM_DeleteContext(ccHand); | |
253 | } | |
254 | return crtn; | |
255 | } | |
256 | ||
257 | /* | |
258 | * Free memory via specified plugin's app-level allocator | |
259 | */ | |
260 | void impExpFreeCssmMemory( | |
261 | CSSM_HANDLE hand, | |
262 | void *p) | |
263 | { | |
264 | CSSM_API_MEMORY_FUNCS memFuncs; | |
265 | CSSM_RETURN crtn = CSSM_GetAPIMemoryFunctions(hand, &memFuncs); | |
266 | if(crtn) { | |
267 | return; | |
268 | } | |
269 | memFuncs.free_func(p, memFuncs.AllocRef); | |
270 | } | |
271 | ||
272 | /* | |
273 | * Key attrribute names and values. | |
274 | * | |
275 | * This is where the public key hash goes. | |
276 | */ | |
277 | #define SEC_KEY_HASH_ATTR_NAME "Label" | |
278 | ||
279 | /* | |
280 | * This is where the publicly visible name goes. | |
281 | */ | |
282 | #define SEC_KEY_PRINT_NAME_ATTR_NAME "PrintName" | |
283 | ||
284 | /* | |
285 | * Look up public key by label | |
286 | * Set label to new specified label (SHA1 digest) | |
287 | * Set print name to new specified user-visible name | |
288 | */ | |
289 | static CSSM_RETURN setPubKeyLabel( | |
290 | CSSM_CSP_HANDLE cspHand, // where the key lives | |
291 | CSSM_DL_DB_HANDLE *dlDbHand, // ditto | |
292 | const CSSM_DATA *existKeyLabel, // existing label, a random string, for lookup | |
293 | const CSSM_DATA *keyDigest, // SHA1 digest, the new label | |
294 | const CSSM_DATA *newPrintName) // new user-visible name | |
295 | { | |
296 | CSSM_QUERY query; | |
297 | CSSM_SELECTION_PREDICATE predicate; | |
298 | CSSM_DB_UNIQUE_RECORD_PTR record = NULL; | |
299 | CSSM_RETURN crtn; | |
300 | CSSM_HANDLE resultHand = 0; | |
301 | ||
302 | /* | |
303 | * Look up the key in the DL. | |
304 | */ | |
305 | query.RecordType = CSSM_DL_DB_RECORD_PUBLIC_KEY; | |
306 | query.Conjunctive = CSSM_DB_NONE; | |
307 | query.NumSelectionPredicates = 1; | |
308 | predicate.DbOperator = CSSM_DB_EQUAL; | |
309 | ||
310 | predicate.Attribute.Info.AttributeNameFormat = | |
311 | CSSM_DB_ATTRIBUTE_NAME_AS_STRING; | |
312 | predicate.Attribute.Info.Label.AttributeName = (char *)"Label"; | |
313 | predicate.Attribute.Info.AttributeFormat = | |
314 | CSSM_DB_ATTRIBUTE_FORMAT_BLOB; | |
315 | /* hope this cast is OK */ | |
316 | predicate.Attribute.Value = (CSSM_DATA_PTR)existKeyLabel; | |
317 | query.SelectionPredicate = &predicate; | |
318 | ||
319 | query.QueryLimits.TimeLimit = 0; // FIXME - meaningful? | |
320 | query.QueryLimits.SizeLimit = 1; // FIXME - meaningful? | |
321 | query.QueryFlags = 0; // CSSM_QUERY_RETURN_DATA; // FIXME - used? | |
322 | ||
323 | /* build Record attribute with two attrs */ | |
324 | CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs; | |
325 | CSSM_DB_ATTRIBUTE_DATA attr[2]; | |
326 | ||
327 | attr[0].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; | |
328 | attr[0].Info.Label.AttributeName = (char *)SEC_KEY_HASH_ATTR_NAME; | |
329 | attr[0].Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB; | |
330 | attr[1].Info.AttributeNameFormat = CSSM_DB_ATTRIBUTE_NAME_AS_STRING; | |
331 | attr[1].Info.Label.AttributeName = (char *)SEC_KEY_PRINT_NAME_ATTR_NAME; | |
332 | attr[1].Info.AttributeFormat = CSSM_DB_ATTRIBUTE_FORMAT_BLOB; | |
333 | ||
334 | recordAttrs.DataRecordType = CSSM_DL_DB_RECORD_PUBLIC_KEY; | |
335 | recordAttrs.NumberOfAttributes = 2; | |
336 | recordAttrs.AttributeData = attr; | |
337 | ||
338 | crtn = CSSM_DL_DataGetFirst(*dlDbHand, | |
339 | &query, | |
340 | &resultHand, | |
341 | &recordAttrs, | |
342 | NULL, // theData | |
343 | &record); | |
344 | /* abort only on success */ | |
345 | if(crtn != CSSM_OK) { | |
346 | cssmPerror("CSSM_DL_DataGetFirst", crtn); | |
347 | goto errOut; | |
348 | } | |
349 | ||
350 | /* | |
351 | * Update existing attr data. | |
352 | * NOTE: the module which allocated this attribute data - a DL - | |
353 | * was loaded and attached by the keychain layer, not by us. Thus | |
354 | * we can't use the memory allocator functions *we* used when | |
355 | * attaching to the CSP - we have to use the ones | |
356 | * which the client registered with the DL. | |
357 | */ | |
358 | impExpFreeCssmMemory(dlDbHand->DLHandle, attr[0].Value->Data); | |
359 | impExpFreeCssmMemory(dlDbHand->DLHandle, attr[0].Value); | |
360 | impExpFreeCssmMemory(dlDbHand->DLHandle, attr[1].Value->Data); | |
361 | impExpFreeCssmMemory(dlDbHand->DLHandle, attr[1].Value); | |
362 | attr[0].Value = const_cast<CSSM_DATA *>(keyDigest); | |
363 | attr[1].Value = const_cast<CSSM_DATA *>(newPrintName); | |
364 | ||
365 | crtn = CSSM_DL_DataModify(*dlDbHand, | |
366 | CSSM_DL_DB_RECORD_PUBLIC_KEY, | |
367 | record, | |
368 | &recordAttrs, | |
369 | NULL, // DataToBeModified | |
370 | CSSM_DB_MODIFY_ATTRIBUTE_REPLACE); | |
371 | if(crtn) { | |
372 | cssmPerror("CSSM_DL_DataModify", crtn); | |
373 | } | |
374 | errOut: | |
375 | /* free resources */ | |
376 | if(resultHand) { | |
377 | CSSM_DL_DataAbortQuery(*dlDbHand, resultHand); | |
378 | } | |
379 | if(record) { | |
380 | CSSM_DL_FreeUniqueRecord(*dlDbHand, record); | |
381 | } | |
382 | return crtn; | |
383 | } | |
384 | ||
385 | #define SHA1_LABEL_LEN 20 | |
386 | #define IMPORTED_KEY_NAME "Imported Public Key" | |
387 | ||
388 | /* | |
389 | * Import a public key into a keychain, with proper Label attribute setting. | |
390 | * A workaround for Radar 4191851. | |
391 | */ | |
392 | static int pubKeyImport( | |
393 | const char *kcName, | |
394 | const CSSM_KEY *pubKey, | |
395 | CSSM_CSP_HANDLE rawCspHand) /* raw CSP handle for calculating digest */ | |
396 | { | |
397 | CSSM_CSP_HANDLE cspHand; | |
398 | CSSM_DL_DB_HANDLE dlDbHand; | |
399 | OSStatus ortn; | |
400 | CSSM_RETURN crtn; | |
401 | SecKeychainRef kcRef = NULL; | |
402 | int ourRtn = 0; | |
403 | CSSM_DATA_PTR digest = NULL; | |
404 | CSSM_KEY importedKey; | |
405 | CSSM_DATA newPrintName = | |
406 | { (uint32)strlen(IMPORTED_KEY_NAME), (uint8 *)IMPORTED_KEY_NAME}; | |
407 | ||
408 | /* NULL unwrap stuff */ | |
409 | uint8 tempLabel[SHA1_LABEL_LEN]; | |
410 | CSSM_DATA labelData = {SHA1_LABEL_LEN, tempLabel}; | |
411 | ||
412 | ortn = SecKeychainOpen(kcName, &kcRef); | |
413 | if(ortn) { | |
414 | cssmPerror("SecKeychainOpen", ortn); | |
415 | return -1; | |
416 | } | |
417 | /* subsequent errors to errOut: */ | |
418 | ||
419 | /* Get CSSM handles */ | |
420 | ortn = SecKeychainGetCSPHandle(kcRef, &cspHand); | |
421 | if(ortn) { | |
422 | cssmPerror("SecKeychainGetCSPHandle", ortn); | |
423 | ourRtn = -1; | |
424 | goto errOut; | |
425 | } | |
426 | ortn = SecKeychainGetDLDBHandle(kcRef, &dlDbHand); | |
427 | if(ortn) { | |
428 | cssmPerror("SecKeychainGetCSPHandle", ortn); | |
429 | ourRtn = -1; | |
430 | goto errOut; | |
431 | } | |
432 | ||
433 | /* public key hash from raw CSP */ | |
434 | crtn = keyDigest(rawCspHand, pubKey, &digest); | |
435 | if(crtn) { | |
436 | ourRtn = -1; | |
437 | goto errOut; | |
438 | } | |
439 | ||
440 | /* random label for initial storage and later retrieval */ | |
441 | appGetRandomBytes(tempLabel, SHA1_LABEL_LEN); | |
442 | ||
443 | /* import the key into the keychain's DLDB */ | |
444 | memset(&importedKey, 0, sizeof(CSSM_KEY)); | |
445 | crtn = importToDlDb(cspHand, &dlDbHand, pubKey, &labelData, &importedKey); | |
446 | if(crtn) { | |
447 | ourRtn = -1; | |
448 | goto errOut; | |
449 | } | |
450 | ||
451 | /* don't need this */ | |
452 | CSSM_FreeKey(cspHand, NULL, &importedKey, CSSM_FALSE); | |
453 | ||
454 | /* update the label and printName attributes */ | |
455 | crtn = setPubKeyLabel(cspHand, &dlDbHand, &labelData, digest, &newPrintName); | |
456 | if(crtn) { | |
457 | ourRtn = -1; | |
458 | } | |
459 | errOut: | |
460 | CFRelease(kcRef); | |
461 | if(digest) { | |
462 | APP_FREE(digest->Data); | |
463 | APP_FREE(digest); | |
464 | } | |
465 | return ourRtn; | |
466 | } | |
467 | ||
468 | int main(int argc, char **argv) | |
469 | { | |
470 | char *privKeyFile = NULL; | |
471 | char *pubKeyFile = NULL; | |
472 | char *certFile = NULL; | |
473 | char *outFile = NULL; | |
474 | bool printDigest = false; | |
475 | CSSM_KEYBLOB_FORMAT keyForm = CSSM_KEYBLOB_RAW_FORMAT_NONE; | |
476 | char *kcName = NULL; | |
477 | ||
478 | if(argc < 3) { | |
479 | usage(argv); | |
480 | } | |
481 | extern char *optarg; | |
482 | int arg; | |
483 | while ((arg = getopt(argc, argv, "k:b:c:do:f:K:h")) != -1) { | |
484 | switch (arg) { | |
485 | case 'k': | |
486 | privKeyFile = optarg; | |
487 | break; | |
488 | case 'b': | |
489 | pubKeyFile = optarg; | |
490 | break; | |
491 | case 'c': | |
492 | certFile = optarg; | |
493 | break; | |
494 | case 'd': | |
495 | printDigest = true; | |
496 | break; | |
497 | case 'o': | |
498 | outFile = optarg; | |
499 | break; | |
500 | case 'f': | |
501 | if(!strcmp("pkcs1", optarg)) { | |
502 | keyForm = CSSM_KEYBLOB_RAW_FORMAT_PKCS1; | |
503 | } | |
504 | else if(!strcmp("pkcs8", optarg)) { | |
505 | keyForm = CSSM_KEYBLOB_RAW_FORMAT_PKCS8; | |
506 | } | |
507 | else if(!strcmp("x509", optarg)) { | |
508 | keyForm = CSSM_KEYBLOB_RAW_FORMAT_X509; | |
509 | } | |
510 | break; | |
511 | case 'K': | |
512 | kcName = optarg; | |
513 | break; | |
514 | case 'h': | |
515 | usage(argv); | |
516 | } | |
517 | } | |
518 | if(optind != argc) { | |
519 | usage(argv); | |
520 | } | |
521 | ||
522 | CSSM_DATA privKeyBlob = {0, NULL}; | |
523 | CSSM_DATA pubKeyBlob = {0, NULL}; | |
524 | CSSM_KEY thePrivKey; // constructed | |
525 | CSSM_KEY thePubKey; // null-wrapped | |
526 | CSSM_KEY_PTR pubKey = NULL; | |
527 | CSSM_KEY_PTR privKey = NULL; | |
528 | CSSM_RETURN crtn; | |
529 | CSSM_CL_HANDLE clHand = 0; | |
530 | CSSM_CSP_HANDLE cspHand = cuCspStartup(CSSM_TRUE); | |
531 | ||
532 | /* gather input */ | |
533 | if(privKeyFile) { | |
534 | /* key blob from a file ==> a private CSSM_KEY */ | |
535 | ||
536 | if(pubKeyFile || certFile) { | |
537 | printf("****Specify exactly one of {cert_file, priv_key_file, " | |
538 | "pub_key_file}.\n"); | |
539 | exit(1); | |
540 | } | |
541 | unsigned len; | |
542 | if(readFile(privKeyFile, &privKeyBlob.Data, &len)) { | |
543 | printf("***Error reading private key from %s. Aborting.\n", privKeyFile); | |
544 | exit(1); | |
545 | } | |
546 | privKeyBlob.Length = len; | |
547 | if(keyForm == CSSM_KEYBLOB_RAW_FORMAT_NONE) { | |
548 | /* default for private keys */ | |
549 | keyForm = CSSM_KEYBLOB_RAW_FORMAT_PKCS8; | |
550 | } | |
551 | crtn = inferCssmKey(privKeyBlob, true, keyForm, cspHand, thePrivKey); | |
552 | if(crtn) { | |
553 | goto errOut; | |
554 | } | |
555 | privKey = &thePrivKey; | |
556 | } | |
557 | if(pubKeyFile) { | |
558 | /* key blob from a file ==> a public CSSM_KEY */ | |
559 | ||
560 | if(privKeyFile || certFile) { | |
561 | printf("****Specify exactly one of {cert_file, priv_key_file, " | |
562 | "pub_key_file}.\n"); | |
563 | exit(1); | |
564 | } | |
565 | ||
566 | unsigned len; | |
567 | if(readFile(pubKeyFile, &pubKeyBlob.Data, &len)) { | |
568 | printf("***Error reading public key from %s. Aborting.\n", pubKeyFile); | |
569 | exit(1); | |
570 | } | |
571 | pubKeyBlob.Length = len; | |
572 | if(keyForm == CSSM_KEYBLOB_RAW_FORMAT_NONE) { | |
573 | /* default for public keys */ | |
574 | keyForm = CSSM_KEYBLOB_RAW_FORMAT_PKCS1; | |
575 | } | |
576 | crtn = inferCssmKey(pubKeyBlob, false, keyForm, cspHand, thePubKey); | |
577 | if(crtn) { | |
578 | goto errOut; | |
579 | } | |
580 | pubKey = &thePubKey; | |
581 | } | |
582 | if(certFile) { | |
583 | /* cert from a file ==> a public CSSM_KEY */ | |
584 | ||
585 | if(privKeyFile || pubKeyFile) { | |
586 | printf("****Specify exactly one of {cert_file, priv_key_file, " | |
587 | "pub_key_file}.\n"); | |
588 | exit(1); | |
589 | } | |
590 | ||
591 | CSSM_DATA certData = {0, NULL}; | |
592 | unsigned len; | |
593 | if(readFile(certFile, &certData.Data, &len)) { | |
594 | printf("***Error reading cert from %s. Aborting.\n", certFile); | |
595 | exit(1); | |
596 | } | |
597 | certData.Length = len; | |
598 | ||
599 | /* Extract public key - that's what we will be using later */ | |
600 | clHand = cuClStartup(); | |
601 | crtn = CSSM_CL_CertGetKeyInfo(clHand, &certData, &pubKey); | |
602 | if(crtn) { | |
603 | cssmPerror("CSSM_CL_CertGetKeyInfo", crtn); | |
604 | goto errOut; | |
605 | } | |
606 | } | |
607 | ||
608 | /* now do something useful */ | |
609 | if(printDigest) { | |
610 | CSSM_KEY_PTR theKey = privKey; | |
611 | if(theKey == NULL) { | |
612 | /* maybe we got public key from a cert */ | |
613 | theKey = pubKey; | |
614 | } | |
615 | if(theKey == NULL) { | |
616 | printf("***Can't calculate digest because I don't have a key or a clue.\n"); | |
617 | goto errOut; | |
618 | } | |
619 | CSSM_DATA_PTR dig = NULL; | |
620 | crtn = keyDigest(cspHand, theKey, &dig); | |
621 | if(crtn) { | |
622 | printf("Sorry, can't get the digest for this key.\n"); | |
623 | goto errOut; | |
624 | } | |
625 | if((dig == NULL) || (dig->Length == 0)) { | |
626 | printf("Screwup calculating digest.\n"); | |
627 | goto errOut; | |
628 | } | |
629 | printf("Key Digest:\n"); | |
630 | for(unsigned dex=0; dex<dig->Length; dex++) { | |
631 | printf("%02X ", dig->Data[dex]); | |
632 | } | |
633 | printf("\n"); | |
634 | APP_FREE(dig->Data); | |
635 | APP_FREE(dig); | |
636 | } | |
637 | ||
638 | if(outFile || kcName) { | |
639 | /* get a public key if we don't already have one */ | |
640 | if(pubKey == NULL) { | |
641 | if(privKey == NULL) { | |
642 | printf("***PubKey file name specified but no privKey or cert. " | |
643 | "Aborting.\n"); | |
644 | goto errOut; | |
645 | } | |
646 | crtn = pubKeyFromPrivKey(cspHand, privKey, &thePubKey); | |
647 | if(crtn) { | |
648 | goto errOut; | |
649 | } | |
650 | pubKey = &thePubKey; | |
651 | } | |
652 | } | |
653 | if(outFile) { | |
654 | if(writeFile(outFile, pubKey->KeyData.Data, pubKey->KeyData.Length)) { | |
655 | printf("***Error writing to %s.\n", outFile); | |
656 | } | |
657 | else { | |
658 | printf("...%lu bytes written to %s.\n", pubKey->KeyData.Length, outFile); | |
659 | } | |
660 | } | |
661 | if(kcName) { | |
662 | if(pubKeyImport(kcName, pubKey, cspHand) == 0) { | |
663 | printf("....public key %s imported to %s\n", pubKeyFile, kcName); | |
664 | } | |
665 | else { | |
666 | printf("***Error importing public key %s to %s\n", pubKeyFile, kcName); | |
667 | } | |
668 | } | |
669 | errOut: | |
670 | /* clean up here if you must */ | |
671 | return 0; | |
672 | } |