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