xref: /illumos-gate/usr/src/cmd/cmd-crypto/pktool/genkeypair.c (revision 33efde4275d24731ef87927237b0ffb0630b6b2d)
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 	if (kmfrv == KMF_OK) {
121 		if (outPriKey != NULL)
122 			*outPriKey = prik;
123 		if (outPubKey != NULL)
124 			*outPubKey = pubk;
125 	}
126 
127 	return (kmfrv);
128 }
129 
130 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)131 genkeypair_file(KMF_HANDLE_T kmfhandle,
132 	KMF_KEY_ALG keyAlg, int keylen, KMF_ENCODE_FORMAT fmt,
133 	char *outkey,
134 	KMF_KEY_HANDLE *outPriKey, KMF_KEY_HANDLE *outPubKey)
135 {
136 	KMF_RETURN kmfrv;
137 	KMF_KEY_HANDLE pubk, prik;
138 	char *fullkeypath = NULL;
139 	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL;
140 	KMF_ATTRIBUTE attrlist[10];
141 	int numattr = 0;
142 	KMF_KEY_ALG keytype;
143 	uint32_t keylength;
144 	KMF_ENCODE_FORMAT format;
145 
146 	if (EMPTYSTRING(outkey)) {
147 		cryptoerror(LOG_STDERR,
148 		    gettext("No output file was specified for "
149 		    "the key\n"));
150 		return (PK_ERR_USAGE);
151 	}
152 
153 	fullkeypath = strdup(outkey);
154 	if (verify_file(fullkeypath)) {
155 		cryptoerror(LOG_STDERR,
156 		    gettext("Cannot write the indicated output "
157 		    "key file (%s).\n"), fullkeypath);
158 		free(fullkeypath);
159 		return (PK_ERR_USAGE);
160 	}
161 
162 	keylength = keylen; /* bits */
163 	keytype = keyAlg;
164 	format = fmt;
165 
166 	kmf_set_attr_at_index(attrlist, numattr,
167 	    KMF_KEYSTORE_TYPE_ATTR, &kstype,
168 	    sizeof (kstype));
169 	numattr++;
170 
171 	kmf_set_attr_at_index(attrlist, numattr,
172 	    KMF_KEYALG_ATTR, &keytype,
173 	    sizeof (keytype));
174 	numattr++;
175 
176 	kmf_set_attr_at_index(attrlist, numattr,
177 	    KMF_KEYLENGTH_ATTR, &keylength,
178 	    sizeof (keylength));
179 	numattr++;
180 
181 	if (fullkeypath != NULL) {
182 		kmf_set_attr_at_index(attrlist, numattr,
183 		    KMF_KEY_FILENAME_ATTR, fullkeypath,
184 		    strlen(fullkeypath));
185 		numattr++;
186 	}
187 
188 	kmf_set_attr_at_index(attrlist, numattr,
189 	    KMF_ENCODE_FORMAT_ATTR, &format,
190 	    sizeof (format));
191 	numattr++;
192 
193 	kmf_set_attr_at_index(attrlist, numattr,
194 	    KMF_PRIVKEY_HANDLE_ATTR, &prik,
195 	    sizeof (KMF_KEY_HANDLE));
196 	numattr++;
197 
198 	kmf_set_attr_at_index(attrlist, numattr,
199 	    KMF_PUBKEY_HANDLE_ATTR, &pubk,
200 	    sizeof (KMF_KEY_HANDLE));
201 	numattr++;
202 
203 	kmfrv = kmf_create_keypair(kmfhandle, numattr, attrlist);
204 	if (kmfrv != KMF_OK) {
205 		goto cleanup;
206 	}
207 
208 cleanup:
209 	if (fullkeypath != NULL)
210 		free(fullkeypath);
211 
212 	if (kmfrv == KMF_OK) {
213 		if (outPriKey != NULL)
214 			*outPriKey = prik;
215 		if (outPubKey != NULL)
216 			*outPubKey = pubk;
217 	}
218 
219 	return (kmfrv);
220 }
221 
222 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)223 genkeypair_nss(KMF_HANDLE_T kmfhandle,
224 	char *token,
225 	char *nickname, char *dir, char *prefix,
226 	KMF_KEY_ALG keyAlg,
227 	int keylen, KMF_CREDENTIAL *tokencred,
228 	KMF_OID *curveoid,
229 	KMF_KEY_HANDLE *outPriKey, KMF_KEY_HANDLE *outPubKey)
230 {
231 	KMF_RETURN kmfrv;
232 	KMF_KEY_HANDLE pubk, prik;
233 	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS;
234 	KMF_ATTRIBUTE attrlist[16];
235 	int numattr = 0;
236 	KMF_KEY_ALG keytype;
237 	uint32_t keylength;
238 
239 	if (token == NULL)
240 		token = DEFAULT_NSS_TOKEN;
241 
242 	kmfrv = configure_nss(kmfhandle, dir, prefix);
243 	if (kmfrv != KMF_OK)
244 		return (kmfrv);
245 
246 	keylength = keylen; /* bits */
247 	keytype = keyAlg;
248 
249 	kmf_set_attr_at_index(attrlist, numattr,
250 	    KMF_KEYSTORE_TYPE_ATTR, &kstype,
251 	    sizeof (kstype));
252 	numattr++;
253 
254 	kmf_set_attr_at_index(attrlist, numattr,
255 	    KMF_KEYALG_ATTR, &keytype,
256 	    sizeof (keytype));
257 	numattr++;
258 
259 	kmf_set_attr_at_index(attrlist, numattr,
260 	    KMF_KEYLENGTH_ATTR, &keylength,
261 	    sizeof (keylength));
262 	numattr++;
263 
264 	if (nickname != NULL) {
265 		kmf_set_attr_at_index(attrlist, numattr,
266 		    KMF_KEYLABEL_ATTR, nickname,
267 		    strlen(nickname));
268 		numattr++;
269 	}
270 
271 	if (tokencred != NULL && tokencred->cred != NULL) {
272 		kmf_set_attr_at_index(attrlist, numattr,
273 		    KMF_CREDENTIAL_ATTR, tokencred,
274 		    sizeof (KMF_CREDENTIAL));
275 		numattr++;
276 	}
277 
278 	if (token != NULL) {
279 		kmf_set_attr_at_index(attrlist, numattr,
280 		    KMF_TOKEN_LABEL_ATTR, token,
281 		    strlen(token));
282 		numattr++;
283 	}
284 
285 	kmf_set_attr_at_index(attrlist, numattr,
286 	    KMF_PRIVKEY_HANDLE_ATTR, &prik,
287 	    sizeof (KMF_KEY_HANDLE));
288 	numattr++;
289 
290 	kmf_set_attr_at_index(attrlist, numattr,
291 	    KMF_PUBKEY_HANDLE_ATTR, &pubk,
292 	    sizeof (KMF_KEY_HANDLE));
293 	numattr++;
294 
295 	if (keytype == KMF_ECDSA && curveoid != NULL) {
296 		kmf_set_attr_at_index(attrlist, numattr,
297 		    KMF_ECC_CURVE_OID_ATTR, curveoid,
298 		    sizeof (KMF_OID));
299 		numattr++;
300 	}
301 
302 	kmfrv = kmf_create_keypair(kmfhandle, numattr, attrlist);
303 	if (kmfrv != KMF_OK) {
304 		return (kmfrv);
305 	}
306 
307 	if (kmfrv == KMF_OK) {
308 		if (outPriKey != NULL)
309 			*outPriKey = prik;
310 		if (outPubKey != NULL)
311 			*outPubKey = pubk;
312 	}
313 	return (kmfrv);
314 }
315 
316 int
pk_genkeypair(int argc,char * argv[])317 pk_genkeypair(int argc, char *argv[])
318 {
319 	int rv;
320 	int opt;
321 	extern int	optind_av;
322 	extern char	*optarg_av;
323 	KMF_KEYSTORE_TYPE kstype = 0;
324 	char *tokenname = NULL;
325 	char *dir = NULL;
326 	char *prefix = NULL;
327 	char *keytype = PK_DEFAULT_KEYTYPE;
328 	int keylen = PK_DEFAULT_KEYLENGTH;
329 	char *label = NULL;
330 	char *outkey = NULL;
331 	char *format = NULL;
332 	KMF_HANDLE_T kmfhandle = NULL;
333 	KMF_ENCODE_FORMAT fmt = KMF_FORMAT_ASN1;
334 	KMF_KEY_ALG keyAlg = KMF_RSA;
335 	KMF_ALGORITHM_INDEX sigAlg;
336 	KMF_CREDENTIAL tokencred = { NULL, 0 };
337 	KMF_OID *curveoid = NULL; /* ECC */
338 	int y_flag = 0;
339 
340 	while ((opt = getopt_av(argc, argv,
341 	    "k:(keystore)s:(subject)n:(nickname)"
342 	    "T:(token)d:(dir)p:(prefix)t:(keytype)y:(keylen)"
343 	    "l:(label)K:(outkey)F:(format)C:(curve)"
344 	    "E(listcurves)")) != EOF) {
345 
346 		if (opt != 'i' && opt != 'E' && EMPTYSTRING(optarg_av))
347 			return (PK_ERR_USAGE);
348 
349 		switch (opt) {
350 			case 'k':
351 				kstype = KS2Int(optarg_av);
352 				if (kstype == 0)
353 					return (PK_ERR_USAGE);
354 				break;
355 			case 'l':
356 			case 'n':
357 				if (label)
358 					return (PK_ERR_USAGE);
359 				label = optarg_av;
360 				break;
361 			case 'T':
362 				if (tokenname)
363 					return (PK_ERR_USAGE);
364 				tokenname = optarg_av;
365 				break;
366 			case 'd':
367 				if (dir)
368 					return (PK_ERR_USAGE);
369 				dir = optarg_av;
370 				break;
371 			case 'p':
372 				if (prefix)
373 					return (PK_ERR_USAGE);
374 				prefix = optarg_av;
375 				break;
376 			case 't':
377 				keytype = optarg_av;
378 				break;
379 			case 'y':
380 				if (sscanf(optarg_av, "%d",
381 				    &keylen) != 1) {
382 					cryptoerror(LOG_STDERR,
383 					    gettext("key length must be"
384 					    "a numeric value (%s)\n"),
385 					    optarg_av);
386 					return (PK_ERR_USAGE);
387 				}
388 				y_flag++;
389 				break;
390 			case 'K':
391 				if (outkey)
392 					return (PK_ERR_USAGE);
393 				outkey = optarg_av;
394 				break;
395 			case 'F':
396 				if (format)
397 					return (PK_ERR_USAGE);
398 				format = optarg_av;
399 				break;
400 			case 'C':
401 				curveoid = ecc_name_to_oid(optarg_av);
402 				if (curveoid == NULL) {
403 					cryptoerror(LOG_STDERR,
404 					    gettext(
405 					    "Unrecognized ECC curve.\n"));
406 					return (PK_ERR_USAGE);
407 				}
408 				break;
409 			case 'E':
410 				show_ecc_curves();
411 				return (0);
412 			default:
413 				return (PK_ERR_USAGE);
414 		}
415 	}
416 
417 	/* No additional args allowed. */
418 	argc -= optind_av;
419 	argv += optind_av;
420 	if (argc) {
421 		return (PK_ERR_USAGE);
422 	}
423 
424 	if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
425 		cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n"));
426 		return (PK_ERR_USAGE);
427 	}
428 
429 	/* Assume keystore = PKCS#11 if not specified. */
430 	if (kstype == 0)
431 		kstype = KMF_KEYSTORE_PK11TOKEN;
432 
433 	DIR_OPTION_CHECK(kstype, dir);
434 
435 	if (format && (fmt = Str2Format(format)) == KMF_FORMAT_UNDEF) {
436 		cryptoerror(LOG_STDERR,
437 		    gettext("Error parsing format string (%s).\n"),
438 		    format);
439 		return (PK_ERR_USAGE);
440 	}
441 
442 	if (Str2KeyType(keytype, NULL, &keyAlg, &sigAlg) != 0) {
443 		cryptoerror(LOG_STDERR, gettext("Unrecognized keytype (%s).\n"),
444 		    keytype);
445 		return (PK_ERR_USAGE);
446 	}
447 	if (curveoid != NULL && keyAlg != KMF_ECDSA) {
448 		cryptoerror(LOG_STDERR, gettext("EC curves are only "
449 		    "valid for EC keytypes.\n"));
450 		return (PK_ERR_USAGE);
451 	}
452 	if (keyAlg == KMF_ECDSA && curveoid == NULL) {
453 		cryptoerror(LOG_STDERR, gettext("A curve must be "
454 		    "specifed when using EC keys.\n"));
455 		return (PK_ERR_USAGE);
456 	}
457 	if (keyAlg == KMF_ECDSA && kstype == KMF_KEYSTORE_OPENSSL) {
458 		(void) fprintf(stderr, gettext("ECC certificates are"
459 		    "only supported with the pkcs11 and nss keystores\n"));
460 		rv = PK_ERR_USAGE;
461 		goto end;
462 	}
463 	/* Adjust default keylength for NSS and DSA */
464 	if (keyAlg == KMF_DSA && kstype == KMF_KEYSTORE_NSS) {
465 		/* NSS only allows for 512-1024 bit DSA keys */
466 		if (!y_flag)
467 			/* If nothing was given, default to 1024 */
468 			keylen = 1024;
469 		else if (keylen > 1024 || keylen < 512) {
470 			(void) fprintf(stderr, gettext("NSS keystore only "
471 			    "supports DSA keylengths of 512 - 1024 bits\n"));
472 			rv = PK_ERR_USAGE;
473 			goto end;
474 		}
475 	}
476 
477 	if (kstype == KMF_KEYSTORE_NSS || kstype == KMF_KEYSTORE_PK11TOKEN) {
478 		if (label == NULL) {
479 			(void) fprintf(stderr,
480 			    gettext("No key label specified\n"));
481 			rv = PK_ERR_USAGE;
482 			goto end;
483 		}
484 		if (tokenname == NULL || !strlen(tokenname)) {
485 			if (kstype == KMF_KEYSTORE_NSS) {
486 				tokenname = "internal";
487 			} else  {
488 				tokenname = PK_DEFAULT_PK11TOKEN;
489 			}
490 		}
491 
492 		(void) get_token_password(kstype, tokenname, &tokencred);
493 	}
494 
495 	if (kstype == KMF_KEYSTORE_NSS) {
496 		if (dir == NULL)
497 			dir = PK_DEFAULT_DIRECTORY;
498 
499 		rv = genkeypair_nss(kmfhandle,
500 		    tokenname, label, dir, prefix, keyAlg, keylen,
501 		    &tokencred, curveoid, NULL, NULL);
502 
503 	} else if (kstype == KMF_KEYSTORE_PK11TOKEN) {
504 		rv = genkeypair_pkcs11(kmfhandle,
505 		    tokenname, label, keyAlg, keylen,
506 		    &tokencred, curveoid, NULL, NULL);
507 
508 	} else if (kstype == KMF_KEYSTORE_OPENSSL) {
509 		rv = genkeypair_file(kmfhandle, keyAlg, keylen,
510 		    fmt, outkey, NULL, NULL);
511 	}
512 
513 	if (rv != KMF_OK)
514 		display_error(kmfhandle, rv,
515 		    gettext("Error creating and keypair"));
516 end:
517 	if (tokencred.cred != NULL)
518 		free(tokencred.cred);
519 
520 	(void) kmf_finalize(kmfhandle);
521 	return (rv);
522 }
523