xref: /onnv-gate/usr/src/cmd/cmd-crypto/pktool/download.c (revision 5051:cbbb7c8b40a9)
13089Swyllys /*
23089Swyllys  * CDDL HEADER START
33089Swyllys  *
43089Swyllys  * The contents of this file are subject to the terms of the
53089Swyllys  * Common Development and Distribution License (the "License").
63089Swyllys  * You may not use this file except in compliance with the License.
73089Swyllys  *
83089Swyllys  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93089Swyllys  * or http://www.opensolaris.org/os/licensing.
103089Swyllys  * See the License for the specific language governing permissions
113089Swyllys  * and limitations under the License.
123089Swyllys  *
133089Swyllys  * When distributing Covered Code, include this CDDL HEADER in each
143089Swyllys  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153089Swyllys  * If applicable, add the following below this CDDL HEADER, with the
163089Swyllys  * fields enclosed by brackets "[]" replaced with your own identifying
173089Swyllys  * information: Portions Copyright [yyyy] [name of copyright owner]
183089Swyllys  *
193089Swyllys  * CDDL HEADER END
203089Swyllys  */
213089Swyllys /*
22*5051Swyllys  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
233089Swyllys  * Use is subject to license terms.
243089Swyllys  */
253089Swyllys 
263089Swyllys #pragma ident	"%Z%%M%	%I%	%E% SMI"
273089Swyllys 
283089Swyllys #include <stdio.h>
293089Swyllys #include <stdlib.h>
303089Swyllys #include <string.h>
313089Swyllys #include <ctype.h>
323089Swyllys #include <malloc.h>
333089Swyllys #include <libgen.h>
343089Swyllys #include <fcntl.h>
353089Swyllys #include <errno.h>
363089Swyllys #include <cryptoutil.h>
373089Swyllys #include "common.h"
383089Swyllys #include <kmfapi.h>
393089Swyllys 
403089Swyllys int
413089Swyllys pk_download(int argc, char *argv[])
423089Swyllys {
433089Swyllys 	int rv;
443089Swyllys 	int opt;
453089Swyllys 	extern int	optind_av;
463089Swyllys 	extern char	*optarg_av;
473089Swyllys 	int oclass = 0;
483089Swyllys 	char *url = NULL;
493089Swyllys 	char *http_proxy = NULL;
503089Swyllys 	char *dir = NULL;
513089Swyllys 	char *outfile = NULL;
523089Swyllys 	char *proxy = NULL;
533089Swyllys 	int  proxy_port = 0;
543089Swyllys 	KMF_HANDLE_T	kmfhandle = NULL;
553089Swyllys 	KMF_ENCODE_FORMAT format;
563089Swyllys 	KMF_RETURN ch_rv = KMF_OK;
573089Swyllys 	char *fullpath = NULL;
583089Swyllys 	KMF_DATA cert = {NULL, 0};
593089Swyllys 	KMF_DATA cert_der = {NULL, 0};
603089Swyllys 
613089Swyllys 	while ((opt = getopt_av(argc, argv,
623089Swyllys 	    "t:(objtype)u:(url)h:(http_proxy)o:(outfile)d:(dir)")) != EOF) {
633089Swyllys 
643089Swyllys 		if (EMPTYSTRING(optarg_av))
653089Swyllys 			return (PK_ERR_USAGE);
663089Swyllys 		switch (opt) {
673089Swyllys 		case 't':
683089Swyllys 			if (oclass)
693089Swyllys 				return (PK_ERR_USAGE);
703089Swyllys 			oclass = OT2Int(optarg_av);
713089Swyllys 			if (!(oclass & (PK_CERT_OBJ | PK_CRL_OBJ)))
723089Swyllys 				return (PK_ERR_USAGE);
733089Swyllys 			break;
743089Swyllys 		case 'u':
753089Swyllys 			if (url)
763089Swyllys 				return (PK_ERR_USAGE);
773089Swyllys 			url = optarg_av;
783089Swyllys 			break;
793089Swyllys 		case 'h':
803089Swyllys 			if (http_proxy)
813089Swyllys 				return (PK_ERR_USAGE);
823089Swyllys 			http_proxy = optarg_av;
833089Swyllys 			break;
843089Swyllys 		case 'o':
853089Swyllys 			if (outfile)
863089Swyllys 				return (PK_ERR_USAGE);
873089Swyllys 			outfile = optarg_av;
883089Swyllys 			break;
893089Swyllys 		case 'd':
903089Swyllys 			if (dir)
913089Swyllys 				return (PK_ERR_USAGE);
923089Swyllys 			dir = optarg_av;
933089Swyllys 			break;
943089Swyllys 		default:
953089Swyllys 			cryptoerror(LOG_STDERR, gettext(
963089Swyllys 			    "unrecognized download option '%s'\n"),
973089Swyllys 			    argv[optind_av]);
983089Swyllys 			return (PK_ERR_USAGE);
993089Swyllys 		}
1003089Swyllys 	}
1013089Swyllys 
1023089Swyllys 	/* No additional args allowed. */
1033089Swyllys 	argc -= optind_av;
1043089Swyllys 	argv += optind_av;
1053089Swyllys 	if (argc) {
1063089Swyllys 		return (PK_ERR_USAGE);
1073089Swyllys 	}
1083089Swyllys 
1093089Swyllys 	/* Check the dir and outfile options */
1103089Swyllys 	if (outfile == NULL) {
1113089Swyllys 		/* If outfile is not specified, use the basename of URI */
1123089Swyllys 		outfile = basename(url);
1133089Swyllys 	}
1143089Swyllys 
1153089Swyllys 	fullpath = get_fullpath(dir, outfile);
1163089Swyllys 	if (fullpath == NULL) {
1173089Swyllys 		cryptoerror(LOG_STDERR, gettext("Incorrect dir or outfile "
1183089Swyllys 		    "option value \n"));
1193089Swyllys 		return (PK_ERR_USAGE);
1203089Swyllys 	}
1213089Swyllys 	/* Check if the file exists and might be overwritten. */
1223089Swyllys 	if (access(fullpath, F_OK) == 0) {
1233089Swyllys 		cryptoerror(LOG_STDERR,
124*5051Swyllys 		    gettext("Warning: file \"%s\" exists, "
125*5051Swyllys 		    "will be overwritten."), fullpath);
1263089Swyllys 		if (yesno(gettext("Continue with download? "),
1273089Swyllys 		    gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) {
1283089Swyllys 			return (0);
1293089Swyllys 		}
1303089Swyllys 	} else {
1313089Swyllys 		rv = verify_file(fullpath);
1323089Swyllys 		if (rv != KMF_OK) {
1333089Swyllys 			cryptoerror(LOG_STDERR, gettext("The file (%s) "
134*5051Swyllys 			    "cannot be created.\n"), fullpath);
1353089Swyllys 			return (PK_ERR_USAGE);
1363089Swyllys 		}
1373089Swyllys 	}
1383089Swyllys 
1393089Swyllys 
1403089Swyllys 	/* URI MUST be specified */
1413089Swyllys 	if (url == NULL) {
1423089Swyllys 		cryptoerror(LOG_STDERR, gettext("A URL must be specified\n"));
1433089Swyllys 		rv = PK_ERR_USAGE;
1443089Swyllys 		goto end;
1453089Swyllys 	}
1463089Swyllys 
1473089Swyllys 	/*
1483089Swyllys 	 * Get the http proxy from the command "http_proxy" option or the
1493089Swyllys 	 * environment variable.  The command option has a higher priority.
1503089Swyllys 	 */
1513089Swyllys 	if (http_proxy == NULL)
1523089Swyllys 		http_proxy = getenv("http_proxy");
1533089Swyllys 
1543089Swyllys 	if (http_proxy != NULL) {
1553089Swyllys 		char *ptmp = http_proxy;
1563089Swyllys 		char *proxy_port_s;
1573089Swyllys 
1583089Swyllys 		if (strncasecmp(ptmp, "http://", 7) == 0)
1593089Swyllys 			ptmp += 7;	/* skip the scheme prefix */
1603089Swyllys 
1613089Swyllys 		proxy = strtok(ptmp, ":");
1623089Swyllys 		proxy_port_s = strtok(NULL, "\0");
1633089Swyllys 		if (proxy_port_s != NULL)
1643089Swyllys 			proxy_port = strtol(proxy_port_s, NULL, 0);
1653089Swyllys 		else
1663089Swyllys 			proxy_port = 8080;
1673089Swyllys 	}
1683089Swyllys 
1693089Swyllys 	/* If objtype is not specified, default to CRL */
1703089Swyllys 	if (oclass == 0) {
1713089Swyllys 		oclass = PK_CRL_OBJ;
1723089Swyllys 	}
1733089Swyllys 
174*5051Swyllys 	if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) {
1753089Swyllys 		cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n"));
1763089Swyllys 		rv = PK_ERR_USAGE;
1773089Swyllys 		goto end;
1783089Swyllys 	}
1793089Swyllys 
1803089Swyllys 	/* Now we are ready to download */
1813089Swyllys 	if (oclass & PK_CRL_OBJ) {
182*5051Swyllys 		rv = kmf_download_crl(kmfhandle, url, proxy, proxy_port, 30,
1833089Swyllys 		    fullpath, &format);
1843089Swyllys 	} else if (oclass & PK_CERT_OBJ) {
185*5051Swyllys 		rv = kmf_download_cert(kmfhandle, url, proxy, proxy_port, 30,
1863089Swyllys 		    fullpath, &format);
1873089Swyllys 	}
1883089Swyllys 
1893089Swyllys 	if (rv != KMF_OK) {
1903089Swyllys 		switch (rv) {
1913089Swyllys 		case KMF_ERR_BAD_URI:
1923089Swyllys 			cryptoerror(LOG_STDERR,
1933089Swyllys 			    gettext("Error in parsing URI\n"));
1943089Swyllys 			rv = PK_ERR_USAGE;
1953089Swyllys 			break;
1963089Swyllys 		case KMF_ERR_OPEN_FILE:
1973089Swyllys 			cryptoerror(LOG_STDERR,
1983089Swyllys 			    gettext("Error in opening file\n"));
1993089Swyllys 			rv = PK_ERR_USAGE;
2003089Swyllys 			break;
2013089Swyllys 		case KMF_ERR_WRITE_FILE:
2023089Swyllys 			cryptoerror(LOG_STDERR,
2033089Swyllys 			    gettext("Error in writing file\n"));
2043089Swyllys 			rv = PK_ERR_USAGE;
2053089Swyllys 			break;
2063089Swyllys 		case KMF_ERR_BAD_CRLFILE:
2073089Swyllys 			cryptoerror(LOG_STDERR, gettext("Not a CRL file\n"));
2083089Swyllys 			rv = PK_ERR_USAGE;
2093089Swyllys 			break;
2103089Swyllys 		case KMF_ERR_BAD_CERTFILE:
2113089Swyllys 			cryptoerror(LOG_STDERR,
2123089Swyllys 			    gettext("Not a certificate file\n"));
2133089Swyllys 			rv = PK_ERR_USAGE;
2143089Swyllys 			break;
2153089Swyllys 		case KMF_ERR_MEMORY:
2163089Swyllys 			cryptoerror(LOG_STDERR,
2173089Swyllys 			    gettext("Not enough memory\n"));
2183089Swyllys 			rv = PK_ERR_SYSTEM;
2193089Swyllys 			break;
2203089Swyllys 		default:
2213089Swyllys 			cryptoerror(LOG_STDERR,
2223089Swyllys 			    gettext("Error in downloading the file.\n"));
2233089Swyllys 			rv = PK_ERR_SYSTEM;
2243089Swyllys 			break;
2253089Swyllys 		}
2263089Swyllys 		goto end;
2273089Swyllys 	}
2283089Swyllys 
2293089Swyllys 	/*
2303089Swyllys 	 * If the file is successfully downloaded, we also check the date.
2313089Swyllys 	 * If the downloaded file is outdated, give a warning.
2323089Swyllys 	 */
2333089Swyllys 	if (oclass & PK_CRL_OBJ) {
234*5051Swyllys 		ch_rv = kmf_check_crl_date(kmfhandle, fullpath);
2353089Swyllys 	} else { /* certificate */
236*5051Swyllys 		ch_rv = kmf_read_input_file(kmfhandle, fullpath, &cert);
2373089Swyllys 		if (ch_rv != KMF_OK)
2383089Swyllys 			goto end;
2393089Swyllys 
2403089Swyllys 		if (format == KMF_FORMAT_PEM) {
2413089Swyllys 			int len;
242*5051Swyllys 			ch_rv = kmf_pem_to_der(cert.Data, cert.Length,
2433089Swyllys 			    &cert_der.Data, &len);
2443089Swyllys 			if (ch_rv != KMF_OK)
2453089Swyllys 				goto end;
2463089Swyllys 			cert_der.Length = (size_t)len;
2473089Swyllys 		}
2483089Swyllys 
249*5051Swyllys 		ch_rv = kmf_check_cert_date(kmfhandle,
2503089Swyllys 		    format == KMF_FORMAT_ASN1 ? &cert : &cert_der);
2513089Swyllys 	}
2523089Swyllys 
2533089Swyllys end:
2543089Swyllys 	if (ch_rv == KMF_ERR_VALIDITY_PERIOD) {
2553089Swyllys 		cryptoerror(LOG_STDERR,
2563089Swyllys 		    gettext("Warning: the downloaded file is expired.\n"));
2573089Swyllys 	} else if (ch_rv != KMF_OK) {
2583089Swyllys 		cryptoerror(LOG_STDERR,
2593089Swyllys 		    gettext("Warning: failed to check the validity.\n"));
2603089Swyllys 	}
2613089Swyllys 
2623089Swyllys 	if (fullpath)
2633089Swyllys 		free(fullpath);
2643089Swyllys 
265*5051Swyllys 	kmf_free_data(&cert);
266*5051Swyllys 	kmf_free_data(&cert_der);
2673089Swyllys 
268*5051Swyllys 	(void) kmf_finalize(kmfhandle);
2693089Swyllys 	return (rv);
2703089Swyllys }
271