import.c revision 3089:8ddeb2ace8aa
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 import operation for this tool.
30 * The basic flow of the process is to decrypt the PKCS#12
31 * input file if it has a password, parse the elements in
32 * the file, find the soft token, log into it, import the
33 * PKCS#11 objects into the soft token, and log out.
34 */
35
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <ctype.h>
40#include <errno.h>
41#include <fcntl.h>
42#include <sys/types.h>
43#include <sys/stat.h>
44#include "common.h"
45
46#include <kmfapi.h>
47
48static KMF_RETURN
49pk_import_pk12_files(KMF_HANDLE_T kmfhandle, KMF_CREDENTIAL *cred,
50	char *outfile, char *certfile, char *keyfile,
51	char *dir, char *keydir, KMF_ENCODE_FORMAT outformat)
52{
53	KMF_RETURN rv = KMF_OK;
54	KMF_DATA *certs = NULL;
55	KMF_RAW_KEY_DATA *keys = NULL;
56	int ncerts = 0;
57	int nkeys = 0;
58	int i;
59
60	rv = KMF_ImportPK12(kmfhandle, outfile, cred,
61		&certs, &ncerts, &keys, &nkeys);
62
63	if (rv == KMF_OK) {
64		(void) printf(gettext("Found %d certificate(s) and %d "
65			"key(s) in %s\n"), ncerts, nkeys, outfile);
66	}
67
68	if (rv == KMF_OK && ncerts > 0) {
69		KMF_STORECERT_PARAMS params;
70		char newcertfile[MAXPATHLEN];
71
72		(void) memset(&params, 0, sizeof (KMF_STORECERT_PARAMS));
73		params.kstype = KMF_KEYSTORE_OPENSSL;
74		params.sslparms.dirpath = dir;
75		params.sslparms.format = outformat;
76
77		for (i = 0; rv == KMF_OK && i < ncerts; i++) {
78			/*
79			 * If storing more than 1 cert, gotta change
80			 * the name so we don't overwrite the previous one.
81			 * Just append a _# to the name.
82			 */
83			if (i > 0) {
84				(void) snprintf(newcertfile,
85					sizeof (newcertfile),
86					"%s_%d", certfile, i);
87				params.sslparms.certfile = newcertfile;
88			} else {
89				params.sslparms.certfile = certfile;
90			}
91			rv = KMF_StoreCert(kmfhandle, &params, &certs[i]);
92		}
93	}
94	if (rv == KMF_OK && nkeys > 0) {
95		KMF_STOREKEY_PARAMS skparms;
96		char newkeyfile[MAXPATHLEN];
97
98		(void) memset(&skparms, 0, sizeof (skparms));
99
100		/* The order of certificates and keys should match */
101		for (i = 0; rv == KMF_OK && i < nkeys; i++) {
102			skparms.kstype = KMF_KEYSTORE_OPENSSL;
103			skparms.sslparms.dirpath = keydir;
104			skparms.sslparms.format = outformat;
105			skparms.cred = *cred;
106			skparms.certificate = &certs[i];
107
108			if (i > 0) {
109				(void) snprintf(newkeyfile,
110					sizeof (newkeyfile),
111					"%s_%d", keyfile, i);
112				skparms.sslparms.keyfile = newkeyfile;
113			} else {
114				skparms.sslparms.keyfile = keyfile;
115			}
116
117			rv = KMF_StorePrivateKey(kmfhandle, &skparms,
118				&keys[i]);
119		}
120	}
121	/*
122	 * Cleanup memory.
123	 */
124	if (certs) {
125		for (i = 0; i < ncerts; i++)
126			KMF_FreeData(&certs[i]);
127		free(certs);
128	}
129	if (keys) {
130		for (i = 0; i < nkeys; i++)
131			KMF_FreeRawKey(&keys[i]);
132		free(keys);
133	}
134
135
136	return (rv);
137}
138
139
140static KMF_RETURN
141pk_import_pk12_nss(
142	KMF_HANDLE_T kmfhandle, KMF_CREDENTIAL *kmfcred,
143	KMF_CREDENTIAL *tokencred,
144	char *token_spec, char *dir, char *prefix,
145	char *nickname, char *trustflags, char *filename)
146{
147	KMF_RETURN rv = KMF_OK;
148	KMF_DATA *certs = NULL;
149	KMF_RAW_KEY_DATA *keys = NULL;
150	int ncerts = 0;
151	int nkeys = 0;
152	int i;
153
154	rv = configure_nss(kmfhandle, dir, prefix);
155	if (rv != KMF_OK)
156		return (rv);
157
158	rv = KMF_ImportPK12(kmfhandle, filename, kmfcred,
159		&certs, &ncerts, &keys, &nkeys);
160
161	if (rv == KMF_OK)
162		(void) printf(gettext("Found %d certificate(s) and %d "
163			"key(s) in %s\n"), ncerts, nkeys, filename);
164
165	if (rv == KMF_OK) {
166		KMF_STORECERT_PARAMS params;
167
168		(void) memset(&params, 0, sizeof (KMF_STORECERT_PARAMS));
169		params.kstype = KMF_KEYSTORE_NSS;
170		params.nssparms.slotlabel = token_spec;
171		params.nssparms.trustflag = trustflags;
172
173		for (i = 0; rv == KMF_OK && i < ncerts; i++) {
174			if (i == 0)
175				params.certLabel = nickname;
176			else
177				params.certLabel = NULL;
178
179			rv = KMF_StoreCert(kmfhandle, &params, &certs[i]);
180		}
181		if (rv != KMF_OK) {
182			display_error(kmfhandle, rv,
183				gettext("Error storing certificate "
184					"in PKCS11 token"));
185		}
186	}
187
188	if (rv == KMF_OK) {
189		KMF_STOREKEY_PARAMS skparms;
190
191		/* The order of certificates and keys should match */
192		for (i = 0; i < nkeys; i++) {
193			(void) memset(&skparms, 0,
194				sizeof (KMF_STOREKEY_PARAMS));
195			skparms.kstype = KMF_KEYSTORE_NSS;
196			skparms.cred = *tokencred;
197			skparms.label = nickname;
198			skparms.certificate = &certs[i];
199			skparms.nssparms.slotlabel = token_spec;
200
201			rv = KMF_StorePrivateKey(kmfhandle, &skparms, &keys[i]);
202		}
203	}
204
205	/*
206	 * Cleanup memory.
207	 */
208	if (certs) {
209		for (i = 0; i < ncerts; i++)
210			KMF_FreeData(&certs[i]);
211		free(certs);
212	}
213	if (keys) {
214		for (i = 0; i < nkeys; i++)
215			KMF_FreeRawKey(&keys[i]);
216		free(keys);
217	}
218
219	return (rv);
220}
221
222static KMF_RETURN
223pk_import_cert(
224	KMF_HANDLE_T kmfhandle,
225	KMF_KEYSTORE_TYPE kstype,
226	char *label, char *token_spec, char *filename,
227	char *dir, char *prefix, char *trustflags)
228{
229	KMF_RETURN rv = KMF_OK;
230	KMF_IMPORTCERT_PARAMS params;
231
232	if (kstype == KMF_KEYSTORE_PK11TOKEN) {
233		rv = select_token(kmfhandle, token_spec, FALSE);
234
235		if (rv != KMF_OK) {
236			return (rv);
237		}
238	}
239
240	(void) memset(&params, 0, sizeof (params));
241	params.kstype = kstype;
242	params.certfile = filename;
243	params.certLabel = label;
244
245	if (kstype == KMF_KEYSTORE_NSS) {
246		rv = configure_nss(kmfhandle, dir, prefix);
247		if (rv != KMF_OK)
248			return (rv);
249		params.nssparms.trustflag = trustflags;
250		params.nssparms.slotlabel = token_spec;
251	}
252
253	rv = KMF_ImportCert(kmfhandle, &params);
254
255	return (rv);
256}
257
258static KMF_RETURN
259pk_import_file_crl(void *kmfhandle,
260	char *infile,
261	char *outfile,
262	char *outdir,
263	KMF_ENCODE_FORMAT outfmt)
264{
265	KMF_IMPORTCRL_PARAMS 	icrl_params;
266	KMF_OPENSSL_PARAMS sslparams;
267
268	sslparams.crlfile = infile;
269	sslparams.dirpath = outdir;
270	sslparams.outcrlfile = outfile;
271	sslparams.format = outfmt;
272	sslparams.crl_check = B_FALSE;
273
274	icrl_params.kstype = KMF_KEYSTORE_OPENSSL;
275	icrl_params.sslparms = sslparams;
276
277	return (KMF_ImportCRL(kmfhandle, &icrl_params));
278
279}
280
281static KMF_RETURN
282pk_import_nss_crl(void *kmfhandle,
283	boolean_t verify_crl_flag,
284	char *infile,
285	char *outdir,
286	char *prefix)
287{
288	KMF_IMPORTCRL_PARAMS 	icrl_params;
289	KMF_RETURN rv;
290
291	rv = configure_nss(kmfhandle, outdir, prefix);
292	if (rv != KMF_OK)
293		return (rv);
294
295	icrl_params.kstype = KMF_KEYSTORE_NSS;
296	icrl_params.nssparms.slotlabel = NULL;
297	icrl_params.nssparms.crlfile = infile;
298	icrl_params.nssparms.crl_check = verify_crl_flag;
299
300	return (KMF_ImportCRL(kmfhandle, &icrl_params));
301
302}
303
304static KMF_RETURN
305pk_import_pk12_pk11(
306	KMF_HANDLE_T kmfhandle,
307	KMF_CREDENTIAL *p12cred,
308	KMF_CREDENTIAL *tokencred,
309	char *label, char *token_spec,
310	char *filename)
311{
312	KMF_RETURN rv = KMF_OK;
313	KMF_DATA *certs = NULL;
314	KMF_RAW_KEY_DATA *keys = NULL;
315	int ncerts = 0;
316	int nkeys = 0;
317	int i;
318
319	rv = select_token(kmfhandle, token_spec, FALSE);
320
321	if (rv != KMF_OK) {
322		return (rv);
323	}
324
325	rv = KMF_ImportPK12(kmfhandle, filename, p12cred,
326		&certs, &ncerts, &keys, &nkeys);
327
328	if (rv == KMF_OK) {
329		KMF_STOREKEY_PARAMS skparms;
330
331		/* The order of certificates and keys should match */
332		for (i = 0; i < nkeys; i++) {
333			(void) memset(&skparms, 0,
334				sizeof (KMF_STOREKEY_PARAMS));
335			skparms.kstype = KMF_KEYSTORE_PK11TOKEN;
336			skparms.certificate = &certs[i];
337			if (tokencred != NULL)
338				skparms.cred = *tokencred;
339			if (i == 0)
340				skparms.label = label;
341			else
342				skparms.label = NULL;
343
344			rv = KMF_StorePrivateKey(kmfhandle, &skparms,
345				&keys[i]);
346		}
347	}
348
349	if (rv == KMF_OK) {
350		KMF_STORECERT_PARAMS params;
351
352		(void) printf(gettext("Found %d certificate(s) and %d "
353			"key(s) in %s\n"), ncerts, nkeys, filename);
354		(void) memset(&params, 0, sizeof (KMF_STORECERT_PARAMS));
355
356		params.kstype = KMF_KEYSTORE_PK11TOKEN;
357
358		for (i = 0; rv == KMF_OK && i < ncerts; i++) {
359			if (i == 0)
360				params.certLabel = label;
361			else
362				params.certLabel = NULL;
363
364			rv = KMF_StoreCert(kmfhandle, &params, &certs[i]);
365		}
366	}
367
368	/*
369	 * Cleanup memory.
370	 */
371	if (certs) {
372		for (i = 0; i < ncerts; i++)
373			KMF_FreeData(&certs[i]);
374		free(certs);
375	}
376	if (keys) {
377		for (i = 0; i < nkeys; i++)
378			KMF_FreeRawKey(&keys[i]);
379		free(keys);
380	}
381
382	return (rv);
383}
384
385/*
386 * Import objects from into KMF repositories.
387 */
388int
389pk_import(int argc, char *argv[])
390{
391	int		opt;
392	extern int	optind_av;
393	extern char	*optarg_av;
394	char		*token_spec = NULL;
395	char		*filename = NULL;
396	char		*keyfile = NULL;
397	char		*certfile = NULL;
398	char		*crlfile = NULL;
399	char		*certlabel = NULL;
400	char		*dir = NULL;
401	char		*keydir = NULL;
402	char		*prefix = NULL;
403	char		*trustflags = NULL;
404	char		*verify_crl = NULL;
405	boolean_t	verify_crl_flag = B_FALSE;
406	int		oclass = 0;
407	KMF_KEYSTORE_TYPE	kstype = 0;
408	KMF_ENCODE_FORMAT	kfmt = 0;
409	KMF_ENCODE_FORMAT	okfmt = KMF_FORMAT_ASN1;
410	KMF_RETURN		rv = KMF_OK;
411	KMF_CREDENTIAL	pk12cred = { NULL, 0 };
412	KMF_CREDENTIAL	tokencred = { NULL, 0 };
413	KMF_HANDLE_T	kmfhandle = NULL;
414
415	/* Parse command line options.  Do NOT i18n/l10n. */
416	while ((opt = getopt_av(argc, argv,
417		"T:(token)i:(infile)"
418		"k:(keystore)y:(objtype)"
419		"d:(dir)p:(prefix)"
420		"n:(certlabel)N:(label)"
421		"K:(outkey)c:(outcert)"
422		"v:(verifycrl)l:(outcrl)"
423		"t:(trust)D:(keydir)F:(outformat)")) != EOF) {
424		if (EMPTYSTRING(optarg_av))
425			return (PK_ERR_USAGE);
426		switch (opt) {
427		case 'T':	/* token specifier */
428			if (token_spec)
429				return (PK_ERR_USAGE);
430			token_spec = optarg_av;
431			break;
432		case 'c':	/* output cert file name */
433			if (certfile)
434				return (PK_ERR_USAGE);
435			certfile = optarg_av;
436			break;
437		case 'l':	/* output CRL file name */
438			if (crlfile)
439				return (PK_ERR_USAGE);
440			crlfile = optarg_av;
441			break;
442		case 'K':	/* output key file name */
443			if (keyfile)
444				return (PK_ERR_USAGE);
445			keyfile = optarg_av;
446			break;
447		case 'i':	/* input file name */
448			if (filename)
449				return (PK_ERR_USAGE);
450			filename = optarg_av;
451			break;
452		case 'k':
453			kstype = KS2Int(optarg_av);
454			if (kstype == 0)
455				return (PK_ERR_USAGE);
456			break;
457		case 'y':
458			oclass = OT2Int(optarg_av);
459			if (oclass == -1)
460				return (PK_ERR_USAGE);
461			break;
462		case 'd':
463			dir = optarg_av;
464			break;
465		case 'D':
466			keydir = optarg_av;
467			break;
468		case 'p':
469			if (prefix)
470				return (PK_ERR_USAGE);
471			prefix = optarg_av;
472			break;
473		case 'n':
474		case 'N':
475			if (certlabel)
476				return (PK_ERR_USAGE);
477			certlabel = optarg_av;
478			break;
479		case 'F':
480			okfmt = Str2Format(optarg_av);
481			if (okfmt == KMF_FORMAT_UNDEF)
482				return (PK_ERR_USAGE);
483			break;
484		case 't':
485			if (trustflags)
486				return (PK_ERR_USAGE);
487			trustflags = optarg_av;
488			break;
489		case 'v':
490			verify_crl = optarg_av;
491			if (tolower(verify_crl[0]) == 'y')
492				verify_crl_flag = B_TRUE;
493			else if (tolower(verify_crl[0]) == 'n')
494				verify_crl_flag = B_FALSE;
495			else
496				return (PK_ERR_USAGE);
497			break;
498		default:
499			return (PK_ERR_USAGE);
500			break;
501		}
502	}
503
504	/* Assume keystore = PKCS#11 if not specified */
505	if (kstype == 0)
506		kstype = KMF_KEYSTORE_PK11TOKEN;
507
508	/* Filename arg is required. */
509	if (EMPTYSTRING(filename)) {
510		cryptoerror(LOG_STDERR, gettext("The 'infile' parameter"
511			"is required for the import operation.\n"));
512		return (PK_ERR_USAGE);
513	}
514
515	/* No additional args allowed. */
516	argc -= optind_av;
517	argv += optind_av;
518	if (argc)
519		return (PK_ERR_USAGE);
520
521	/* if PUBLIC or PRIVATE obj was given, the old syntax was used. */
522	if ((oclass & (PK_PUBLIC_OBJ | PK_PRIVATE_OBJ)) &&
523		kstype != KMF_KEYSTORE_PK11TOKEN) {
524
525		(void) fprintf(stderr, gettext("The objtype parameter "
526			"is only relevant if keystore=pkcs11\n"));
527		return (PK_ERR_USAGE);
528	}
529
530	/*
531	 * You must specify a certlabel (cert label) when importing
532	 * into NSS or PKCS#11.
533	 */
534	if (kstype == KMF_KEYSTORE_NSS &&
535		(oclass != PK_CRL_OBJ) && EMPTYSTRING(certlabel)) {
536		cryptoerror(LOG_STDERR, gettext("The 'label' argument "
537			"is required for this operation\n"));
538		return (PK_ERR_USAGE);
539	}
540
541	/*
542	 * PKCS11 only imports PKCS#12 files or PEM/DER Cert files.
543	 */
544	if (kstype == KMF_KEYSTORE_PK11TOKEN) {
545		/* we do not import private keys except in PKCS12 bundles */
546		if (oclass & (PK_PRIVATE_OBJ | PK_PRIKEY_OBJ)) {
547			cryptoerror(LOG_STDERR, gettext(
548				"The PKCS11 keystore only imports PKCS12 "
549				"files or raw certificate data files "
550				" or CRL file.\n"));
551			return (PK_ERR_USAGE);
552		}
553	}
554
555	if ((rv = KMF_GetFileFormat(filename, &kfmt)) != KMF_OK) {
556		cryptoerror(LOG_STDERR,
557			gettext("File format not recognized."));
558		return (rv);
559	}
560	if (oclass == 0 && (kfmt == KMF_FORMAT_ASN1 ||
561		kfmt == KMF_FORMAT_PEM))
562		oclass = PK_CERT_OBJ;
563
564	if (kstype == KMF_KEYSTORE_NSS) {
565		if (oclass == PK_CRL_OBJ &&
566			(kfmt != KMF_FORMAT_ASN1 && kfmt != KMF_FORMAT_PEM)) {
567			cryptoerror(LOG_STDERR, gettext(
568				"CRL data can only be imported as DER or "
569				"PEM format"));
570			return (PK_ERR_USAGE);
571		}
572
573		if (oclass == PK_CERT_OBJ &&
574			(kfmt != KMF_FORMAT_ASN1 && kfmt != KMF_FORMAT_PEM)) {
575			cryptoerror(LOG_STDERR, gettext(
576				"Certificates can only be imported as DER or "
577				"PEM format"));
578			return (PK_ERR_USAGE);
579		}
580
581		/* we do not import private keys except in PKCS12 bundles */
582		if (oclass & (PK_PRIVATE_OBJ | PK_PRIKEY_OBJ)) {
583			cryptoerror(LOG_STDERR, gettext(
584				"Private key data can only be imported as part "
585				"of a PKCS12 file.\n"));
586			return (PK_ERR_USAGE);
587		}
588	}
589
590	if (kstype == KMF_KEYSTORE_OPENSSL && oclass != PK_CRL_OBJ) {
591		if (EMPTYSTRING(keyfile) || EMPTYSTRING(certfile)) {
592			cryptoerror(LOG_STDERR, gettext(
593				"The 'outkey' and 'outcert' parameters "
594				"are required for the import operation "
595				"when the 'file' keystore is used.\n"));
596			return (PK_ERR_USAGE);
597		}
598	}
599
600	if (kstype == KMF_KEYSTORE_PK11TOKEN && EMPTYSTRING(token_spec))
601		token_spec = PK_DEFAULT_PK11TOKEN;
602	else if (kstype == KMF_KEYSTORE_NSS && EMPTYSTRING(token_spec))
603		token_spec = DEFAULT_NSS_TOKEN;
604
605	if (kfmt == KMF_FORMAT_PKCS12) {
606		(void) get_pk12_password(&pk12cred);
607
608		if (kstype == KMF_KEYSTORE_PK11TOKEN ||
609			kstype == KMF_KEYSTORE_NSS)
610			(void) get_token_password(kstype, token_spec,
611				&tokencred);
612	}
613
614	if ((rv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
615		cryptoerror(LOG_STDERR, gettext("Error initializing "
616				"KMF: 0x%02x\n"), rv);
617		goto end;
618	}
619
620	switch (kstype) {
621		case KMF_KEYSTORE_PK11TOKEN:
622			if (kfmt == KMF_FORMAT_PKCS12)
623				rv = pk_import_pk12_pk11(
624					kmfhandle,
625					&pk12cred,
626					&tokencred,
627					certlabel,
628					token_spec,
629					filename);
630			else if (oclass == PK_CERT_OBJ)
631				rv = pk_import_cert(
632					kmfhandle,
633					kstype,
634					certlabel,
635					token_spec,
636					filename,
637					NULL, NULL, NULL);
638			else if (oclass == PK_CRL_OBJ)
639				rv = pk_import_file_crl(
640					kmfhandle,
641					filename,
642					crlfile,
643					dir,
644					okfmt);
645			break;
646		case KMF_KEYSTORE_NSS:
647			if (dir == NULL)
648				dir = PK_DEFAULT_DIRECTORY;
649			if (kfmt == KMF_FORMAT_PKCS12)
650				rv = pk_import_pk12_nss(
651					kmfhandle, &pk12cred,
652					&tokencred,
653					token_spec, dir, prefix,
654					certlabel, trustflags, filename);
655			else if (oclass == PK_CERT_OBJ) {
656				rv = pk_import_cert(
657					kmfhandle, kstype,
658					certlabel, token_spec,
659					filename, dir, prefix, trustflags);
660			} else if (oclass == PK_CRL_OBJ) {
661				rv = pk_import_nss_crl(
662					kmfhandle,
663					verify_crl_flag,
664					filename,
665					dir,
666					prefix);
667			}
668			break;
669		case KMF_KEYSTORE_OPENSSL:
670			if (kfmt == KMF_FORMAT_PKCS12)
671				rv = pk_import_pk12_files(
672					kmfhandle, &pk12cred,
673					filename, certfile, keyfile,
674					dir, keydir, okfmt);
675			else if (oclass == PK_CRL_OBJ) {
676				rv = pk_import_file_crl(
677					kmfhandle,
678					filename,
679					crlfile,
680					dir,
681					okfmt);
682			} else
683				/*
684				 * It doesn't make sense to import anything
685				 * else for the files plugin.
686				 */
687				return (PK_ERR_USAGE);
688			break;
689		default:
690			rv = PK_ERR_USAGE;
691			break;
692	}
693
694end:
695	if (rv != KMF_OK)
696		display_error(kmfhandle, rv,
697			gettext("Error importing objects"));
698
699	if (tokencred.cred != NULL)
700		free(tokencred.cred);
701
702	if (pk12cred.cred != NULL)
703		free(pk12cred.cred);
704
705	(void) KMF_Finalize(kmfhandle);
706
707	if (rv != KMF_OK)
708		return (PK_ERR_USAGE);
709
710	return (0);
711}
712