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
202c9a247fSWyllys Ingersoll *
212c9a247fSWyllys 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
pk_download(int argc,char * argv[])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;
54*6b35cb3cSRichard PALO KMF_DATA cert = { 0, NULL };
55*6b35cb3cSRichard PALO KMF_DATA cert_der = { 0, NULL };
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. */
1182c9a247fSWyllys 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