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