]> git.saurik.com Git - apple/security.git/blob - CertTool/CertTool/CertUI.cpp
087122f88200555c60cf74fbe53aecc18fd215aa
[apple/security.git] / CertTool / CertTool / CertUI.cpp
1 /*
2 File: CertUI.cpp
3
4 Description: stdio-based routines to get cert info from user.
5
6 Author: dmitch
7
8 Copyright: © Copyright 2002 Apple Computer, Inc. All rights reserved.
9
10 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple
11 Computer, Inc. ("Apple") in consideration of your agreement to
12 the following terms, and your use, installation, modification
13 or redistribution of this Apple software constitutes acceptance
14 of these terms. If you do not agree with these terms, please
15 do not use, install, modify or redistribute this Apple software.
16
17 In consideration of your agreement to abide by the following
18 terms, and subject to these terms, Apple grants you a personal,
19 non-exclusive license, under Apple's copyrights in this
20 original Apple software (the "Apple Software"), to use,
21 reproduce, modify and redistribute the Apple Software, with
22 or without modifications, in source and/or binary forms;
23 provided that if you redistribute the Apple Software in
24 its entirety and without modifications, you must retain
25 this notice and the following text and disclaimers in all
26 such redistributions of the Apple Software. Neither the
27 name, trademarks, service marks or logos of Apple Computer,
28 Inc. may be used to endorse or promote products derived from the
29 Apple Software without specific prior written permission from
30 Apple. Except as expressly stated in this notice, no other
31 rights or licenses, express or implied, are granted by Apple
32 herein, including but not limited to any patent rights that
33 may be infringed by your derivative works or by other works
34 in which the Apple Software may be incorporated.
35
36 The Apple Software is provided by Apple on an "AS IS" basis.
37 APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
38 WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
39 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
40 REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE
41 OR IN COMBINATION WITH YOUR PRODUCTS.
42
43 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT,
44 INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
45 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
48 AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
49 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING
50 NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE
51 HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 */
53
54 #include "CertUI.h"
55 #include <Security/x509defs.h>
56 #include <Security/oidsattr.h>
57 #include <Security/oidscert.h>
58 #include <Security/oidsalg.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <strings.h>
62 #include <ctype.h>
63 #include <cdsaUtils/cdsaUtils.h>
64 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
65
66 void showError(
67 OSStatus ortn,
68 const char *errStr)
69 {
70 printf("%s returned %d\n", errStr, (int)ortn);
71 }
72
73
74 /*
75 * Safe gets().
76 * -- guaranteed no buffer overflow
77 * -- guaranteed NULL-terminated string
78 * -- handles empty string (i.e., response is just CR) properly
79 */
80 void getString(
81 char *buf,
82 unsigned bufSize)
83 {
84 unsigned dex;
85 char c;
86 char *cp = buf;
87
88 for(dex=0; dex<bufSize-1; dex++) {
89 c = getchar();
90 if(!isprint(c)) {
91 break;
92 }
93 switch(c) {
94 case '\n':
95 case '\r':
96 goto done;
97 default:
98 *cp++ = c;
99 }
100 }
101 done:
102 *cp = '\0';
103 }
104
105 /*
106 * Prompt and safe getString.
107 */
108 void getStringWithPrompt(
109 const char *prompt, // need not end in newline
110 char *buf,
111 unsigned bufSize)
112 {
113 fpurge(stdin);
114 printf("%s", prompt);
115 fflush(stdout);
116 getString(buf, bufSize);
117 }
118
119 static const NameOidInfo nameOidInfo[MAX_NAMES] =
120 {
121 { &CSSMOID_CommonName, "Common Name ", "www.apple.com"},
122 { &CSSMOID_CountryName, "Country ", "US"},
123 { &CSSMOID_OrganizationName, "Organization ", "Apple Computer, Inc."},
124 { &CSSMOID_OrganizationalUnitName, "Organization Unit", "Apple Data Security"},
125 { &CSSMOID_StateProvinceName, "State/Province ", "California" }
126 };
127
128 static const char *oidToDesc(
129 const CSSM_OID *oid)
130 {
131 unsigned dex;
132
133 for(dex=0; dex<MAX_NAMES; dex++) {
134 if(cuCompareCssmData(oid, nameOidInfo[dex].oid)) {
135 return nameOidInfo[dex].description;
136 }
137 }
138 printf("oidToDesc error!\n");
139 exit(1);
140 /* NOT REACHED */
141 return NULL;
142 }
143
144 void getNameOids(
145 CSSM_APPLE_TP_NAME_OID *subjectNames, // size MAX_NAMES mallocd by caller
146 uint32 *numNames) // RETURNED
147 {
148 bool ok = false;
149 const NameOidInfo *nameOidIn;
150 CSSM_APPLE_TP_NAME_OID *nameOidOut = subjectNames;
151 unsigned dex;
152 char resp[200];
153 unsigned outNames;
154
155 *numNames = 0;
156 memset(subjectNames, 0, MAX_NAMES * sizeof(CSSM_APPLE_TP_NAME_OID));
157
158 printf("\nYou will now specify the various components of the certificate's\n"
159 "Relative Distinguished Name (RDN). An RDN has a number of \n"
160 "components, all of which are optional, but at least one of \n"
161 "which must be present. \n\n"
162 "Note that if you are creating a certificate for use in an \n"
163 "SSL/TLS server, the Common Name component of the RDN must match\n"
164 "exactly the host name of the server. This must not be an IP\n"
165 "address, but the actual domain name, e.g. www.apple.com.\n\n"
166 "Entering a CR for a given RDN component results in no value for\n"
167 "that component.\n\n");
168 while(!ok) {
169 nameOidOut = subjectNames;
170 outNames = 0;
171 for(dex=0; dex<MAX_NAMES; dex++) {
172 nameOidIn = &nameOidInfo[dex];
173 fpurge(stdin);
174 printf("%s (e.g, %s) : ",
175 nameOidIn->description, nameOidIn->example);
176 fflush(stdout);
177 getString(resp, sizeof(resp));
178 if(resp[0] != '\0') {
179 unsigned len = strlen(resp) + 1;
180 nameOidOut->string = (char *)malloc(len);
181 strcpy((char *)nameOidOut->string, resp);
182 nameOidOut->oid = nameOidIn->oid;
183 nameOidOut++;
184 outNames++;
185 }
186 }
187 if(outNames == 0) {
188 printf("\nYou must enter at least one value RDN component.\n\n");
189 continue;
190 }
191 printf("\nYou have specified:\n");
192 for(dex=0; dex<outNames; dex++) {
193 nameOidOut = &subjectNames[dex];
194 printf(" %s : %s\n", oidToDesc(nameOidOut->oid), nameOidOut->string);
195 }
196 getStringWithPrompt("Is this OK (y/anything)? ", resp, sizeof(resp));
197 if(resp[0] == 'y') {
198 ok = true;
199 break;
200 }
201 }
202 *numNames = outNames;
203 }
204
205 /*
206 * Free strings mallocd in getNameOids.
207 */
208 void freeNameOids(
209 CSSM_APPLE_TP_NAME_OID *subjectNames,
210 uint32 numNames)
211 {
212 for(unsigned i=0; i<numNames; i++) {
213 if(subjectNames[i].string) {
214 free((char *)subjectNames[i].string);
215 }
216 }
217 }
218
219 /* key size verifier - one for each key alg */
220
221 static bool rsaKeySizeVerify(
222 unsigned keySize)
223 {
224 if(keySize < 512) {
225 return false;
226 }
227 if(keySize > 2048) {
228 return false;
229 }
230 return true;
231 }
232
233 static bool dsaKeySizeVerify(
234 unsigned keySize)
235 {
236 return((keySize >= 512) & (keySize <= 2048));
237 }
238
239 static bool feeKeySizeVerify(
240 unsigned keySize)
241 {
242 switch(keySize) {
243 case 128:
244 case 161:
245 case 192:
246 return true;
247 default:
248 return false;
249 }
250 }
251
252 typedef bool (*keySizeVerifyFcn)(unsigned keySize);
253
254 /* map between algorithms, string, char selector, OID */
255 typedef struct _AlgInfo {
256 CSSM_ALGORITHMS alg;
257 char *str;
258 char selector;
259 const CSSM_OID *oid; // only for signatures
260 uint32 defaultKeySize; // only for keys
261 char *keyRangeString; // only for keys
262 const struct _AlgInfo *sigAlgInfo; // only for keys
263 keySizeVerifyFcn vfyFcn; // only for keys
264 } AlgInfo;
265
266 /*
267 * Note: CSSM_ALGID_MD2WithRSA does not work due to an inimplemented
268 * Security Server feature. Even though CSP nad CL support this, we
269 * don't really want to provide this capability anyway - it's a known
270 * insecure digest algorithm.
271 */
272 static const AlgInfo rsaSigAlgInfo[] =
273 {
274 { CSSM_ALGID_MD5WithRSA, "RSA with MD5", '5', &CSSMOID_MD5WithRSA},
275 // { CSSM_ALGID_MD2WithRSA, "RSA with MD2", '2', &CSSMOID_MD2WithRSA},
276 { CSSM_ALGID_SHA1WithRSA, "RSA with SHA1", 's', &CSSMOID_SHA1WithRSA},
277 { CSSM_ALGID_NONE, NULL, 0 }
278 };
279
280 static const AlgInfo feeSigAlgInfo[] =
281 {
282 { CSSM_ALGID_FEE_MD5, "FEE with MD5", '5', &CSSMOID_APPLE_FEE_MD5 },
283 { CSSM_ALGID_FEE_SHA1, "FEE with SHA1", 's', &CSSMOID_APPLE_FEE_SHA1 },
284 { CSSM_ALGID_SHA1WithECDSA, "ECDSA/SHA1", 'e', &CSSMOID_APPLE_ECDSA },
285 { CSSM_ALGID_NONE, NULL, 0, NULL }
286 };
287
288 static const AlgInfo dsaSigAlgInfo[] =
289 {
290 { CSSM_ALGID_SHA1WithDSA, "DSA with SHA1", 's', &CSSMOID_APPLE_FEE_MD5 },
291 { CSSM_ALGID_NONE, NULL, 0, NULL }
292 };
293
294 static const AlgInfo keyAlgInfo[] =
295 {
296 { CSSM_ALGID_RSA, "RSA", 'r', NULL, 512, "512..2048",
297 rsaSigAlgInfo, rsaKeySizeVerify},
298 { CSSM_ALGID_DSA, "DSA", 'd', NULL, 512, "512..2048",
299 dsaSigAlgInfo, dsaKeySizeVerify},
300 { CSSM_ALGID_FEE, "FEE", 'f', NULL, 128, "128, 161, 192",
301 feeSigAlgInfo, feeKeySizeVerify},
302 { CSSM_ALGID_NONE, NULL, 0, NULL }
303 };
304
305
306 /* map a char response to an element of an AlgInfo array */
307 static const AlgInfo *algInfoForSelect(
308 const AlgInfo *algInfo, // NULL terminated
309 char c)
310 {
311 while(algInfo->str != NULL) {
312 if(algInfo->selector == c) {
313 return algInfo;
314 }
315 algInfo++;
316 }
317 /* not found */
318 return NULL;
319 }
320
321 /* map a CSSM_ALGORITHM to an entry in keyAlgInfo[] */
322 static const AlgInfo *algInfoForAlg(
323 CSSM_ALGORITHMS alg)
324 {
325 const AlgInfo *algInfo = keyAlgInfo;
326 while(algInfo->str != NULL) {
327 if(algInfo->alg == alg) {
328 return algInfo;
329 }
330 algInfo++;
331 }
332 /* not found */
333 return NULL;
334 }
335
336 /* get key size and algorithm for subject key */
337 void getKeyParams(
338 CSSM_ALGORITHMS &keyAlg,
339 uint32 &keySizeInBits)
340 {
341 char resp[200];
342 const AlgInfo *keyInfo;
343 const AlgInfo *tempInfo;
344
345 /* get a key algorithm */
346 printf("\nPlease specify parameters for the key pair you will generate.\n\n");
347 while(1) {
348 /* break when we get a valid key algorithm */
349 tempInfo = keyAlgInfo;
350 while(tempInfo->str != NULL) {
351 printf(" %c %s\n", tempInfo->selector, tempInfo->str);
352 tempInfo++;
353 }
354 getStringWithPrompt("\nSelect key algorithm by letter: ", resp, sizeof(resp));
355 if(resp[0] == '\0') {
356 printf("***There is no default. Please choose a key algorithm.\n");
357 continue;
358 }
359 keyInfo = algInfoForSelect(keyAlgInfo, resp[0]);
360 if(keyInfo) {
361 break;
362 }
363 }
364
365 while(1) {
366 /* until we get a valid key size */
367 printf("\nValid key sizes for %s are %s; default is %u\n",
368 keyInfo->str, keyInfo->keyRangeString, (unsigned)keyInfo->defaultKeySize);
369 getStringWithPrompt("Enter key size in bits or CR for default: ",
370 resp, sizeof(resp));
371 if(resp[0] == '\0') {
372 keySizeInBits = keyInfo->defaultKeySize;
373 }
374 else {
375 keySizeInBits = atoi(resp);
376 }
377 if(keyInfo->vfyFcn(keySizeInBits)) {
378 printf("\nYou have selected algorithm %s, key size %u bits.\n",
379 keyInfo->str, (unsigned)keySizeInBits);
380 getStringWithPrompt("OK (y/anything)? ", resp, sizeof(resp));
381 if(resp[0] == 'y') {
382 break;
383 }
384 }
385 else {
386 printf("***%u is not a legal key size for algorithm %s.\n",
387 (unsigned)keySizeInBits, keyInfo->str);
388 }
389 }
390 keyAlg = keyInfo->alg;
391 }
392
393 /* given a signing key, obtain signing algorithm (int and oid format) */
394 OSStatus getSigAlg(
395 const CSSM_KEY *signingKey,
396 CSSM_ALGORITHMS &sigAlg,
397 const CSSM_OID * &sigOid)
398 {
399 char resp[200];
400 const AlgInfo *keyInfo;
401 const AlgInfo *tempInfo;
402 const AlgInfo *sigInfoArray;
403 const AlgInfo *sigInfo;
404
405 keyInfo = algInfoForAlg(signingKey->KeyHeader.AlgorithmId);
406 if(keyInfo == NULL) {
407 printf("***Signing key has unknown algorithm (%u).\n",
408 (unsigned)signingKey->KeyHeader.AlgorithmId);
409 return paramErr;
410 }
411 sigInfoArray = keyInfo->sigAlgInfo;
412 printf("\nPlease specify the algorithm with which your certificate will be "
413 "signed.\n\n");
414 while(1) {
415 /* break when we get a valid sig algorithm */
416 tempInfo = sigInfoArray;
417 while(tempInfo->str != NULL) {
418 printf(" %c %s\n", tempInfo->selector, tempInfo->str);
419 tempInfo++;
420 }
421 getStringWithPrompt("\nSelect signature algorithm by letter: ",
422 resp, sizeof(resp));
423 if(resp[0] == '\0') {
424 printf("***There is no default. Please choose a signature algorithm.\n");
425 continue;
426 }
427 sigInfo = algInfoForSelect(sigInfoArray, resp[0]);
428 if(sigInfo == NULL) {
429 printf("Try again.\n");
430 continue;
431 }
432 printf("\nYou have selected algorithm %s.\n", sigInfo->str);
433 getStringWithPrompt("OK (y/anything)? ", resp, sizeof(resp));
434 if(resp[0] == 'y') {
435 break;
436 }
437 }
438 sigAlg = sigInfo->alg;
439 sigOid = sigInfo->oid;
440 return noErr;
441 }
442
443 CU_KeyUsage getKeyUsage(bool isRoot)
444 {
445 char resp[200];
446 char *prompt;
447
448 if(isRoot) {
449 /* root HAS to be capable of signing */
450 prompt = "Enter cert/key usage (s=signing, b=signing AND encrypting): ";
451 }
452 else {
453 prompt = "Enter cert/key usage (s=signing, e=encrypting, b=both): ";
454 }
455 while(1) {
456 getStringWithPrompt(prompt, resp, sizeof(resp));
457 switch(resp[0]) {
458 case 's':
459 return kKeyUseSigning;
460 case 'e':
461 if(isRoot) {
462 continue;
463 }
464 return kKeyUseEncrypting;
465 case 'b':
466 return kKeyUseSigning | kKeyUseEncrypting;
467
468 }
469 }
470 }
471
472