xref: /illumos-gate/usr/src/cmd/cmd-crypto/pktool/export.c (revision 99dda20867d903eec23291ba1ecb18a82d70096b)
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 2007 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_ATTRIBUTE *attrlist,
48 	int numattr, 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 
56 	kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR,
57 	    &numcerts, sizeof (uint32_t));
58 	numattr++;
59 
60 	rv = kmf_find_cert(kmfhandle, numattr, attrlist);
61 	if (rv != KMF_OK) {
62 		return (rv);
63 	}
64 	if (numcerts == 0) {
65 		cryptoerror(LOG_STDERR,
66 		    gettext("No matching certificates found."));
67 		return (KMF_ERR_CERT_NOT_FOUND);
68 
69 	} else if (numcerts == 1) {
70 		kmf_set_attr_at_index(attrlist, numattr,
71 		    KMF_X509_DER_CERT_ATTR, cert,
72 		    sizeof (KMF_X509_DER_CERT));
73 		numattr++;
74 		rv = kmf_find_cert(kmfhandle, numattr, attrlist);
75 
76 	} else if (numcerts > 1) {
77 		cryptoerror(LOG_STDERR,
78 		    gettext("%d certificates found, refine the "
79 		    "search parameters to eliminate ambiguity\n"),
80 		    numcerts);
81 		return (KMF_ERR_BAD_PARAMETER);
82 	}
83 	return (rv);
84 }
85 
86 static KMF_RETURN
87 pk_export_file_objects(KMF_HANDLE_T kmfhandle, int oclass,
88 	char *issuer, char *subject, KMF_BIGINT *serial,
89 	char *dir, char *infile, char *filename)
90 {
91 	KMF_RETURN rv = KMF_OK;
92 	KMF_X509_DER_CERT kmfcert;
93 	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_OPENSSL;
94 	int numattr = 0;
95 	KMF_ATTRIBUTE attrlist[16];
96 
97 	/* If searching for public objects or certificates, find certs now */
98 	if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) {
99 		kmf_set_attr_at_index(attrlist, numattr,
100 		    KMF_KEYSTORE_TYPE_ATTR, &kstype,
101 		    sizeof (kstype));
102 		numattr++;
103 
104 		if (issuer != NULL) {
105 			kmf_set_attr_at_index(attrlist, numattr,
106 			    KMF_ISSUER_NAME_ATTR, issuer,
107 			    strlen(issuer));
108 			numattr++;
109 		}
110 
111 		if (subject != NULL) {
112 			kmf_set_attr_at_index(attrlist, numattr,
113 			    KMF_SUBJECT_NAME_ATTR, subject,
114 			    strlen(subject));
115 			numattr++;
116 		}
117 
118 		if (serial != NULL) {
119 			kmf_set_attr_at_index(attrlist, numattr,
120 			    KMF_BIGINT_ATTR, serial,
121 			    sizeof (KMF_BIGINT));
122 			numattr++;
123 		}
124 
125 		if (dir != NULL) {
126 			kmf_set_attr_at_index(attrlist, numattr,
127 			    KMF_DIRPATH_ATTR, dir,
128 			    strlen(dir));
129 			numattr++;
130 		}
131 
132 		if (infile != NULL) {
133 			kmf_set_attr_at_index(attrlist, numattr,
134 			    KMF_CERT_FILENAME_ATTR, infile,
135 			    strlen(infile));
136 			numattr++;
137 		}
138 
139 		rv = pk_find_export_cert(kmfhandle, attrlist, numattr,
140 		    &kmfcert);
141 		if (rv == KMF_OK) {
142 			kstype = KMF_KEYSTORE_OPENSSL;
143 			numattr = 0;
144 
145 			kmf_set_attr_at_index(attrlist, numattr,
146 			    KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype));
147 			numattr++;
148 
149 			kmf_set_attr_at_index(attrlist, numattr,
150 			    KMF_CERT_DATA_ATTR, &kmfcert.certificate,
151 			    sizeof (KMF_DATA));
152 			numattr++;
153 
154 			kmf_set_attr_at_index(attrlist, numattr,
155 			    KMF_CERT_FILENAME_ATTR, filename,
156 			    strlen(filename));
157 			numattr++;
158 
159 			rv = kmf_store_cert(kmfhandle, numattr,
160 			    attrlist);
161 
162 			kmf_free_kmf_cert(kmfhandle, &kmfcert);
163 		}
164 	}
165 	return (rv);
166 }
167 
168 static KMF_RETURN
169 pk_export_pk12_nss(KMF_HANDLE_T kmfhandle,
170 	char *token_spec, char *dir, char *prefix,
171 	char *certlabel, char *issuer, char *subject,
172 	KMF_BIGINT *serial, KMF_CREDENTIAL *tokencred,
173 	char *filename)
174 {
175 	KMF_RETURN rv = KMF_OK;
176 	KMF_KEYSTORE_TYPE kstype;
177 	KMF_CREDENTIAL p12cred = { NULL, 0};
178 	KMF_ATTRIBUTE attrlist[16];
179 	int numattr = 0;
180 
181 	rv = configure_nss(kmfhandle, dir, prefix);
182 	if (rv != KMF_OK)
183 		return (rv);
184 
185 	if (token_spec == NULL)
186 		token_spec = DEFAULT_NSS_TOKEN;
187 
188 	kstype = KMF_KEYSTORE_NSS;
189 	kmf_set_attr_at_index(attrlist, numattr,
190 	    KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype));
191 	numattr++;
192 
193 	if (certlabel != NULL) {
194 		kmf_set_attr_at_index(attrlist, numattr,
195 		    KMF_CERT_LABEL_ATTR, certlabel, strlen(certlabel));
196 		numattr++;
197 	}
198 
199 	if (issuer != NULL) {
200 		kmf_set_attr_at_index(attrlist, numattr,
201 		    KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer));
202 		numattr++;
203 	}
204 
205 	if (subject != NULL) {
206 		kmf_set_attr_at_index(attrlist, numattr,
207 		    KMF_SUBJECT_NAME_ATTR, subject, strlen(subject));
208 		numattr++;
209 	}
210 
211 	if (serial != NULL) {
212 		kmf_set_attr_at_index(attrlist, numattr,
213 		    KMF_BIGINT_ATTR, serial, sizeof (KMF_BIGINT));
214 		numattr++;
215 	}
216 
217 	if (tokencred != NULL) {
218 		kmf_set_attr_at_index(attrlist, numattr,
219 		    KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL));
220 		numattr++;
221 	}
222 
223 	kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_LABEL_ATTR,
224 	    token_spec, strlen(token_spec));
225 	numattr++;
226 
227 	(void) get_pk12_password(&p12cred);
228 	kmf_set_attr_at_index(attrlist, numattr,
229 	    KMF_PK12CRED_ATTR, &p12cred, sizeof (KMF_CREDENTIAL));
230 	numattr++;
231 
232 	kmf_set_attr_at_index(attrlist, numattr,
233 	    KMF_OUTPUT_FILENAME_ATTR, filename, strlen(filename));
234 	numattr++;
235 
236 	rv = kmf_export_pk12(kmfhandle, numattr, attrlist);
237 
238 	if (p12cred.cred)
239 		free(p12cred.cred);
240 
241 	return (rv);
242 }
243 
244 static KMF_RETURN
245 pk_export_pk12_files(KMF_HANDLE_T kmfhandle,
246 	char *certfile, char *keyfile, char *dir,
247 	char *outfile)
248 {
249 	KMF_RETURN rv;
250 	KMF_KEYSTORE_TYPE kstype;
251 	KMF_CREDENTIAL p12cred = { NULL, 0};
252 	KMF_ATTRIBUTE attrlist[16];
253 	int numattr = 0;
254 
255 	kstype = KMF_KEYSTORE_OPENSSL;
256 	kmf_set_attr_at_index(attrlist, numattr,
257 	    KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype));
258 	numattr++;
259 
260 	if (dir != NULL) {
261 		kmf_set_attr_at_index(attrlist, numattr,
262 		    KMF_DIRPATH_ATTR, dir, strlen(dir));
263 		numattr++;
264 	}
265 
266 	if (certfile != NULL) {
267 		kmf_set_attr_at_index(attrlist, numattr,
268 		    KMF_CERT_FILENAME_ATTR, certfile, strlen(certfile));
269 		numattr++;
270 	}
271 
272 	if (keyfile != NULL) {
273 		kmf_set_attr_at_index(attrlist, numattr,
274 		    KMF_KEY_FILENAME_ATTR, keyfile, strlen(keyfile));
275 		numattr++;
276 	}
277 
278 	(void) get_pk12_password(&p12cred);
279 	kmf_set_attr_at_index(attrlist, numattr,
280 	    KMF_PK12CRED_ATTR, &p12cred, sizeof (KMF_CREDENTIAL));
281 	numattr++;
282 
283 	kmf_set_attr_at_index(attrlist, numattr,
284 	    KMF_OUTPUT_FILENAME_ATTR, outfile, strlen(outfile));
285 	numattr++;
286 
287 	rv = kmf_export_pk12(kmfhandle, numattr, attrlist);
288 
289 	if (p12cred.cred)
290 		free(p12cred.cred);
291 
292 	return (rv);
293 }
294 
295 static KMF_RETURN
296 pk_export_nss_objects(KMF_HANDLE_T kmfhandle, char *token_spec,
297 	int oclass, char *certlabel, char *issuer, char *subject,
298 	KMF_BIGINT *serial, KMF_ENCODE_FORMAT kfmt, char *dir,
299 	char *prefix, char *filename)
300 {
301 	KMF_RETURN rv = KMF_OK;
302 	KMF_X509_DER_CERT kmfcert;
303 	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_NSS;
304 	KMF_ATTRIBUTE attrlist[16];
305 	int numattr = 0;
306 
307 	rv = configure_nss(kmfhandle, dir, prefix);
308 	if (rv != KMF_OK)
309 		return (rv);
310 
311 	/* If searching for public objects or certificates, find certs now */
312 	if (oclass & (PK_CERT_OBJ | PK_PUBLIC_OBJ)) {
313 		kmf_set_attr_at_index(attrlist, numattr,
314 		    KMF_KEYSTORE_TYPE_ATTR, &kstype,
315 		    sizeof (kstype));
316 		numattr++;
317 
318 		if (certlabel != NULL) {
319 			kmf_set_attr_at_index(attrlist, numattr,
320 			    KMF_CERT_LABEL_ATTR, certlabel,
321 			    strlen(certlabel));
322 			numattr++;
323 		}
324 
325 		if (issuer != NULL) {
326 			kmf_set_attr_at_index(attrlist, numattr,
327 			    KMF_ISSUER_NAME_ATTR, issuer,
328 			    strlen(issuer));
329 			numattr++;
330 		}
331 
332 		if (subject != NULL) {
333 			kmf_set_attr_at_index(attrlist, numattr,
334 			    KMF_SUBJECT_NAME_ATTR, subject,
335 			    strlen(subject));
336 			numattr++;
337 		}
338 
339 		if (serial != NULL) {
340 			kmf_set_attr_at_index(attrlist, numattr,
341 			    KMF_BIGINT_ATTR, serial,
342 			    sizeof (KMF_BIGINT));
343 			numattr++;
344 		}
345 
346 		if (token_spec != NULL) {
347 			kmf_set_attr_at_index(attrlist, numattr,
348 			    KMF_TOKEN_LABEL_ATTR, token_spec,
349 			    strlen(token_spec));
350 			numattr++;
351 		}
352 
353 		rv = pk_find_export_cert(kmfhandle, attrlist, numattr,
354 		    &kmfcert);
355 		if (rv == KMF_OK) {
356 			kstype = KMF_KEYSTORE_OPENSSL;
357 			numattr = 0;
358 
359 			kmf_set_attr_at_index(attrlist, numattr,
360 			    KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype));
361 			numattr++;
362 
363 			kmf_set_attr_at_index(attrlist, numattr,
364 			    KMF_CERT_DATA_ATTR, &kmfcert.certificate,
365 			    sizeof (KMF_DATA));
366 			numattr++;
367 
368 			kmf_set_attr_at_index(attrlist, numattr,
369 			    KMF_CERT_FILENAME_ATTR, filename,
370 			    strlen(filename));
371 			numattr++;
372 
373 			kmf_set_attr_at_index(attrlist, numattr,
374 			    KMF_ENCODE_FORMAT_ATTR, &kfmt, sizeof (kfmt));
375 			numattr++;
376 
377 			rv = kmf_store_cert(kmfhandle, numattr, attrlist);
378 
379 			kmf_free_kmf_cert(kmfhandle, &kmfcert);
380 		}
381 	}
382 	return (rv);
383 }
384 
385 static KMF_RETURN
386 pk_export_pk12_pk11(KMF_HANDLE_T kmfhandle, char *token_spec,
387 	char *certlabel, char *issuer, char *subject,
388 	KMF_BIGINT *serial, KMF_CREDENTIAL *tokencred, char *filename)
389 {
390 	KMF_RETURN rv = KMF_OK;
391 	KMF_KEYSTORE_TYPE kstype;
392 	KMF_CREDENTIAL p12cred = { NULL, 0};
393 	KMF_ATTRIBUTE attrlist[16];
394 	int numattr = 0;
395 
396 	rv = select_token(kmfhandle, token_spec, TRUE);
397 	if (rv != KMF_OK) {
398 		return (rv);
399 	}
400 
401 	kstype = KMF_KEYSTORE_PK11TOKEN;
402 	kmf_set_attr_at_index(attrlist, numattr,
403 	    KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype));
404 	numattr++;
405 
406 	if (certlabel != NULL) {
407 		kmf_set_attr_at_index(attrlist, numattr,
408 		    KMF_CERT_LABEL_ATTR, certlabel, strlen(certlabel));
409 		numattr++;
410 	}
411 
412 	if (issuer != NULL) {
413 		kmf_set_attr_at_index(attrlist, numattr,
414 		    KMF_ISSUER_NAME_ATTR, issuer, strlen(issuer));
415 		numattr++;
416 	}
417 
418 	if (subject != NULL) {
419 		kmf_set_attr_at_index(attrlist, numattr,
420 		    KMF_SUBJECT_NAME_ATTR, subject, strlen(subject));
421 		numattr++;
422 	}
423 
424 	if (serial != NULL) {
425 		kmf_set_attr_at_index(attrlist, numattr,
426 		    KMF_BIGINT_ATTR, serial, sizeof (KMF_BIGINT));
427 		numattr++;
428 	}
429 
430 	if (tokencred != NULL) {
431 		kmf_set_attr_at_index(attrlist, numattr,
432 		    KMF_CREDENTIAL_ATTR, tokencred, sizeof (KMF_CREDENTIAL));
433 		numattr++;
434 	}
435 
436 	(void) get_pk12_password(&p12cred);
437 	kmf_set_attr_at_index(attrlist, numattr,
438 	    KMF_PK12CRED_ATTR, &p12cred, sizeof (KMF_CREDENTIAL));
439 	numattr++;
440 
441 	kmf_set_attr_at_index(attrlist, numattr,
442 	    KMF_OUTPUT_FILENAME_ATTR, filename, strlen(filename));
443 	numattr++;
444 
445 	rv = kmf_export_pk12(kmfhandle, numattr, attrlist);
446 
447 	if (p12cred.cred)
448 		free(p12cred.cred);
449 
450 	return (rv);
451 }
452 
453 static KMF_RETURN
454 pk_export_pk11_keys(KMF_HANDLE_T kmfhandle, char *token,
455 	KMF_CREDENTIAL *cred, KMF_ENCODE_FORMAT format,
456 	char *label, char *filename, int oclass)
457 {
458 	KMF_RETURN rv = KMF_OK;
459 	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
460 	KMF_KEY_CLASS kclass = KMF_KEYCLASS_NONE;
461 	int numattr = 0;
462 	uint32_t numkeys = 1;
463 	KMF_ATTRIBUTE attrlist[16];
464 	KMF_KEY_HANDLE key;
465 	boolean_t is_token = B_TRUE;
466 
467 	if (EMPTYSTRING(label)) {
468 		cryptoerror(LOG_STDERR, gettext("A label "
469 		    "must be specified to export a key."));
470 		return (KMF_ERR_BAD_PARAMETER);
471 	}
472 
473 	rv = select_token(kmfhandle, token, TRUE);
474 	if (rv != KMF_OK) {
475 		return (rv);
476 	}
477 
478 	kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
479 	    &kstype, sizeof (kstype));
480 	numattr++;
481 
482 	if (cred != NULL) {
483 		kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR,
484 		    cred, sizeof (KMF_CREDENTIAL));
485 		numattr++;
486 	}
487 
488 	kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR,
489 	    label, strlen(label));
490 	numattr++;
491 
492 	kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR,
493 	    &numkeys, sizeof (numkeys));
494 	numattr++;
495 
496 	kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR,
497 	    &key, sizeof (key));
498 	numattr++;
499 
500 	kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_BOOL_ATTR,
501 	    &is_token, sizeof (is_token));
502 	numattr++;
503 
504 	kmf_set_attr_at_index(attrlist, numattr, KMF_ENCODE_FORMAT_ATTR,
505 	    &format, sizeof (format));
506 	numattr++;
507 
508 	/* Check to see if we are exporting private or public only */
509 	if ((oclass & PK_KEY_OBJ) == PK_PRIKEY_OBJ)
510 		kclass = KMF_ASYM_PRI;
511 	else if ((oclass & PK_KEY_OBJ) == PK_PUBKEY_OBJ)
512 		kclass = KMF_ASYM_PUB;
513 	else if ((oclass & PK_KEY_OBJ) == PK_SYMKEY_OBJ)
514 		kclass = KMF_SYMMETRIC;
515 	else /* only 1 key at a time can be exported here, so default to pri */
516 		kclass = KMF_ASYM_PRI;
517 
518 	kmf_set_attr_at_index(attrlist, numattr, KMF_KEYCLASS_ATTR,
519 	    &kclass, sizeof (kclass));
520 	numattr++;
521 
522 	rv = kmf_find_key(kmfhandle, numattr, attrlist);
523 	/*
524 	 * If nothing found but caller wanted ALL keys, try symmetric
525 	 * this time.
526 	 */
527 	if (rv == KMF_ERR_KEY_NOT_FOUND && (oclass == PK_KEY_OBJ)) {
528 		kclass = KMF_SYMMETRIC;
529 		rv = kmf_find_key(kmfhandle, numattr, attrlist);
530 	}
531 	/*
532 	 * If nothing found but caller wanted ALL keys, try asymmetric
533 	 * public this time.
534 	 */
535 	if (rv == KMF_ERR_KEY_NOT_FOUND && (oclass == PK_KEY_OBJ)) {
536 		kclass = KMF_ASYM_PUB;
537 		rv = kmf_find_key(kmfhandle, numattr, attrlist);
538 	}
539 	if (rv == KMF_OK && key.keyclass == KMF_SYMMETRIC) {
540 		KMF_RAW_SYM_KEY rkey;
541 
542 		(void) memset(&rkey, 0, sizeof (KMF_RAW_SYM_KEY));
543 		rv = kmf_get_sym_key_value(kmfhandle, &key, &rkey);
544 		if (rv == KMF_OK) {
545 			int fd, n, total = 0;
546 
547 			fd = open(filename, O_CREAT | O_RDWR |O_TRUNC, 0600);
548 			if (fd == -1) {
549 				rv = KMF_ERR_OPEN_FILE;
550 				goto done;
551 			}
552 			do {
553 				n = write(fd, rkey.keydata.val + total,
554 				    rkey.keydata.len - total);
555 				if (n < 0) {
556 					if (errno == EINTR)
557 						continue;
558 					(void) close(fd);
559 					rv = KMF_ERR_WRITE_FILE;
560 					goto done;
561 				}
562 				total += n;
563 
564 			} while (total < rkey.keydata.len);
565 			(void) close(fd);
566 		}
567 done:
568 		kmf_free_bigint(&rkey.keydata);
569 		kmf_free_kmf_key(kmfhandle, &key);
570 	} else if (rv == KMF_OK) {
571 		KMF_KEYSTORE_TYPE sslks = KMF_KEYSTORE_OPENSSL;
572 		(void) printf(gettext("Found %d asymmetric keys\n"), numkeys);
573 
574 		numattr = 0;
575 		kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
576 		    &sslks, sizeof (sslks));
577 		numattr++;
578 
579 		kmf_set_attr_at_index(attrlist, numattr, KMF_RAW_KEY_ATTR,
580 		    key.keyp, sizeof (KMF_RAW_KEY_DATA));
581 		numattr++;
582 
583 		kmf_set_attr_at_index(attrlist, numattr, KMF_ENCODE_FORMAT_ATTR,
584 		    &format, sizeof (format));
585 		numattr++;
586 
587 		kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_FILENAME_ATTR,
588 		    filename, strlen(filename));
589 		numattr++;
590 
591 		kmf_set_attr_at_index(attrlist, numattr, KMF_KEYCLASS_ATTR,
592 		    &key.keyclass, sizeof (KMF_KEY_CLASS));
593 		numattr++;
594 
595 		rv = kmf_store_key(kmfhandle, numattr, attrlist);
596 		kmf_free_kmf_key(kmfhandle, &key);
597 	}
598 
599 	return (rv);
600 }
601 
602 static KMF_RETURN
603 pk_export_pk11_objects(KMF_HANDLE_T kmfhandle, char *token_spec,
604 	char *certlabel, char *issuer, char *subject,
605 	KMF_BIGINT *serial, KMF_ENCODE_FORMAT kfmt,
606 	char *filename)
607 {
608 	KMF_RETURN rv = KMF_OK;
609 	KMF_X509_DER_CERT kmfcert;
610 	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
611 	int numattr = 0;
612 	KMF_ATTRIBUTE attrlist[16];
613 
614 	rv = select_token(kmfhandle, token_spec, TRUE);
615 
616 	if (rv != KMF_OK) {
617 		return (rv);
618 	}
619 
620 	kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
621 	    &kstype, sizeof (kstype));
622 	numattr++;
623 
624 	if (certlabel != NULL) {
625 		kmf_set_attr_at_index(attrlist, numattr,
626 		    KMF_CERT_LABEL_ATTR, certlabel,
627 		    strlen(certlabel));
628 		numattr++;
629 	}
630 
631 	if (issuer != NULL) {
632 		kmf_set_attr_at_index(attrlist, numattr,
633 		    KMF_ISSUER_NAME_ATTR, issuer,
634 		    strlen(issuer));
635 		numattr++;
636 	}
637 
638 	if (subject != NULL) {
639 		kmf_set_attr_at_index(attrlist, numattr,
640 		    KMF_SUBJECT_NAME_ATTR, subject,
641 		    strlen(subject));
642 		numattr++;
643 	}
644 
645 	if (serial != NULL) {
646 		kmf_set_attr_at_index(attrlist, numattr,
647 		    KMF_BIGINT_ATTR, serial,
648 		    sizeof (KMF_BIGINT));
649 		numattr++;
650 	}
651 
652 	rv = pk_find_export_cert(kmfhandle, attrlist, numattr, &kmfcert);
653 
654 	if (rv == KMF_OK) {
655 		kstype = KMF_KEYSTORE_OPENSSL;
656 		numattr = 0;
657 
658 		kmf_set_attr_at_index(attrlist, numattr,
659 		    KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype));
660 		numattr++;
661 
662 		kmf_set_attr_at_index(attrlist, numattr,
663 		    KMF_CERT_DATA_ATTR, &kmfcert.certificate,
664 		    sizeof (KMF_DATA));
665 		numattr++;
666 
667 		kmf_set_attr_at_index(attrlist, numattr,
668 		    KMF_CERT_FILENAME_ATTR, filename, strlen(filename));
669 		numattr++;
670 
671 		kmf_set_attr_at_index(attrlist, numattr,
672 		    KMF_ENCODE_FORMAT_ATTR, &kfmt, sizeof (kfmt));
673 		numattr++;
674 
675 		rv = kmf_store_cert(kmfhandle, numattr, attrlist);
676 
677 		kmf_free_kmf_cert(kmfhandle, &kmfcert);
678 	}
679 	return (rv);
680 }
681 
682 /*
683  * Export objects from one keystore to a file.
684  */
685 int
686 pk_export(int argc, char *argv[])
687 {
688 	int		opt;
689 	extern int	optind_av;
690 	extern char	*optarg_av;
691 	char		*token_spec = NULL;
692 	char		*filename = NULL;
693 	char		*dir = NULL;
694 	char		*prefix = NULL;
695 	char		*certlabel = NULL;
696 	char		*subject = NULL;
697 	char		*issuer = NULL;
698 	char		*infile = NULL;
699 	char		*keyfile = NULL;
700 	char		*certfile = NULL;
701 	char		*serstr = NULL;
702 	KMF_KEYSTORE_TYPE	kstype = 0;
703 	KMF_ENCODE_FORMAT	kfmt = KMF_FORMAT_PKCS12;
704 	KMF_RETURN		rv = KMF_OK;
705 	int		oclass = PK_CERT_OBJ;
706 	KMF_BIGINT	serial = { NULL, 0 };
707 	KMF_HANDLE_T	kmfhandle = NULL;
708 	KMF_CREDENTIAL	tokencred = {NULL, 0};
709 
710 	/* Parse command line options.  Do NOT i18n/l10n. */
711 	while ((opt = getopt_av(argc, argv,
712 	    "k:(keystore)y:(objtype)T:(token)"
713 	    "d:(dir)p:(prefix)"
714 	    "l:(label)n:(nickname)s:(subject)"
715 	    "i:(issuer)S:(serial)"
716 	    "K:(keyfile)c:(certfile)"
717 	    "F:(outformat)"
718 	    "I:(infile)o:(outfile)")) != EOF) {
719 		if (EMPTYSTRING(optarg_av))
720 			return (PK_ERR_USAGE);
721 		switch (opt) {
722 		case 'k':
723 			kstype = KS2Int(optarg_av);
724 			if (kstype == 0)
725 				return (PK_ERR_USAGE);
726 			break;
727 		case 'y':
728 			oclass = OT2Int(optarg_av);
729 			if (oclass == -1)
730 				return (PK_ERR_USAGE);
731 			break;
732 		case 'T':	/* token specifier */
733 			if (token_spec)
734 				return (PK_ERR_USAGE);
735 			token_spec = optarg_av;
736 			break;
737 		case 'd':
738 			if (dir)
739 				return (PK_ERR_USAGE);
740 			dir = optarg_av;
741 			break;
742 		case 'p':
743 			if (prefix)
744 				return (PK_ERR_USAGE);
745 			prefix = optarg_av;
746 			break;
747 		case 'n':
748 		case 'l':
749 			if (certlabel)
750 				return (PK_ERR_USAGE);
751 			certlabel = optarg_av;
752 			break;
753 		case 's':
754 			if (subject)
755 				return (PK_ERR_USAGE);
756 			subject = optarg_av;
757 			break;
758 		case 'i':
759 			if (issuer)
760 				return (PK_ERR_USAGE);
761 			issuer = optarg_av;
762 			break;
763 		case 'S':
764 			serstr = optarg_av;
765 			break;
766 		case 'F':
767 			kfmt = Str2Format(optarg_av);
768 			if (kfmt == KMF_FORMAT_UNDEF)
769 				return (PK_ERR_USAGE);
770 			break;
771 		case 'I':	/* output file name */
772 			if (infile)
773 				return (PK_ERR_USAGE);
774 			infile = optarg_av;
775 			break;
776 		case 'o':	/* output file name */
777 			if (filename)
778 				return (PK_ERR_USAGE);
779 			filename = optarg_av;
780 			break;
781 		case 'c':	/* input cert file name */
782 			if (certfile)
783 				return (PK_ERR_USAGE);
784 			certfile = optarg_av;
785 			break;
786 		case 'K':	/* input key file name */
787 			if (keyfile)
788 				return (PK_ERR_USAGE);
789 			keyfile = optarg_av;
790 			break;
791 		default:
792 			return (PK_ERR_USAGE);
793 			break;
794 		}
795 	}
796 
797 	/* Assume keystore = PKCS#11 if not specified */
798 	if (kstype == 0)
799 		kstype = KMF_KEYSTORE_PK11TOKEN;
800 
801 	/* Filename arg is required. */
802 	if (EMPTYSTRING(filename)) {
803 		cryptoerror(LOG_STDERR, gettext("You must specify "
804 		    "an 'outfile' parameter when exporting.\n"));
805 		return (PK_ERR_USAGE);
806 	}
807 
808 	/* No additional args allowed. */
809 	argc -= optind_av;
810 	argv += optind_av;
811 	if (argc)
812 		return (PK_ERR_USAGE);
813 
814 	/* if PUBLIC or PRIVATE obj was given, the old syntax was used. */
815 	if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) &&
816 	    kstype != KMF_KEYSTORE_PK11TOKEN) {
817 
818 		(void) fprintf(stderr, gettext("The objtype parameter "
819 		    "is only relevant if keystore=pkcs11\n"));
820 		return (PK_ERR_USAGE);
821 	}
822 
823 	if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec))
824 		token_spec = PK_DEFAULT_PK11TOKEN;
825 	else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec))
826 		token_spec = DEFAULT_NSS_TOKEN;
827 
828 	if (kstype == KMF_KEYSTORE_OPENSSL) {
829 		if (kfmt != KMF_FORMAT_PKCS12) {
830 			cryptoerror(LOG_STDERR, gettext("PKCS12 "
831 			    "is the only export format "
832 			    "supported for the 'file' "
833 			    "keystore.\n"));
834 			return (PK_ERR_USAGE);
835 		}
836 		if (EMPTYSTRING(keyfile) || EMPTYSTRING(certfile)) {
837 			cryptoerror(LOG_STDERR, gettext("A cert file"
838 			    "and a key file must be specified "
839 			    "when exporting to PKCS12 from the "
840 			    "'file' keystore.\n"));
841 			return (PK_ERR_USAGE);
842 		}
843 	}
844 
845 	/* Check if the file exists and might be overwritten. */
846 	if (access(filename, F_OK) == 0) {
847 		cryptoerror(LOG_STDERR,
848 		    gettext("Warning: file \"%s\" exists, "
849 		    "will be overwritten."), filename);
850 		if (yesno(gettext("Continue with export? "),
851 		    gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) {
852 			return (0);
853 		} else {
854 			/* remove the file */
855 			(void) unlink(filename);
856 		}
857 	} else {
858 		rv = verify_file(filename);
859 		if (rv != KMF_OK) {
860 			cryptoerror(LOG_STDERR, gettext("The file (%s) "
861 			    "cannot be created.\n"), filename);
862 			return (PK_ERR_USAGE);
863 		}
864 	}
865 
866 	if (serstr != NULL) {
867 		uchar_t *bytes = NULL;
868 		size_t bytelen;
869 
870 		rv = kmf_hexstr_to_bytes((uchar_t *)serstr, &bytes, &bytelen);
871 		if (rv != KMF_OK || bytes == NULL) {
872 			(void) fprintf(stderr, gettext("serial number "
873 			    "must be specified as a hex number "
874 			    "(ex: 0x0102030405ffeeddee)\n"));
875 			return (PK_ERR_USAGE);
876 		}
877 		serial.val = bytes;
878 		serial.len = bytelen;
879 	}
880 
881 	if ((kstype == KMF_KEYSTORE_PK11TOKEN ||
882 	    kstype == KMF_KEYSTORE_NSS) &&
883 	    (oclass & (PK_KEY_OBJ | PK_PRIVATE_OBJ) ||
884 	    kfmt == KMF_FORMAT_PKCS12)) {
885 			(void) get_token_password(kstype, token_spec,
886 			    &tokencred);
887 	}
888 
889 	if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
890 		cryptoerror(LOG_STDERR, gettext("Error initializing "
891 		    "KMF: 0x%02x\n"), rv);
892 		return (rv);
893 	}
894 
895 	switch (kstype) {
896 		case KMF_KEYSTORE_PK11TOKEN:
897 			if (kfmt == KMF_FORMAT_PKCS12)
898 				rv = pk_export_pk12_pk11(kmfhandle,
899 				    token_spec, certlabel,
900 				    issuer, subject,
901 				    &serial, &tokencred,
902 				    filename);
903 			else if ((oclass & PK_KEY_OBJ) ||
904 			    kfmt == KMF_FORMAT_RAWKEY)
905 				rv = pk_export_pk11_keys(kmfhandle,
906 				    token_spec, &tokencred, kfmt,
907 				    certlabel, filename, oclass);
908 			else
909 				rv = pk_export_pk11_objects(kmfhandle,
910 				    token_spec, certlabel,
911 				    issuer, subject, &serial, kfmt,
912 				    filename);
913 			break;
914 		case KMF_KEYSTORE_NSS:
915 			if (dir == NULL)
916 				dir = PK_DEFAULT_DIRECTORY;
917 			if (kfmt == KMF_FORMAT_PKCS12)
918 				rv = pk_export_pk12_nss(kmfhandle,
919 				    token_spec, dir, prefix,
920 				    certlabel, issuer,
921 				    subject, &serial,
922 				    &tokencred, filename);
923 			else
924 				rv = pk_export_nss_objects(kmfhandle,
925 				    token_spec,
926 				    oclass, certlabel, issuer, subject,
927 				    &serial, kfmt, dir, prefix, filename);
928 			break;
929 		case KMF_KEYSTORE_OPENSSL:
930 			if (kfmt == KMF_FORMAT_PKCS12)
931 				rv = pk_export_pk12_files(kmfhandle,
932 				    certfile, keyfile, dir,
933 				    filename);
934 			else
935 				rv = pk_export_file_objects(kmfhandle, oclass,
936 				    issuer, subject, &serial,
937 				    dir, infile, filename);
938 			break;
939 		default:
940 			rv = PK_ERR_USAGE;
941 			break;
942 	}
943 
944 	if (rv != KMF_OK) {
945 		display_error(kmfhandle, rv,
946 		    gettext("Error exporting objects"));
947 	}
948 
949 	if (serial.val != NULL)
950 		free(serial.val);
951 
952 	(void) kmf_finalize(kmfhandle);
953 
954 	return (rv);
955 }
956