xref: /illumos-gate/usr/src/cmd/cmd-crypto/pktool/export.c (revision 4e93fb0f6383eaac21897dcdae56b87118131e4d)
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 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * This file implements the export operation for this tool.
30  * The basic flow of the process is to find the soft token,
31  * log into it, find the PKCS#11 objects in the soft token
32  * to be exported matching keys with their certificates, export
33  * them to the PKCS#12 file encrypting them with a file password
34  * if desired, and log out.
35  */
36 
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include "common.h"
43 
44 #include <kmfapi.h>
45 
46 static KMF_RETURN
47 pk_find_export_cert(KMF_HANDLE_T kmfhandle, KMF_FINDCERT_PARAMS *parms,
48 	KMF_X509_DER_CERT *cert)
49 {
50 	KMF_RETURN rv = KMF_OK;
51 	uint32_t numcerts = 0;
52 
53 	numcerts = 0;
54 	(void) memset(cert, 0, sizeof (KMF_X509_DER_CERT));
55 	rv = KMF_FindCert(kmfhandle, parms, NULL, &numcerts);
56 	if (rv != KMF_OK) {
57 		return (rv);
58 	}
59 	if (numcerts == 0) {
60 		cryptoerror(LOG_STDERR,
61 			gettext("No matching certificates found."));
62 		return (KMF_ERR_CERT_NOT_FOUND);
63 
64 	} else if (numcerts == 1) {
65 		rv = KMF_FindCert(kmfhandle, parms, cert, &numcerts);
66 
67 	} else if (numcerts > 1) {
68 		cryptoerror(LOG_STDERR,
69 			gettext("%d certificates found, refine the "
70 			"search parameters to eliminate ambiguity\n"),
71 			numcerts);
72 		return (KMF_ERR_BAD_PARAMETER);
73 	}
74 	return (rv);
75 }
76 
77 static KMF_RETURN
78 pk_export_file_objects(KMF_HANDLE_T kmfhandle, int oclass,
79 	char *issuer, char *subject, KMF_BIGINT *serial,
80 	KMF_ENCODE_FORMAT ofmt,
81 	char *dir, char *infile, char *filename)
82 {
83 	KMF_RETURN rv = KMF_OK;
84 	KMF_STORECERT_PARAMS scparms;
85 	KMF_X509_DER_CERT kmfcert;
86 
87 	/* If searching for public objects or certificates, find certs now */
88 	if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) {
89 		KMF_FINDCERT_PARAMS fcargs;
90 
91 		(void) memset(&fcargs, 0, sizeof (fcargs));
92 		fcargs.kstype = KMF_KEYSTORE_OPENSSL;
93 		fcargs.certLabel = NULL;
94 		fcargs.issuer = issuer;
95 		fcargs.subject = subject;
96 		fcargs.serial = serial;
97 		fcargs.sslparms.dirpath = dir;
98 		fcargs.sslparms.certfile = infile;
99 		fcargs.sslparms.format = ofmt;
100 
101 		rv = pk_find_export_cert(kmfhandle, &fcargs, &kmfcert);
102 		if (rv == KMF_OK) {
103 			(void) memset(&scparms, 0, sizeof (scparms));
104 			scparms.kstype = KMF_KEYSTORE_OPENSSL;
105 			scparms.sslparms.certfile = filename;
106 			rv = KMF_StoreCert(kmfhandle, &scparms,
107 				&kmfcert.certificate);
108 
109 			KMF_FreeKMFCert(kmfhandle, &kmfcert);
110 		}
111 	}
112 	return (rv);
113 }
114 
115 static KMF_RETURN
116 pk_export_pk12_nss(KMF_HANDLE_T kmfhandle,
117 	char *token_spec, char *dir, char *prefix,
118 	char *certlabel, char *issuer, char *subject,
119 	KMF_BIGINT *serial, KMF_CREDENTIAL *tokencred,
120 	char *filename)
121 {
122 	KMF_RETURN rv = KMF_OK;
123 	KMF_EXPORTP12_PARAMS p12parms;
124 
125 	rv = configure_nss(kmfhandle, dir, prefix);
126 	if (rv != KMF_OK)
127 		return (rv);
128 
129 	(void) memset(&p12parms, 0, sizeof (p12parms));
130 	if (token_spec == NULL)
131 		token_spec = DEFAULT_NSS_TOKEN;
132 
133 	p12parms.kstype = KMF_KEYSTORE_NSS;
134 	p12parms.certLabel = certlabel;
135 	p12parms.issuer = issuer;
136 	p12parms.subject = subject;
137 	p12parms.serial = serial;
138 	p12parms.idstr = NULL;
139 	if (tokencred != NULL)
140 		p12parms.cred = *tokencred;
141 	p12parms.nssparms.slotlabel = token_spec;
142 
143 	(void) get_pk12_password(&p12parms.p12cred);
144 
145 	rv = KMF_ExportPK12(kmfhandle, &p12parms, filename);
146 	if (p12parms.p12cred.cred)
147 		free(p12parms.p12cred.cred);
148 
149 	return (rv);
150 }
151 
152 static KMF_RETURN
153 pk_export_pk12_files(KMF_HANDLE_T kmfhandle,
154 	char *certfile, char *keyfile, char *dir,
155 	char *outfile)
156 {
157 	KMF_RETURN rv;
158 	KMF_EXPORTP12_PARAMS p12parms;
159 
160 	(void) memset(&p12parms, 0, sizeof (p12parms));
161 
162 	p12parms.kstype = KMF_KEYSTORE_OPENSSL;
163 	p12parms.certLabel = NULL;
164 	p12parms.issuer = NULL;
165 	p12parms.subject = NULL;
166 	p12parms.serial = 0;
167 	p12parms.idstr = NULL;
168 	p12parms.sslparms.dirpath = dir;
169 	p12parms.sslparms.certfile = certfile;
170 	p12parms.sslparms.keyfile = keyfile;
171 
172 	(void) get_pk12_password(&p12parms.p12cred);
173 
174 	rv = KMF_ExportPK12(kmfhandle, &p12parms, outfile);
175 
176 	if (p12parms.p12cred.cred)
177 		free(p12parms.p12cred.cred);
178 
179 	return (rv);
180 }
181 
182 static KMF_RETURN
183 pk_export_nss_objects(KMF_HANDLE_T kmfhandle, char *token_spec,
184 	int oclass, char *certlabel, char *issuer, char *subject,
185 	KMF_BIGINT *serial, KMF_ENCODE_FORMAT kfmt, char *dir,
186 	char *prefix, char *filename)
187 {
188 	KMF_RETURN rv = KMF_OK;
189 	KMF_STORECERT_PARAMS scparms;
190 	KMF_X509_DER_CERT kmfcert;
191 
192 	rv = configure_nss(kmfhandle, dir, prefix);
193 	if (rv != KMF_OK)
194 		return (rv);
195 
196 	/* If searching for public objects or certificates, find certs now */
197 	if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) {
198 		KMF_FINDCERT_PARAMS fcargs;
199 
200 		(void) memset(&fcargs, 0, sizeof (fcargs));
201 		fcargs.kstype = KMF_KEYSTORE_NSS;
202 		fcargs.certLabel = certlabel;
203 		fcargs.issuer = issuer;
204 		fcargs.subject = subject;
205 		fcargs.serial = serial;
206 		fcargs.nssparms.slotlabel = token_spec;
207 
208 		rv = pk_find_export_cert(kmfhandle, &fcargs, &kmfcert);
209 		if (rv == KMF_OK) {
210 			(void) memset(&scparms, 0, sizeof (scparms));
211 			scparms.kstype = KMF_KEYSTORE_OPENSSL;
212 			scparms.sslparms.certfile = filename;
213 			scparms.sslparms.format = kfmt;
214 
215 			rv = KMF_StoreCert(kmfhandle, &scparms,
216 				&kmfcert.certificate);
217 
218 			KMF_FreeKMFCert(kmfhandle, &kmfcert);
219 		}
220 	}
221 	return (rv);
222 }
223 
224 static KMF_RETURN
225 pk_export_pk12_pk11(KMF_HANDLE_T kmfhandle, char *token_spec,
226 	char *certlabel, char *issuer, char *subject,
227 	KMF_BIGINT *serial, KMF_CREDENTIAL *tokencred, char *filename)
228 {
229 	KMF_RETURN rv = KMF_OK;
230 	KMF_EXPORTP12_PARAMS p12parms;
231 
232 	rv = select_token(kmfhandle, token_spec, TRUE);
233 	if (rv != KMF_OK) {
234 		return (rv);
235 	}
236 
237 	(void) memset(&p12parms, 0, sizeof (p12parms));
238 
239 	p12parms.kstype = KMF_KEYSTORE_PK11TOKEN;
240 	p12parms.certLabel = certlabel;
241 	p12parms.issuer = issuer;
242 	p12parms.subject = subject;
243 	p12parms.serial = serial;
244 	p12parms.idstr = NULL;
245 	if (tokencred != NULL)
246 		p12parms.cred = *tokencred;
247 	(void) get_pk12_password(&p12parms.p12cred);
248 
249 	rv = KMF_ExportPK12(kmfhandle, &p12parms, filename);
250 
251 	if (p12parms.p12cred.cred)
252 		free(p12parms.p12cred.cred);
253 
254 	return (rv);
255 }
256 
257 static KMF_RETURN
258 pk_export_pk11_objects(KMF_HANDLE_T kmfhandle, char *token_spec,
259 	char *certlabel, char *issuer, char *subject,
260 	KMF_BIGINT *serial, KMF_ENCODE_FORMAT kfmt,
261 	char *filename)
262 {
263 	KMF_RETURN rv = KMF_OK;
264 	KMF_FINDCERT_PARAMS fcparms;
265 	KMF_STORECERT_PARAMS scparms;
266 	KMF_X509_DER_CERT kmfcert;
267 
268 	rv = select_token(kmfhandle, token_spec, TRUE);
269 
270 	if (rv != KMF_OK) {
271 		return (rv);
272 	}
273 
274 	(void) memset(&fcparms, 0, sizeof (fcparms));
275 	fcparms.kstype = KMF_KEYSTORE_PK11TOKEN;
276 	fcparms.certLabel = certlabel;
277 	fcparms.issuer = issuer;
278 	fcparms.subject = subject;
279 	fcparms.serial = serial;
280 
281 	rv = pk_find_export_cert(kmfhandle, &fcparms, &kmfcert);
282 
283 	if (rv == KMF_OK) {
284 		(void) memset(&scparms, 0, sizeof (scparms));
285 		scparms.kstype = KMF_KEYSTORE_OPENSSL;
286 		scparms.sslparms.certfile = filename;
287 		scparms.sslparms.format = kfmt;
288 
289 		rv = KMF_StoreCert(kmfhandle, &scparms,
290 			&kmfcert.certificate);
291 
292 		KMF_FreeKMFCert(kmfhandle, &kmfcert);
293 	}
294 	return (rv);
295 }
296 
297 /*
298  * Export objects from one keystore to a file.
299  */
300 int
301 pk_export(int argc, char *argv[])
302 {
303 	int		opt;
304 	extern int	optind_av;
305 	extern char	*optarg_av;
306 	char		*token_spec = NULL;
307 	char		*filename = NULL;
308 	char		*dir = NULL;
309 	char		*prefix = NULL;
310 	char		*certlabel = NULL;
311 	char		*subject = NULL;
312 	char		*issuer = NULL;
313 	char		*infile = NULL;
314 	char		*keyfile = NULL;
315 	char		*certfile = NULL;
316 	char		*serstr = NULL;
317 	KMF_KEYSTORE_TYPE	kstype = 0;
318 	KMF_ENCODE_FORMAT	kfmt = KMF_FORMAT_PKCS12;
319 	KMF_RETURN		rv = KMF_OK;
320 	int		oclass = PK_CERT_OBJ;
321 	KMF_BIGINT	serial = { NULL, 0 };
322 	KMF_HANDLE_T	kmfhandle = NULL;
323 	KMF_CREDENTIAL	tokencred = {NULL, 0};
324 
325 	/* Parse command line options.  Do NOT i18n/l10n. */
326 	while ((opt = getopt_av(argc, argv,
327 		"k:(keystore)y:(objtype)T:(token)"
328 		"d:(dir)p:(prefix)"
329 		"l:(label)n:(nickname)s:(subject)"
330 		"i:(issuer)S:(serial)"
331 		"K:(keyfile)c:(certfile)"
332 		"F:(outformat)"
333 		"I:(infile)o:(outfile)")) != EOF) {
334 		if (EMPTYSTRING(optarg_av))
335 			return (PK_ERR_USAGE);
336 		switch (opt) {
337 		case 'k':
338 			kstype = KS2Int(optarg_av);
339 			if (kstype == 0)
340 				return (PK_ERR_USAGE);
341 			break;
342 		case 'y':
343 			oclass = OT2Int(optarg_av);
344 			if (oclass == -1)
345 				return (PK_ERR_USAGE);
346 			break;
347 		case 'T':	/* token specifier */
348 			if (token_spec)
349 				return (PK_ERR_USAGE);
350 			token_spec = optarg_av;
351 			break;
352 		case 'd':
353 			if (dir)
354 				return (PK_ERR_USAGE);
355 			dir = optarg_av;
356 			break;
357 		case 'p':
358 			if (prefix)
359 				return (PK_ERR_USAGE);
360 			prefix = optarg_av;
361 			break;
362 		case 'n':
363 		case 'l':
364 			if (certlabel)
365 				return (PK_ERR_USAGE);
366 			certlabel = optarg_av;
367 			break;
368 		case 's':
369 			if (subject)
370 				return (PK_ERR_USAGE);
371 			subject = optarg_av;
372 			break;
373 		case 'i':
374 			if (issuer)
375 				return (PK_ERR_USAGE);
376 			issuer = optarg_av;
377 			break;
378 		case 'S':
379 			serstr = optarg_av;
380 			break;
381 		case 'F':
382 			kfmt = Str2Format(optarg_av);
383 			if (kfmt == KMF_FORMAT_UNDEF)
384 				return (PK_ERR_USAGE);
385 			break;
386 		case 'I':	/* output file name */
387 			if (infile)
388 				return (PK_ERR_USAGE);
389 			infile = optarg_av;
390 			break;
391 		case 'o':	/* output file name */
392 			if (filename)
393 				return (PK_ERR_USAGE);
394 			filename = optarg_av;
395 			break;
396 		case 'c':	/* input cert file name */
397 			if (certfile)
398 				return (PK_ERR_USAGE);
399 			certfile = optarg_av;
400 			break;
401 		case 'K':	/* input key file name */
402 			if (keyfile)
403 				return (PK_ERR_USAGE);
404 			keyfile = optarg_av;
405 			break;
406 		default:
407 			return (PK_ERR_USAGE);
408 			break;
409 		}
410 	}
411 
412 	/* Assume keystore = PKCS#11 if not specified */
413 	if (kstype == 0)
414 		kstype = KMF_KEYSTORE_PK11TOKEN;
415 
416 	/* Filename arg is required. */
417 	if (EMPTYSTRING(filename)) {
418 		cryptoerror(LOG_STDERR, gettext("You must specify "
419 			"an 'outfile' parameter when exporting.\n"));
420 		return (PK_ERR_USAGE);
421 	}
422 
423 	/* No additional args allowed. */
424 	argc -= optind_av;
425 	argv += optind_av;
426 	if (argc)
427 		return (PK_ERR_USAGE);
428 
429 	/* if PUBLIC or PRIVATE obj was given, the old syntax was used. */
430 	if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) &&
431 		kstype != KMF_KEYSTORE_PK11TOKEN) {
432 
433 		(void) fprintf(stderr, gettext("The objtype parameter "
434 			"is only relevant if keystore=pkcs11\n"));
435 		return (PK_ERR_USAGE);
436 	}
437 
438 	if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec))
439 		token_spec = PK_DEFAULT_PK11TOKEN;
440 	else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec))
441 		token_spec = DEFAULT_NSS_TOKEN;
442 
443 	if (kstype == KMF_KEYSTORE_OPENSSL) {
444 		if (kfmt != KMF_FORMAT_PKCS12) {
445 			cryptoerror(LOG_STDERR, gettext("PKCS12 "
446 				"is the only export format "
447 				"supported for the 'file' "
448 				"keystore.\n"));
449 			return (PK_ERR_USAGE);
450 		}
451 		if (EMPTYSTRING(keyfile) || EMPTYSTRING(certfile)) {
452 			cryptoerror(LOG_STDERR, gettext("A cert file"
453 				"and a key file must be specified "
454 				"when exporting to PKCS12 from the "
455 				"'file' keystore.\n"));
456 			return (PK_ERR_USAGE);
457 		}
458 	}
459 
460 	/* Check if the file exists and might be overwritten. */
461 	if (access(filename, F_OK) == 0) {
462 		cryptoerror(LOG_STDERR,
463 			gettext("Warning: file \"%s\" exists, "
464 				"will be overwritten."), filename);
465 		if (yesno(gettext("Continue with export? "),
466 		    gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) {
467 			return (0);
468 		}
469 	} else {
470 		rv = verify_file(filename);
471 		if (rv != KMF_OK) {
472 			cryptoerror(LOG_STDERR, gettext("The file (%s) "
473 				"cannot be created.\n"), filename);
474 			return (PK_ERR_USAGE);
475 		}
476 	}
477 
478 	if (serstr != NULL) {
479 		uchar_t *bytes = NULL;
480 		size_t bytelen;
481 
482 		rv = KMF_HexString2Bytes((uchar_t *)serstr, &bytes, &bytelen);
483 		if (rv != KMF_OK || bytes == NULL) {
484 			(void) fprintf(stderr, gettext("serial number "
485 				"must be specified as a hex number "
486 				"(ex: 0x0102030405ffeeddee)\n"));
487 			return (PK_ERR_USAGE);
488 		}
489 		serial.val = bytes;
490 		serial.len = bytelen;
491 	}
492 
493 	if ((kstype == KMF_KEYSTORE_PK11TOKEN ||
494 		kstype == KMF_KEYSTORE_NSS) &&
495 		(oclass & (PK_KEY_OBJ | PK_PRIVATE_OBJ) ||
496 		kfmt == KMF_FORMAT_PKCS12)) {
497 			(void) get_token_password(kstype, token_spec,
498 				&tokencred);
499 	}
500 
501 	if ((rv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
502 		cryptoerror(LOG_STDERR, gettext("Error initializing "
503 				"KMF: 0x%02x\n"), rv);
504 		return (rv);
505 	}
506 
507 	switch (kstype) {
508 		case KMF_KEYSTORE_PK11TOKEN:
509 			if (kfmt == KMF_FORMAT_PKCS12)
510 				rv = pk_export_pk12_pk11(
511 					kmfhandle,
512 					token_spec,
513 					certlabel,
514 					issuer, subject,
515 					&serial, &tokencred,
516 					filename);
517 			else
518 				rv = pk_export_pk11_objects(kmfhandle,
519 					token_spec,
520 					certlabel,
521 					issuer, subject,
522 					&serial, kfmt,
523 					filename);
524 			break;
525 		case KMF_KEYSTORE_NSS:
526 			if (dir == NULL)
527 				dir = PK_DEFAULT_DIRECTORY;
528 			if (kfmt == KMF_FORMAT_PKCS12)
529 				rv = pk_export_pk12_nss(kmfhandle,
530 					token_spec, dir, prefix,
531 					certlabel, issuer,
532 					subject, &serial,
533 					&tokencred, filename);
534 			else
535 				rv = pk_export_nss_objects(kmfhandle,
536 					token_spec,
537 					oclass, certlabel, issuer, subject,
538 					&serial, kfmt, dir, prefix, filename);
539 			break;
540 		case KMF_KEYSTORE_OPENSSL:
541 			if (kfmt == KMF_FORMAT_PKCS12)
542 				rv = pk_export_pk12_files(kmfhandle,
543 					certfile, keyfile, dir,
544 					filename);
545 			else
546 				rv = pk_export_file_objects(kmfhandle, oclass,
547 					issuer, subject, &serial, kfmt,
548 					dir, infile, filename);
549 			break;
550 		default:
551 			rv = PK_ERR_USAGE;
552 			break;
553 	}
554 
555 	if (rv != KMF_OK) {
556 		display_error(kmfhandle, rv,
557 			gettext("Error exporting objects"));
558 	}
559 
560 	if (serial.val != NULL)
561 		free(serial.val);
562 
563 	(void) KMF_Finalize(kmfhandle);
564 
565 	return (rv);
566 }
567