xref: /titanic_50/usr/src/cmd/cmd-crypto/pktool/download.c (revision 99ebb4ca412cb0a19d77a3899a87c055b9c30fa8)
1*99ebb4caSwyllys /*
2*99ebb4caSwyllys  * CDDL HEADER START
3*99ebb4caSwyllys  *
4*99ebb4caSwyllys  * The contents of this file are subject to the terms of the
5*99ebb4caSwyllys  * Common Development and Distribution License (the "License").
6*99ebb4caSwyllys  * You may not use this file except in compliance with the License.
7*99ebb4caSwyllys  *
8*99ebb4caSwyllys  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*99ebb4caSwyllys  * or http://www.opensolaris.org/os/licensing.
10*99ebb4caSwyllys  * See the License for the specific language governing permissions
11*99ebb4caSwyllys  * and limitations under the License.
12*99ebb4caSwyllys  *
13*99ebb4caSwyllys  * When distributing Covered Code, include this CDDL HEADER in each
14*99ebb4caSwyllys  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*99ebb4caSwyllys  * If applicable, add the following below this CDDL HEADER, with the
16*99ebb4caSwyllys  * fields enclosed by brackets "[]" replaced with your own identifying
17*99ebb4caSwyllys  * information: Portions Copyright [yyyy] [name of copyright owner]
18*99ebb4caSwyllys  *
19*99ebb4caSwyllys  * CDDL HEADER END
20*99ebb4caSwyllys  */
21*99ebb4caSwyllys /*
22*99ebb4caSwyllys  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*99ebb4caSwyllys  * Use is subject to license terms.
24*99ebb4caSwyllys  */
25*99ebb4caSwyllys 
26*99ebb4caSwyllys #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*99ebb4caSwyllys 
28*99ebb4caSwyllys #include <stdio.h>
29*99ebb4caSwyllys #include <stdlib.h>
30*99ebb4caSwyllys #include <string.h>
31*99ebb4caSwyllys #include <ctype.h>
32*99ebb4caSwyllys #include <malloc.h>
33*99ebb4caSwyllys #include <libgen.h>
34*99ebb4caSwyllys #include <fcntl.h>
35*99ebb4caSwyllys #include <errno.h>
36*99ebb4caSwyllys #include <cryptoutil.h>
37*99ebb4caSwyllys #include "common.h"
38*99ebb4caSwyllys #include <kmfapi.h>
39*99ebb4caSwyllys 
40*99ebb4caSwyllys int
41*99ebb4caSwyllys pk_download(int argc, char *argv[])
42*99ebb4caSwyllys {
43*99ebb4caSwyllys 	int rv;
44*99ebb4caSwyllys 	int opt;
45*99ebb4caSwyllys 	extern int	optind_av;
46*99ebb4caSwyllys 	extern char	*optarg_av;
47*99ebb4caSwyllys 	int oclass = 0;
48*99ebb4caSwyllys 	char *url = NULL;
49*99ebb4caSwyllys 	char *http_proxy = NULL;
50*99ebb4caSwyllys 	char *dir = NULL;
51*99ebb4caSwyllys 	char *outfile = NULL;
52*99ebb4caSwyllys 	char *proxy = NULL;
53*99ebb4caSwyllys 	int  proxy_port = 0;
54*99ebb4caSwyllys 	KMF_HANDLE_T	kmfhandle = NULL;
55*99ebb4caSwyllys 	KMF_ENCODE_FORMAT format;
56*99ebb4caSwyllys 	KMF_RETURN ch_rv = KMF_OK;
57*99ebb4caSwyllys 	char *fullpath = NULL;
58*99ebb4caSwyllys 	KMF_DATA cert = {NULL, 0};
59*99ebb4caSwyllys 	KMF_DATA cert_der = {NULL, 0};
60*99ebb4caSwyllys 
61*99ebb4caSwyllys 	while ((opt = getopt_av(argc, argv,
62*99ebb4caSwyllys 	    "t:(objtype)u:(url)h:(http_proxy)o:(outfile)d:(dir)")) != EOF) {
63*99ebb4caSwyllys 
64*99ebb4caSwyllys 		if (EMPTYSTRING(optarg_av))
65*99ebb4caSwyllys 			return (PK_ERR_USAGE);
66*99ebb4caSwyllys 		switch (opt) {
67*99ebb4caSwyllys 		case 't':
68*99ebb4caSwyllys 			if (oclass)
69*99ebb4caSwyllys 				return (PK_ERR_USAGE);
70*99ebb4caSwyllys 			oclass = OT2Int(optarg_av);
71*99ebb4caSwyllys 			if (!(oclass & (PK_CERT_OBJ | PK_CRL_OBJ)))
72*99ebb4caSwyllys 				return (PK_ERR_USAGE);
73*99ebb4caSwyllys 			break;
74*99ebb4caSwyllys 		case 'u':
75*99ebb4caSwyllys 			if (url)
76*99ebb4caSwyllys 				return (PK_ERR_USAGE);
77*99ebb4caSwyllys 			url = optarg_av;
78*99ebb4caSwyllys 			break;
79*99ebb4caSwyllys 		case 'h':
80*99ebb4caSwyllys 			if (http_proxy)
81*99ebb4caSwyllys 				return (PK_ERR_USAGE);
82*99ebb4caSwyllys 			http_proxy = optarg_av;
83*99ebb4caSwyllys 			break;
84*99ebb4caSwyllys 		case 'o':
85*99ebb4caSwyllys 			if (outfile)
86*99ebb4caSwyllys 				return (PK_ERR_USAGE);
87*99ebb4caSwyllys 			outfile = optarg_av;
88*99ebb4caSwyllys 			break;
89*99ebb4caSwyllys 		case 'd':
90*99ebb4caSwyllys 			if (dir)
91*99ebb4caSwyllys 				return (PK_ERR_USAGE);
92*99ebb4caSwyllys 			dir = optarg_av;
93*99ebb4caSwyllys 			break;
94*99ebb4caSwyllys 		default:
95*99ebb4caSwyllys 			cryptoerror(LOG_STDERR, gettext(
96*99ebb4caSwyllys 			    "unrecognized download option '%s'\n"),
97*99ebb4caSwyllys 			    argv[optind_av]);
98*99ebb4caSwyllys 			return (PK_ERR_USAGE);
99*99ebb4caSwyllys 		}
100*99ebb4caSwyllys 	}
101*99ebb4caSwyllys 
102*99ebb4caSwyllys 	/* No additional args allowed. */
103*99ebb4caSwyllys 	argc -= optind_av;
104*99ebb4caSwyllys 	argv += optind_av;
105*99ebb4caSwyllys 	if (argc) {
106*99ebb4caSwyllys 		return (PK_ERR_USAGE);
107*99ebb4caSwyllys 	}
108*99ebb4caSwyllys 
109*99ebb4caSwyllys 	/* Check the dir and outfile options */
110*99ebb4caSwyllys 	if (outfile == NULL) {
111*99ebb4caSwyllys 		/* If outfile is not specified, use the basename of URI */
112*99ebb4caSwyllys 		outfile = basename(url);
113*99ebb4caSwyllys 	}
114*99ebb4caSwyllys 
115*99ebb4caSwyllys 	fullpath = get_fullpath(dir, outfile);
116*99ebb4caSwyllys 	if (fullpath == NULL) {
117*99ebb4caSwyllys 		cryptoerror(LOG_STDERR, gettext("Incorrect dir or outfile "
118*99ebb4caSwyllys 		    "option value \n"));
119*99ebb4caSwyllys 		return (PK_ERR_USAGE);
120*99ebb4caSwyllys 	}
121*99ebb4caSwyllys 	/* Check if the file exists and might be overwritten. */
122*99ebb4caSwyllys 	if (access(fullpath, F_OK) == 0) {
123*99ebb4caSwyllys 		cryptoerror(LOG_STDERR,
124*99ebb4caSwyllys 			gettext("Warning: file \"%s\" exists, "
125*99ebb4caSwyllys 				"will be overwritten."), fullpath);
126*99ebb4caSwyllys 		if (yesno(gettext("Continue with download? "),
127*99ebb4caSwyllys 		    gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) {
128*99ebb4caSwyllys 			return (0);
129*99ebb4caSwyllys 		}
130*99ebb4caSwyllys 	} else {
131*99ebb4caSwyllys 		rv = verify_file(fullpath);
132*99ebb4caSwyllys 		if (rv != KMF_OK) {
133*99ebb4caSwyllys 			cryptoerror(LOG_STDERR, gettext("The file (%s) "
134*99ebb4caSwyllys 				"cannot be created.\n"), fullpath);
135*99ebb4caSwyllys 			return (PK_ERR_USAGE);
136*99ebb4caSwyllys 		}
137*99ebb4caSwyllys 	}
138*99ebb4caSwyllys 
139*99ebb4caSwyllys 
140*99ebb4caSwyllys 	/* URI MUST be specified */
141*99ebb4caSwyllys 	if (url == NULL) {
142*99ebb4caSwyllys 		cryptoerror(LOG_STDERR, gettext("A URL must be specified\n"));
143*99ebb4caSwyllys 		rv = PK_ERR_USAGE;
144*99ebb4caSwyllys 		goto end;
145*99ebb4caSwyllys 	}
146*99ebb4caSwyllys 
147*99ebb4caSwyllys 	/*
148*99ebb4caSwyllys 	 * Get the http proxy from the command "http_proxy" option or the
149*99ebb4caSwyllys 	 * environment variable.  The command option has a higher priority.
150*99ebb4caSwyllys 	 */
151*99ebb4caSwyllys 	if (http_proxy == NULL)
152*99ebb4caSwyllys 		http_proxy = getenv("http_proxy");
153*99ebb4caSwyllys 
154*99ebb4caSwyllys 	if (http_proxy != NULL) {
155*99ebb4caSwyllys 		char *ptmp = http_proxy;
156*99ebb4caSwyllys 		char *proxy_port_s;
157*99ebb4caSwyllys 
158*99ebb4caSwyllys 		if (strncasecmp(ptmp, "http://", 7) == 0)
159*99ebb4caSwyllys 			ptmp += 7;	/* skip the scheme prefix */
160*99ebb4caSwyllys 
161*99ebb4caSwyllys 		proxy = strtok(ptmp, ":");
162*99ebb4caSwyllys 		proxy_port_s = strtok(NULL, "\0");
163*99ebb4caSwyllys 		if (proxy_port_s != NULL)
164*99ebb4caSwyllys 			proxy_port = strtol(proxy_port_s, NULL, 0);
165*99ebb4caSwyllys 		else
166*99ebb4caSwyllys 			proxy_port = 8080;
167*99ebb4caSwyllys 	}
168*99ebb4caSwyllys 
169*99ebb4caSwyllys 	/* If objtype is not specified, default to CRL */
170*99ebb4caSwyllys 	if (oclass == 0) {
171*99ebb4caSwyllys 		oclass = PK_CRL_OBJ;
172*99ebb4caSwyllys 	}
173*99ebb4caSwyllys 
174*99ebb4caSwyllys 	if ((rv = KMF_Initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
175*99ebb4caSwyllys 		cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n"));
176*99ebb4caSwyllys 		rv = PK_ERR_USAGE;
177*99ebb4caSwyllys 		goto end;
178*99ebb4caSwyllys 	}
179*99ebb4caSwyllys 
180*99ebb4caSwyllys 	/* Now we are ready to download */
181*99ebb4caSwyllys 	if (oclass & PK_CRL_OBJ) {
182*99ebb4caSwyllys 		rv = KMF_DownloadCRL(kmfhandle, url, proxy, proxy_port, 30,
183*99ebb4caSwyllys 		    fullpath, &format);
184*99ebb4caSwyllys 	} else if (oclass & PK_CERT_OBJ) {
185*99ebb4caSwyllys 		rv = KMF_DownloadCert(kmfhandle, url, proxy, proxy_port, 30,
186*99ebb4caSwyllys 		    fullpath, &format);
187*99ebb4caSwyllys 	}
188*99ebb4caSwyllys 
189*99ebb4caSwyllys 	if (rv != KMF_OK) {
190*99ebb4caSwyllys 		switch (rv) {
191*99ebb4caSwyllys 		case KMF_ERR_BAD_URI:
192*99ebb4caSwyllys 			cryptoerror(LOG_STDERR,
193*99ebb4caSwyllys 			    gettext("Error in parsing URI\n"));
194*99ebb4caSwyllys 			rv = PK_ERR_USAGE;
195*99ebb4caSwyllys 			break;
196*99ebb4caSwyllys 		case KMF_ERR_OPEN_FILE:
197*99ebb4caSwyllys 			cryptoerror(LOG_STDERR,
198*99ebb4caSwyllys 			    gettext("Error in opening file\n"));
199*99ebb4caSwyllys 			rv = PK_ERR_USAGE;
200*99ebb4caSwyllys 			break;
201*99ebb4caSwyllys 		case KMF_ERR_WRITE_FILE:
202*99ebb4caSwyllys 			cryptoerror(LOG_STDERR,
203*99ebb4caSwyllys 			    gettext("Error in writing file\n"));
204*99ebb4caSwyllys 			rv = PK_ERR_USAGE;
205*99ebb4caSwyllys 			break;
206*99ebb4caSwyllys 		case KMF_ERR_BAD_CRLFILE:
207*99ebb4caSwyllys 			cryptoerror(LOG_STDERR, gettext("Not a CRL file\n"));
208*99ebb4caSwyllys 			rv = PK_ERR_USAGE;
209*99ebb4caSwyllys 			break;
210*99ebb4caSwyllys 		case KMF_ERR_BAD_CERTFILE:
211*99ebb4caSwyllys 			cryptoerror(LOG_STDERR,
212*99ebb4caSwyllys 			    gettext("Not a certificate file\n"));
213*99ebb4caSwyllys 			rv = PK_ERR_USAGE;
214*99ebb4caSwyllys 			break;
215*99ebb4caSwyllys 		case KMF_ERR_MEMORY:
216*99ebb4caSwyllys 			cryptoerror(LOG_STDERR,
217*99ebb4caSwyllys 			    gettext("Not enough memory\n"));
218*99ebb4caSwyllys 			rv = PK_ERR_SYSTEM;
219*99ebb4caSwyllys 			break;
220*99ebb4caSwyllys 		default:
221*99ebb4caSwyllys 			cryptoerror(LOG_STDERR,
222*99ebb4caSwyllys 			    gettext("Error in downloading the file.\n"));
223*99ebb4caSwyllys 			rv = PK_ERR_SYSTEM;
224*99ebb4caSwyllys 			break;
225*99ebb4caSwyllys 		}
226*99ebb4caSwyllys 		goto end;
227*99ebb4caSwyllys 	}
228*99ebb4caSwyllys 
229*99ebb4caSwyllys 	/*
230*99ebb4caSwyllys 	 * If the file is successfully downloaded, we also check the date.
231*99ebb4caSwyllys 	 * If the downloaded file is outdated, give a warning.
232*99ebb4caSwyllys 	 */
233*99ebb4caSwyllys 	if (oclass & PK_CRL_OBJ) {
234*99ebb4caSwyllys 		KMF_CHECKCRLDATE_PARAMS params;
235*99ebb4caSwyllys 
236*99ebb4caSwyllys 		params.crl_name = fullpath;
237*99ebb4caSwyllys 		ch_rv = KMF_CheckCRLDate(kmfhandle, &params);
238*99ebb4caSwyllys 
239*99ebb4caSwyllys 	} else { /* certificate */
240*99ebb4caSwyllys 		ch_rv = KMF_ReadInputFile(kmfhandle, fullpath, &cert);
241*99ebb4caSwyllys 		if (ch_rv != KMF_OK)
242*99ebb4caSwyllys 			goto end;
243*99ebb4caSwyllys 
244*99ebb4caSwyllys 		if (format == KMF_FORMAT_PEM) {
245*99ebb4caSwyllys 			int len;
246*99ebb4caSwyllys 			ch_rv = KMF_Pem2Der(cert.Data, cert.Length,
247*99ebb4caSwyllys 			    &cert_der.Data, &len);
248*99ebb4caSwyllys 			if (ch_rv != KMF_OK)
249*99ebb4caSwyllys 				goto end;
250*99ebb4caSwyllys 			cert_der.Length = (size_t)len;
251*99ebb4caSwyllys 		}
252*99ebb4caSwyllys 
253*99ebb4caSwyllys 		ch_rv = KMF_CheckCertDate(kmfhandle,
254*99ebb4caSwyllys 		    format == KMF_FORMAT_ASN1 ? &cert : &cert_der);
255*99ebb4caSwyllys 	}
256*99ebb4caSwyllys 
257*99ebb4caSwyllys end:
258*99ebb4caSwyllys 	if (ch_rv == KMF_ERR_VALIDITY_PERIOD) {
259*99ebb4caSwyllys 		cryptoerror(LOG_STDERR,
260*99ebb4caSwyllys 		    gettext("Warning: the downloaded file is expired.\n"));
261*99ebb4caSwyllys 	} else if (ch_rv != KMF_OK) {
262*99ebb4caSwyllys 		cryptoerror(LOG_STDERR,
263*99ebb4caSwyllys 		    gettext("Warning: failed to check the validity.\n"));
264*99ebb4caSwyllys 	}
265*99ebb4caSwyllys 
266*99ebb4caSwyllys 	if (fullpath)
267*99ebb4caSwyllys 		free(fullpath);
268*99ebb4caSwyllys 
269*99ebb4caSwyllys 	KMF_FreeData(&cert);
270*99ebb4caSwyllys 	KMF_FreeData(&cert_der);
271*99ebb4caSwyllys 
272*99ebb4caSwyllys 	(void) KMF_Finalize(kmfhandle);
273*99ebb4caSwyllys 	return (rv);
274*99ebb4caSwyllys }
275