xref: /illumos-gate/usr/src/cmd/cmd-crypto/pktool/genkeypair.c (revision 6b35cb3cf158584a9408d44b9b6796564e8e1882)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <stdio.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <malloc.h>
30 #include <libgen.h>
31 #include <errno.h>
32 #include <cryptoutil.h>
33 #include <security/cryptoki.h>
34 #include "common.h"
35 
36 #include <kmfapi.h>
37 
38 #define	SET_VALUE(f, s) \
39 	kmfrv = f; \
40 	if (kmfrv != KMF_OK) { \
41 		cryptoerror(LOG_STDERR, \
42 			gettext("Failed to set %s: 0x%02x\n"), \
43 			s, kmfrv); \
44 		goto cleanup; \
45 	}
46 
47 KMF_RETURN
genkeypair_pkcs11(KMF_HANDLE_T kmfhandle,char * token,char * keylabel,KMF_KEY_ALG keyAlg,int keylen,KMF_CREDENTIAL * tokencred,KMF_OID * curveoid,KMF_KEY_HANDLE * outPriKey,KMF_KEY_HANDLE * outPubKey)48 genkeypair_pkcs11(KMF_HANDLE_T kmfhandle,
49 	char *token, char *keylabel, KMF_KEY_ALG keyAlg,
50 	int keylen, KMF_CREDENTIAL *tokencred, KMF_OID *curveoid,
51 	KMF_KEY_HANDLE *outPriKey, KMF_KEY_HANDLE *outPubKey)
52 {
53 	KMF_RETURN kmfrv = KMF_OK;
54 	KMF_KEY_HANDLE pubk, prik;
55 	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
56 	KMF_ATTRIBUTE attrlist[16];
57 	int numattr = 0;
58 	KMF_KEY_ALG keytype;
59 	uint32_t keylength;
60 
61 	keylength = keylen; /* bits */
62 	keytype = keyAlg;
63 
64 	/* Select a PKCS11 token */
65 	kmfrv = select_token(kmfhandle, token, FALSE);
66 	if (kmfrv != KMF_OK)
67 		return (kmfrv);
68 
69 	kmf_set_attr_at_index(attrlist, numattr,
70 	    KMF_KEYSTORE_TYPE_ATTR, &kstype,
71 	    sizeof (kstype));
72 	numattr++;
73 
74 	kmf_set_attr_at_index(attrlist, numattr,
75 	    KMF_KEYALG_ATTR, &keytype,
76 	    sizeof (keytype));
77 	numattr++;
78 
79 	kmf_set_attr_at_index(attrlist, numattr,
80 	    KMF_KEYLENGTH_ATTR, &keylength,
81 	    sizeof (keylength));
82 	numattr++;
83 
84 	if (keylabel != NULL) {
85 		kmf_set_attr_at_index(attrlist, numattr,
86 		    KMF_KEYLABEL_ATTR, keylabel,
87 		    strlen(keylabel));
88 		numattr++;
89 	}
90 
91 	if (tokencred != NULL && tokencred->cred != NULL) {
92 		kmf_set_attr_at_index(attrlist, numattr,
93 		    KMF_CREDENTIAL_ATTR, tokencred,
94 		    sizeof (KMF_CREDENTIAL));
95 		numattr++;
96 	}
97 
98 	kmf_set_attr_at_index(attrlist, numattr,
99 	    KMF_PRIVKEY_HANDLE_ATTR, &prik,
100 	    sizeof (KMF_KEY_HANDLE));
101 	numattr++;
102 
103 	kmf_set_attr_at_index(attrlist, numattr,
104 	    KMF_PUBKEY_HANDLE_ATTR, &pubk,
105 	    sizeof (KMF_KEY_HANDLE));
106 	numattr++;
107 
108 	if (keytype == KMF_ECDSA && curveoid != NULL) {
109 		kmf_set_attr_at_index(attrlist, numattr,
110 		    KMF_ECC_CURVE_OID_ATTR, curveoid,
111 		    sizeof (KMF_OID));
112 		numattr++;
113 	}
114 
115 	kmfrv = kmf_create_keypair(kmfhandle, numattr, attrlist);
116 	if (kmfrv != KMF_OK) {
117 		return (kmfrv);
118 	}
119 
120 cleanup:
121 	if (kmfrv == KMF_OK) {
122 		if (outPriKey != NULL)
123 			*outPriKey = prik;
124 		if (outPubKey != NULL)
125 			*outPubKey = pubk;
126 	}
127 
128 	return (kmfrv);
129 }
130 
131 KMF_RETURN
genkeypair_file(KMF_HANDLE_T kmfhandle,KMF_KEY_ALG keyAlg,int keylen,KMF_ENCODE_FORMAT fmt,char * outkey,KMF_KEY_HANDLE * outPriKey,KMF_KEY_HANDLE * outPubKey)132 genkeypair_file(KMF_HANDLE_T kmfhandle,
133 	KMF_KEY_ALG keyAlg, int keylen, KMF_ENCODE_FORMAT fmt,
134 	char *outkey,
135 	KMF_KEY_HANDLE *outPriKey, KMF_KEY_HANDLE *outPubKey)
136 {
137 	KMF_RETURN kmfrv;
138 	KMF_KEY_HANDLE pubk, prik;
139 	char *fullkeypath = NULL;
140 	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL;
141 	KMF_ATTRIBUTE attrlist[10];
142 	int numattr = 0;
143 	KMF_KEY_ALG keytype;
144 	uint32_t keylength;
145 	KMF_ENCODE_FORMAT format;
146 
147 	if (EMPTYSTRING(outkey)) {
148 		cryptoerror(LOG_STDERR,
149 		    gettext("No output file was specified for "
150 		    "the key\n"));
151 		return (PK_ERR_USAGE);
152 	}
153 
154 	fullkeypath = strdup(outkey);
155 	if (verify_file(fullkeypath)) {
156 		cryptoerror(LOG_STDERR,
157 		    gettext("Cannot write the indicated output "
158 		    "key file (%s).\n"), fullkeypath);
159 		free(fullkeypath);
160 		return (PK_ERR_USAGE);
161 	}
162 
163 	keylength = keylen; /* bits */
164 	keytype = keyAlg;
165 	format = fmt;
166 
167 	kmf_set_attr_at_index(attrlist, numattr,
168 	    KMF_KEYSTORE_TYPE_ATTR, &kstype,
169 	    sizeof (kstype));
170 	numattr++;
171 
172 	kmf_set_attr_at_index(attrlist, numattr,
173 	    KMF_KEYALG_ATTR, &keytype,
174 	    sizeof (keytype));
175 	numattr++;
176 
177 	kmf_set_attr_at_index(attrlist, numattr,
178 	    KMF_KEYLENGTH_ATTR, &keylength,
179 	    sizeof (keylength));
180 	numattr++;
181 
182 	if (fullkeypath != NULL) {
183 		kmf_set_attr_at_index(attrlist, numattr,
184 		    KMF_KEY_FILENAME_ATTR, fullkeypath,
185 		    strlen(fullkeypath));
186 		numattr++;
187 	}
188 
189 	kmf_set_attr_at_index(attrlist, numattr,
190 	    KMF_ENCODE_FORMAT_ATTR, &format,
191 	    sizeof (format));
192 	numattr++;
193 
194 	kmf_set_attr_at_index(attrlist, numattr,
195 	    KMF_PRIVKEY_HANDLE_ATTR, &prik,
196 	    sizeof (KMF_KEY_HANDLE));
197 	numattr++;
198 
199 	kmf_set_attr_at_index(attrlist, numattr,
200 	    KMF_PUBKEY_HANDLE_ATTR, &pubk,
201 	    sizeof (KMF_KEY_HANDLE));
202 	numattr++;
203 
204 	kmfrv = kmf_create_keypair(kmfhandle, numattr, attrlist);
205 	if (kmfrv != KMF_OK) {
206 		goto cleanup;
207 	}
208 
209 cleanup:
210 	if (fullkeypath != NULL)
211 		free(fullkeypath);
212 
213 	if (kmfrv == KMF_OK) {
214 		if (outPriKey != NULL)
215 			*outPriKey = prik;
216 		if (outPubKey != NULL)
217 			*outPubKey = pubk;
218 	}
219 
220 	return (kmfrv);
221 }
222 
223 KMF_RETURN
genkeypair_nss(KMF_HANDLE_T kmfhandle,char * token,char * nickname,char * dir,char * prefix,KMF_KEY_ALG keyAlg,int keylen,KMF_CREDENTIAL * tokencred,KMF_OID * curveoid,KMF_KEY_HANDLE * outPriKey,KMF_KEY_HANDLE * outPubKey)224 genkeypair_nss(KMF_HANDLE_T kmfhandle,
225 	char *token,
226 	char *nickname, char *dir, char *prefix,
227 	KMF_KEY_ALG keyAlg,
228 	int keylen, KMF_CREDENTIAL *tokencred,
229 	KMF_OID *curveoid,
230 	KMF_KEY_HANDLE *outPriKey, KMF_KEY_HANDLE *outPubKey)
231 {
232 	KMF_RETURN kmfrv;
233 	KMF_KEY_HANDLE pubk, prik;
234 	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS;
235 	KMF_ATTRIBUTE attrlist[16];
236 	int numattr = 0;
237 	KMF_KEY_ALG keytype;
238 	uint32_t keylength;
239 
240 	if (token == NULL)
241 		token = DEFAULT_NSS_TOKEN;
242 
243 	kmfrv = configure_nss(kmfhandle, dir, prefix);
244 	if (kmfrv != KMF_OK)
245 		return (kmfrv);
246 
247 	keylength = keylen; /* bits */
248 	keytype = keyAlg;
249 
250 	kmf_set_attr_at_index(attrlist, numattr,
251 	    KMF_KEYSTORE_TYPE_ATTR, &kstype,
252 	    sizeof (kstype));
253 	numattr++;
254 
255 	kmf_set_attr_at_index(attrlist, numattr,
256 	    KMF_KEYALG_ATTR, &keytype,
257 	    sizeof (keytype));
258 	numattr++;
259 
260 	kmf_set_attr_at_index(attrlist, numattr,
261 	    KMF_KEYLENGTH_ATTR, &keylength,
262 	    sizeof (keylength));
263 	numattr++;
264 
265 	if (nickname != NULL) {
266 		kmf_set_attr_at_index(attrlist, numattr,
267 		    KMF_KEYLABEL_ATTR, nickname,
268 		    strlen(nickname));
269 		numattr++;
270 	}
271 
272 	if (tokencred != NULL && tokencred->cred != NULL) {
273 		kmf_set_attr_at_index(attrlist, numattr,
274 		    KMF_CREDENTIAL_ATTR, tokencred,
275 		    sizeof (KMF_CREDENTIAL));
276 		numattr++;
277 	}
278 
279 	if (token != NULL) {
280 		kmf_set_attr_at_index(attrlist, numattr,
281 		    KMF_TOKEN_LABEL_ATTR, token,
282 		    strlen(token));
283 		numattr++;
284 	}
285 
286 	kmf_set_attr_at_index(attrlist, numattr,
287 	    KMF_PRIVKEY_HANDLE_ATTR, &prik,
288 	    sizeof (KMF_KEY_HANDLE));
289 	numattr++;
290 
291 	kmf_set_attr_at_index(attrlist, numattr,
292 	    KMF_PUBKEY_HANDLE_ATTR, &pubk,
293 	    sizeof (KMF_KEY_HANDLE));
294 	numattr++;
295 
296 	if (keytype == KMF_ECDSA && curveoid != NULL) {
297 		kmf_set_attr_at_index(attrlist, numattr,
298 		    KMF_ECC_CURVE_OID_ATTR, curveoid,
299 		    sizeof (KMF_OID));
300 		numattr++;
301 	}
302 
303 	kmfrv = kmf_create_keypair(kmfhandle, numattr, attrlist);
304 	if (kmfrv != KMF_OK) {
305 		return (kmfrv);
306 	}
307 cleanup:
308 	if (kmfrv == KMF_OK) {
309 		if (outPriKey != NULL)
310 			*outPriKey = prik;
311 		if (outPubKey != NULL)
312 			*outPubKey = pubk;
313 	}
314 	return (kmfrv);
315 }
316 
317 int
pk_genkeypair(int argc,char * argv[])318 pk_genkeypair(int argc, char *argv[])
319 {
320 	int rv;
321 	int opt;
322 	extern int	optind_av;
323 	extern char	*optarg_av;
324 	KMF_KEYSTORE_TYPE kstype = 0;
325 	char *tokenname = NULL;
326 	char *dir = NULL;
327 	char *prefix = NULL;
328 	char *keytype = PK_DEFAULT_KEYTYPE;
329 	int keylen = PK_DEFAULT_KEYLENGTH;
330 	char *label = NULL;
331 	char *outkey = NULL;
332 	char *format = NULL;
333 	KMF_HANDLE_T kmfhandle = NULL;
334 	KMF_ENCODE_FORMAT fmt = KMF_FORMAT_ASN1;
335 	KMF_KEY_ALG keyAlg = KMF_RSA;
336 	KMF_ALGORITHM_INDEX sigAlg;
337 	KMF_CREDENTIAL tokencred = { NULL, 0 };
338 	KMF_OID *curveoid = NULL; /* ECC */
339 	int y_flag = 0;
340 
341 	while ((opt = getopt_av(argc, argv,
342 	    "k:(keystore)s:(subject)n:(nickname)"
343 	    "T:(token)d:(dir)p:(prefix)t:(keytype)y:(keylen)"
344 	    "l:(label)K:(outkey)F:(format)C:(curve)"
345 	    "E(listcurves)")) != EOF) {
346 
347 		if (opt != 'i' && opt != 'E' && EMPTYSTRING(optarg_av))
348 			return (PK_ERR_USAGE);
349 
350 		switch (opt) {
351 			case 'k':
352 				kstype = KS2Int(optarg_av);
353 				if (kstype == 0)
354 					return (PK_ERR_USAGE);
355 				break;
356 			case 'l':
357 			case 'n':
358 				if (label)
359 					return (PK_ERR_USAGE);
360 				label = optarg_av;
361 				break;
362 			case 'T':
363 				if (tokenname)
364 					return (PK_ERR_USAGE);
365 				tokenname = optarg_av;
366 				break;
367 			case 'd':
368 				if (dir)
369 					return (PK_ERR_USAGE);
370 				dir = optarg_av;
371 				break;
372 			case 'p':
373 				if (prefix)
374 					return (PK_ERR_USAGE);
375 				prefix = optarg_av;
376 				break;
377 			case 't':
378 				keytype = optarg_av;
379 				break;
380 			case 'y':
381 				if (sscanf(optarg_av, "%d",
382 				    &keylen) != 1) {
383 					cryptoerror(LOG_STDERR,
384 					    gettext("key length must be"
385 					    "a numeric value (%s)\n"),
386 					    optarg_av);
387 					return (PK_ERR_USAGE);
388 				}
389 				y_flag++;
390 				break;
391 			case 'K':
392 				if (outkey)
393 					return (PK_ERR_USAGE);
394 				outkey = optarg_av;
395 				break;
396 			case 'F':
397 				if (format)
398 					return (PK_ERR_USAGE);
399 				format = optarg_av;
400 				break;
401 			case 'C':
402 				curveoid = ecc_name_to_oid(optarg_av);
403 				if (curveoid == NULL) {
404 					cryptoerror(LOG_STDERR,
405 					    gettext(
406 					    "Unrecognized ECC curve.\n"));
407 					return (PK_ERR_USAGE);
408 				}
409 				break;
410 			case 'E':
411 				show_ecc_curves();
412 				return (0);
413 			default:
414 				return (PK_ERR_USAGE);
415 		}
416 	}
417 
418 	/* No additional args allowed. */
419 	argc -= optind_av;
420 	argv += optind_av;
421 	if (argc) {
422 		return (PK_ERR_USAGE);
423 	}
424 
425 	if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
426 		cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n"));
427 		return (PK_ERR_USAGE);
428 	}
429 
430 	/* Assume keystore = PKCS#11 if not specified. */
431 	if (kstype == 0)
432 		kstype = KMF_KEYSTORE_PK11TOKEN;
433 
434 	DIR_OPTION_CHECK(kstype, dir);
435 
436 	if (format && (fmt = Str2Format(format)) == KMF_FORMAT_UNDEF) {
437 		cryptoerror(LOG_STDERR,
438 		    gettext("Error parsing format string (%s).\n"),
439 		    format);
440 		return (PK_ERR_USAGE);
441 	}
442 
443 	if (Str2KeyType(keytype, NULL, &keyAlg, &sigAlg) != 0) {
444 		cryptoerror(LOG_STDERR, gettext("Unrecognized keytype (%s).\n"),
445 		    keytype);
446 		return (PK_ERR_USAGE);
447 	}
448 	if (curveoid != NULL && keyAlg != KMF_ECDSA) {
449 		cryptoerror(LOG_STDERR, gettext("EC curves are only "
450 		    "valid for EC keytypes.\n"));
451 		return (PK_ERR_USAGE);
452 	}
453 	if (keyAlg == KMF_ECDSA && curveoid == NULL) {
454 		cryptoerror(LOG_STDERR, gettext("A curve must be "
455 		    "specifed when using EC keys.\n"));
456 		return (PK_ERR_USAGE);
457 	}
458 	if (keyAlg == KMF_ECDSA && kstype == KMF_KEYSTORE_OPENSSL) {
459 		(void) fprintf(stderr, gettext("ECC certificates are"
460 		    "only supported with the pkcs11 and nss keystores\n"));
461 		rv = PK_ERR_USAGE;
462 		goto end;
463 	}
464 	/* Adjust default keylength for NSS and DSA */
465 	if (keyAlg == KMF_DSA && kstype == KMF_KEYSTORE_NSS) {
466 		/* NSS only allows for 512-1024 bit DSA keys */
467 		if (!y_flag)
468 			/* If nothing was given, default to 1024 */
469 			keylen = 1024;
470 		else if (keylen > 1024 || keylen < 512) {
471 			(void) fprintf(stderr, gettext("NSS keystore only "
472 			    "supports DSA keylengths of 512 - 1024 bits\n"));
473 			rv = PK_ERR_USAGE;
474 			goto end;
475 		}
476 	}
477 
478 	if (kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN) {
479 		if (label == NULL) {
480 			(void) fprintf(stderr,
481 			    gettext("No key label specified\n"));
482 			rv = PK_ERR_USAGE;
483 			goto end;
484 		}
485 		if (tokenname == NULL || !strlen(tokenname)) {
486 			if (kstype == KMF_KEYSTORE_NSS) {
487 				tokenname = "internal";
488 			} else  {
489 				tokenname = PK_DEFAULT_PK11TOKEN;
490 			}
491 		}
492 
493 		(void) get_token_password(kstype, tokenname, &tokencred);
494 	}
495 
496 	if (kstype == KMF_KEYSTORE_NSS) {
497 		if (dir == NULL)
498 			dir = PK_DEFAULT_DIRECTORY;
499 
500 		rv = genkeypair_nss(kmfhandle,
501 		    tokenname, label, dir, prefix, keyAlg, keylen,
502 		    &tokencred, curveoid, NULL, NULL);
503 
504 	} else if (kstype == KMF_KEYSTORE_PK11TOKEN) {
505 		rv = genkeypair_pkcs11(kmfhandle,
506 		    tokenname, label, keyAlg, keylen,
507 		    &tokencred, curveoid, NULL, NULL);
508 
509 	} else if (kstype == KMF_KEYSTORE_OPENSSL) {
510 		rv = genkeypair_file(kmfhandle, keyAlg, keylen,
511 		    fmt, outkey, NULL, NULL);
512 	}
513 
514 	if (rv != KMF_OK)
515 		display_error(kmfhandle, rv,
516 		    gettext("Error creating and keypair"));
517 end:
518 	if (tokencred.cred != NULL)
519 		free(tokencred.cred);
520 
521 	(void) kmf_finalize(kmfhandle);
522 	return (rv);
523 }
524