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, ¶ms); 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