199ebb4caSwyllys /* 299ebb4caSwyllys * CDDL HEADER START 399ebb4caSwyllys * 499ebb4caSwyllys * The contents of this file are subject to the terms of the 599ebb4caSwyllys * Common Development and Distribution License (the "License"). 699ebb4caSwyllys * You may not use this file except in compliance with the License. 799ebb4caSwyllys * 899ebb4caSwyllys * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 999ebb4caSwyllys * or http://www.opensolaris.org/os/licensing. 1099ebb4caSwyllys * See the License for the specific language governing permissions 1199ebb4caSwyllys * and limitations under the License. 1299ebb4caSwyllys * 1399ebb4caSwyllys * When distributing Covered Code, include this CDDL HEADER in each 1499ebb4caSwyllys * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1599ebb4caSwyllys * If applicable, add the following below this CDDL HEADER, with the 1699ebb4caSwyllys * fields enclosed by brackets "[]" replaced with your own identifying 1799ebb4caSwyllys * information: Portions Copyright [yyyy] [name of copyright owner] 1899ebb4caSwyllys * 1999ebb4caSwyllys * CDDL HEADER END 20*2c9a247fSWyllys Ingersoll * 21*2c9a247fSWyllys Ingersoll * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 2299ebb4caSwyllys */ 2399ebb4caSwyllys 2499ebb4caSwyllys #include <stdio.h> 2599ebb4caSwyllys #include <stdlib.h> 2699ebb4caSwyllys #include <string.h> 2799ebb4caSwyllys #include <ctype.h> 2899ebb4caSwyllys #include <malloc.h> 2999ebb4caSwyllys #include <libgen.h> 3099ebb4caSwyllys #include <fcntl.h> 3199ebb4caSwyllys #include <errno.h> 3299ebb4caSwyllys #include <cryptoutil.h> 3399ebb4caSwyllys #include "common.h" 3499ebb4caSwyllys #include <kmfapi.h> 3599ebb4caSwyllys 3699ebb4caSwyllys int 3799ebb4caSwyllys pk_download(int argc, char *argv[]) 3899ebb4caSwyllys { 3999ebb4caSwyllys int rv; 4099ebb4caSwyllys int opt; 4199ebb4caSwyllys extern int optind_av; 4299ebb4caSwyllys extern char *optarg_av; 4399ebb4caSwyllys int oclass = 0; 4499ebb4caSwyllys char *url = NULL; 4599ebb4caSwyllys char *http_proxy = NULL; 4699ebb4caSwyllys char *dir = NULL; 4799ebb4caSwyllys char *outfile = NULL; 4899ebb4caSwyllys char *proxy = NULL; 4999ebb4caSwyllys int proxy_port = 0; 5099ebb4caSwyllys KMF_HANDLE_T kmfhandle = NULL; 5199ebb4caSwyllys KMF_ENCODE_FORMAT format; 5299ebb4caSwyllys KMF_RETURN ch_rv = KMF_OK; 5399ebb4caSwyllys char *fullpath = NULL; 5499ebb4caSwyllys KMF_DATA cert = {NULL, 0}; 5599ebb4caSwyllys KMF_DATA cert_der = {NULL, 0}; 5699ebb4caSwyllys 5799ebb4caSwyllys while ((opt = getopt_av(argc, argv, 5899ebb4caSwyllys "t:(objtype)u:(url)h:(http_proxy)o:(outfile)d:(dir)")) != EOF) { 5999ebb4caSwyllys 6099ebb4caSwyllys if (EMPTYSTRING(optarg_av)) 6199ebb4caSwyllys return (PK_ERR_USAGE); 6299ebb4caSwyllys switch (opt) { 6399ebb4caSwyllys case 't': 6499ebb4caSwyllys if (oclass) 6599ebb4caSwyllys return (PK_ERR_USAGE); 6699ebb4caSwyllys oclass = OT2Int(optarg_av); 6799ebb4caSwyllys if (!(oclass & (PK_CERT_OBJ | PK_CRL_OBJ))) 6899ebb4caSwyllys return (PK_ERR_USAGE); 6999ebb4caSwyllys break; 7099ebb4caSwyllys case 'u': 7199ebb4caSwyllys if (url) 7299ebb4caSwyllys return (PK_ERR_USAGE); 7399ebb4caSwyllys url = optarg_av; 7499ebb4caSwyllys break; 7599ebb4caSwyllys case 'h': 7699ebb4caSwyllys if (http_proxy) 7799ebb4caSwyllys return (PK_ERR_USAGE); 7899ebb4caSwyllys http_proxy = optarg_av; 7999ebb4caSwyllys break; 8099ebb4caSwyllys case 'o': 8199ebb4caSwyllys if (outfile) 8299ebb4caSwyllys return (PK_ERR_USAGE); 8399ebb4caSwyllys outfile = optarg_av; 8499ebb4caSwyllys break; 8599ebb4caSwyllys case 'd': 8699ebb4caSwyllys if (dir) 8799ebb4caSwyllys return (PK_ERR_USAGE); 8899ebb4caSwyllys dir = optarg_av; 8999ebb4caSwyllys break; 9099ebb4caSwyllys default: 9199ebb4caSwyllys cryptoerror(LOG_STDERR, gettext( 9299ebb4caSwyllys "unrecognized download option '%s'\n"), 9399ebb4caSwyllys argv[optind_av]); 9499ebb4caSwyllys return (PK_ERR_USAGE); 9599ebb4caSwyllys } 9699ebb4caSwyllys } 9799ebb4caSwyllys 9899ebb4caSwyllys /* No additional args allowed. */ 9999ebb4caSwyllys argc -= optind_av; 10099ebb4caSwyllys argv += optind_av; 10199ebb4caSwyllys if (argc) { 10299ebb4caSwyllys return (PK_ERR_USAGE); 10399ebb4caSwyllys } 10499ebb4caSwyllys 10599ebb4caSwyllys /* Check the dir and outfile options */ 10699ebb4caSwyllys if (outfile == NULL) { 10799ebb4caSwyllys /* If outfile is not specified, use the basename of URI */ 10899ebb4caSwyllys outfile = basename(url); 10999ebb4caSwyllys } 11099ebb4caSwyllys 11199ebb4caSwyllys fullpath = get_fullpath(dir, outfile); 11299ebb4caSwyllys if (fullpath == NULL) { 11399ebb4caSwyllys cryptoerror(LOG_STDERR, gettext("Incorrect dir or outfile " 11499ebb4caSwyllys "option value \n")); 11599ebb4caSwyllys return (PK_ERR_USAGE); 11699ebb4caSwyllys } 11799ebb4caSwyllys /* Check if the file exists and might be overwritten. */ 118*2c9a247fSWyllys Ingersoll if (verify_file(fullpath) != KMF_OK) { 11999ebb4caSwyllys cryptoerror(LOG_STDERR, 12030a5e8faSwyllys gettext("Warning: file \"%s\" exists, " 12130a5e8faSwyllys "will be overwritten."), fullpath); 12299ebb4caSwyllys if (yesno(gettext("Continue with download? "), 12399ebb4caSwyllys gettext("Respond with yes or no.\n"), B_FALSE) == B_FALSE) { 12499ebb4caSwyllys return (0); 12599ebb4caSwyllys } 12699ebb4caSwyllys } 12799ebb4caSwyllys /* URI MUST be specified */ 12899ebb4caSwyllys if (url == NULL) { 12999ebb4caSwyllys cryptoerror(LOG_STDERR, gettext("A URL must be specified\n")); 13099ebb4caSwyllys rv = PK_ERR_USAGE; 13199ebb4caSwyllys goto end; 13299ebb4caSwyllys } 13399ebb4caSwyllys 13499ebb4caSwyllys /* 13599ebb4caSwyllys * Get the http proxy from the command "http_proxy" option or the 13699ebb4caSwyllys * environment variable. The command option has a higher priority. 13799ebb4caSwyllys */ 13899ebb4caSwyllys if (http_proxy == NULL) 13999ebb4caSwyllys http_proxy = getenv("http_proxy"); 14099ebb4caSwyllys 14199ebb4caSwyllys if (http_proxy != NULL) { 14299ebb4caSwyllys char *ptmp = http_proxy; 14399ebb4caSwyllys char *proxy_port_s; 14499ebb4caSwyllys 14599ebb4caSwyllys if (strncasecmp(ptmp, "http://", 7) == 0) 14699ebb4caSwyllys ptmp += 7; /* skip the scheme prefix */ 14799ebb4caSwyllys 14899ebb4caSwyllys proxy = strtok(ptmp, ":"); 14999ebb4caSwyllys proxy_port_s = strtok(NULL, "\0"); 15099ebb4caSwyllys if (proxy_port_s != NULL) 15199ebb4caSwyllys proxy_port = strtol(proxy_port_s, NULL, 0); 15299ebb4caSwyllys else 15399ebb4caSwyllys proxy_port = 8080; 15499ebb4caSwyllys } 15599ebb4caSwyllys 15699ebb4caSwyllys /* If objtype is not specified, default to CRL */ 15799ebb4caSwyllys if (oclass == 0) { 15899ebb4caSwyllys oclass = PK_CRL_OBJ; 15999ebb4caSwyllys } 16099ebb4caSwyllys 16130a5e8faSwyllys if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK) { 16299ebb4caSwyllys cryptoerror(LOG_STDERR, gettext("Error initializing KMF\n")); 16399ebb4caSwyllys rv = PK_ERR_USAGE; 16499ebb4caSwyllys goto end; 16599ebb4caSwyllys } 16699ebb4caSwyllys 16799ebb4caSwyllys /* Now we are ready to download */ 16899ebb4caSwyllys if (oclass & PK_CRL_OBJ) { 16930a5e8faSwyllys rv = kmf_download_crl(kmfhandle, url, proxy, proxy_port, 30, 17099ebb4caSwyllys fullpath, &format); 17199ebb4caSwyllys } else if (oclass & PK_CERT_OBJ) { 17230a5e8faSwyllys rv = kmf_download_cert(kmfhandle, url, proxy, proxy_port, 30, 17399ebb4caSwyllys fullpath, &format); 17499ebb4caSwyllys } 17599ebb4caSwyllys 17699ebb4caSwyllys if (rv != KMF_OK) { 17799ebb4caSwyllys switch (rv) { 17899ebb4caSwyllys case KMF_ERR_BAD_URI: 17999ebb4caSwyllys cryptoerror(LOG_STDERR, 18099ebb4caSwyllys gettext("Error in parsing URI\n")); 18199ebb4caSwyllys rv = PK_ERR_USAGE; 18299ebb4caSwyllys break; 18399ebb4caSwyllys case KMF_ERR_OPEN_FILE: 18499ebb4caSwyllys cryptoerror(LOG_STDERR, 18599ebb4caSwyllys gettext("Error in opening file\n")); 18699ebb4caSwyllys rv = PK_ERR_USAGE; 18799ebb4caSwyllys break; 18899ebb4caSwyllys case KMF_ERR_WRITE_FILE: 18999ebb4caSwyllys cryptoerror(LOG_STDERR, 19099ebb4caSwyllys gettext("Error in writing file\n")); 19199ebb4caSwyllys rv = PK_ERR_USAGE; 19299ebb4caSwyllys break; 19399ebb4caSwyllys case KMF_ERR_BAD_CRLFILE: 19499ebb4caSwyllys cryptoerror(LOG_STDERR, gettext("Not a CRL file\n")); 19599ebb4caSwyllys rv = PK_ERR_USAGE; 19699ebb4caSwyllys break; 19799ebb4caSwyllys case KMF_ERR_BAD_CERTFILE: 19899ebb4caSwyllys cryptoerror(LOG_STDERR, 19999ebb4caSwyllys gettext("Not a certificate file\n")); 20099ebb4caSwyllys rv = PK_ERR_USAGE; 20199ebb4caSwyllys break; 20299ebb4caSwyllys case KMF_ERR_MEMORY: 20399ebb4caSwyllys cryptoerror(LOG_STDERR, 20499ebb4caSwyllys gettext("Not enough memory\n")); 20599ebb4caSwyllys rv = PK_ERR_SYSTEM; 20699ebb4caSwyllys break; 20799ebb4caSwyllys default: 20899ebb4caSwyllys cryptoerror(LOG_STDERR, 20999ebb4caSwyllys gettext("Error in downloading the file.\n")); 21099ebb4caSwyllys rv = PK_ERR_SYSTEM; 21199ebb4caSwyllys break; 21299ebb4caSwyllys } 21399ebb4caSwyllys goto end; 21499ebb4caSwyllys } 21599ebb4caSwyllys 21699ebb4caSwyllys /* 21799ebb4caSwyllys * If the file is successfully downloaded, we also check the date. 21899ebb4caSwyllys * If the downloaded file is outdated, give a warning. 21999ebb4caSwyllys */ 22099ebb4caSwyllys if (oclass & PK_CRL_OBJ) { 22130a5e8faSwyllys ch_rv = kmf_check_crl_date(kmfhandle, fullpath); 22299ebb4caSwyllys } else { /* certificate */ 22330a5e8faSwyllys ch_rv = kmf_read_input_file(kmfhandle, fullpath, &cert); 22499ebb4caSwyllys if (ch_rv != KMF_OK) 22599ebb4caSwyllys goto end; 22699ebb4caSwyllys 22799ebb4caSwyllys if (format == KMF_FORMAT_PEM) { 22899ebb4caSwyllys int len; 22930a5e8faSwyllys ch_rv = kmf_pem_to_der(cert.Data, cert.Length, 23099ebb4caSwyllys &cert_der.Data, &len); 23199ebb4caSwyllys if (ch_rv != KMF_OK) 23299ebb4caSwyllys goto end; 23399ebb4caSwyllys cert_der.Length = (size_t)len; 23499ebb4caSwyllys } 23599ebb4caSwyllys 23630a5e8faSwyllys ch_rv = kmf_check_cert_date(kmfhandle, 23799ebb4caSwyllys format == KMF_FORMAT_ASN1 ? &cert : &cert_der); 23899ebb4caSwyllys } 23999ebb4caSwyllys 24099ebb4caSwyllys end: 24199ebb4caSwyllys if (ch_rv == KMF_ERR_VALIDITY_PERIOD) { 24299ebb4caSwyllys cryptoerror(LOG_STDERR, 24399ebb4caSwyllys gettext("Warning: the downloaded file is expired.\n")); 24499ebb4caSwyllys } else if (ch_rv != KMF_OK) { 24599ebb4caSwyllys cryptoerror(LOG_STDERR, 24699ebb4caSwyllys gettext("Warning: failed to check the validity.\n")); 24799ebb4caSwyllys } 24899ebb4caSwyllys 24999ebb4caSwyllys if (fullpath) 25099ebb4caSwyllys free(fullpath); 25199ebb4caSwyllys 25230a5e8faSwyllys kmf_free_data(&cert); 25330a5e8faSwyllys kmf_free_data(&cert_der); 25499ebb4caSwyllys 25530a5e8faSwyllys (void) kmf_finalize(kmfhandle); 25699ebb4caSwyllys return (rv); 25799ebb4caSwyllys } 258