diff options
author | Peter Tribble <peter.tribble@gmail.com> | 2017-03-13 20:25:34 +0000 |
---|---|---|
committer | Gordon Ross <gwr@nexenta.com> | 2017-03-29 19:13:24 -0400 |
commit | 32991bedc3a6475f1401855c2318ae5b15f8a16b (patch) | |
tree | 3360e7844885746ed96019a9e3a42cd7e5e73409 /usr/src/lib/libpkg | |
parent | 4383d9578c9d399b19edc33e552a4c543ebf9468 (diff) | |
download | illumos-gate-32991bedc3a6475f1401855c2318ae5b15f8a16b.tar.gz |
5188 SVR4 packaging shouldn't depend on openssl or libwanboot
Reviewed by: Igor Kozhukhov <igor@dilos.org>
Reviewed by: Alexander Eremin <alexander.r.eremin@gmail.com>
Approved by: Gordon Ross <gordon.w.ross@gmail.com>
Diffstat (limited to 'usr/src/lib/libpkg')
22 files changed, 134 insertions, 10581 deletions
diff --git a/usr/src/lib/libpkg/Makefile.com b/usr/src/lib/libpkg/Makefile.com index 3e3b294c7e..a0dd3bcab5 100644 --- a/usr/src/lib/libpkg/Makefile.com +++ b/usr/src/lib/libpkg/Makefile.com @@ -20,6 +20,9 @@ # # +# Copyright 2017 Peter Tribble. + +# # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # @@ -33,12 +36,11 @@ OBJECTS= \ devtype.o dstream.o gpkglist.o \ gpkgmap.o isdir.o logerr.o \ mappath.o ncgrpw.o nhash.o \ - pkgexecl.o pkgexecv.o pkgmount.o \ - pkgtrans.o ppkgmap.o \ + path_valid.o pkgexecl.o pkgexecv.o \ + pkgmount.o pkgtrans.o ppkgmap.o \ progerr.o putcfile.o rrmdir.o \ runcmd.o srchcfile.o tputcfent.o \ - verify.o security.o pkgweb.o \ - pkgerr.o keystore.o p12lib.o \ + verify.o \ vfpops.o fmkdir.o pkgstr.o \ handlelocalfs.o pkgserv.o @@ -52,29 +54,19 @@ POFILE = libpkg.po MSGFILES = $(OBJECTS:%.o=../common/%.i) CLEANFILES += $(MSGFILES) -# This library is NOT lint clean - -# openssl forces us to ignore dubious pointer casts, thanks to its clever -# use of macros for stack management. -LINTFLAGS= -umx -errtags \ - -erroff=E_BAD_PTR_CAST_ALIGN,E_BAD_PTR_CAST -LINTFLAGS += -erroff=E_SUPPRESSION_DIRECTIVE_UNUSED -LINTFLAGS64 += -erroff=E_SUPPRESSION_DIRECTIVE_UNUSED $(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC) LIBS = $(DYNLIB) $(LINTLIB) -LDLIBS += -lc -lssl -lwanboot -lcrypto -lscf -ladm +LDLIBS += -lc -lscf -ladm CFLAGS += $(CCVERBOSE) -CERRWARN += -_gcc=-Wno-unused-label CERRWARN += -_gcc=-Wno-parentheses CERRWARN += -_gcc=-Wno-uninitialized CERRWARN += -_gcc=-Wno-clobbered CERRWARN += -_gcc=-Wno-switch -CERRWARN += -_gcc=-Wno-unused-value CPPFLAGS += -I$(SRCDIR) -D_FILE_OFFSET_BITS=64 .KEEP_STATE: diff --git a/usr/src/lib/libpkg/THIRDPARTYLICENSE b/usr/src/lib/libpkg/THIRDPARTYLICENSE deleted file mode 100644 index 0051c6904d..0000000000 --- a/usr/src/lib/libpkg/THIRDPARTYLICENSE +++ /dev/null @@ -1,51 +0,0 @@ - * ==================================================================== - * Copyright (c) 1999 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * licensing@OpenSSL.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). diff --git a/usr/src/lib/libpkg/common/ckparam.c b/usr/src/lib/libpkg/common/ckparam.c index 47beb1c6be..209d3b4d5d 100644 --- a/usr/src/lib/libpkg/common/ckparam.c +++ b/usr/src/lib/libpkg/common/ckparam.c @@ -20,6 +20,10 @@ */ /* + * Copyright (c) 2017 Peter Tribble. + */ + +/* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -31,6 +35,7 @@ #include <ctype.h> #include <string.h> +#include <stdlib.h> #include <sys/types.h> #include "pkglib.h" #include "pkglibmsgs.h" diff --git a/usr/src/lib/libpkg/common/dstream.c b/usr/src/lib/libpkg/common/dstream.c index 38ca430614..6622b74361 100644 --- a/usr/src/lib/libpkg/common/dstream.c +++ b/usr/src/lib/libpkg/common/dstream.c @@ -20,6 +20,10 @@ */ /* + * Copyright (c) 2017 Peter Tribble. + */ + +/* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -42,7 +46,6 @@ #include <sys/stat.h> #include <sys/statvfs.h> #include <fcntl.h> -#include <openssl/err.h> #include "pkglib.h" #include "pkglibmsgs.h" #include "pkglocale.h" @@ -135,7 +138,6 @@ ds_order(char *list[]) static char *pds_header; static char *ds_header; -static char *ds_header_raw; static int ds_headsize; static char * @@ -421,15 +423,6 @@ ds_init(char *device, char **pkg, char *norewind) pds_header = ds_header; - /* save raw copy of header for later use in BIO_dump_header */ - if ((ds_header_raw = (char *)malloc(header_size)) == NULL) { - progerr(pkg_gt(ERR_UNPACK)); - logerr(pkg_gt(MSG_MEM)); - (void) ds_close(0); - return (1); - } - (void) memcpy(ds_header_raw, ds_header, header_size); - /* read datastream table of contents */ ds_head = tail = (struct dstoc *)0; ds_volcnt = 1; @@ -491,16 +484,9 @@ ds_init(char *device, char **pkg, char *norewind) } (void) strlcat(cmd, pkg[i], CMDSIZ); (void) strlcat(cmd, "'/*' ", CMDSIZ); - - /* extract signature too, if present. */ - (void) strlcat(cmd, SIGNATURE_FILENAME, CMDSIZ); (void) strlcat(cmd, " ", CMDSIZ); } - /* - * if we are extracting all packages (pkgs == NULL), - * signature will automatically be extracted - */ if (n = esystem(cmd, ds_fd, -1)) { rpterr(); progerr(pkg_gt(ERR_UNPACK)); @@ -718,73 +704,6 @@ ds_next(char *device, char *instdir) } /* - * Name: BIO_ds_dump - * Description: Dumps all data from the static 'ds_fd' file handle into - * the supplied BIO. - * - * Arguments: err - where to record any errors. - * device - Description of device being dumped into, - * for error reporting - * bio - BIO object to dump data into - * - * Returns : zero - successfully dumped all data to EOF - * non-zero - some failure occurred. - */ -int -BIO_ds_dump(PKG_ERR *err, char *device, BIO *bio) -{ - int amtread; - char readbuf[BLK_SIZE]; - - /* - * note this will read to the end of the device, so it won't - * work for character devices since we don't know when the - * end of the CPIO archive is - */ - while ((amtread = read(ds_fd, readbuf, BLK_SIZE)) != 0) { - if (BIO_write(bio, readbuf, amtread) != amtread) { - pkgerr_add(err, PKGERR_WRITE, ERR_WRITE, device, - ERR_error_string(ERR_get_error(), NULL)); - return (1); - } - } - - return (0); - /*NOTREACHED*/ -} - - -/* - * Name: BIO_ds_dump_header - * Description: Dumps all ds_headsize bytes from the - * static 'ds_header_raw' character array - * to the supplied BIO. - * - * Arguments: err - where to record any errors. - * bio - BIO object to dump data into - * - * Returns : zero - successfully dumped all raw - * header characters - * non-zero - some failure occurred. - */ -int -BIO_ds_dump_header(PKG_ERR *err, BIO *bio) -{ - - char zeros[BLK_SIZE]; - - (void) memset(zeros, 0, BLK_SIZE); - - if (BIO_write(bio, ds_header_raw, ds_headsize) != ds_headsize) { - pkgerr_add(err, PKGERR_WRITE, ERR_WRITE, "bio", - ERR_error_string(ERR_get_error(), NULL)); - return (1); - } - - return (0); -} - -/* * ds_ginit: Determine the device being accessed, set the buffer size, * and perform any device specific initialization. */ diff --git a/usr/src/lib/libpkg/common/gpkgmap.c b/usr/src/lib/libpkg/common/gpkgmap.c index 4bbe60dfc3..a8bd01c87c 100644 --- a/usr/src/lib/libpkg/common/gpkgmap.c +++ b/usr/src/lib/libpkg/common/gpkgmap.c @@ -20,6 +20,10 @@ */ /* + * Copyright (c) 2017 Peter Tribble. + */ + +/* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -389,7 +393,6 @@ end: return (-1); } -done: return (1); } @@ -930,7 +933,6 @@ end: return (-1); } -done: return (1); } diff --git a/usr/src/lib/libpkg/common/keystore.c b/usr/src/lib/libpkg/common/keystore.c deleted file mode 100644 index 633c04b58e..0000000000 --- a/usr/src/lib/libpkg/common/keystore.c +++ /dev/null @@ -1,2474 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * Module: keystore.c - * Description: This module contains the structure definitions for processing - * package keystore files. - */ - -#include <errno.h> -#include <fcntl.h> -#include <unistd.h> -#include <strings.h> -#include <libintl.h> -#include <time.h> -#include <ctype.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <openssl/evp.h> -#include <openssl/x509.h> -#include <openssl/pkcs12.h> -#include <openssl/asn1.h> -#include <openssl/pem.h> -#include <openssl/err.h> -#include <openssl/safestack.h> -#include <openssl/stack.h> -#include "p12lib.h" -#include "pkgerr.h" -#include "keystore.h" -#include "pkglib.h" -#include "pkglibmsgs.h" - -typedef struct keystore_t { - boolean_t dirty; - boolean_t new; - char *path; - char *passphrase; - /* truststore handles */ - int cafd; - STACK_OF(X509) *cacerts; - char *capath; - - /* user certificate handles */ - STACK_OF(X509) *clcerts; - char *clpath; - - /* private key handles */ - STACK_OF(EVP_PKEY) *pkeys; - char *keypath; -} keystore_t; - -/* local routines */ -static keystore_t *new_keystore(void); -static void free_keystore(keystore_t *); -static boolean_t verify_keystore_integrity(PKG_ERR *, keystore_t *); -static boolean_t check_password(PKCS12 *, char *); -static boolean_t resolve_paths(PKG_ERR *, char *, char *, - long, keystore_t *); -static boolean_t lock_keystore(PKG_ERR *, long, keystore_t *); - -static boolean_t unlock_keystore(PKG_ERR *, keystore_t *); -static boolean_t read_keystore(PKG_ERR *, keystore_t *, - keystore_passphrase_cb); -static boolean_t write_keystore(PKG_ERR *, keystore_t *, - keystore_passphrase_cb); -static boolean_t write_keystore_file(PKG_ERR *, char *, PKCS12 *); -static boolean_t clear_keystore_file(PKG_ERR *, char *); -static PKCS12 *read_keystore_file(PKG_ERR *, char *); -static char *get_time_string(ASN1_TIME *); - -/* locking routines */ -static boolean_t restore_keystore_file(PKG_ERR *, char *); -static int file_lock(int, int, int); -static int file_unlock(int); -static boolean_t file_lock_test(int, int); -static boolean_t file_empty(char *); -static boolean_t get_keystore_passwd(PKG_ERR *err, PKCS12 *p12, - keystore_passphrase_cb cb, keystore_t *keystore); -static boolean_t wait_restore(int, char *, char *, char *); - -#define KEYSTORE_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) - -/* wait on other keystore access for 1 minute before giving up */ -#define LOCK_TIMEOUT 60 - -/* - * print_certs - prints certificates out of a keystore, to a file. - * - * Arguments: - * err - Error object to append errors to - * keystore - Keystore on which to operate - * alias - Name of certificate to print, NULL means print all - * format - Format in which to print certificates - * outfile - Where to print certificates - * - * Returns: - * 0 - Success - * non-zero - Failure, errors added to err - */ -int -print_certs(PKG_ERR *err, keystore_handle_t keystore_h, char *alias, - keystore_encoding_format_t format, FILE *outfile) -{ - int i; - X509 *cert; - char *fname = NULL; - boolean_t found = B_FALSE; - keystore_t *keystore = keystore_h; - - if (keystore->clcerts != NULL) { - /* print out each client cert */ - for (i = 0; i < sk_X509_num(keystore->clcerts); i++) { - cert = sk_X509_value(keystore->clcerts, i); - (void) sunw_get_cert_fname(GETDO_COPY, cert, - &fname); - - if (fname == NULL) { - /* no name recorded, keystore is corrupt */ - pkgerr_add(err, PKGERR_CORRUPT, - gettext(ERR_KEYSTORE_NO_ALIAS), - get_subject_display_name(cert)); - return (1); - } - - if ((alias != NULL) && (!streq(alias, fname))) { - /* name does not match, skip it */ - (void) OPENSSL_free(fname); - fname = NULL; - continue; - } else { - found = B_TRUE; - (void) print_cert(err, cert, format, - fname, B_FALSE, outfile); - (void) OPENSSL_free(fname); - fname = NULL; - } - } - } - - if (fname != NULL) { - (void) OPENSSL_free(fname); - fname = NULL; - } - - if (keystore->cacerts != NULL) { - /* print out each trusted cert */ - for (i = 0; i < sk_X509_num(keystore->cacerts); i++) { - cert = sk_X509_value(keystore->cacerts, i); - (void) sunw_get_cert_fname(GETDO_COPY, - cert, &fname); - - if (fname == NULL) { - /* no name recorded, keystore is corrupt */ - pkgerr_add(err, PKGERR_CORRUPT, - gettext(ERR_KEYSTORE_NO_ALIAS), - get_subject_display_name(cert)); - return (1); - } - - if ((alias != NULL) && (!streq(alias, fname))) { - /* name does not match, skip it */ - (void) OPENSSL_free(fname); - fname = NULL; - continue; - } else { - found = B_TRUE; - (void) print_cert(err, cert, format, - fname, B_TRUE, outfile); - (void) OPENSSL_free(fname); - fname = NULL; - } - } - } - - if (fname != NULL) { - (void) OPENSSL_free(fname); - fname = NULL; - } - - if (found) { - return (0); - } else { - /* no certs printed */ - if (alias != NULL) { - pkgerr_add(err, PKGERR_NOALIASMATCH, - gettext(ERR_KEYSTORE_NOCERT), - alias, keystore->path); - } else { - pkgerr_add(err, PKGERR_NOPUBKEY, - gettext(ERR_KEYSTORE_NOPUBCERTS), - keystore->path); - pkgerr_add(err, PKGERR_NOCACERT, - gettext(ERR_KEYSTORE_NOCACERTS), - keystore->path); - } - return (1); - } -} - -/* - * print_cert - prints a single certificate, to a file - * - * Arguments: - * err - Error object to append errors to - * x - The certificate to print - * alias - Name of certificate to print - * format - Format in which to print certificate - * outfile - Where to print certificate - * - * Returns: - * 0 - Success - * non-zero - Failure, errors added to err - */ -int print_cert(PKG_ERR *err, X509 *x, - keystore_encoding_format_t format, char *alias, boolean_t is_trusted, - FILE *outfile) -{ - - char *vdb_str; - char *vda_str; - char vd_str[ATTR_MAX]; - int ret = 0; - char *cn_str, *icn_str, *typ_str; - char *tmp; - char *md5_fp; - char *sha1_fp; - int len; - - /* need to localize the word "Fingerprint", hence these pointers */ - char md5_label[ATTR_MAX]; - char sha1_label[ATTR_MAX]; - - if (is_trusted) { - typ_str = gettext(MSG_KEYSTORE_TRUSTED); - } else { - typ_str = gettext(MSG_KEYSTORE_UNTRUSTED); - } - - if ((cn_str = get_subject_display_name(x)) == NULL) { - cn_str = gettext(MSG_KEYSTORE_UNKNOWN); - } - - if ((icn_str = get_issuer_display_name(x)) == NULL) { - icn_str = gettext(MSG_KEYSTORE_UNKNOWN); - } - - vdb_str = xstrdup(get_time_string(X509_get_notBefore(x))); - vda_str = xstrdup(get_time_string(X509_get_notAfter(x))); - if (((len = snprintf(vd_str, ATTR_MAX, "<%s> - <%s>", - vdb_str, vda_str)) < 0) || (len >= ATTR_MAX)) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN), vdb_str); - ret = 1; - goto cleanup; - } - - if ((tmp = get_fingerprint(x, EVP_md5())) == NULL) { - md5_fp = gettext(MSG_KEYSTORE_UNKNOWN); - } else { - /* - * make a copy, otherwise the next call to get_fingerprint - * will overwrite this one - */ - md5_fp = xstrdup(tmp); - } - - if ((tmp = get_fingerprint(x, EVP_sha1())) == NULL) { - sha1_fp = gettext(MSG_KEYSTORE_UNKNOWN); - } else { - sha1_fp = xstrdup(tmp); - } - - (void) snprintf(md5_label, ATTR_MAX, "%s %s", - OBJ_nid2sn(EVP_MD_type(EVP_md5())), - /* i18n: 14 characters max */ - gettext(MSG_KEYSTORE_FP)); - - (void) snprintf(sha1_label, ATTR_MAX, "%s %s", - OBJ_nid2sn(EVP_MD_type(EVP_sha1())), - /* i18n: 14 characters max */ - gettext(MSG_KEYSTORE_FP)); - - switch (format) { - case KEYSTORE_FORMAT_PEM: - (void) PEM_write_X509(outfile, x); - break; - case KEYSTORE_FORMAT_DER: - (void) i2d_X509_fp(outfile, x); - break; - case KEYSTORE_FORMAT_TEXT: - (void) fprintf(outfile, "%18s: %s\n", - /* i18n: 18 characters max */ - gettext(MSG_KEYSTORE_AL), alias); - (void) fprintf(outfile, "%18s: %s\n", - /* i18n: 18 characters max */ - gettext(MSG_KEYSTORE_CN), cn_str); - (void) fprintf(outfile, "%18s: %s\n", - /* i18n: 18 characters max */ - gettext(MSG_KEYSTORE_TY), typ_str); - (void) fprintf(outfile, "%18s: %s\n", - /* i18n: 18 characters max */ - gettext(MSG_KEYSTORE_IN), icn_str); - (void) fprintf(outfile, "%18s: %s\n", - /* i18n: 18 characters max */ - gettext(MSG_KEYSTORE_VD), vd_str); - (void) fprintf(outfile, "%18s: %s\n", md5_label, md5_fp); - (void) fprintf(outfile, "%18s: %s\n", sha1_label, sha1_fp); - (void) fprintf(outfile, "\n"); - break; - default: - pkgerr_add(err, PKGERR_INTERNAL, - gettext(ERR_KEYSTORE_INTERNAL), - __FILE__, __LINE__); - ret = 1; - goto cleanup; - } - -cleanup: - if (md5_fp != NULL) - free(md5_fp); - if (sha1_fp != NULL) - free(sha1_fp); - if (vda_str != NULL) - free(vda_str); - if (vdb_str != NULL) - free(vdb_str); - return (ret); -} - -/* - * open_keystore - Initialize new keystore object for - * impending access. - * - * Arguments: - * err - Error object to append errors to - * keystore_file - Base filename or directory of keystore - * app - Application making request - * passwd - Password used to decrypt keystore - * flags - Control flags used to control access mode and behavior - * result - Resulting keystore object stored here on success - * - * Returns: - * 0 - Success - result contains a pointer to the opened keystore - * non-zero - Failure, errors added to err - */ -int -open_keystore(PKG_ERR *err, char *keystore_file, char *app, - keystore_passphrase_cb cb, long flags, keystore_handle_t *result) -{ - int ret = 0; - keystore_t *tmpstore; - - tmpstore = new_keystore(); - - tmpstore->dirty = B_FALSE; - tmpstore->new = B_FALSE; - tmpstore->path = xstrdup(keystore_file); - - if (!resolve_paths(err, keystore_file, app, flags, tmpstore)) { - /* unable to determine keystore paths */ - pkgerr_add(err, PKGERR_CORRUPT, gettext(ERR_KEYSTORE_REPAIR), - keystore_file); - ret = 1; - goto cleanup; - } - - if (!verify_keystore_integrity(err, tmpstore)) { - /* unable to repair keystore */ - pkgerr_add(err, PKGERR_CORRUPT, gettext(ERR_KEYSTORE_REPAIR), - keystore_file); - ret = 1; - goto cleanup; - } - - if (!lock_keystore(err, flags, tmpstore)) { - pkgerr_add(err, PKGERR_LOCKED, gettext(ERR_KEYSTORE_LOCKED), - keystore_file); - ret = 1; - goto cleanup; - } - - /* now that we have locked the keystore, go ahead and read it */ - if (!read_keystore(err, tmpstore, cb)) { - pkgerr_add(err, PKGERR_READ, gettext(ERR_PARSE), - keystore_file); - ret = 1; - goto cleanup; - } - - *result = tmpstore; - tmpstore = NULL; - -cleanup: - if (tmpstore != NULL) - free_keystore(tmpstore); - return (ret); -} - -/* - * new_keystore - Allocates and initializes a Keystore object - * - * Arguments: - * NONE - * - * Returns: - * NULL - out of memory - * otherwise, returns a pointer to the newly allocated object, - * which should be freed with free_keystore() when no longer - * needed. - */ -static keystore_t -*new_keystore(void) -{ - keystore_t *tmpstore; - - if ((tmpstore = (keystore_t *)malloc(sizeof (keystore_t))) == NULL) { - return (NULL); - } - tmpstore->dirty = B_FALSE; - tmpstore->new = B_FALSE; - tmpstore->path = NULL; - tmpstore->passphrase = NULL; - tmpstore->cafd = -1; - tmpstore->cacerts = NULL; - tmpstore->capath = NULL; - tmpstore->clcerts = NULL; - tmpstore->clpath = NULL; - tmpstore->pkeys = NULL; - tmpstore->keypath = NULL; - - return (tmpstore); -} - -/* - * free_keystore - Deallocates a Keystore object - * - * Arguments: - * keystore - The keystore to deallocate - * - * Returns: - * NONE - */ -static void -free_keystore(keystore_t *keystore) -{ - if (keystore->path != NULL) - free(keystore->path); - if (keystore->capath != NULL) - free(keystore->capath); - if (keystore->passphrase != NULL) - free(keystore->passphrase); - if (keystore->clpath != NULL) - free(keystore->clpath); - if (keystore->keypath != NULL) - free(keystore->keypath); - - if (keystore->pkeys != NULL) { - sk_EVP_PKEY_pop_free(keystore->pkeys, - sunw_evp_pkey_free); - } - if (keystore->clcerts != NULL) - sk_X509_free(keystore->clcerts); - if (keystore->cacerts != NULL) - sk_X509_free(keystore->cacerts); - free(keystore); -} - -/* - * close_keystore - Writes keystore to disk if needed, then - * unlocks and closes keystore. - * - * Arguments: - * err - Error object to append errors to - * keystore - Keystore which should be closed - * passwd - Password used to encrypt keystore - * - * Returns: - * 0 - Success - keystore is committed to disk, and unlocked - * non-zero - Failure, errors added to err - */ -int -close_keystore(PKG_ERR *err, keystore_handle_t keystore_h, - keystore_passphrase_cb cb) -{ - int ret = 0; - keystore_t *keystore = keystore_h; - - if (keystore->dirty) { - /* write out the keystore first */ - if (!write_keystore(err, keystore, cb)) { - pkgerr_add(err, PKGERR_WRITE, - gettext(ERR_KEYSTORE_WRITE), - keystore->path); - ret = 1; - goto cleanup; - } - } - - if (!unlock_keystore(err, keystore)) { - pkgerr_add(err, PKGERR_UNLOCK, gettext(ERR_KEYSTORE_UNLOCK), - keystore->path); - ret = 1; - goto cleanup; - } - - free_keystore(keystore); -cleanup: - return (ret); -} - -/* - * merge_ca_cert - Adds a trusted certificate (trust anchor) to a keystore. - * certificate checked for validity dates and non-duplicity. - * - * Arguments: - * err - Error object to add errors to - * cacert - Certificate which to merge into keystore - * keystore - The keystore into which the certificate is merged - * - * Returns: - * 0 - Success - Certificate passes validity, and - * is merged into keystore - * non-zero - Failure, errors recorded in err - */ -int -merge_ca_cert(PKG_ERR *err, X509 *cacert, keystore_handle_t keystore_h) -{ - - int ret = 0; - X509 *existing = NULL; - char *fname; - keystore_t *keystore = keystore_h; - - /* check validity dates */ - if (check_cert(err, cacert) != 0) { - ret = 1; - goto cleanup; - } - - /* create the certificate's friendlyName */ - fname = get_subject_display_name(cacert); - - if (sunw_set_fname(fname, NULL, cacert) != 0) { - pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM)); - ret = 1; - goto cleanup; - } - - /* merge certificate into the keystore */ - if (keystore->cacerts == NULL) { - /* no existing truststore, so make a new one */ - if ((keystore->cacerts = sk_X509_new_null()) == NULL) { - pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM)); - ret = 1; - goto cleanup; - } - } else { - /* existing truststore, make sure there's no duplicate */ - if (sunw_find_fname(fname, NULL, keystore->cacerts, - NULL, &existing) < 0) { - pkgerr_add(err, PKGERR_INTERNAL, - gettext(ERR_KEYSTORE_INTERNAL), - __FILE__, __LINE__); - ERR_print_errors_fp(stderr); - ret = 1; - goto cleanup; - /* could not search properly! */ - } - if (existing != NULL) { - /* whoops, found one already */ - pkgerr_add(err, PKGERR_DUPLICATE, - gettext(ERR_KEYSTORE_DUPLICATECERT), fname); - ret = 1; - goto cleanup; - } - } - - (void) sk_X509_push(keystore->cacerts, cacert); - keystore->dirty = B_TRUE; -cleanup: - if (existing != NULL) - X509_free(existing); - return (ret); -} - -/* - * find_key_cert_pair - Searches a keystore for a matching - * public key certificate and private key, given an alias. - * - * Arguments: - * err - Error object to add errors to - * ks - Keystore to search - * alias - Name to used to match certificate's alias - * key - Resulting key is placed here - * cert - Resulting cert is placed here - * - * Returns: - * 0 - Success - Matching cert/key pair placed in key and cert. - * non-zero - Failure, errors recorded in err - */ -int -find_key_cert_pair(PKG_ERR *err, keystore_handle_t ks_h, char *alias, - EVP_PKEY **key, X509 **cert) -{ - X509 *tmpcert = NULL; - EVP_PKEY *tmpkey = NULL; - int ret = 0; - int items_found; - keystore_t *ks = ks_h; - - if (key == NULL || cert == NULL) { - pkgerr_add(err, PKGERR_NOPUBKEY, - gettext(ERR_KEYSTORE_NOPUBCERTS), ks->path); - ret = 1; - goto cleanup; - } - - if (ks->clcerts == NULL) { - /* no public certs */ - pkgerr_add(err, PKGERR_NOPUBKEY, - gettext(ERR_KEYSTORE_NOCERTS), ks->path); - ret = 1; - goto cleanup; - } - if (ks->pkeys == NULL) { - /* no private keys */ - pkgerr_add(err, PKGERR_NOPRIVKEY, - gettext(ERR_KEYSTORE_NOKEYS), ks->path); - ret = 1; - goto cleanup; - } - - /* try the easy case first */ - if ((sk_EVP_PKEY_num(ks->pkeys) == 1) && - (sk_X509_num(ks->clcerts) == 1)) { - tmpkey = sk_EVP_PKEY_value(ks->pkeys, 0); - tmpcert = sk_X509_value(ks->clcerts, 0); - if (sunw_check_keys(tmpcert, tmpkey)) { - /* - * only one private key and public key cert, and they - * match, so use them - */ - *key = tmpkey; - tmpkey = NULL; - *cert = tmpcert; - tmpcert = NULL; - goto cleanup; - } - } - - /* Attempt to find the right pair given the alias */ - items_found = sunw_find_fname(alias, ks->pkeys, ks->clcerts, - &tmpkey, &tmpcert); - - if ((items_found < 0) || - (items_found & (FOUND_PKEY | FOUND_CERT)) == 0) { - /* no key/cert pair found. bail. */ - pkgerr_add(err, PKGERR_BADALIAS, - gettext(ERR_KEYSTORE_NOMATCH), alias); - ret = 1; - goto cleanup; - } - - /* success */ - *key = tmpkey; - tmpkey = NULL; - *cert = tmpcert; - tmpcert = NULL; - -cleanup: - - if (tmpcert != NULL) - (void) X509_free(tmpcert); - - if (tmpkey != NULL) - sunw_evp_pkey_free(tmpkey); - - return (ret); -} - -/* - * find_ca_certs - Searches a keystore for trusted certificates - * - * Arguments: - * err - Error object to add errors to - * ks - Keystore to search - * cacerts - resulting set of trusted certs are placed here - * - * Returns: - * 0 - Success - trusted cert list returned in cacerts - * non-zero - Failure, errors recorded in err - */ -int -find_ca_certs(PKG_ERR *err, keystore_handle_t ks_h, STACK_OF(X509) **cacerts) -{ - - keystore_t *ks = ks_h; - - /* easy */ - if (cacerts == NULL) { - pkgerr_add(err, PKGERR_INTERNAL, - gettext(ERR_KEYSTORE_INTERNAL), __FILE__, __LINE__); - return (1); - } - - *cacerts = ks->cacerts; - return (0); -} - -/* - * find_cl_certs - Searches a keystore for user certificates - * - * Arguments: - * err - Error object to add errors to - * ks - Keystore to search - * cacerts - resulting set of user certs are placed here - * - * No matching of any kind is performed. - * Returns: - * 0 - Success - trusted cert list returned in cacerts - * non-zero - Failure, errors recorded in err - */ -/* ARGSUSED */ -int -find_cl_certs(PKG_ERR *err, keystore_handle_t ks_h, STACK_OF(X509) **clcerts) -{ - keystore_t *ks = ks_h; - - /* easy */ - *clcerts = ks->clcerts; - return (0); -} - - -/* - * merge_cert_and_key - Adds a user certificate and matching - * private key to a keystore. - * certificate checked for validity dates and non-duplicity. - * - * Arguments: - * err - Error object to add errors to - * cert - Certificate which to merge into keystore - * key - matching private key to 'cert' - * alias - Name which to store the cert and key under - * keystore - The keystore into which the certificate is merged - * - * Returns: - * 0 - Success - Certificate passes validity, and - * is merged into keystore, along with key - * non-zero - Failure, errors recorded in err - */ -int -merge_cert_and_key(PKG_ERR *err, X509 *cert, EVP_PKEY *key, char *alias, - keystore_handle_t keystore_h) -{ - X509 *existingcert = NULL; - EVP_PKEY *existingkey = NULL; - int ret = 0; - keystore_t *keystore = keystore_h; - - /* check validity dates */ - if (check_cert(err, cert) != 0) { - ret = 1; - goto cleanup; - } - - /* set the friendlyName of the key and cert to the supplied alias */ - if (sunw_set_fname(alias, key, cert) != 0) { - pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM)); - ret = 1; - goto cleanup; - } - - /* merge certificate and key into the keystore */ - if (keystore->clcerts == NULL) { - /* no existing truststore, so make a new one */ - if ((keystore->clcerts = sk_X509_new_null()) == NULL) { - pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM)); - ret = 1; - goto cleanup; - } - } else { - /* existing certstore, make sure there's no duplicate */ - if (sunw_find_fname(alias, NULL, keystore->clcerts, - NULL, &existingcert) < 0) { - pkgerr_add(err, PKGERR_INTERNAL, - gettext(ERR_KEYSTORE_INTERNAL), - __FILE__, __LINE__); - ERR_print_errors_fp(stderr); - ret = 1; - goto cleanup; - /* could not search properly! */ - } - if (existingcert != NULL) { - /* whoops, found one already */ - pkgerr_add(err, PKGERR_DUPLICATE, - gettext(ERR_KEYSTORE_DUPLICATECERT), alias); - ret = 1; - goto cleanup; - } - } - - if (keystore->pkeys == NULL) { - /* no existing keystore, so make a new one */ - if ((keystore->pkeys = sk_EVP_PKEY_new_null()) == NULL) { - pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM)); - ret = 1; - goto cleanup; - } - } else { - /* existing keystore, so make sure there's no duplicate entry */ - if (sunw_find_fname(alias, keystore->pkeys, NULL, - &existingkey, NULL) < 0) { - pkgerr_add(err, PKGERR_INTERNAL, - gettext(ERR_KEYSTORE_INTERNAL), - __FILE__, __LINE__); - ERR_print_errors_fp(stderr); - ret = 1; - goto cleanup; - /* could not search properly! */ - } - if (existingkey != NULL) { - /* whoops, found one already */ - pkgerr_add(err, PKGERR_DUPLICATE, - gettext(ERR_KEYSTORE_DUPLICATEKEY), alias); - ret = 1; - goto cleanup; - } - } - - (void) sk_X509_push(keystore->clcerts, cert); - (void) sk_EVP_PKEY_push(keystore->pkeys, key); - keystore->dirty = B_TRUE; -cleanup: - if (existingcert != NULL) - (void) X509_free(existingcert); - if (existingkey != NULL) - (void) sunw_evp_pkey_free(existingkey); - return (ret); -} - -/* - * delete_cert_and_keys - Deletes one or more certificates - * and matching private keys from a keystore. - * - * Arguments: - * err - Error object to add errors to - * ks - The keystore from which certs and keys are deleted - * alias - Name which to search for certificates and keys - * to delete - * - * Returns: - * 0 - Success - All trusted certs which match 'alias' - * are deleted. All user certificates - * which match 'alias' are deleted, along - * with the matching private key. - * non-zero - Failure, errors recorded in err - */ -int -delete_cert_and_keys(PKG_ERR *err, keystore_handle_t ks_h, char *alias) -{ - X509 *existingcert; - EVP_PKEY *existingkey; - int i; - char *fname = NULL; - boolean_t found = B_FALSE; - keystore_t *ks = ks_h; - - /* delete any and all client certs with the supplied name */ - if (ks->clcerts != NULL) { - for (i = 0; i < sk_X509_num(ks->clcerts); i++) { - existingcert = sk_X509_value(ks->clcerts, i); - if (sunw_get_cert_fname(GETDO_COPY, - existingcert, &fname) >= 0) { - if (streq(fname, alias)) { - /* match, so nuke it */ - existingcert = - sk_X509_delete(ks->clcerts, i); - X509_free(existingcert); - existingcert = NULL; - found = B_TRUE; - } - (void) OPENSSL_free(fname); - fname = NULL; - } - } - if (sk_X509_num(ks->clcerts) <= 0) { - /* we deleted all the client certs */ - sk_X509_free(ks->clcerts); - ks->clcerts = NULL; - } - } - - /* and now the private keys */ - if (ks->pkeys != NULL) { - for (i = 0; i < sk_EVP_PKEY_num(ks->pkeys); i++) { - existingkey = sk_EVP_PKEY_value(ks->pkeys, i); - if (sunw_get_pkey_fname(GETDO_COPY, - existingkey, &fname) >= 0) { - if (streq(fname, alias)) { - /* match, so nuke it */ - existingkey = - sk_EVP_PKEY_delete(ks->pkeys, i); - sunw_evp_pkey_free(existingkey); - existingkey = NULL; - found = B_TRUE; - } - (void) OPENSSL_free(fname); - fname = NULL; - } - } - if (sk_EVP_PKEY_num(ks->pkeys) <= 0) { - /* we deleted all the private keys */ - sk_EVP_PKEY_free(ks->pkeys); - ks->pkeys = NULL; - } - } - - /* finally, remove any trust anchors that match */ - - if (ks->cacerts != NULL) { - for (i = 0; i < sk_X509_num(ks->cacerts); i++) { - existingcert = sk_X509_value(ks->cacerts, i); - if (sunw_get_cert_fname(GETDO_COPY, - existingcert, &fname) >= 0) { - if (streq(fname, alias)) { - /* match, so nuke it */ - existingcert = - sk_X509_delete(ks->cacerts, i); - X509_free(existingcert); - existingcert = NULL; - found = B_TRUE; - } - (void) OPENSSL_free(fname); - fname = NULL; - } - } - if (sk_X509_num(ks->cacerts) <= 0) { - /* we deleted all the CA certs */ - sk_X509_free(ks->cacerts); - ks->cacerts = NULL; - } - } - - if (found) { - ks->dirty = B_TRUE; - return (0); - } else { - /* no certs or keys deleted */ - pkgerr_add(err, PKGERR_NOALIASMATCH, - gettext(ERR_KEYSTORE_NOCERTKEY), - alias, ks->path); - return (1); - } -} - -/* - * check_cert - Checks certificate validity. This routine - * checks that the current time falls within the period - * of validity for the cert. - * - * Arguments: - * err - Error object to add errors to - * cert - The certificate to check - * - * Returns: - * 0 - Success - Certificate checks out - * non-zero - Failure, errors and reasons recorded in err - */ -int -check_cert(PKG_ERR *err, X509 *cert) -{ - char currtimestr[ATTR_MAX]; - time_t currtime; - char *r; - /* get current time */ - if ((currtime = time(NULL)) == (time_t)-1) { - pkgerr_add(err, PKGERR_TIME, gettext(ERR_CURR_TIME)); - return (1); - } - - (void) strlcpy(currtimestr, ctime(&currtime), ATTR_MAX); - - /* trim whitespace from end of time string */ - for (r = (currtimestr + strlen(currtimestr) - 1); isspace(*r); r--) { - *r = '\0'; - } - /* check validity of cert */ - switch (sunw_check_cert_times(CHK_BOTH, cert)) { - case CHKERR_TIME_OK: - /* Current time meets requested checks */ - break; - case CHKERR_TIME_BEFORE_BAD: - /* 'not before' field is invalid */ - case CHKERR_TIME_AFTER_BAD: - /* 'not after' field is invalid */ - pkgerr_add(err, PKGERR_TIME, gettext(ERR_CERT_TIME_BAD)); - return (1); - case CHKERR_TIME_IS_BEFORE: - /* Current time is before 'not before' */ - case CHKERR_TIME_HAS_EXPIRED: - /* - * Ignore expiration time since the trust cert used to - * verify the certs used to sign Sun patches is already - * expired. Once the patches get resigned with the new - * cert we will check expiration against the time the - * patch was signed and not the time it is installed. - */ - return (0); - default: - pkgerr_add(err, PKGERR_INTERNAL, - gettext(ERR_KEYSTORE_INTERNAL), - __FILE__, __LINE__); - return (1); - } - - /* all checks ok */ - return (0); -} - -/* - * check_cert - Checks certificate validity. This routine - * checks everything that check_cert checks, and additionally - * verifies that the private key and corresponding public - * key are indeed a pair. - * - * Arguments: - * err - Error object to add errors to - * cert - The certificate to check - * key - the key to check - * Returns: - * 0 - Success - Certificate checks out - * non-zero - Failure, errors and reasons recorded in err - */ -int -check_cert_and_key(PKG_ERR *err, X509 *cert, EVP_PKEY *key) -{ - - /* check validity dates */ - if (check_cert(err, cert) != 0) { - return (1); - } - - /* check key pair match */ - if (sunw_check_keys(cert, key) == 0) { - pkgerr_add(err, PKGERR_VERIFY, gettext(ERR_MISMATCHED_KEYS), - get_subject_display_name(cert)); - return (1); - } - - /* all checks OK */ - return (0); -} - -/* ------------------ private functions ---------------------- */ - -/* - * verify_keystore_integrity - Searches for the remnants - * of a failed or aborted keystore modification, and - * cleans up the files, retstores the keystore to a known - * state. - * - * Arguments: - * err - Error object to add errors to - * keystore_file - Base directory or filename of keystore - * app - Application making request - * - * Returns: - * 0 - Success - Keystore is restored, or untouched in the - * case that cleanup was unnecessary - * non-zero - Failure, errors and reasons recorded in err - */ -static boolean_t -verify_keystore_integrity(PKG_ERR *err, keystore_t *keystore) -{ - if (keystore->capath != NULL) { - if (!restore_keystore_file(err, keystore->capath)) { - return (B_FALSE); - } - } - if (keystore->clpath != NULL) { - if (!restore_keystore_file(err, keystore->clpath)) { - return (B_FALSE); - } - } - if (keystore->keypath != NULL) { - if (!restore_keystore_file(err, keystore->keypath)) { - return (B_FALSE); - } - } - return (B_TRUE); -} - -/* - * restore_keystore_file - restores a keystore file to - * a known state. - * - * Keystore files can possibly be corrupted by a variety - * of error conditions during reading/writing. This - * routine, along with write_keystore_file, tries to - * maintain keystore integrity by writing the files - * out in a particular order, minimizing the time period - * that the keystore is in an indeterminate state. - * - * With the current implementation, there are some failures - * that are wholly unrecoverable, such as disk corruption. - * These routines attempt to minimize the risk, but not - * eliminate it. When better, atomic operations are available - * (such as a trued atabase with commit, rollback, and - * guaranteed atomicity), this implementation should use that. - * - * Arguments: - * err - Error object to add errors to - * keystore_file - keystore file path to restore. - * - * Returns: - * 0 - Success - Keystore file is restored, or untouched in the - * case that cleanup was unnecessary - * non-zero - Failure, errors and reasons recorded in err - */ -/* ARGSUSED */ -static boolean_t -restore_keystore_file(PKG_ERR *err, char *keystore_file) -{ - char newpath[MAXPATHLEN]; - char backuppath[MAXPATHLEN]; - int newfd; - struct stat buf; - int len; - - if (((len = snprintf(newpath, MAXPATHLEN, "%s.new", - keystore_file)) < 0) || - (len >= ATTR_MAX)) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN), keystore_file); - return (B_FALSE); - } - - if (((len = snprintf(backuppath, MAXPATHLEN, "%s.bak", - keystore_file)) < 0) || - (len >= ATTR_MAX)) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN), keystore_file); - return (B_FALSE); - } - - if ((newfd = open(newpath, O_RDWR|O_NONBLOCK, 0)) != -1) { - if (fstat(newfd, &buf) != -1) { - if (S_ISREG(buf.st_mode)) { - /* - * restore the file, waiting on it - * to be free for locking, or for - * it to disappear - */ - if (!wait_restore(newfd, keystore_file, - newpath, backuppath)) { - pkgerr_add(err, PKGERR_WRITE, - gettext(ERR_WRITE), - newpath, strerror(errno)); - (void) close(newfd); - return (B_FALSE); - } else { - return (B_TRUE); - } - } else { - /* "new" file is not a regular file */ - pkgerr_add(err, PKGERR_WRITE, - gettext(ERR_NOT_REG), newpath); - (void) close(newfd); - return (B_FALSE); - } - } else { - /* couldn't stat "new" file */ - pkgerr_add(err, PKGERR_WRITE, - gettext(ERR_WRITE), newpath, - strerror(errno)); - (void) close(newfd); - return (B_FALSE); - } - } else { - /* "new" file doesn't exist */ - return (B_TRUE); - } -} - -static boolean_t -wait_restore(int newfd, char *keystore_file, - char *origpath, char *backuppath) -{ - struct stat buf; - FILE *newstream; - PKCS12 *p12; - - (void) alarm(LOCK_TIMEOUT); - if (file_lock(newfd, F_WRLCK, 1) == -1) { - /* could not lock file */ - (void) alarm(0); - return (B_FALSE); - } - (void) alarm(0); - - if (fstat(newfd, &buf) != -1) { - if (S_ISREG(buf.st_mode)) { - /* - * The new file still - * exists, with no - * owner. It must be - * the result of an - * aborted update. - */ - newstream = fdopen(newfd, "r"); - if ((p12 = - d2i_PKCS12_fp(newstream, - NULL)) != NULL) { - /* - * The file - * appears - * complete. - * Replace the - * exsisting - * keystore - * file with - * this one - */ - (void) rename(keystore_file, backuppath); - (void) rename(origpath, keystore_file); - PKCS12_free(p12); - } else { - /* The file is not complete. Remove it */ - (void) remove(origpath); - } - /* remove backup file */ - (void) remove(backuppath); - (void) fclose(newstream); - (void) close(newfd); - return (B_TRUE); - } else { - /* - * new file exists, but is not a - * regular file - */ - (void) close(newfd); - return (B_FALSE); - } - } else { - /* - * could not stat file. Unless - * the reason was that the file - * is now gone, this is an error - */ - if (errno != ENOENT) { - (void) close(newfd); - return (B_FALSE); - } - /* - * otherwise, file is gone. The process - * that held the lock must have - * successfully cleaned up and - * exited with a valid keystore - * state - */ - (void) close(newfd); - return (B_TRUE); - } -} - -/* - * resolve_paths - figure out if we are dealing with a single-file - * or multi-file keystore - * - * The flags tell resolve_paths how to behave: - * - * KEYSTORE_PATH_SOFT - * If the keystore file does not exist at <base>/<app> then - * use <base> as the path to the keystore. This can be used, - * for example, to access an app-specific keystore iff it - * exists, otherwise revert back to an app-generic keystore. - * - * KEYSTORE_PATH_HARD - * Always use the keystore located at <keystore_path>/<app>. - * In read/write mode, if the files do not exist, then - * they will be created. This is used to avoid falling - * back to an app-generic keystore path when the app-specific - * one does not exist. - * - * Arguments: - * err - Error object to add errors to - * keystore_file - base keystore file path to lock - * app - Application making requests - * flags - Control flags (see above description) - * keystore - object which is being locked - * - * Returns: - * B_TRUE - Success - Keystore file is locked, paths to - * appropriate files placed in keystore. - * B_FALSE - Failure, errors and reasons recorded in err - */ -static boolean_t -resolve_paths(PKG_ERR *err, char *keystore_file, char *app, - long flags, keystore_t *keystore) -{ - char storepath[PATH_MAX]; - struct stat buf; - boolean_t multi = B_FALSE; - int fd1, fd2, len; - - /* - * figure out whether we are dealing with a single-file keystore - * or a multi-file keystore - */ - if (app != NULL) { - if (((len = snprintf(storepath, PATH_MAX, "%s/%s", - keystore_file, app)) < 0) || - (len >= ATTR_MAX)) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN), - keystore_file); - return (B_FALSE); - } - - if (((fd1 = open(storepath, O_NONBLOCK|O_RDONLY)) == -1) || - (fstat(fd1, &buf) == -1) || - !S_ISDIR(buf.st_mode)) { - /* - * app-specific does not exist - * fallback to app-generic, if flags say we can - */ - if ((flags & KEYSTORE_PATH_MASK) == - KEYSTORE_PATH_SOFT) { - - if (((fd2 = open(keystore_file, - O_NONBLOCK|O_RDONLY)) != -1) && - (fstat(fd2, &buf) != -1)) { - if (S_ISDIR(buf.st_mode)) { - /* - * app-generic dir - * exists, so use it - * as a multi-file - * keystore - */ - multi = B_TRUE; - app = NULL; - } else if (S_ISREG(buf.st_mode)) { - /* - * app-generic file exists, so - * use it as a single file ks - */ - multi = B_FALSE; - app = NULL; - } - } - } - } - if (fd1 != -1) - (void) close(fd1); - if (fd2 != -1) - (void) close(fd2); - } else { - if (((fd1 = open(keystore_file, - O_NONBLOCK|O_RDONLY)) != -1) && - (fstat(fd1, &buf) != -1) && - S_ISDIR(buf.st_mode)) { - /* - * app-generic dir exists, so use - * it as a multi-file keystore - */ - multi = B_TRUE; - } - if (fd1 != -1) - (void) close(fd1); - } - - if (app != NULL) { - /* app-specific keystore */ - (void) snprintf(storepath, PATH_MAX, "%s/%s/%s", - keystore_file, app, TRUSTSTORE); - keystore->capath = xstrdup(storepath); - (void) snprintf(storepath, PATH_MAX, "%s/%s/%s", - keystore_file, app, CERTSTORE); - keystore->clpath = xstrdup(storepath); - (void) snprintf(storepath, PATH_MAX, "%s/%s/%s", - keystore_file, app, KEYSTORE); - keystore->keypath = xstrdup(storepath); - } else { - /* app-generic keystore */ - if (!multi) { - /* single-file app-generic keystore */ - keystore->capath = xstrdup(keystore_file); - keystore->keypath = NULL; - keystore->clpath = NULL; - } else { - /* multi-file app-generic keystore */ - (void) snprintf(storepath, PATH_MAX, "%s/%s", - keystore_file, TRUSTSTORE); - keystore->capath = xstrdup(storepath); - (void) snprintf(storepath, PATH_MAX, "%s/%s", - keystore_file, CERTSTORE); - keystore->clpath = xstrdup(storepath); - (void) snprintf(storepath, PATH_MAX, "%s/%s", - keystore_file, KEYSTORE); - keystore->keypath = xstrdup(storepath); - } - } - - return (B_TRUE); -} - -/* - * lock_keystore - Locks a keystore for shared (read-only) - * or exclusive (read-write) access. - * - * The flags tell lock_keystore how to behave: - * - * KEYSTORE_ACCESS_READONLY - * opens keystore read-only. Attempts to modify results in an error - * - * KEYSTORE_ACCESS_READWRITE - * opens keystore read-write - * - * KEYSTORE_PATH_SOFT - * If the keystore file does not exist at <base>/<app> then - * use <base> as the path to the keystore. This can be used, - * for example, to access an app-specific keystore iff it - * exists, otherwise revert back to an app-generic keystore. - * - * KEYSTORE_PATH_HARD - * Always use the keystore located at <keystore_path>/<app>. - * In read/write mode, if the files do not exist, then - * they will be created. This is used to avoid falling - * back to an app-generic keystore path when the app-specific - * one does not exist. - * - * Arguments: - * err - Error object to add errors to - * flags - Control flags (see above description) - * keystore - object which is being locked - * - * Returns: - * 0 - Success - Keystore file is locked, paths to - * appropriate files placed in keystore. - * non-zero - Failure, errors and reasons recorded in err - */ -static boolean_t -lock_keystore(PKG_ERR *err, long flags, keystore_t *keystore) -{ - boolean_t ret = B_TRUE; - struct stat buf; - - switch (flags & KEYSTORE_ACCESS_MASK) { - case KEYSTORE_ACCESS_READONLY: - if ((keystore->cafd = - open(keystore->capath, O_NONBLOCK|O_RDONLY)) == -1) { - if (errno == ENOENT) { - /* - * no keystore. try to create an - * empty one so we can lock on it and - * prevent others from gaining - * exclusive access. It will be - * deleted when the keystore is closed. - */ - if ((keystore->cafd = - open(keystore->capath, - O_NONBLOCK|O_RDWR|O_CREAT|O_EXCL, - S_IRUSR|S_IWUSR)) == -1) { - pkgerr_add(err, PKGERR_READ, - gettext(ERR_NO_KEYSTORE), - keystore->capath); - ret = B_FALSE; - goto cleanup; - } - } else { - pkgerr_add(err, PKGERR_READ, - gettext(ERR_KEYSTORE_OPEN), - keystore->capath, strerror(errno)); - ret = B_FALSE; - goto cleanup; - } - } - if (fstat(keystore->cafd, &buf) != -1) { - if (S_ISREG(buf.st_mode)) { - if (file_lock(keystore->cafd, F_RDLCK, - 0) == -1) { - pkgerr_add(err, PKGERR_LOCKED, - gettext(ERR_KEYSTORE_LOCKED_READ), - keystore->capath); - ret = B_FALSE; - goto cleanup; - } - } else { - /* ca file not a regular file! */ - pkgerr_add(err, PKGERR_READ, - gettext(ERR_NOT_REG), - keystore->capath); - ret = B_FALSE; - goto cleanup; - } - } else { - pkgerr_add(err, PKGERR_READ, - gettext(ERR_KEYSTORE_OPEN), - keystore->capath, strerror(errno)); - ret = B_FALSE; - goto cleanup; - } - break; - case KEYSTORE_ACCESS_READWRITE: - - if ((keystore->cafd = open(keystore->capath, - O_RDWR|O_NONBLOCK)) == -1) { - /* does not exist. try to create an empty one */ - if (errno == ENOENT) { - if ((keystore->cafd = - open(keystore->capath, - O_NONBLOCK|O_RDWR|O_CREAT|O_EXCL, - S_IRUSR|S_IWUSR)) == -1) { - pkgerr_add(err, PKGERR_READ, - gettext(ERR_KEYSTORE_WRITE), - keystore->capath); - ret = B_FALSE; - goto cleanup; - } - } else { - pkgerr_add(err, PKGERR_READ, - gettext(ERR_KEYSTORE_OPEN), - keystore->capath, strerror(errno)); - ret = B_FALSE; - goto cleanup; - } - } - if (fstat(keystore->cafd, &buf) != -1) { - if (S_ISREG(buf.st_mode)) { - if (file_lock(keystore->cafd, F_WRLCK, - 0) == -1) { - pkgerr_add(err, PKGERR_LOCKED, - gettext(ERR_KEYSTORE_LOCKED), - keystore->capath); - ret = B_FALSE; - goto cleanup; - } - } else { - /* ca file not a regular file! */ - pkgerr_add(err, PKGERR_READ, - gettext(ERR_NOT_REG), - keystore->capath); - ret = B_FALSE; - goto cleanup; - } - } else { - pkgerr_add(err, PKGERR_READ, - gettext(ERR_KEYSTORE_OPEN), - keystore->capath, strerror(errno)); - ret = B_FALSE; - goto cleanup; - } - - break; - default: - pkgerr_add(err, PKGERR_INTERNAL, - gettext(ERR_KEYSTORE_INTERNAL), - __FILE__, __LINE__); - ret = B_FALSE; - goto cleanup; - } - -cleanup: - if (!ret) { - if (keystore->cafd > 0) { - (void) file_unlock(keystore->cafd); - (void) close(keystore->cafd); - keystore->cafd = -1; - } - - if (keystore->capath != NULL) - free(keystore->capath); - if (keystore->clpath != NULL) - free(keystore->clpath); - if (keystore->keypath != NULL) - free(keystore->keypath); - keystore->capath = NULL; - keystore->clpath = NULL; - keystore->keypath = NULL; - } - - return (ret); -} - -/* - * unlock_keystore - Unocks a keystore - * - * Arguments: - * err - Error object to add errors to - * keystore - keystore object to unlock - * Returns: - * 0 - Success - Keystore files are unlocked, files are closed, - * non-zero - Failure, errors and reasons recorded in err - */ -/* ARGSUSED */ -static boolean_t -unlock_keystore(PKG_ERR *err, keystore_t *keystore) -{ - - /* - * Release lock on the CA file. - * Delete file if it is empty - */ - if (file_empty(keystore->capath)) { - (void) remove(keystore->capath); - } - - (void) file_unlock(keystore->cafd); - (void) close(keystore->cafd); - return (B_TRUE); -} - -/* - * read_keystore - Reads keystore files of disk, parses - * into internal structures. - * - * Arguments: - * err - Error object to add errors to - * keystore - keystore object to read into - * cb - callback to get password, if required - * Returns: - * 0 - Success - Keystore files are read, and placed - * into keystore structure. - * non-zero - Failure, errors and reasons recorded in err - */ -static boolean_t -read_keystore(PKG_ERR *err, keystore_t *keystore, keystore_passphrase_cb cb) -{ - boolean_t ret = B_TRUE; - PKCS12 *p12 = NULL; - boolean_t ca_empty; - boolean_t have_passwd = B_FALSE; - boolean_t cl_empty = B_TRUE; - boolean_t key_empty = B_TRUE; - - ca_empty = file_empty(keystore->capath); - - if (keystore->clpath != NULL) - cl_empty = file_empty(keystore->clpath); - if (keystore->keypath != NULL) - key_empty = file_empty(keystore->keypath); - - if (ca_empty && cl_empty && key_empty) { - keystore->new = B_TRUE; - } - - if (!ca_empty) { - /* first read the ca file */ - if ((p12 = read_keystore_file(err, - keystore->capath)) == NULL) { - pkgerr_add(err, PKGERR_CORRUPT, - gettext(ERR_KEYSTORE_CORRUPT), keystore->capath); - ret = B_FALSE; - goto cleanup; - } - - /* Get password, using callback if necessary */ - if (!have_passwd) { - if (!get_keystore_passwd(err, p12, cb, keystore)) { - ret = B_FALSE; - goto cleanup; - } - have_passwd = B_TRUE; - } - - /* decrypt and parse keystore file */ - if (sunw_PKCS12_contents(p12, keystore->passphrase, - &keystore->pkeys, &keystore->cacerts) < 0) { - /* could not parse the contents */ - pkgerr_add(err, PKGERR_CORRUPT, - gettext(ERR_KEYSTORE_CORRUPT), keystore->capath); - ret = B_FALSE; - goto cleanup; - } - - PKCS12_free(p12); - p12 = NULL; - } else { - - /* - * truststore is empty, so we don't have any trusted - * certs - */ - keystore->cacerts = NULL; - } - - /* - * if there is no cl file or key file, use the cl's and key's found - * in the ca file - */ - if (keystore->clpath == NULL && !ca_empty) { - if (sunw_split_certs(keystore->pkeys, keystore->cacerts, - &keystore->clcerts, NULL) < 0) { - pkgerr_add(err, PKGERR_CORRUPT, - gettext(ERR_KEYSTORE_CORRUPT), keystore->capath); - ret = B_FALSE; - goto cleanup; - } - } else { - /* - * files are in separate files. read keys out of the keystore - * certs out of the certstore, if they are not empty - */ - if (!cl_empty) { - if ((p12 = read_keystore_file(err, - keystore->clpath)) == NULL) { - pkgerr_add(err, PKGERR_CORRUPT, - gettext(ERR_KEYSTORE_CORRUPT), - keystore->clpath); - ret = B_FALSE; - goto cleanup; - } - - /* Get password, using callback if necessary */ - if (!have_passwd) { - if (!get_keystore_passwd(err, p12, cb, - keystore)) { - ret = B_FALSE; - goto cleanup; - } - have_passwd = B_TRUE; - } - - if (check_password(p12, - keystore->passphrase) == B_FALSE) { - /* - * password in client cert file - * is different than - * the one in the other files! - */ - pkgerr_add(err, PKGERR_BADPASS, - gettext(ERR_MISMATCHPASS), - keystore->clpath, - keystore->capath, keystore->path); - ret = B_FALSE; - goto cleanup; - } - - if (sunw_PKCS12_contents(p12, keystore->passphrase, - NULL, &keystore->clcerts) < 0) { - /* could not parse the contents */ - pkgerr_add(err, PKGERR_CORRUPT, - gettext(ERR_KEYSTORE_CORRUPT), - keystore->clpath); - ret = B_FALSE; - goto cleanup; - } - - PKCS12_free(p12); - p12 = NULL; - } else { - keystore->clcerts = NULL; - } - - if (!key_empty) { - if ((p12 = read_keystore_file(err, - keystore->keypath)) == NULL) { - pkgerr_add(err, PKGERR_CORRUPT, - gettext(ERR_KEYSTORE_CORRUPT), - keystore->keypath); - ret = B_FALSE; - goto cleanup; - } - - /* Get password, using callback if necessary */ - if (!have_passwd) { - if (!get_keystore_passwd(err, p12, cb, - keystore)) { - ret = B_FALSE; - goto cleanup; - } - have_passwd = B_TRUE; - } - - if (check_password(p12, - keystore->passphrase) == B_FALSE) { - pkgerr_add(err, PKGERR_BADPASS, - gettext(ERR_MISMATCHPASS), - keystore->keypath, - keystore->capath, keystore->path); - ret = B_FALSE; - goto cleanup; - } - - if (sunw_PKCS12_contents(p12, keystore->passphrase, - &keystore->pkeys, NULL) < 0) { - /* could not parse the contents */ - pkgerr_add(err, PKGERR_CORRUPT, - gettext(ERR_KEYSTORE_CORRUPT), - keystore->keypath); - ret = B_FALSE; - goto cleanup; - } - - PKCS12_free(p12); - p12 = NULL; - } else { - keystore->pkeys = NULL; - } - } - -cleanup: - if (p12 != NULL) - PKCS12_free(p12); - return (ret); -} - -/* - * get_keystore_password - retrieves pasword used to - * decrypt PKCS12 structure. - * - * Arguments: - * err - Error object to add errors to - * p12 - PKCS12 structure which returned password should - * decrypt - * cb - callback to collect password. - * keystore - The keystore in which the PKCS12 structure - * will eventually populate. - * Returns: - * B_TRUE - success. - * keystore password is set in keystore->passphrase. - * B_FALSE - failure, errors logged - */ -static boolean_t -get_keystore_passwd(PKG_ERR *err, PKCS12 *p12, keystore_passphrase_cb cb, - keystore_t *keystore) -{ - char *passwd; - char passbuf[KEYSTORE_PASS_MAX + 1]; - keystore_passphrase_data data; - - /* see if no password is the right password */ - if (check_password(p12, "") == B_TRUE) { - passwd = ""; - } else if (check_password(p12, NULL) == B_TRUE) { - passwd = NULL; - } else { - /* oops, it's encrypted. get password */ - data.err = err; - if (cb(passbuf, KEYSTORE_PASS_MAX, 0, - &data) == -1) { - /* could not get password */ - return (B_FALSE); - } - - if (check_password(p12, passbuf) == B_FALSE) { - /* wrong password */ - pkgerr_add(err, PKGERR_BADPASS, - gettext(ERR_BADPASS)); - return (B_FALSE); - } - - /* - * make copy of password buffer, since it - * goes away upon return - */ - passwd = xstrdup(passbuf); - } - keystore->passphrase = passwd; - return (B_TRUE); -} - -/* - * write_keystore - Writes keystore files to disk - * - * Arguments: - * err - Error object to add errors to - * keystore - keystore object to write from - * passwd - password used to encrypt keystore - * Returns: - * 0 - Success - Keystore contents are written out to - * the same locations as read from - * non-zero - Failure, errors and reasons recorded in err - */ -static boolean_t -write_keystore(PKG_ERR *err, keystore_t *keystore, - keystore_passphrase_cb cb) -{ - PKCS12 *p12 = NULL; - boolean_t ret = B_TRUE; - keystore_passphrase_data data; - char passbuf[KEYSTORE_PASS_MAX + 1]; - - if (keystore->capath != NULL && keystore->clpath == NULL && - keystore->keypath == NULL) { - - /* - * keystore is a file. - * just write out a single file - */ - if ((keystore->pkeys == NULL) && - (keystore->clcerts == NULL) && - (keystore->cacerts == NULL)) { - if (!clear_keystore_file(err, keystore->capath)) { - /* - * no keys or certs to write out, so - * blank the ca file. we do not - * delete it since it is used as a - * lock by lock_keystore() in - * subsequent invocations - */ - pkgerr_add(err, PKGERR_WRITE, - gettext(ERR_KEYSTORE_WRITE), - keystore->capath); - ret = B_FALSE; - goto cleanup; - } - } else { - /* - * if the keystore is being created for the first time, - * prompt for a passphrase for encryption - */ - if (keystore->new) { - data.err = err; - if (cb(passbuf, KEYSTORE_PASS_MAX, - 1, &data) == -1) { - ret = B_FALSE; - goto cleanup; - } - } else { - /* - * use the one used when the keystore - * was read - */ - (void) strlcpy(passbuf, keystore->passphrase, - KEYSTORE_PASS_MAX); - } - - p12 = sunw_PKCS12_create(passbuf, keystore->pkeys, - keystore->clcerts, keystore->cacerts); - - if (p12 == NULL) { - pkgerr_add(err, PKGERR_WRITE, - gettext(ERR_KEYSTORE_FORM), - keystore->capath); - ret = B_FALSE; - goto cleanup; - } - - if (!write_keystore_file(err, keystore->capath, p12)) { - pkgerr_add(err, PKGERR_WRITE, - gettext(ERR_KEYSTORE_WRITE), - keystore->capath); - ret = B_FALSE; - goto cleanup; - } - } - - } else { - /* files are seprate. Do one at a time */ - - /* - * if the keystore is being created for the first time, - * prompt for a passphrase for encryption - */ - if (keystore->new && ((keystore->pkeys != NULL) || - (keystore->clcerts != NULL) || - (keystore->cacerts != NULL))) { - data.err = err; - if (cb(passbuf, KEYSTORE_PASS_MAX, - 1, &data) == -1) { - ret = B_FALSE; - goto cleanup; - } - } else { - /* use the one used when the keystore was read */ - (void) strlcpy(passbuf, keystore->passphrase, - KEYSTORE_PASS_MAX); - } - - /* do private keys first */ - if (keystore->pkeys != NULL) { - p12 = sunw_PKCS12_create(passbuf, keystore->pkeys, - NULL, NULL); - - if (p12 == NULL) { - pkgerr_add(err, PKGERR_WRITE, - gettext(ERR_KEYSTORE_FORM), - keystore->keypath); - ret = B_FALSE; - goto cleanup; - } - - if (!write_keystore_file(err, keystore->keypath, - p12)) { - pkgerr_add(err, PKGERR_WRITE, - gettext(ERR_KEYSTORE_WRITE), - keystore->keypath); - ret = B_FALSE; - goto cleanup; - } - - PKCS12_free(p12); - } else { - if ((remove(keystore->keypath) != 0) && - (errno != ENOENT)) { - pkgerr_add(err, PKGERR_WRITE, - gettext(ERR_KEYSTORE_REMOVE), - keystore->keypath); - ret = B_FALSE; - goto cleanup; - } - } - - /* do user certs next */ - if (keystore->clcerts != NULL) { - p12 = sunw_PKCS12_create(passbuf, NULL, - keystore->clcerts, NULL); - - if (p12 == NULL) { - pkgerr_add(err, PKGERR_WRITE, - gettext(ERR_KEYSTORE_FORM), - keystore->clpath); - ret = B_FALSE; - goto cleanup; - } - - if (!write_keystore_file(err, keystore->clpath, p12)) { - pkgerr_add(err, PKGERR_WRITE, - gettext(ERR_KEYSTORE_WRITE), - keystore->clpath); - ret = B_FALSE; - goto cleanup; - } - - PKCS12_free(p12); - } else { - if ((remove(keystore->clpath) != 0) && - (errno != ENOENT)) { - pkgerr_add(err, PKGERR_WRITE, - gettext(ERR_KEYSTORE_REMOVE), - keystore->clpath); - ret = B_FALSE; - goto cleanup; - } - } - - - /* finally do CA cert file */ - if (keystore->cacerts != NULL) { - p12 = sunw_PKCS12_create(passbuf, NULL, - NULL, keystore->cacerts); - - if (p12 == NULL) { - pkgerr_add(err, PKGERR_WRITE, - gettext(ERR_KEYSTORE_FORM), - keystore->capath); - ret = B_FALSE; - goto cleanup; - } - - if (!write_keystore_file(err, keystore->capath, p12)) { - pkgerr_add(err, PKGERR_WRITE, - gettext(ERR_KEYSTORE_WRITE), - keystore->capath); - ret = B_FALSE; - goto cleanup; - } - - PKCS12_free(p12); - p12 = NULL; - } else { - /* - * nothing to write out, so truncate the file - * (it will be deleted during close_keystore) - */ - if (!clear_keystore_file(err, keystore->capath)) { - pkgerr_add(err, PKGERR_WRITE, - gettext(ERR_KEYSTORE_WRITE), - keystore->capath); - ret = B_FALSE; - goto cleanup; - } - } - } - -cleanup: - if (p12 != NULL) - PKCS12_free(p12); - - return (ret); -} - -/* - * clear_keystore_file - Clears (zeros out) a keystore file. - * - * Arguments: - * err - Error object to add errors to - * dest - Path of keystore file to zero out. - * Returns: - * 0 - Success - Keystore file is truncated to zero length - * non-zero - Failure, errors and reasons recorded in err - */ -static boolean_t -clear_keystore_file(PKG_ERR *err, char *dest) -{ - int fd; - struct stat buf; - - fd = open(dest, O_RDWR|O_NONBLOCK); - if (fd == -1) { - /* can't open for writing */ - pkgerr_add(err, PKGERR_WRITE, gettext(MSG_OPEN), - errno); - return (B_FALSE); - } - - if ((fstat(fd, &buf) == -1) || !S_ISREG(buf.st_mode)) { - /* not a regular file */ - (void) close(fd); - pkgerr_add(err, PKGERR_WRITE, gettext(ERR_NOT_REG), - dest); - return (B_FALSE); - } - - if (ftruncate(fd, 0) == -1) { - (void) close(fd); - pkgerr_add(err, PKGERR_WRITE, gettext(ERR_WRITE), - dest, strerror(errno)); - return (B_FALSE); - } - - (void) close(fd); - return (B_TRUE); -} - -/* - * write_keystore_file - Writes keystore file to disk. - * - * Keystore files can possibly be corrupted by a variety - * of error conditions during reading/writing. This - * routine, along with restore_keystore_file, tries to - * maintain keystore integity by writing the files - * out in a particular order, minimizing the time period - * that the keystore is in an indeterminate state. - * - * With the current implementation, there are some failures - * that are wholly unrecoverable, such as disk corruption. - * These routines attempt to minimize the risk, but not - * eliminate it. When better, atomic operations are available - * (such as a true database with commit, rollback, and - * guaranteed atomicity), this implementation should use that. - * - * - * Arguments: - * err - Error object to add errors to - * dest - Destination filename - * contents - Contents to write to the file - * Returns: - * 0 - Success - Keystore contents are written out to - * the destination. - * non-zero - Failure, errors and reasons recorded in err - */ -static boolean_t -write_keystore_file(PKG_ERR *err, char *dest, PKCS12 *contents) -{ - FILE *newfile = NULL; - boolean_t ret = B_TRUE; - char newpath[MAXPATHLEN]; - char backuppath[MAXPATHLEN]; - struct stat buf; - int fd; - - (void) snprintf(newpath, MAXPATHLEN, "%s.new", dest); - (void) snprintf(backuppath, MAXPATHLEN, "%s.bak", dest); - - if ((fd = open(newpath, O_CREAT|O_EXCL|O_WRONLY|O_NONBLOCK, - S_IRUSR|S_IWUSR)) == -1) { - pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN), - newpath, strerror(errno)); - ret = B_FALSE; - goto cleanup; - } - - if (fstat(fd, &buf) == -1) { - pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN), - newpath, strerror(errno)); - ret = B_FALSE; - goto cleanup; - } - - if (!S_ISREG(buf.st_mode)) { - pkgerr_add(err, PKGERR_READ, gettext(ERR_NOT_REG), - newpath); - ret = B_FALSE; - goto cleanup; - } - - if ((newfile = fdopen(fd, "w")) == NULL) { - pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN), - newpath, strerror(errno)); - ret = B_FALSE; - goto cleanup; - } - - if (i2d_PKCS12_fp(newfile, contents) == 0) { - pkgerr_add(err, PKGERR_WRITE, gettext(ERR_KEYSTORE_WRITE), - newpath); - ret = B_FALSE; - goto cleanup; - } - - /* flush, then close */ - (void) fflush(newfile); - (void) fclose(newfile); - newfile = NULL; - - /* now back up the original file */ - (void) rename(dest, backuppath); - - /* put new one in its place */ - (void) rename(newpath, dest); - - /* remove backup */ - (void) remove(backuppath); - -cleanup: - if (newfile != NULL) - (void) fclose(newfile); - if (fd != -1) - (void) close(fd); - - return (ret); -} - -/* - * read_keystore_file - Reads single keystore file - * off disk in PKCS12 format. - * - * Arguments: - * err - Error object to add errors to - * file - File path to read - * Returns: - * PKCS12 contents of file, or NULL if an error occurred. - * errors recorded in 'err'. - */ -static PKCS12 -*read_keystore_file(PKG_ERR *err, char *file) -{ - int fd; - struct stat buf; - FILE *newfile; - PKCS12 *p12 = NULL; - - if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) { - pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN), - file, strerror(errno)); - goto cleanup; - } - - if (fstat(fd, &buf) == -1) { - pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN), - file, strerror(errno)); - goto cleanup; - } - - if (!S_ISREG(buf.st_mode)) { - pkgerr_add(err, PKGERR_READ, gettext(ERR_NOT_REG), - file); - goto cleanup; - } - - if ((newfile = fdopen(fd, "r")) == NULL) { - pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN), - file, strerror(errno)); - goto cleanup; - } - - if ((p12 = d2i_PKCS12_fp(newfile, NULL)) == NULL) { - pkgerr_add(err, PKGERR_CORRUPT, - gettext(ERR_KEYSTORE_CORRUPT), file); - goto cleanup; - } - -cleanup: - if (newfile != NULL) - (void) fclose(newfile); - if (fd != -1) - (void) close(fd); - - return (p12); -} - - -/* - * Locks the specified file. - */ -static int -file_lock(int fd, int type, int wait) -{ - struct flock lock; - - lock.l_type = type; - lock.l_start = 0; - lock.l_whence = SEEK_SET; - lock.l_len = 0; - - if (!wait) { - if (file_lock_test(fd, type)) { - /* - * The caller would have to wait to get the - * lock on this file. - */ - return (-1); - } - } - - return (fcntl(fd, F_SETLKW, &lock)); -} - -/* - * Returns FALSE if the file is not locked; TRUE - * otherwise. - */ -static boolean_t -file_lock_test(int fd, int type) -{ - struct flock lock; - - lock.l_type = type; - lock.l_start = 0; - lock.l_whence = SEEK_SET; - lock.l_len = 0; - - if (fcntl(fd, F_GETLK, &lock) != -1) { - if (lock.l_type != F_UNLCK) { - /* - * The caller would have to wait to get the - * lock on this file. - */ - return (B_TRUE); - } - } - - /* - * The file is not locked. - */ - return (B_FALSE); -} - -/* - * Unlocks the specified file. - */ -static int -file_unlock(int fd) -{ - struct flock lock; - - lock.l_type = F_UNLCK; - lock.l_start = 0; - lock.l_whence = SEEK_SET; - lock.l_len = 0; - - return (fcntl(fd, F_SETLK, &lock)); -} - -/* - * Determines if file has a length of 0 or not - */ -static boolean_t -file_empty(char *path) -{ - struct stat buf; - - /* file is empty if size = 0 or it doesn't exist */ - if (lstat(path, &buf) == 0) { - if (buf.st_size == 0) { - return (B_TRUE); - } - } else { - if (errno == ENOENT) { - return (B_TRUE); - } - } - - return (B_FALSE); -} - -/* - * Name: get_time_string - * Description: Generates a human-readable string from an ASN1_TIME - * - * Arguments: intime - The time to convert - * - * Returns : A pointer to a static string representing the passed-in time. - */ -static char -*get_time_string(ASN1_TIME *intime) -{ - - static char time[ATTR_MAX]; - BIO *mem; - char *p; - - if (intime == NULL) { - return (NULL); - } - if ((mem = BIO_new(BIO_s_mem())) == NULL) { - return (NULL); - } - - if (ASN1_TIME_print(mem, intime) == 0) { - (void) BIO_free(mem); - return (NULL); - } - - if (BIO_gets(mem, time, ATTR_MAX) <= 0) { - (void) BIO_free(mem); - return (NULL); - } - - (void) BIO_free(mem); - - /* trim the end of the string */ - for (p = time + strlen(time) - 1; isspace(*p); p--) { - *p = '\0'; - } - - return (time); -} - -/* - * check_password - do various password checks to see if the current password - * will work or we need to prompt for a new one. - * - * Arguments: - * pass - password to check - * - * Returns: - * B_TRUE - Password is OK. - * B_FALSE - Password not valid. - */ -static boolean_t -check_password(PKCS12 *p12, char *pass) -{ - boolean_t ret = B_TRUE; - - /* - * If password is zero length or NULL then try verifying both cases - * to determine which password is correct. The reason for this is that - * under PKCS#12 password based encryption no password and a zero - * length password are two different things... - */ - - /* Check the mac */ - if (pass == NULL || *pass == '\0') { - if (PKCS12_verify_mac(p12, NULL, 0) == 0 && - PKCS12_verify_mac(p12, "", 0) == 0) - ret = B_FALSE; - } else if (PKCS12_verify_mac(p12, pass, -1) == 0) { - ret = B_FALSE; - } - return (ret); -} diff --git a/usr/src/lib/libpkg/common/keystore.h b/usr/src/lib/libpkg/common/keystore.h deleted file mode 100644 index b48ba030aa..0000000000 --- a/usr/src/lib/libpkg/common/keystore.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _KEYSTORE_H -#define _KEYSTORE_H - - -/* - * Module: keystore.h - * Description: This module contains the structure definitions for processing - * package keystore files. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -#include <openssl/evp.h> -#include <openssl/x509.h> -#include "pkgerr.h" - -/* keystore structures */ - -/* this opaque type represents a keystore */ -typedef void *keystore_handle_t; - -/* flags passed to open_keystore */ - -/* opens keystore read-only. Attempts to modify results in an error */ -#define KEYSTORE_ACCESS_READONLY 0x00000001L - -/* opens keystore read-write */ -#define KEYSTORE_ACCESS_READWRITE 0x00000002L - -/* - * tells open_keystore to fall back to app-generic paths in the case that - * the app-specific paths do not exist. - */ -#define KEYSTORE_PATH_SOFT 0x00000010L - -/* - * tells open_keystore to use the app-specific paths no matter what, - * failing if they cannot be used for any reason. - */ -#define KEYSTORE_PATH_HARD 0x00000020L - -/* masks off various types of flags */ -#define KEYSTORE_ACCESS_MASK 0x0000000FL -#define KEYSTORE_PATH_MASK 0x000000F0L - -/* default is read-only, soft */ -#define KEYSTORE_DFLT_FLAGS \ - (KEYSTORE_ACCESS_READONLY|KEYSTORE_PATH_SOFT) - -/* - * possible encoding formats used by the library, used - * by print_cert - */ -typedef enum { - KEYSTORE_FORMAT_PEM, - KEYSTORE_FORMAT_DER, - KEYSTORE_FORMAT_TEXT -} keystore_encoding_format_t; - -/* - * structure passed back to password callback for determining how - * to prompt for passphrase, and where to record errors - */ -typedef struct { - PKG_ERR *err; -} keystore_passphrase_data; - - -/* max length of a passphrase. One could use a short story! */ -#define KEYSTORE_PASS_MAX 1024 - -/* callback for collecting passphrase when open_keystore() is called */ -typedef int keystore_passphrase_cb(char *, int, int, void *); - -/* names of the individual files within the keystore path */ -#define TRUSTSTORE "truststore" -#define KEYSTORE "keystore" -#define CERTSTORE "certstore" - -/* keystore.c */ -extern int open_keystore(PKG_ERR *, char *, char *, - keystore_passphrase_cb, long flags, keystore_handle_t *); - -extern int print_certs(PKG_ERR *, keystore_handle_t, char *, - keystore_encoding_format_t, FILE *); - -extern int check_cert(PKG_ERR *, X509 *); - -extern int check_cert_and_key(PKG_ERR *, X509 *, EVP_PKEY *); - -extern int print_cert(PKG_ERR *, X509 *, - keystore_encoding_format_t, char *, boolean_t, FILE *); - -extern int close_keystore(PKG_ERR *, keystore_handle_t, - keystore_passphrase_cb); - -extern int merge_ca_cert(PKG_ERR *, X509 *, keystore_handle_t); -extern int merge_cert_and_key(PKG_ERR *, X509 *, EVP_PKEY *, - char *, keystore_handle_t); - -extern int delete_cert_and_keys(PKG_ERR *, keystore_handle_t, - char *); - -extern int find_key_cert_pair(PKG_ERR *, keystore_handle_t, - char *, EVP_PKEY **, X509 **); - -extern int find_ca_certs(PKG_ERR *, keystore_handle_t, - STACK_OF(X509) **); - -extern int find_cl_certs(PKG_ERR *, keystore_handle_t, - STACK_OF(X509) **); - -#ifdef __cplusplus -} -#endif - -#endif /* _KEYSTORE_H */ diff --git a/usr/src/lib/libpkg/common/llib-lpkg b/usr/src/lib/libpkg/common/llib-lpkg index b60597a9bc..b2fdb70d75 100644 --- a/usr/src/lib/libpkg/common/llib-lpkg +++ b/usr/src/lib/libpkg/common/llib-lpkg @@ -20,6 +20,10 @@ */ /* + * Copyright (c) 2017 Peter Tribble. + */ + +/* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -28,9 +32,5 @@ /* LINTLIBRARY */ /* PROTOLIB1 */ #include <cfext.h> -#include <keystore.h> -#include <p12lib.h> -#include <pkgerr.h> #include <pkglib.h> #include <pkglocale.h> -#include <pkgweb.h> diff --git a/usr/src/lib/libpkg/common/mapfile-vers b/usr/src/lib/libpkg/common/mapfile-vers index ffdda251f7..40dcd44f49 100644 --- a/usr/src/lib/libpkg/common/mapfile-vers +++ b/usr/src/lib/libpkg/common/mapfile-vers @@ -20,6 +20,10 @@ # # +# Copyright (c) 2017 Peter Tribble. +# + +# # Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. # @@ -45,28 +49,23 @@ SYMBOL_VERSION SUNWprivate { attrdefault; attrpreset; averify; - backoff; basepath; canonize; canonize_slashes; cgrgid; cgrnam; - check_cert; - check_cert_and_key; checksum_off; checksum_on; ckparam; ckvolseq; clgrgid; clgrnam; - close_keystore; clpwnam; clpwuid; compute_checksum; cpwnam; cpwuid; cverify; - delete_cert_and_keys; devtype; disable_attribute_check; ds_close; @@ -81,32 +80,21 @@ SYMBOL_VERSION SUNWprivate { ds_putinfo; ds_readbuf; ds_skiptoend; - ds_validate_signature; e_ExecCmdArray; e_ExecCmdList; - echo_out; ecleanup; enable_local_fs; epclose; epopen; esystem; - find_ca_certs; - find_cl_certs; - find_key_cert_pair; fmkdir; fverify; getErrbufAddr; getErrbufSize; getErrstr; get_categories; - get_cert_chain; get_disable_attribute_check; - get_endof_string; get_prog_name; - get_proxy_port; - get_signature; - get_startof_string; - get_subject_display_name; getmapmode; gpkglist; gpkgmap; @@ -118,7 +106,6 @@ SYMBOL_VERSION SUNWprivate { isPathRemote; is_not_valid_category; is_not_valid_length; - is_web_install; iscpio; isdir; isfile; @@ -126,22 +113,11 @@ SYMBOL_VERSION SUNWprivate { lookup_cache; mappath; mapvar; - merge_ca_cert; - merge_cert_and_key; nonABI_symlinks; - open_keystore; path_valid; - pkg_passphrase_cb; pkgclosefilter; pkgcloseserver; pkgcmd; - pkgerr; - pkgerr_add; - pkgerr_clear; - pkgerr_free; - pkgerr_get; - pkgerr_new; - pkgerr_num; pkgexecl; pkgexecv; pkggetentry; @@ -176,42 +152,19 @@ SYMBOL_VERSION SUNWprivate { pkgtrans; pkgumount; ppkgmap; - print_cert; - print_certs; progerr; putcfile; putcvfpfile; - reset_backoff; restore_local_fs; rpterr; rrmdir; - sec_init; setErrstr; set_memalloc_failure_func; set_nonABI_symlinks; - set_passphrase_passarg; - set_passphrase_prompt; set_prog_name; - set_web_install; setmapmode; srchcfile; - strip_port; - sunw_PKCS12_contents; - sunw_PKCS12_create; - sunw_check_cert_times; - sunw_check_keys; - sunw_evp_pkey_free; - sunw_find_fname; - sunw_find_localkeyid; - sunw_get_cert_fname; - sunw_get_pkey_fname; - sunw_get_pkey_localkeyid; - sunw_set_fname; - sunw_set_localkeyid; - sunw_split_certs; - sunw_PEM_contents; tputcfent; - validate_signature; vfpCheckpointFile; vfpCheckpointOpen; vfpClearModified; @@ -226,8 +179,6 @@ SYMBOL_VERSION SUNWprivate { vfpSetSize; vfpTruncate; vfpWriteToFile; - web_cleanup; - web_session_control; xmalloc; xrealloc; xstrdup; diff --git a/usr/src/lib/libpkg/common/p12lib.c b/usr/src/lib/libpkg/common/p12lib.c deleted file mode 100644 index 238aa57d54..0000000000 --- a/usr/src/lib/libpkg/common/p12lib.c +++ /dev/null @@ -1,2798 +0,0 @@ -/* - * ==================================================================== - * Copyright (c) 1999 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * licensing@OpenSSL.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). - * - */ - -/* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * Copyright (c) 2012, OmniTI Computer Consulting, Inc. All rights reserved. - */ - - -#include <strings.h> -#include <stdlib.h> -#include <assert.h> - -#include <openssl/crypto.h> -#include <openssl/err.h> -#include <openssl/x509.h> -#include <openssl/pem.h> - -#include <openssl/pkcs12.h> -#include "p12lib.h" - -/* - * OpenSSL provides a framework for pushing error codes onto a stack. - * When an error occurs, the consumer may use the framework to - * pop the errors off the stack and provide a trace of where the - * errors occurred. - * - * Our PKCS12 code plugs into this framework by calling - * ERR_load_SUNW_strings(). To push an error (which by the way, consists - * of a function code and an error code) onto the stack our PKCS12 code - * calls SUNWerr(). - * - * Consumers of our PKCS12 code can then call the OpenSSL error routines - * when an error occurs and retrieve the stack of errors. - */ - -#ifndef OPENSSL_NO_ERR - -/* Function codes and their matching strings */ -static ERR_STRING_DATA SUNW_str_functs[] = { - { ERR_PACK(0, SUNW_F_USE_X509CERT, 0), "sunw_use_x509cert" }, - { ERR_PACK(0, SUNW_F_USE_PKEY, 0), "sunw_use_pkey" }, - { ERR_PACK(0, SUNW_F_USE_TASTORE, 0), "sunw_use_tastore" }, - { ERR_PACK(0, SUNW_F_USE_CERTFILE, 0), "sunw_p12_use_certfile" }, - { ERR_PACK(0, SUNW_F_USE_KEYFILE, 0), "sunw_p12_use_keyfile" }, - { ERR_PACK(0, SUNW_F_USE_TRUSTFILE, 0), "sunw_p12_use_trustfile" }, - { ERR_PACK(0, SUNW_F_READ_FILE, 0), "p12_read_file" }, - { ERR_PACK(0, SUNW_F_DOPARSE, 0), "p12_doparse" }, - { ERR_PACK(0, SUNW_F_PKCS12_PARSE, 0), "sunw_PKCS12_parse" }, - { ERR_PACK(0, SUNW_F_PKCS12_CONTENTS, 0), "sunw_PKCS12_contents" }, - { ERR_PACK(0, SUNW_F_PARSE_ONE_BAG, 0), "parse_one_bag" }, - { ERR_PACK(0, SUNW_F_PKCS12_CREATE, 0), "sunw_PKCS12_create" }, - { ERR_PACK(0, SUNW_F_SPLIT_CERTS, 0), "sunw_split_certs" }, - { ERR_PACK(0, SUNW_F_FIND_LOCALKEYID, 0), "sunw_find_localkeyid" }, - { ERR_PACK(0, SUNW_F_SET_LOCALKEYID, 0), "sunw_set_localkeyid" }, - { ERR_PACK(0, SUNW_F_GET_LOCALKEYID, 0), "sunw_get_localkeyid" }, - { ERR_PACK(0, SUNW_F_SET_FNAME, 0), "sunw_set_fname" }, - { ERR_PACK(0, SUNW_F_GET_PKEY_FNAME, 0), "sunw_get_pkey_fname" }, - { ERR_PACK(0, SUNW_F_APPEND_KEYS, 0), "sunw_append_keys" }, - { ERR_PACK(0, SUNW_F_PEM_CONTENTS, 0), "sunw_PEM_contents" }, - { ERR_PACK(0, SUNW_F_PEM_INFO, 0), "pem_info" }, - { ERR_PACK(0, SUNW_F_ASC2BMPSTRING, 0), "asc2bmpstring" }, - { ERR_PACK(0, SUNW_F_UTF82ASCSTR, 0), "utf82ascstr" }, - { ERR_PACK(0, SUNW_F_FINDATTR, 0), "findattr" }, - { ERR_PACK(0, SUNW_F_TYPE2ATTRIB, 0), "type2attrib" }, - { ERR_PACK(0, SUNW_F_MOVE_CERTS, 0), "move_certs" }, - { ERR_PACK(0, SUNW_F_FIND_FNAME, 0), "sunw_find_fname" }, - { ERR_PACK(0, SUNW_F_PARSE_OUTER, 0), "parse_outer" }, - { ERR_PACK(0, SUNW_F_CHECKFILE, 0), "checkfile" }, - { 0, NULL } -}; - -/* Error codes and their matching strings */ -static ERR_STRING_DATA SUNW_str_reasons[] = { - { SUNW_R_INVALID_ARG, "invalid argument" }, - { SUNW_R_MEMORY_FAILURE, "memory failure" }, - { SUNW_R_MAC_VERIFY_FAILURE, "mac verify failure" }, - { SUNW_R_MAC_CREATE_FAILURE, "mac create failure" }, - { SUNW_R_BAD_FILETYPE, "bad file type" }, - { SUNW_R_BAD_PKEY, "bad or missing private key" }, - { SUNW_R_BAD_PKEYTYPE, "unsupported key type" }, - { SUNW_R_PKEY_READ_ERR, "unable to read private key" }, - { SUNW_R_NO_TRUST_ANCHOR, "no trust anchors found" }, - { SUNW_R_READ_TRUST_ERR, "unable to read trust anchor" }, - { SUNW_R_ADD_TRUST_ERR, "unable to add trust anchor" }, - { SUNW_R_PKCS12_PARSE_ERR, "PKCS12 parse error" }, - { SUNW_R_PKCS12_CREATE_ERR, "PKCS12 create error" }, - { SUNW_R_BAD_CERTTYPE, "unsupported certificate type" }, - { SUNW_R_PARSE_CERT_ERR, "error parsing PKCS12 certificate" }, - { SUNW_R_PARSE_BAG_ERR, "error parsing PKCS12 bag" }, - { SUNW_R_MAKE_BAG_ERR, "error making PKCS12 bag" }, - { SUNW_R_BAD_LKID, "bad localKeyID format" }, - { SUNW_R_SET_LKID_ERR, "error setting localKeyID" }, - { SUNW_R_BAD_FNAME, "bad friendlyName format" }, - { SUNW_R_SET_FNAME_ERR, "error setting friendlyName" }, - { SUNW_R_BAD_TRUST, "bad or missing trust anchor" }, - { SUNW_R_BAD_BAGTYPE, "unsupported bag type" }, - { SUNW_R_CERT_ERR, "certificate error" }, - { SUNW_R_PKEY_ERR, "private key error" }, - { SUNW_R_READ_ERR, "error reading file" }, - { SUNW_R_ADD_ATTR_ERR, "error adding attribute" }, - { SUNW_R_STR_CONVERT_ERR, "error converting string" }, - { SUNW_R_PKCS12_EMPTY_ERR, "empty PKCS12 structure" }, - { SUNW_R_PASSWORD_ERR, "bad password" }, - { 0, NULL } -}; - -/* - * The library name that our module will be known as. This name - * may be retrieved via OpenSSLs error APIs. - */ -static ERR_STRING_DATA SUNW_lib_name[] = { - { 0, SUNW_LIB_NAME }, - { 0, NULL } -}; -#endif - -/* - * The value of this variable (initialized by a call to - * ERR_load_SUNW_strings()) is what identifies our errors - * to OpenSSL as being ours. - */ -static int SUNW_lib_error_code = 0; - -/* local routines */ -static int parse_pkcs12(PKCS12 *, const char *, int, char *, int, char *, - EVP_PKEY **, X509 **, STACK_OF(X509) **); -static int pem_info(FILE *, pem_password_cb, void *, - STACK_OF(EVP_PKEY) **, STACK_OF(X509) **); - -static int parse_outer(PKCS12 *, const char *, STACK_OF(EVP_PKEY) *, - STACK_OF(X509) *); - -static int parse_all_bags(STACK_OF(PKCS12_SAFEBAG) *, const char *, - STACK_OF(EVP_PKEY) *, STACK_OF(X509) *); - -static int parse_one_bag(PKCS12_SAFEBAG *, const char *, - STACK_OF(EVP_PKEY) *, STACK_OF(X509) *); - -static X509_ATTRIBUTE *type2attrib(ASN1_TYPE *, int); -static ASN1_TYPE *attrib2type(X509_ATTRIBUTE *); -static uchar_t *utf82ascstr(ASN1_UTF8STRING *); -static ASN1_BMPSTRING *asc2bmpstring(const char *, int); -static int find_attr_by_nid(STACK_OF(X509_ATTRIBUTE) *, int); -static int find_attr(int, ASN1_STRING *, STACK_OF(EVP_PKEY) *, - EVP_PKEY **, STACK_OF(X509) *, X509 **); - -static chk_errs_t check_time(chk_actions_t, X509 *); -static int get_key_cert(int, STACK_OF(EVP_PKEY) *, EVP_PKEY **, - STACK_OF(X509) *, X509 **cert); -static int move_certs(STACK_OF(X509) *, STACK_OF(X509) *); -static int sunw_append_keys(STACK_OF(EVP_PKEY) *, - STACK_OF(EVP_PKEY) *); -static int set_results(STACK_OF(EVP_PKEY) **, - STACK_OF(EVP_PKEY) **, STACK_OF(X509) **, STACK_OF(X509) **, - STACK_OF(X509) **, STACK_OF(X509) **, - STACK_OF(EVP_PKEY) **, STACK_OF(EVP_PKEY) **); - -/* - * ---------------------------------------------------------------------------- - * Public routines - * ---------------------------------------------------------------------------- - */ - -/* - * sunw_PKCS12_parse - Parse a PKCS12 structure and break it into its parts. - * - * Parse and decrypt a PKCS#12 structure returning user key, user cert and/or - * other (CA) certs. Note either ca should be NULL, *ca should be NULL, - * or it should point to a valid STACK_OF(X509) structure. pkey and cert can - * be passed uninitialized. - * - * Arguments: - * p12 - Structure with pkcs12 info to be parsed - * pass - Pass phrase for the private key (possibly empty) or NULL if - * there is none. - * matchty - Info about which certs/keys to return if many are in the file. - * keyid - If private key localkeyids friendlynames are to match a - * predetermined value, the value to match. This value should - * be an octet string. - * keyid_len- Length of the keyid byte string. - * name_str - If friendlynames are to match a predetermined value, the value - * to match. This value should be a NULL terminated string. - * pkey - Points to location pointing to the private key returned. - * cert - Points to locaiton which points to the client cert returned - * ca - Points to location that points to a stack of 'certificate - * authority' certs/trust anchors. - * - * Match based on the value of 'matchty' and the contents of 'keyid' - * and/or 'name_str', as appropriate. Go through the lists of certs and - * private keys which were taken from the pkcs12 structure, looking for - * matches of the requested type. This function only searches the lists of - * matching private keys and client certificates. Kinds of matches allowed, - * and the order in which they will be checked, are: - * - * 1) Find the key and/or cert whose localkeyid attributes matches - * 'keyid'. - * 2) Find the key and/or cert whose friendlyname attributes matches - * 'name_str' - * 3) Return the first matching key/cert pair found. - * 4) Return the last matching key/cert pair found. - * 5) Return whatever cert and/or key are available, even unmatching. - * - * Append to the CA list, the certs which do not have matching private - * keys and which were not selected. - * - * If none of the bits are set, no client certs or private keys will be - * returned. CA (aka trust anchor) certs can be. - * - * Notes: If #3 is selected, then #4 will never occur. CA certs will be - * selected after a cert/key pairs are isolated. - * - * Returns: - * < 0 - An error returned. Call ERR_get_error() to get errors information. - * Where possible, memory has been freed. - * >= 0 - Objects were found and returned. Which objects are indicated by - * which bits are set (FOUND_PKEY, FOUND_CERT, FOUND_CA_CERTS). - */ -int -sunw_PKCS12_parse(PKCS12 *p12, const char *pass, int matchty, char *keyid, - int keyid_len, char *name_str, EVP_PKEY **pkey, X509 **cert, - STACK_OF(X509) **ca) -{ - boolean_t ca_supplied; - int retval = -1; - - /* If NULL PKCS12 structure, this is an error */ - if (p12 == NULL) { - SUNWerr(SUNW_F_PKCS12_PARSE, SUNW_R_INVALID_ARG); - return (-1); - } - - /* Set up arguments.... These will be allocated if needed */ - if (pkey) - *pkey = NULL; - if (cert) - *cert = NULL; - - /* - * If there is already a ca list, use it. Otherwise, allocate one - * and free is later if an error occurs or whatever.) - */ - ca_supplied = (ca != NULL && *ca != NULL); - if (ca != NULL && *ca == NULL) { - if ((*ca = sk_X509_new_null()) == NULL) { - SUNWerr(SUNW_F_PKCS12_PARSE, SUNW_R_MEMORY_FAILURE); - return (-1); - } - } - - /* - * If password is zero length or NULL then try verifying both cases - * to determine which password is correct. The reason for this is that - * under PKCS#12 password based encryption no password and a zero - * length password are two different things. If the password has a - * non-zero length and is not NULL then call PKCS12_verify_mac() with - * a length of '-1' and let it use strlen() to figure out the length - * of the password. - */ - /* Check the mac */ - if (pass == NULL || *pass == '\0') { - if (PKCS12_verify_mac(p12, NULL, 0)) - pass = NULL; - else if (PKCS12_verify_mac(p12, "", 0)) - pass = ""; - else { - SUNWerr(SUNW_F_PKCS12_PARSE, - SUNW_R_MAC_VERIFY_FAILURE); - goto err; - } - } else if (PKCS12_verify_mac(p12, pass, -1) == 0) { - SUNWerr(SUNW_F_PKCS12_PARSE, SUNW_R_MAC_VERIFY_FAILURE); - goto err; - } - - retval = parse_pkcs12(p12, pass, matchty, keyid, keyid_len, - name_str, pkey, cert, ca); - if (retval < 0) { - SUNWerr(SUNW_F_PKCS12_PARSE, SUNW_R_PKCS12_PARSE_ERR); - goto err; - } - return (retval); - -err: - if (pkey && *pkey) { - sunw_evp_pkey_free(*pkey); - } - if (cert && *cert) - X509_free(*cert); - if (ca_supplied == B_FALSE && ca != NULL) - sk_X509_pop_free(*ca, X509_free); - - return (-1); - -} - - -/* - * sunw_PEM_contents() parses a PEM file and returns component parts found - * - * Parse and decrypt a PEM file, returning any user keys and certs. - * - * There are some limits to this function. It will ignore the following: - * - certificates identified by "TRUSTED CERTIFICATE" - * - CERTIFICATE REQUEST and NEW CERTIFICATE REQUEST records. - * - X509 CRL - * - DH PARAMETERS - * - DSA PARAMETERS - * - Any PUBLIC KEY - * - PKCS7 - * - PRIVATE KEY or ENCRYPTED PRIVATE KEY (PKCS 8) - * - * Arguments: - * fp - File pointer for file containing PEM data. - * pass - Pass phrase for the private key or NULL if there is none. - * pkeys - Points to address of a stack of private keys to return. - * certs - Points to address of a stack of client certs to return. - * - * The pointers to stacks should either be NULL or their contents should - * either be NULL or should point to a valid STACK_OF(X509) structure. - * If the stacks contain information, corresponding information from the - * file will be appended to the original contents. - * - * Note: Client certs and and their matching private keys will be in any - * order. - * - * Certs which have no matching private key are assumed to be ca certs. - * - * Returns: - * < 0 - An error returned. Call ERR_get_error() to get errors information. - * Where possible, memory has been freed. - * >= 0 - Objects were found and returned. Which objects are indicated by - * which bits are set (FOUND_PKEY, FOUND_CERT) - */ -int sunw_PEM_contents(FILE *fp, pem_password_cb *cb, void *userdata, - STACK_OF(EVP_PKEY) **pkey, STACK_OF(X509) **certs) -{ - STACK_OF(EVP_PKEY) *work_kl = NULL; - STACK_OF(X509) *work_ca = NULL; - int retval = -1; - - /* - * Allocate the working stacks for private key and for the - * ca certs. - */ - if ((work_kl = sk_EVP_PKEY_new_null()) == NULL) { - SUNWerr(SUNW_F_PEM_CONTENTS, SUNW_R_MEMORY_FAILURE); - goto cleanup; - } - - if ((work_ca = sk_X509_new_null()) == NULL) { - SUNWerr(SUNW_F_PEM_CONTENTS, SUNW_R_MEMORY_FAILURE); - goto cleanup; - } - - /* Error strings are set within the following. */ - if (pem_info(fp, cb, userdata, &work_kl, &work_ca) <= 0) { - goto cleanup; - } - - /* on error, set_results() returns an error on the stack */ - retval = set_results(pkey, &work_kl, certs, &work_ca, NULL, NULL, NULL, - NULL); -cleanup: - if (work_kl != NULL) { - sk_EVP_PKEY_pop_free(work_kl, sunw_evp_pkey_free); - } - if (work_ca != NULL) - sk_X509_pop_free(work_ca, X509_free); - - return (retval); -} - - -/* - * sunw_PKCS12_contents() parses a pkcs#12 structure and returns component - * parts found, without evaluation. - * - * Parse and decrypt a PKCS#12 structure returning any user keys and/or - * various certs. Note these should either be NULL, *whatever should - * be NULL, or it should point to a valid STACK_OF(X509) structure. - * - * Arguments: - * p12 - Structure with pkcs12 info to be parsed - * pass - Pass phrase for the private key and entire pkcs12 wad (possibly - * empty) or NULL if there is none. - * pkeys - Points to address of a stack of private keys to return. - * certs - Points to address of a stack of client certs return. - * - * Note: The certs and keys being returned are in random order. - * - * Returns: - * < 0 - An error returned. Call ERR_get_error() to get errors information. - * Where possible, memory has been freed. - * >= 0 - Objects were found and returned. Which objects are indicated by - * which bits are set (FOUND_PKEY or FOUND_CERT) - */ -int -sunw_PKCS12_contents(PKCS12 *p12, const char *pass, STACK_OF(EVP_PKEY) **pkey, - STACK_OF(X509) **certs) -{ - STACK_OF(EVP_PKEY) *work_kl = NULL; - STACK_OF(X509) *work_ca = NULL; - int retval = -1; - - /* - * Allocate the working stacks for private key and for the - * ca certs. - */ - if ((work_kl = sk_EVP_PKEY_new_null()) == NULL) { - SUNWerr(SUNW_F_PKCS12_CONTENTS, SUNW_R_MEMORY_FAILURE); - goto cleanup; - } - - if ((work_ca = sk_X509_new_null()) == NULL) { - SUNWerr(SUNW_F_PKCS12_CONTENTS, SUNW_R_MEMORY_FAILURE); - goto cleanup; - } - - if (parse_outer(p12, pass, work_kl, work_ca) == 0) { - /* - * Error already on stack - */ - goto cleanup; - } - - /* on error, set_results() returns an error on the stack */ - retval = set_results(pkey, &work_kl, certs, &work_ca, NULL, - NULL, NULL, NULL); - -cleanup: - if (work_kl != NULL) { - sk_EVP_PKEY_pop_free(work_kl, sunw_evp_pkey_free); - } - - return (retval); -} - - - -/* - * sunw_split_certs() - Given a list of certs and a list of private keys, - * moves certs which match one of the keys to a different stack. - * - * Arguments: - * allkeys - Points to a stack of private keys to search. - * allcerts - Points to a stack of certs to be searched. - * keycerts - Points to address of a stack of certs with matching private - * keys. They are moved from 'allcerts'. This may not be NULL - * when called. If *keycerts is NULL upon entry, a new stack will - * be allocated. Otherwise, it must be a valid STACK_OF(509). - * nocerts - Points to address of a stack for keys which have no matching - * certs. Keys are moved from 'allkeys' here when they have no - * matching certs. If this is NULL, matchless keys will be - * discarded. - * - * Notes: If an error occurs while moving certs, the cert being move may be - * lost. 'keycerts' may only contain part of the matching certs. The number - * of certs successfully moved can be found by checking sk_X509_num(keycerts). - * - * If there is a key which does not have a matching cert, it is moved to - * the list nocerts. - * - * If all certs are removed from 'certs' and/or 'pkeys', it will be the - * caller's responsibility to free the empty stacks. - * - * Returns: - * < 0 - An error returned. Call ERR_get_error() to get errors information. - * Where possible, memory has been freed. - * >= 0 - The number of certs moved from 'cert' to 'pkcerts'. - */ -int -sunw_split_certs(STACK_OF(EVP_PKEY) *allkeys, STACK_OF(X509) *allcerts, - STACK_OF(X509) **keycerts, STACK_OF(EVP_PKEY) **nocerts) -{ - STACK_OF(X509) *matching; - STACK_OF(EVP_PKEY) *nomatch; - EVP_PKEY *tmpkey; - X509 *tmpcert; - int count = 0; - int found; - int res; - int i; - int k; - - *keycerts = NULL; - if (nocerts != NULL) - *nocerts = NULL; - nomatch = NULL; - - if ((matching = sk_X509_new_null()) == NULL) { - SUNWerr(SUNW_F_SPLIT_CERTS, SUNW_R_MEMORY_FAILURE); - return (-1); - } - *keycerts = matching; - - k = 0; - while (k < sk_EVP_PKEY_num(allkeys)) { - found = 0; - tmpkey = sk_EVP_PKEY_value(allkeys, k); - - for (i = 0; i < sk_X509_num(allcerts); i++) { - tmpcert = sk_X509_value(allcerts, i); - res = X509_check_private_key(tmpcert, tmpkey); - if (res != 0) { - count++; - found = 1; - tmpcert = sk_X509_delete(allcerts, i); - if (sk_X509_push(matching, tmpcert) == 0) { - X509_free(tmpcert); - SUNWerr(SUNW_F_SPLIT_CERTS, - SUNW_R_MEMORY_FAILURE); - return (-1); - } - break; - } - } - if (found != 0) { - /* - * Found a match - keep the key & check out the next - * one. - */ - k++; - } else { - /* - * No cert matching this key. Move the key if - * possible or discard it. Don't increment the - * index. - */ - if (nocerts == NULL) { - tmpkey = sk_EVP_PKEY_delete(allkeys, k); - sunw_evp_pkey_free(tmpkey); - } else { - if (*nocerts == NULL) { - nomatch = sk_EVP_PKEY_new_null(); - if (nomatch == NULL) { - SUNWerr(SUNW_F_SPLIT_CERTS, - SUNW_R_MEMORY_FAILURE); - return (-1); - } - *nocerts = nomatch; - } - tmpkey = sk_EVP_PKEY_delete(allkeys, k); - if (sk_EVP_PKEY_push(nomatch, tmpkey) == 0) { - sunw_evp_pkey_free(tmpkey); - SUNWerr(SUNW_F_SPLIT_CERTS, - SUNW_R_MEMORY_FAILURE); - return (-1); - } - } - } - } - - return (count); -} - -/* - * sunw_PKCS12_create() creates a pkcs#12 structure and given component parts. - * - * Given one or more of user private key, user cert and/or other (CA) certs, - * return an encrypted PKCS12 structure containing them. - * - * Arguments: - * pass - Pass phrase for the pkcs12 structure and private key (possibly - * empty) or NULL if there is none. It will be used to encrypt - * both the private key(s) and as the pass phrase for the whole - * pkcs12 wad. - * pkeys - Points to stack of private keys. - * certs - Points to stack of client (public ke) certs - * cacerts - Points to stack of 'certificate authority' certs (or trust - * anchors). - * - * Note that any of these may be NULL. - * - * Returns: - * NULL - An error occurred. - * != NULL - Address of PKCS12 structure. The user is responsible for - * freeing the memory when done. - */ -PKCS12 * -sunw_PKCS12_create(const char *pass, STACK_OF(EVP_PKEY) *pkeys, - STACK_OF(X509) *certs, STACK_OF(X509) *cacerts) -{ - int nid_cert = NID_pbe_WithSHA1And40BitRC2_CBC; - int nid_key = NID_pbe_WithSHA1And3_Key_TripleDES_CBC; - STACK_OF(PKCS12_SAFEBAG) *bags = NULL; - STACK_OF(PKCS7) *safes = NULL; - PKCS12_SAFEBAG *bag = NULL; - PKCS8_PRIV_KEY_INFO *p8 = NULL; - EVP_PKEY *pkey = NULL; - PKCS12 *ret_p12 = NULL; - PKCS12 *p12 = NULL; - PKCS7 *authsafe = NULL; - X509 *cert = NULL; - uchar_t *str = NULL; - int certs_there = 0; - int keys_there = 0; - int len; - int i; - - if ((safes = sk_PKCS7_new_null()) == NULL) { - SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_MEMORY_FAILURE); - return (NULL); - } - - if ((bags = sk_PKCS12_SAFEBAG_new_null()) == NULL) { - SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_MEMORY_FAILURE); - goto err_ret; - } - - if (certs != NULL && sk_X509_num(certs) > 0) { - - for (i = 0; i < sk_X509_num(certs); i++) { - cert = sk_X509_value(certs, i); - - /* Add user certificate */ - if ((bag = M_PKCS12_x5092certbag(cert)) == NULL) { - SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_CERT_ERR); - goto err_ret; - } - if (cert->aux != NULL && cert->aux->alias != NULL && - cert->aux->alias->type == V_ASN1_UTF8STRING) { - str = utf82ascstr(cert->aux->alias); - if (str == NULL) { - /* - * Error already on stack - */ - goto err_ret; - } - if (PKCS12_add_friendlyname_asc(bag, - (char const *) str, - strlen((char const *) str)) == 0) { - SUNWerr(SUNW_F_PKCS12_CREATE, - SUNW_R_ADD_ATTR_ERR); - goto err_ret; - } - } - if (cert->aux != NULL && cert->aux->keyid != NULL && - cert->aux->keyid->type == V_ASN1_OCTET_STRING) { - str = cert->aux->keyid->data; - len = cert->aux->keyid->length; - - if (str != NULL && - PKCS12_add_localkeyid(bag, str, len) == 0) { - SUNWerr(SUNW_F_PKCS12_CREATE, - SUNW_R_ADD_ATTR_ERR); - goto err_ret; - } - } - if (sk_PKCS12_SAFEBAG_push(bags, bag) == 0) { - SUNWerr(SUNW_F_PKCS12_CREATE, - SUNW_R_MEMORY_FAILURE); - goto err_ret; - } - certs_there++; - bag = NULL; - } - } - - if (cacerts != NULL && sk_X509_num(cacerts) > 0) { - - /* Put all certs in structure */ - for (i = 0; i < sk_X509_num(cacerts); i++) { - cert = sk_X509_value(cacerts, i); - if ((bag = M_PKCS12_x5092certbag(cert)) == NULL) { - SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_CERT_ERR); - goto err_ret; - } - - if (cert->aux != NULL && cert->aux->alias != NULL && - cert->aux->alias->type == V_ASN1_UTF8STRING) { - str = utf82ascstr(cert->aux->alias); - if (str == NULL) { - /* - * Error already on stack - */ - goto err_ret; - } - if (PKCS12_add_friendlyname_asc( - bag, (char const *) str, - strlen((char const *) str)) == 0) { - SUNWerr(SUNW_F_PKCS12_CREATE, - SUNW_R_ADD_ATTR_ERR); - goto err_ret; - } - } - if (cert->aux != NULL && cert->aux->keyid != NULL && - cert->aux->keyid->type == V_ASN1_OCTET_STRING) { - str = cert->aux->keyid->data; - len = cert->aux->keyid->length; - - if (str != NULL && - PKCS12_add_localkeyid(bag, str, len) == 0) { - SUNWerr(SUNW_F_PKCS12_CREATE, - SUNW_R_ADD_ATTR_ERR); - goto err_ret; - } - } - if (sk_PKCS12_SAFEBAG_push(bags, bag) == 0) { - SUNWerr(SUNW_F_PKCS12_CREATE, - SUNW_R_MEMORY_FAILURE); - goto err_ret; - } - certs_there++; - bag = NULL; - } - } - - if (certs != NULL || cacerts != NULL && certs_there) { - /* Turn certbags into encrypted authsafe */ - authsafe = PKCS12_pack_p7encdata(nid_cert, pass, -1, - NULL, 0, PKCS12_DEFAULT_ITER, bags); - if (authsafe == NULL) { - SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_CERT_ERR); - goto err_ret; - } - sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); - bags = NULL; - - if (sk_PKCS7_push(safes, authsafe) == 0) { - SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_MEMORY_FAILURE); - goto err_ret; - } - authsafe = NULL; - } - - if (pkeys != NULL && sk_EVP_PKEY_num(pkeys) > 0) { - - if (bags == NULL && - (bags = sk_PKCS12_SAFEBAG_new_null()) == NULL) { - SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_MEMORY_FAILURE); - goto err_ret; - } - - for (i = 0; i < sk_EVP_PKEY_num(pkeys); i++) { - - pkey = sk_EVP_PKEY_value(pkeys, i); - - /* Make a shrouded key bag */ - if ((p8 = EVP_PKEY2PKCS8(pkey)) == NULL) { - SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_PKEY_ERR); - goto err_ret; - } - - bag = PKCS12_MAKE_SHKEYBAG(nid_key, pass, -1, NULL, 0, - PKCS12_DEFAULT_ITER, p8); - if (bag == NULL) { - SUNWerr(SUNW_F_PKCS12_CREATE, - SUNW_R_MAKE_BAG_ERR); - goto err_ret; - } - PKCS8_PRIV_KEY_INFO_free(p8); - p8 = NULL; - - len = sunw_get_pkey_fname(GETDO_COPY, pkey, - (char **)&str); - if (str != NULL) { - if (PKCS12_add_friendlyname_asc(bag, - (const char *)str, len) == 0) { - SUNWerr(SUNW_F_PKCS12_CREATE, - SUNW_R_ADD_ATTR_ERR); - goto err_ret; - } - } - str = NULL; - - len = sunw_get_pkey_localkeyid(GETDO_COPY, pkey, - (char **)&str, &len); - if (str != NULL) { - if (PKCS12_add_localkeyid(bag, str, len) == 0) { - SUNWerr(SUNW_F_PKCS12_CREATE, - SUNW_R_ADD_ATTR_ERR); - goto err_ret; - } - } - str = NULL; - - if (sk_PKCS12_SAFEBAG_push(bags, bag) == 0) { - SUNWerr(SUNW_F_PKCS12_CREATE, - SUNW_R_MEMORY_FAILURE); - goto err_ret; - } - keys_there++; - bag = NULL; - } - - if (keys_there) { - /* Turn into unencrypted authsafe */ - authsafe = PKCS12_pack_p7data(bags); - if (authsafe == NULL) { - SUNWerr(SUNW_F_PKCS12_CREATE, - SUNW_R_PKCS12_CREATE_ERR); - goto err_ret; - } - sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); - bags = NULL; - - if (sk_PKCS7_push(safes, authsafe) == 0) { - SUNWerr(SUNW_F_PKCS12_CREATE, - SUNW_R_MEMORY_FAILURE); - } - authsafe = NULL; - } - } - - if (certs_there == 0 && keys_there == 0) { - SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_PKCS12_EMPTY_ERR); - goto err_ret; - } - - if ((p12 = PKCS12_init(NID_pkcs7_data)) == NULL) { - SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_PKCS12_CREATE_ERR); - goto err_ret; - } - - /* - * Note that safes is copied by the following. Therefore, it needs - * to be freed whether or not the following succeeds. - */ - if (M_PKCS12_pack_authsafes(p12, safes) == 0) { - SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_PKCS12_CREATE_ERR); - goto err_ret; - } - if (PKCS12_set_mac(p12, pass, -1, NULL, 0, 2048, NULL) == 0) { - SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_MAC_CREATE_FAILURE); - goto err_ret; - } - - ret_p12 = p12; - p12 = NULL; - - /* Fallthrough is intentional */ - -err_ret: - - if (str != NULL) - free(str); - - if (p8 != NULL) - PKCS8_PRIV_KEY_INFO_free(p8); - - if (bag != NULL) - PKCS12_SAFEBAG_free(bag); - if (bags != NULL) - sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); - if (authsafe != NULL) - PKCS7_free(authsafe); - if (safes != NULL) - sk_PKCS7_pop_free(safes, PKCS7_free); - if (p12 != NULL) - PKCS12_free(p12); - - return (ret_p12); -} - -/* - * sunw_evp_pkey_free() Given an EVP_PKEY structure, free any attributes - * that are attached. Then free the EVP_PKEY itself. - * - * This is a replacement for EVP_PKEY_free() for the sunw stuff. - * It should be used in places where EVP_PKEY_free would be used, - * including calls to sk_EVP_PKEY_pop_free(). - * - * Arguments: - * pkey - Entry which potentially has attributes to be freed. - * - * Returns: - * None. - */ -void -sunw_evp_pkey_free(EVP_PKEY *pkey) -{ - if (pkey != NULL) { - if (pkey->attributes != NULL) { - sk_X509_ATTRIBUTE_pop_free(pkey->attributes, - X509_ATTRIBUTE_free); - pkey->attributes = NULL; - } - EVP_PKEY_free(pkey); - } -} - -/* - * sunw_set_localkeyid() sets the localkeyid in a cert, a private key or - * both. Any existing localkeyid will be discarded. - * - * Arguments: - * keyid_str- A byte string with the localkeyid to set - * keyid_len- Length of the keyid byte string. - * pkey - Points to a private key to set the keyidstr in. - * cert - Points to a cert to set the keyidstr in. - * - * Note that setting a keyid into a cert which will not be written out as - * a PKCS12 cert is pointless since it will be lost. - * - * Returns: - * 0 - Success. - * < 0 - An error occurred. It was probably an error in allocating - * memory. The error will be set in the error stack. Call - * ERR_get_error() to get specific information. - */ -int -sunw_set_localkeyid(const char *keyid_str, int keyid_len, EVP_PKEY *pkey, - X509 *cert) -{ - X509_ATTRIBUTE *attr = NULL; - ASN1_STRING *str = NULL; - ASN1_TYPE *keyid = NULL; - int retval = -1; - int i; - - if (cert != NULL) { - if (X509_keyid_set1(cert, (uchar_t *)keyid_str, keyid_len) - == 0) { - SUNWerr(SUNW_F_SET_LOCALKEYID, SUNW_R_SET_LKID_ERR); - goto cleanup; - } - } - if (pkey != NULL) { - str = (ASN1_STRING *)M_ASN1_OCTET_STRING_new(); - if (str == NULL || - M_ASN1_OCTET_STRING_set(str, keyid_str, keyid_len) == 0 || - (keyid = ASN1_TYPE_new()) == NULL) { - SUNWerr(SUNW_F_SET_LOCALKEYID, SUNW_R_MEMORY_FAILURE); - goto cleanup; - } - - ASN1_TYPE_set(keyid, V_ASN1_OCTET_STRING, str); - str = NULL; - - attr = type2attrib(keyid, NID_localKeyID); - if (attr == NULL) { - /* - * Error already on stack - */ - goto cleanup; - } - keyid = NULL; - - if (pkey->attributes == NULL) { - pkey->attributes = sk_X509_ATTRIBUTE_new_null(); - if (pkey->attributes == NULL) { - SUNWerr(SUNW_F_SET_LOCALKEYID, - SUNW_R_MEMORY_FAILURE); - goto cleanup; - } - } else { - i = find_attr_by_nid(pkey->attributes, NID_localKeyID); - if (i >= 0) - sk_X509_ATTRIBUTE_delete(pkey->attributes, i); - } - if (sk_X509_ATTRIBUTE_push(pkey->attributes, attr) == 0) { - SUNWerr(SUNW_F_SET_LOCALKEYID, SUNW_R_MEMORY_FAILURE); - goto cleanup; - } - attr = NULL; - } - retval = 0; - -cleanup: - if (str != NULL) - ASN1_STRING_free(str); - if (keyid != NULL) - ASN1_TYPE_free(keyid); - if (attr != NULL) - X509_ATTRIBUTE_free(attr); - - return (retval); -} - -/* - * sunw_get_pkey_localkeyid() gets the localkeyid from a private key. It can - * optionally remove the value found. - * - * Arguments: - * dowhat - What to do with the attributes (remove them or copy them). - * pkey - Points to a private key to set the keyidstr in. - * keyid_str- Points to a location which will receive the pointer to - * a byte string containing the binary localkeyid. Note that - * this is a copy, and the caller must free it. - * keyid_len- Length of keyid_str. - * - * Returns: - * >= 0 - The number of characters in the keyid returned. - * < 0 - An error occurred. It was probably an error in allocating - * memory. The error will be set in the error stack. Call - * ERR_get_error() to get specific information. - */ -int -sunw_get_pkey_localkeyid(getdo_actions_t dowhat, EVP_PKEY *pkey, - char **keyid_str, int *keyid_len) -{ - X509_ATTRIBUTE *attr = NULL; - ASN1_OCTET_STRING *str = NULL; - ASN1_TYPE *ty = NULL; - int len = 0; - int i; - - if (keyid_str != NULL) - *keyid_str = NULL; - if (keyid_len != NULL) - *keyid_len = 0; - - if (pkey == NULL || pkey->attributes == NULL) { - return (0); - } - - if ((i = find_attr_by_nid(pkey->attributes, NID_localKeyID)) < 0) { - return (0); - } - attr = sk_X509_ATTRIBUTE_value(pkey->attributes, i); - - if ((ty = attrib2type(attr)) == NULL || - ty->type != V_ASN1_OCTET_STRING) { - return (0); - } - - if (dowhat == GETDO_DEL) { - attr = sk_X509_ATTRIBUTE_delete(pkey->attributes, i); - if (attr != NULL) - X509_ATTRIBUTE_free(attr); - return (0); - } - - str = ty->value.octet_string; - len = str->length; - if ((*keyid_str = malloc(len)) == NULL) { - SUNWerr(SUNW_F_GET_LOCALKEYID, SUNW_R_MEMORY_FAILURE); - return (-1); - } - - (void) memcpy(*keyid_str, str->data, len); - *keyid_len = len; - - return (len); -} - -/* - * sunw_get_pkey_fname() gets the friendlyName from a private key. It can - * optionally remove the value found. - * - * Arguments: - * dowhat - What to do with the attributes (remove them or copy them). - * pkey - Points to a private key to get the frientlyname from - * fname - Points to a location which will receive the pointer to a - * byte string with the ASCII friendlyname - * - * Returns: - * >= 0 - The number of characters in the frienlyname returned. - * < 0 - An error occurred. It was probably an error in allocating - * memory. The error will be set in the error stack. Call - * ERR_get_error() to get specific information. - */ -int -sunw_get_pkey_fname(getdo_actions_t dowhat, EVP_PKEY *pkey, char **fname) -{ - X509_ATTRIBUTE *attr = NULL; - ASN1_BMPSTRING *str = NULL; - ASN1_TYPE *ty = NULL; - int len = 0; - int i; - - if (fname != NULL) - *fname = NULL; - - if (pkey == NULL || pkey->attributes == NULL) { - return (0); - } - - if ((i = find_attr_by_nid(pkey->attributes, NID_friendlyName)) < 0) { - return (0); - } - attr = sk_X509_ATTRIBUTE_value(pkey->attributes, i); - - if ((ty = attrib2type(attr)) == NULL || - ty->type != V_ASN1_BMPSTRING) { - return (0); - } - - if (dowhat == GETDO_DEL) { - attr = sk_X509_ATTRIBUTE_delete(pkey->attributes, i); - if (attr != NULL) - X509_ATTRIBUTE_free(attr); - return (0); - } - - str = ty->value.bmpstring; -#if OPENSSL_VERSION_NUMBER < 0x10000000L - *fname = uni2asc(str->data, str->length); -#else - *fname = OPENSSL_uni2asc(str->data, str->length); -#endif - if (*fname == NULL) { - SUNWerr(SUNW_F_GET_PKEY_FNAME, SUNW_R_MEMORY_FAILURE); - return (-1); - } - - len = strlen(*fname); - - return (len); -} - -/* - * sunw_find_localkeyid() searches stacks of certs and private keys, - * and returns the first matching cert/private key found. - * - * Look for a keyid in a stack of certs. if 'certs' is NULL and 'pkeys' is - * not NULL, search the list of private keys. Move the matching cert to - * 'matching_cert' and its matching private key to 'matching_pkey'. If no - * cert or keys match, no match occurred. - * - * Arguments: - * keyid_str- A byte string with the localkeyid to match - * keyid_len- Length of the keyid byte string. - * pkeys - Points to a stack of private keys which match the certs. - * This may be NULL, in which case no keys are returned. - * certs - Points to a stack of certs to search. If NULL, search the - * stack of keys instead. - * matching_pkey - * - Pointer to receive address of first matching pkey found. - * 'matching_pkey' must not be NULL; '*matching_pkey' will be - * reset. - * matching_cert - * - Pointer to receive address of first matching cert found. - * 'matching_cert' must not be NULL; '*matching_cert' will be - * reset. - * - * Returns: - * < 0 - An error returned. Call ERR_get_error() to get errors information. - * Where possible, memory has been freed. - * >= 0 - Objects were found and returned. Which objects are indicated by - * which bits are set (FOUND_PKEY and/or FOUND_CERT). - */ -int -sunw_find_localkeyid(char *keyid_str, int len, STACK_OF(EVP_PKEY) *pkeys, -STACK_OF(X509) *certs, EVP_PKEY **matching_pkey, X509 **matching_cert) -{ - ASN1_STRING *cmpstr = NULL; - EVP_PKEY *tmp_pkey = NULL; - X509 *tmp_cert = NULL; - int retval = 0; - - /* If NULL arguments, this is an error */ - if (keyid_str == NULL || - (pkeys == NULL || certs == NULL) || - (pkeys != NULL && matching_pkey == NULL) || - (certs != NULL && matching_cert == NULL)) { - SUNWerr(SUNW_F_FIND_LOCALKEYID, SUNW_R_INVALID_ARG); - return (-1); - } - - if (matching_pkey != NULL) - *matching_pkey = NULL; - if (matching_cert != NULL) - *matching_cert = NULL; - - cmpstr = (ASN1_STRING *)M_ASN1_OCTET_STRING_new(); - if (cmpstr == NULL || - M_ASN1_OCTET_STRING_set(cmpstr, keyid_str, len) == 0) { - SUNWerr(SUNW_F_FIND_LOCALKEYID, SUNW_R_MEMORY_FAILURE); - return (-1); - } - - retval = find_attr(NID_localKeyID, cmpstr, pkeys, &tmp_pkey, certs, - &tmp_cert); - if (retval == 0) { - ASN1_STRING_free(cmpstr); - return (retval); - } - - if (matching_pkey != NULL) - *matching_pkey = tmp_pkey; - if (matching_cert != NULL) - *matching_cert = tmp_cert; - - return (retval); -} - -/* - * sunw_find_fname() searches stacks of certs and private keys for one with - * a matching friendlyname and returns the first matching cert/private - * key found. - * - * Look for a friendlyname in a stack of certs. if 'certs' is NULL and 'pkeys' - * is not NULL, search the list of private keys. Move the matching cert to - * 'matching_cert' and its matching private key to 'matching_pkey'. If no - * cert or keys match, no match occurred. - * - * Arguments: - * fname - Friendlyname to find (NULL-terminated ASCII string). - * pkeys - Points to a stack of private keys which match the certs. - * This may be NULL, in which case no keys are returned. - * certs - Points to a stack of certs to search. If NULL, search the - * stack of keys instead. - * matching_pkey - * - Pointer to receive address of first matching pkey found. - * matching_cert - * - Pointer to receive address of first matching cert found. - * - * Returns: - * < 0 - An error returned. Call ERR_get_error() to get errors information. - * Where possible, memory has been freed. - * >= 0 - Objects were found and returned. Which objects are indicated by - * which bits are set (FOUND_PKEY and/or FOUND_CERT). - */ -int -sunw_find_fname(char *fname, STACK_OF(EVP_PKEY) *pkeys, STACK_OF(X509) *certs, - EVP_PKEY **matching_pkey, X509 ** matching_cert) -{ - ASN1_STRING *cmpstr = NULL; - EVP_PKEY *tmp_pkey = NULL; - X509 *tmp_cert = NULL; - int retval = 0; - - /* If NULL arguments, this is an error */ - if (fname == NULL || - (pkeys == NULL && certs == NULL) || - (pkeys != NULL && matching_pkey == NULL) || - (certs != NULL && matching_cert == NULL)) { - SUNWerr(SUNW_F_FIND_FNAME, SUNW_R_INVALID_ARG); - return (-1); - } - - if (matching_pkey != NULL) - *matching_pkey = NULL; - if (matching_cert != NULL) - *matching_cert = NULL; - - cmpstr = (ASN1_STRING *)asc2bmpstring(fname, strlen(fname)); - if (cmpstr == NULL) { - /* - * Error already on stack - */ - return (-1); - } - - retval = find_attr(NID_friendlyName, cmpstr, pkeys, &tmp_pkey, certs, - &tmp_cert); - if (retval == 0) { - ASN1_STRING_free(cmpstr); - return (retval); - } - - if (matching_pkey != NULL) - *matching_pkey = tmp_pkey; - if (matching_cert != NULL) - *matching_cert = tmp_cert; - - return (retval); -} - -/* - * sunw_get_cert_fname() gets the fiendlyname from a cert. It can - * optionally remove the value found. - * - * Arguments: - * dowhat - What to do with the attributes (remove them or copy them). - * cert - Points to a cert to get the friendlyName from. - * fname - Points to a location which will receive the pointer to a - * byte string with the ASCII friendlyname - * - * Returns: - * >= 0 - The number of characters in the friendlyname returned. - * < 0 - An error occurred. It was probably an error in allocating - * memory. The error will be set in the error stack. Call - * ERR_get_error() to get specific information. - */ -int -sunw_get_cert_fname(getdo_actions_t dowhat, X509 *cert, char **fname) -{ - int len; - - if (fname != NULL) - *fname = NULL; - - if (cert == NULL || cert->aux == NULL || cert->aux->alias == NULL) { - return (0); - } - - if (dowhat == GETDO_DEL) { - /* Delete the entry */ - ASN1_UTF8STRING_free(cert->aux->alias); - cert->aux->alias = NULL; - return (0); - } - - *((uchar_t **)fname) = utf82ascstr(cert->aux->alias); - if (*fname == NULL) { - /* - * Error already on stack - */ - return (-1); - } - - len = strlen(*fname); - - return (len); -} - -/* - * sunw_set_fname() sets the friendlyName in a cert, a private key or - * both. Any existing friendlyname will be discarded. - * - * Arguments: - * ascname - An ASCII string with the friendlyName to set - * pkey - Points to a private key to set the fname in. - * cert - Points to a cert to set the fname in. - * - * Note that setting a friendlyName into a cert which will not be written out - * as a PKCS12 cert is pointless since it will be lost. - * - * Returns: - * 0 - Success. - * <0 - An error occurred. It was probably an error in allocating - * memory. The error will be set in the error stack. Call - * ERR_get_error() to get specific information. - */ -int -sunw_set_fname(const char *ascname, EVP_PKEY *pkey, X509 *cert) -{ - X509_ATTRIBUTE *attr = NULL; - ASN1_BMPSTRING *str = NULL; - ASN1_TYPE *fname = NULL; - unsigned char *data = NULL; - int retval = -1; - int len; - int i; - - str = asc2bmpstring(ascname, strlen(ascname)); - if (str == NULL) { - /* - * Error already on stack - */ - return (-1); - } - - if (cert != NULL) { - if (cert->aux != NULL && cert->aux->alias != NULL) { - ASN1_UTF8STRING_free(cert->aux->alias); - } - - len = ASN1_STRING_to_UTF8(&data, str); - i = -23; - if (len <= 0 || (i = X509_alias_set1(cert, data, len)) == 0) { - SUNWerr(SUNW_F_SET_FNAME, SUNW_R_SET_FNAME_ERR); - goto cleanup; - } - } - if (pkey != NULL) { - if ((fname = ASN1_TYPE_new()) == NULL) { - SUNWerr(SUNW_F_SET_FNAME, SUNW_R_MEMORY_FAILURE); - goto cleanup; - } - - ASN1_TYPE_set(fname, V_ASN1_BMPSTRING, str); - str = NULL; - - attr = type2attrib(fname, NID_friendlyName); - if (attr == NULL) { - /* - * Error already on stack - */ - goto cleanup; - } - fname = NULL; - - if (pkey->attributes == NULL) { - pkey->attributes = sk_X509_ATTRIBUTE_new_null(); - if (pkey->attributes == NULL) { - SUNWerr(SUNW_F_SET_FNAME, - SUNW_R_MEMORY_FAILURE); - goto cleanup; - } - } else if ((i = find_attr_by_nid(pkey->attributes, - NID_friendlyName)) >= 0) { - (void) sk_X509_ATTRIBUTE_delete(pkey->attributes, i); - } - - if (sk_X509_ATTRIBUTE_push(pkey->attributes, attr) == 0) { - SUNWerr(SUNW_F_SET_FNAME, SUNW_R_MEMORY_FAILURE); - goto cleanup; - } - - attr = NULL; - } - retval = 0; - -cleanup: - if (data != NULL) - OPENSSL_free(data); - if (str != NULL) - ASN1_BMPSTRING_free(str); - if (fname != NULL) - ASN1_TYPE_free(fname); - if (attr != NULL) - X509_ATTRIBUTE_free(attr); - - return (retval); -} - -/* - * sunw_check_keys() compares the public key in the certificate and a - * private key to ensure that they match. - * - * Arguments: - * cert - Points to a certificate. - * pkey - Points to a private key. - * - * Returns: - * == 0 - These do not match. - * != 0 - The cert's public key and the private key match. - */ -int -sunw_check_keys(X509 *cert, EVP_PKEY *pkey) -{ - int retval = 0; - - if (pkey != NULL && cert != NULL) - retval = X509_check_private_key(cert, pkey); - - return (retval); -} - -/* - * sunw_check_cert_times() compares the time fields in a certificate - * - * Compare the 'not before' and the 'not after' times in the cert - * to the current time. Return the results of the comparison (bad time formats, - * cert not yet in force, cert expired or in range) - * - * Arguments: - * dowhat - what field(s) to check. - * cert - Points to a cert to check - * - * Returns: - * Results of the comparison. - */ -chk_errs_t -sunw_check_cert_times(chk_actions_t chkwhat, X509 *cert) -{ - return (check_time(chkwhat, cert)); -} - -/* - * ---------------------------------------------------------------------------- - * Local routines - * ---------------------------------------------------------------------------- - */ - - -/* - * parse_pkcs12 - Oversee parsing of the pkcs12 structure. Get it - * parsed. After that either return what's found directly, or - * do any required matching. - * - * Arguments: - * p12 - Structure with pkcs12 info to be parsed - * pass - Pass phrase for the private key (possibly empty) or NULL if - * there is none. - * matchty - Info about which certs/keys to return if many are in the file. - * keyid - If private key localkeyids friendlynames are to match a - * predetermined value, the value to match. This value should - * be an octet string. - * keyid_len- Length of the keyid byte string. - * name_str - If friendlynames are to match a predetermined value, the value - * to match. This value should be a NULL terminated string. - * pkey - Points to location pointing to the private key returned. - * cert - Points to locaiton which points to the client cert returned - * ca - Points to location that points to a stack of 'certificate - * authority' certs/trust anchors. - * - * Note about error codes: This function is an internal function, and the - * place where it is called sets error codes. Therefore only set an error - * code if it is something that is unique or if the function which detected - * the error doesn't set one. - * - * Returns: - * == -1 - An error occurred. Call ERR_get_error() to get error information. - * Where possible, memory has been freed. - * == 0 - No matching returns were found. - * > 0 - This is the aithmetic 'or' of the FOUND_* bits that indicate which - * of the requested entries were found. - */ -static int -parse_pkcs12(PKCS12 *p12, const char *pass, int matchty, char *keyid, - int kstr_len, char *name_str, EVP_PKEY **pkey, X509 **cert, - STACK_OF(X509) **ca) -{ - STACK_OF(EVP_PKEY) *work_kl = NULL; /* Head for private key list */ - STACK_OF(EVP_PKEY) *nocerts = NULL; /* Head for alt. key list */ - STACK_OF(X509) *work_ca = NULL; /* Head for cert list */ - STACK_OF(X509) *work_cl = NULL; - int retval = 0; - int n; - - retval = sunw_PKCS12_contents(p12, pass, &work_kl, &work_ca); - if (retval < 0) { - goto cleanup; - } else if (retval == 0) { - /* - * Not really an error here - its just that nothing was found. - */ - goto cleanup; - } - - if (sk_EVP_PKEY_num(work_kl) > 0) { - - if (sunw_split_certs(work_kl, work_ca, &work_cl, &nocerts) - < 0) { - goto cleanup; - } - } - - /* - * Go through the lists of certs and private keys which were - * returned, looking for matches of the appropriate type. Do these - * in the order described above. - */ - if ((matchty & DO_FIND_KEYID) != 0) { - - if (keyid == NULL) { - SUNWerr(SUNW_F_PKCS12_PARSE, SUNW_R_INVALID_ARG); - retval = -1; - goto cleanup; - } - - /* See if string matches localkeyid's */ - retval = sunw_find_localkeyid(keyid, kstr_len, - work_kl, work_cl, pkey, cert); - if (retval != 0) { - if (retval == -1) - goto cleanup; - else - goto last_part; - } - } - if ((matchty & DO_FIND_FN) != 0) { - - if (name_str == NULL) { - SUNWerr(SUNW_F_PKCS12_PARSE, SUNW_R_INVALID_ARG); - retval = -1; - goto cleanup; - } - - /* See if string matches friendly names */ - retval = sunw_find_fname(name_str, work_kl, work_cl, - pkey, cert); - if (retval != 0) { - if (retval == -1) - goto cleanup; - else - goto last_part; - } - } - - if (matchty & DO_FIRST_PAIR) { - - /* Find the first cert and private key and return them */ - retval = get_key_cert(0, work_kl, pkey, work_cl, cert); - if (retval != 0) { - if (retval == -1) - goto cleanup; - else - goto last_part; - } - } - - if (matchty & DO_LAST_PAIR) { - - /* - * Find the last matching cert and private key and return - * them. Since keys which don't have matching client certs - * are at the end of the list of keys, use the number of - * client certs to compute the position of the last private - * key which matches a client cert. - */ - n = sk_X509_num(work_cl) - 1; - retval = get_key_cert(n, work_kl, pkey, work_cl, cert); - if (retval != 0) { - if (retval == -1) - goto cleanup; - else - goto last_part; - } - } - - if (matchty & DO_UNMATCHING) { - STACK_OF(EVP_PKEY) *tmpk; - STACK_OF(X509) *tmpc; - - /* Find the first cert and private key and return them */ - tmpc = work_cl; - if (work_cl == NULL || sk_X509_num(work_cl) == 0) - tmpc = work_ca; - tmpk = work_kl; - if (work_kl == NULL || sk_EVP_PKEY_num(work_kl) == 0) - tmpk = nocerts; - retval = get_key_cert(0, tmpk, pkey, tmpc, cert); - if (retval != 0) { - if (retval == -1) - goto cleanup; - else - goto last_part; - } - } - -last_part: - /* If no errors, terminate normally */ - if (retval != -1) - retval |= set_results(NULL, NULL, NULL, NULL, ca, &work_ca, - NULL, NULL); - if (retval >= 0) { - goto clean_part; - } - - /* Fallthrough is intentional in error cases. */ -cleanup: - if (pkey != NULL && *pkey != NULL) { - sunw_evp_pkey_free(*pkey); - *pkey = NULL; - } - if (cert != NULL && *cert != NULL) { - X509_free(*cert); - *cert = NULL; - } - -clean_part: - - if (work_kl != NULL) { - sk_EVP_PKEY_pop_free(work_kl, sunw_evp_pkey_free); - } - if (work_ca != NULL) - sk_X509_pop_free(work_ca, X509_free); - if (work_cl != NULL) - sk_X509_pop_free(work_cl, X509_free); - - return (retval); -} - -/* - * parse_outer - Unpack the outer PKCS#12 structure and go through the - * individual bags. Return stacks of certs, private keys found and - * CA certs found. - * - * Note about error codes: This function is an internal function, and the - * place where it is called sets error codes. - * - * Returns: - * 0 - An error returned. Call ERR_get_error() to get errors information. - * Where possible, memory has been freed. - * 1 - PKCS12 data object was parsed and lists of certs and private keys - * were returned. - */ -static int -parse_outer(PKCS12 *p12, const char *pass, STACK_OF(EVP_PKEY) *kl, - STACK_OF(X509) *cl) -{ - STACK_OF(PKCS12_SAFEBAG) *bags; - STACK_OF(PKCS7) *asafes; - int i, bagnid; - PKCS7 *p7; - - if ((asafes = M_PKCS12_unpack_authsafes(p12)) == NULL) - return (0); - - for (i = 0; i < sk_PKCS7_num(asafes); i++) { - p7 = sk_PKCS7_value(asafes, i); - bagnid = OBJ_obj2nid(p7->type); - if (bagnid == NID_pkcs7_data) { - bags = M_PKCS12_unpack_p7data(p7); - } else if (bagnid == NID_pkcs7_encrypted) { - /* - * A length of '-1' means strlen() can be used - * to determine the password length. - */ - bags = M_PKCS12_unpack_p7encdata(p7, pass, -1); - } else { - SUNWerr(SUNW_F_PARSE_OUTER, SUNW_R_BAD_BAGTYPE); - return (0); - } - - if (bags == NULL) { - SUNWerr(SUNW_F_PARSE_OUTER, SUNW_R_PARSE_BAG_ERR); - sk_PKCS7_pop_free(asafes, PKCS7_free); - return (0); - } - if (parse_all_bags(bags, pass, kl, cl) == 0) { - sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); - sk_PKCS7_pop_free(asafes, PKCS7_free); - return (0); - } - } - - return (1); -} - -/* - * parse_all_bags - go through the stack of bags, parsing each. - * - * Note about error codes: This function is an internal function, and the - * place where it is called sets error codes. - * - * Returns: - * 0 - An error returned. Call ERR_get_error() to get errors information. - * Where possible, memory has been freed. - * 1 - Stack of safebags was parsed and lists of certs and private keys - * were returned. - */ -static int -parse_all_bags(STACK_OF(PKCS12_SAFEBAG) *bags, const char *pass, - STACK_OF(EVP_PKEY) *kl, STACK_OF(X509) *cl) -{ - int i; - for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) { - if (parse_one_bag(sk_PKCS12_SAFEBAG_value(bags, i), - pass, kl, cl) == 0) - return (0); - } - return (1); -} - -/* - * parse_one_bag - Parse an individual bag - * - * i = parse_one_bag(bag, pass, kl, cl); - * - * Arguments: - * bag - pkcs12 safebag to parse. - * pass - password for use in decryption of shrouded keybag - * kl - Stack of private keys found so far. New private keys will - * be added here if found. - * cl - Stack of certs found so far. New certificates will be - * added here if found. - * - * Returns: - * 0 - An error returned. Call ERR_get_error() to get errors information. - * Where possible, memory has been freed. - * 1 - one safebag was parsed. If it contained a cert or private key, it - * was added to the stack of certs or private keys found, respectively. - * localKeyId or friendlyName attributes are returned with the - * private key or certificate. - */ -static int -parse_one_bag(PKCS12_SAFEBAG *bag, const char *pass, STACK_OF(EVP_PKEY) *kl, - STACK_OF(X509) *cl) -{ - X509_ATTRIBUTE *attr = NULL; - ASN1_TYPE *keyid = NULL; - ASN1_TYPE *fname = NULL; - PKCS8_PRIV_KEY_INFO *p8; - EVP_PKEY *pkey = NULL; - X509 *x509 = NULL; - uchar_t *data = NULL; - char *str = NULL; - int retval = 1; - - keyid = PKCS12_get_attr(bag, NID_localKeyID); - fname = PKCS12_get_attr(bag, NID_friendlyName); - - switch (M_PKCS12_bag_type(bag)) { - case NID_keyBag: - if ((pkey = EVP_PKCS82PKEY(bag->value.keybag)) == NULL) { - SUNWerr(SUNW_F_PARSE_ONE_BAG, SUNW_R_PARSE_BAG_ERR); - retval = 0; - break; - } - break; - - case NID_pkcs8ShroudedKeyBag: - /* - * A length of '-1' means strlen() can be used - * to determine the password length. - */ - if ((p8 = M_PKCS12_decrypt_skey(bag, pass, -1)) == NULL) { - SUNWerr(SUNW_F_PARSE_ONE_BAG, SUNW_R_PARSE_BAG_ERR); - retval = 0; - break; - } - pkey = EVP_PKCS82PKEY(p8); - PKCS8_PRIV_KEY_INFO_free(p8); - if (pkey == NULL) { - SUNWerr(SUNW_F_PARSE_ONE_BAG, SUNW_R_PARSE_BAG_ERR); - retval = 0; - } - break; - - case NID_certBag: - if (M_PKCS12_cert_bag_type(bag) != NID_x509Certificate) { - SUNWerr(SUNW_F_PARSE_ONE_BAG, SUNW_R_BAD_CERTTYPE); - break; - } - if ((x509 = M_PKCS12_certbag2x509(bag)) == NULL) { - SUNWerr(SUNW_F_PARSE_ONE_BAG, - SUNW_R_PARSE_CERT_ERR); - retval = 0; - break; - } - - if (keyid != NULL) { - if (keyid->type != V_ASN1_OCTET_STRING) { - SUNWerr(SUNW_F_PARSE_ONE_BAG, - SUNW_R_BAD_LKID); - retval = 0; - break; - } - if (X509_keyid_set1(x509, - keyid->value.octet_string->data, - keyid->value.octet_string->length) == 0) { - SUNWerr(SUNW_F_PARSE_ONE_BAG, - SUNW_R_SET_LKID_ERR); - retval = 0; - break; - } - } - - if (fname != NULL) { - ASN1_STRING *tmpstr = NULL; - int len; - - if (fname->type != V_ASN1_BMPSTRING) { - SUNWerr(SUNW_F_PARSE_ONE_BAG, - SUNW_R_BAD_FNAME); - retval = 0; - break; - } - - tmpstr = fname->value.asn1_string; - len = ASN1_STRING_to_UTF8(&data, tmpstr); - if (len < 0) { - SUNWerr(SUNW_F_PARSE_ONE_BAG, - SUNW_R_SET_FNAME_ERR); - retval = 0; - break; - } - - if (X509_alias_set1(x509, data, len) == 0) { - SUNWerr(SUNW_F_PARSE_ONE_BAG, - SUNW_R_SET_FNAME_ERR); - retval = 0; - break; - } - } - - if (sk_X509_push(cl, x509) == 0) { - SUNWerr(SUNW_F_PARSE_ONE_BAG, SUNW_R_MEMORY_FAILURE); - retval = 0; - break; - } - x509 = NULL; - break; - - case NID_safeContentsBag: - if (keyid != NULL) - ASN1_TYPE_free(keyid); - if (fname != NULL) - ASN1_TYPE_free(fname); - if (parse_all_bags(bag->value.safes, pass, kl, cl) == 0) { - /* - * Error already on stack - */ - return (0); - } - return (1); - - default: - if (keyid != NULL) - ASN1_TYPE_free(keyid); - if (fname != NULL) - ASN1_TYPE_free(fname); - SUNWerr(SUNW_F_PARSE_ONE_BAG, SUNW_R_BAD_BAGTYPE); - return (0); - } - - - if (pkey != NULL) { - if (retval != 0 && (keyid != NULL || fname != NULL) && - pkey->attributes == NULL) { - pkey->attributes = sk_X509_ATTRIBUTE_new_null(); - if (pkey->attributes == NULL) { - SUNWerr(SUNW_F_PARSE_ONE_BAG, - SUNW_R_MEMORY_FAILURE); - retval = 0; - } - } - - if (retval != 0 && keyid != NULL) { - attr = type2attrib(keyid, NID_localKeyID); - if (attr == NULL) - /* - * Error already on stack - */ - retval = 0; - else { - keyid = NULL; - if (sk_X509_ATTRIBUTE_push(pkey->attributes, - attr) == 0) { - SUNWerr(SUNW_F_PARSE_ONE_BAG, - SUNW_R_MEMORY_FAILURE); - retval = 0; - } else { - attr = NULL; - } - } - } - - if (retval != 0 && fname != NULL) { - attr = type2attrib(fname, NID_friendlyName); - if (attr == NULL) { - /* - * Error already on stack - */ - retval = 0; - } else { - fname = NULL; - if (sk_X509_ATTRIBUTE_push(pkey->attributes, - attr) == 0) { - SUNWerr(SUNW_F_PARSE_ONE_BAG, - SUNW_R_MEMORY_FAILURE); - retval = 0; - } else { - attr = NULL; - } - } - } - - /* Save the private key */ - if (retval != 0) { - if (sk_EVP_PKEY_push(kl, pkey) == 0) { - SUNWerr(SUNW_F_PARSE_ONE_BAG, - SUNW_R_MEMORY_FAILURE); - retval = 0; - } else { - pkey = NULL; - } - } - } - - if (pkey != NULL) { - sunw_evp_pkey_free(pkey); - } - - if (x509 != NULL) - X509_free(x509); - - if (keyid != NULL) - ASN1_TYPE_free(keyid); - - if (fname != NULL) - ASN1_TYPE_free(fname); - - if (attr != NULL) - X509_ATTRIBUTE_free(attr); - - if (data != NULL) - OPENSSL_free(data); - - if (str != NULL) - OPENSSL_free(str); - - return (retval); -} - -/* - * This function uses the only function that reads PEM files, regardless of - * the kinds of information included (private keys, public keys, cert requests, - * certs). Other interfaces that read files require that the application - * specifically know what kinds of things to read next, and call different - * interfaces for the different kinds of entities. - * - * There is only one aspect of this function that's a bit problematic. - * If it finds an encrypted private key, it does not decrypt it. It returns - * the encrypted data and other information needed to decrypt it. The caller - * must do the decryption. This function does the decoding. - */ -static int -pem_info(FILE *fp, pem_password_cb cb, void *userdata, - STACK_OF(EVP_PKEY) **pkeys, STACK_OF(X509) **certs) -{ - STACK_OF(X509_INFO) *info; - STACK_OF(EVP_PKEY) *work_kl; - STACK_OF(X509) *work_cl; - X509_INFO *x; - int retval = 0; - int i; - - info = PEM_X509_INFO_read(fp, NULL, cb, userdata); - if (info == NULL) { - SUNWerr(SUNW_F_PEM_INFO, SUNW_R_READ_ERR); - return (-1); - } - - /* - * Allocate the working stacks for private key(s) and for the cert(s). - */ - if ((work_kl = sk_EVP_PKEY_new_null()) == NULL) { - SUNWerr(SUNW_F_PEM_INFO, SUNW_R_MEMORY_FAILURE); - retval = -1; - goto cleanup; - } - - if ((work_cl = sk_X509_new_null()) == NULL) { - SUNWerr(SUNW_F_PEM_INFO, SUNW_R_MEMORY_FAILURE); - retval = -1; - goto cleanup; - } - - /* - * Go through the entries in the info structure. - */ - for (i = 0; i < sk_X509_INFO_num(info); i++) { - x = sk_X509_INFO_value(info, i); - if (x->x509) { - if (sk_X509_push(work_cl, x->x509) == 0) { - retval = -1; - break; - } - x->x509 = NULL; - } - if (x->x_pkey != NULL && x->x_pkey->dec_pkey != NULL && - (x->x_pkey->dec_pkey->type == EVP_PKEY_RSA || - x->x_pkey->dec_pkey->type == EVP_PKEY_DSA)) { - const uchar_t *p; - - /* - * If the key was encrypted, PEM_X509_INFO_read does - * not decrypt it. If that is the case, the 'enc_pkey' - * field is set to point to the unencrypted key data. - * Go through the additional steps to decode it before - * going on. - */ - if (x->x_pkey->enc_pkey != NULL) { - - if (PEM_do_header(&x->enc_cipher, - (uchar_t *)x->enc_data, - (long *)&x->enc_len, - cb, userdata) == 0) { - if (ERR_GET_REASON(ERR_peek_error()) == - PEM_R_BAD_PASSWORD_READ) { - SUNWerr(SUNW_F_PEM_INFO, - SUNW_R_PASSWORD_ERR); - } else { - SUNWerr(SUNW_F_PEM_INFO, - SUNW_R_PKEY_READ_ERR); - } - retval = -1; - break; - } - if (x->x_pkey->dec_pkey->type == EVP_PKEY_RSA) { - RSA **pp; - - pp = &(x->x_pkey->dec_pkey->pkey.rsa); - p = (uchar_t *)x->enc_data; - if (d2i_RSAPrivateKey(pp, &p, - x->enc_len) == NULL) { - SUNWerr(SUNW_F_PEM_INFO, - SUNW_R_PKEY_READ_ERR); - retval = -1; - break; - } - } else { - DSA **pp; - - pp = &(x->x_pkey->dec_pkey->pkey.dsa); - p = (uchar_t *)x->enc_data; - if (d2i_DSAPrivateKey(pp, &p, - x->enc_len) == NULL) { - SUNWerr(SUNW_F_PEM_INFO, - SUNW_R_PKEY_READ_ERR); - retval = -1; - break; - } - } - } - - /* Save the key. */ - retval = sk_EVP_PKEY_push(work_kl, x->x_pkey->dec_pkey); - if (retval == 0) { - retval = -1; - break; - } - x->x_pkey->dec_pkey = NULL; - } else if (x->x_pkey != NULL) { - SUNWerr(SUNW_F_PEM_INFO, SUNW_R_BAD_PKEYTYPE); - retval = -1; - break; - } - } - if (retval == -1) - goto cleanup; - - /* If error occurs, then error already on stack */ - retval = set_results(pkeys, &work_kl, certs, &work_cl, NULL, NULL, - NULL, NULL); - -cleanup: - if (work_kl != NULL) { - sk_EVP_PKEY_pop_free(work_kl, sunw_evp_pkey_free); - } - if (work_cl != NULL) - sk_X509_pop_free(work_cl, X509_free); - - sk_X509_INFO_pop_free(info, X509_INFO_free); - - return (retval); -} - -/* - * sunw_append_keys - Given two stacks of private keys, remove the keys from - * the second stack and append them to the first. Both stacks must exist - * at time of call. - * - * Arguments: - * dst - the stack to receive the keys from 'src' - * src - the stack whose keys are to be moved. - * - * Returns: - * -1 - An error occurred. The error status is set. - * >= 0 - The number of keys that were copied. - */ -static int -sunw_append_keys(STACK_OF(EVP_PKEY) *dst, STACK_OF(EVP_PKEY) *src) -{ - EVP_PKEY *tmpk; - int count = 0; - - while (sk_EVP_PKEY_num(src) > 0) { - tmpk = sk_EVP_PKEY_delete(src, 0); - if (sk_EVP_PKEY_push(dst, tmpk) == 0) { - sunw_evp_pkey_free(tmpk); - SUNWerr(SUNW_F_APPEND_KEYS, SUNW_R_MEMORY_FAILURE); - return (-1); - } - count ++; - } - - return (count); -} - -/* - * move_certs - Given two stacks of certs, remove the certs from - * the second stack and append them to the first. - * - * Arguments: - * dst - the stack to receive the certs from 'src' - * src - the stack whose certs are to be moved. - * - * Returns: - * -1 - An error occurred. The error status is set. - * >= 0 - The number of certs that were copied. - */ -static int -move_certs(STACK_OF(X509) *dst, STACK_OF(X509) *src) -{ - X509 *tmpc; - int count = 0; - - while (sk_X509_num(src) > 0) { - tmpc = sk_X509_delete(src, 0); - if (sk_X509_push(dst, tmpc) == 0) { - X509_free(tmpc); - SUNWerr(SUNW_F_MOVE_CERTS, SUNW_R_MEMORY_FAILURE); - return (-1); - } - count++; - } - - return (count); -} - -/* - * get_key_cert - Get a cert and its matching key from the stacks of certs - * and keys. They are removed from the stacks. - * - * Arguments: - * n - Offset of the entries to return. - * kl - Points to a stack of private keys that matches the list of - * certs below. - * pkey - Points at location where the address of the matching private - * key will be stored. - * cl - Points to a stack of client certs with matching private keys. - * cert - Points to locaiton where the address of the matching client cert - * will be returned - * - * The assumption is that the stacks of keys and certs contain key/cert pairs, - * with entries in the same order and hence at the same offset. Provided - * the key and cert selected match, each will be removed from its stack and - * returned. - * - * A stack of certs can be passed in without a stack of private keys, and vise - * versa. In that case, the indicated key/cert will be returned. - * - * Returns: - * 0 - No matches were found. - * > 0 - Bits set based on FOUND_* definitions, indicating what is returned. - * This can be FOUND_PKEY, FOUND_CERT or (FOUND_PKEY | FOUND_CERT). - */ -static int -get_key_cert(int n, STACK_OF(EVP_PKEY) *kl, EVP_PKEY **pkey, STACK_OF(X509) *cl, - X509 **cert) -{ - int retval = 0; - int nk; - int nc; - - nk = (kl != NULL) ? sk_EVP_PKEY_num(kl) : 0; - nc = (cl != NULL) ? sk_X509_num(cl) : 0; - - if (pkey != NULL && *pkey == NULL) { - if (nk > 0 && n >= 0 || n < nk) { - *pkey = sk_EVP_PKEY_delete(kl, n); - if (*pkey != NULL) - retval |= FOUND_PKEY; - } - } - - if (cert != NULL && *cert == NULL) { - if (nc > 0 && n >= 0 && n < nc) { - *cert = sk_X509_delete(cl, n); - if (*cert != NULL) - retval |= FOUND_CERT; - } - } - - return (retval); -} - - -/* - * asc2bmpstring - Convert a regular C ASCII string to an ASn1_STRING in - * ASN1_BMPSTRING format. - * - * Arguments: - * str - String to be convered. - * len - Length of the string. - * - * Returns: - * == NULL - An error occurred. Error information (accessible by - * ERR_get_error()) is set. - * != NULL - Points to an ASN1_BMPSTRING structure with the converted - * string as a value. - */ -static ASN1_BMPSTRING * -asc2bmpstring(const char *str, int len) -{ - ASN1_BMPSTRING *bmp = NULL; - uchar_t *uni = NULL; - int unilen; - - /* Convert the character to the bmp format. */ -#if OPENSSL_VERSION_NUMBER < 0x10000000L - if (asc2uni(str, len, &uni, &unilen) == 0) { -#else - if (OPENSSL_asc2uni(str, len, &uni, &unilen) == 0) { -#endif - SUNWerr(SUNW_F_ASC2BMPSTRING, SUNW_R_MEMORY_FAILURE); - return (NULL); - } - - /* - * Adjust for possible pair of NULL bytes at the end because - * asc2uni() returns a doubly null terminated string. - */ - if (uni[unilen - 1] == '\0' && uni[unilen - 2] == '\0') - unilen -= 2; - - /* Construct comparison string with correct format */ - bmp = M_ASN1_BMPSTRING_new(); - if (bmp == NULL) { - SUNWerr(SUNW_F_ASC2BMPSTRING, SUNW_R_MEMORY_FAILURE); - OPENSSL_free(uni); - return (NULL); - } - - bmp->data = uni; - bmp->length = unilen; - - return (bmp); -} - -/* - * utf82ascstr - Convert a UTF8STRING string to a regular C ASCII string. - * This goes through an intermediate step with a ASN1_STRING type of - * IA5STRING (International Alphabet 5, which is the same as ASCII). - * - * Arguments: - * str - UTF8STRING to be converted. - * - * Returns: - * == NULL - An error occurred. Error information (accessible by - * ERR_get_error()) is set. - * != NULL - Points to a NULL-termianted ASCII string. The caller must - * free it. - */ -static uchar_t * -utf82ascstr(ASN1_UTF8STRING *ustr) -{ - ASN1_STRING tmpstr; - ASN1_STRING *astr = &tmpstr; - uchar_t *retstr = NULL; - int mbflag; - int ret; - - if (ustr == NULL || ustr->type != V_ASN1_UTF8STRING) { - SUNWerr(SUNW_F_UTF82ASCSTR, SUNW_R_INVALID_ARG); - return (NULL); - } - - mbflag = MBSTRING_ASC; - tmpstr.data = NULL; - tmpstr.length = 0; - - ret = ASN1_mbstring_copy(&astr, ustr->data, ustr->length, mbflag, - B_ASN1_IA5STRING); - if (ret < 0) { - SUNWerr(SUNW_F_UTF82ASCSTR, SUNW_R_STR_CONVERT_ERR); - return (NULL); - } - - retstr = OPENSSL_malloc(astr->length + 1); - if (retstr == NULL) { - SUNWerr(SUNW_F_UTF82ASCSTR, SUNW_R_MEMORY_FAILURE); - return (NULL); - } - - (void) memcpy(retstr, astr->data, astr->length); - retstr[astr->length] = '\0'; - OPENSSL_free(astr->data); - - return (retstr); -} - - -/* - * type2attrib - Given a ASN1_TYPE, return a X509_ATTRIBUTE of the type - * specified by the given NID. - * - * Arguments: - * ty - Type structure to be made into an attribute - * nid - NID of the attribute - * - * Returns: - * NULL An error occurred. - * != NULL An X509_ATTRIBUTE structure. - */ -X509_ATTRIBUTE * -type2attrib(ASN1_TYPE *ty, int nid) -{ - X509_ATTRIBUTE *a; - - if ((a = X509_ATTRIBUTE_new()) == NULL || - (a->value.set = sk_ASN1_TYPE_new_null()) == NULL || - sk_ASN1_TYPE_push(a->value.set, ty) == 0) { - if (a != NULL) - X509_ATTRIBUTE_free(a); - SUNWerr(SUNW_F_TYPE2ATTRIB, SUNW_R_MEMORY_FAILURE); - return (NULL); - } - a->single = 0; - a->object = OBJ_nid2obj(nid); - - return (a); -} - -/* - * attrib2type - Given a X509_ATTRIBUTE, return pointer to the ASN1_TYPE - * component - * - * Arguments: - * attr - Attribute structure containing a type. - * - * Returns: - * NULL An error occurred. - * != NULL An ASN1_TYPE structure. - */ -static ASN1_TYPE * -attrib2type(X509_ATTRIBUTE *attr) -{ - ASN1_TYPE *ty = NULL; - - if (attr == NULL || attr->single == 1) - return (NULL); - - if (sk_ASN1_TYPE_num(attr->value.set) > 0) - ty = sk_ASN1_TYPE_value(attr->value.set, 0); - - return (ty); -} - -/* - * find_attr_by_nid - Given a ASN1_TYPE, return the offset of a X509_ATTRIBUTE - * of the type specified by the given NID. - * - * Arguments: - * attrs - Stack of attributes to search - * nid - NID of the attribute being searched for - * - * Returns: - * -1 None found - * != -1 Offset of the matching attribute. - */ -static int -find_attr_by_nid(STACK_OF(X509_ATTRIBUTE) *attrs, int nid) -{ - X509_ATTRIBUTE *a; - int i; - - if (attrs == NULL) - return (-1); - - for (i = 0; i < sk_X509_ATTRIBUTE_num(attrs); i++) { - a = sk_X509_ATTRIBUTE_value(attrs, i); - if (OBJ_obj2nid(a->object) == nid) - return (i); - } - return (-1); -} - -/* - * Called by our PKCS12 code to read our function and error codes - * into memory so that the OpenSSL framework can retrieve them. - */ -void -ERR_load_SUNW_strings(void) -{ - assert(SUNW_lib_error_code == 0); -#ifndef OPENSSL_NO_ERR - /* - * Have OpenSSL provide us with a unique ID. - */ - SUNW_lib_error_code = ERR_get_next_error_library(); - - ERR_load_strings(SUNW_lib_error_code, SUNW_str_functs); - ERR_load_strings(SUNW_lib_error_code, SUNW_str_reasons); - - SUNW_lib_name->error = ERR_PACK(SUNW_lib_error_code, 0, 0); - ERR_load_strings(0, SUNW_lib_name); -#endif -} - -/* - * The SUNWerr macro resolves to this routine. So when we need - * to push an error, this routine does it for us. Notice that - * the SUNWerr macro provides a filename and line #. - */ -void -ERR_SUNW_error(int function, int reason, char *file, int line) -{ - assert(SUNW_lib_error_code != 0); -#ifndef OPENSSL_NO_ERR - ERR_PUT_error(SUNW_lib_error_code, function, reason, file, line); -#endif -} - -/* - * check_time - Given an indication of the which time(s) to check, check - * that time or those times against the current time and return the - * relationship. - * - * Arguments: - * chkwhat - What kind of check to do. - * cert - The cert to check. - * - * Returns: - * CHKERR_* values. - */ -static chk_errs_t -check_time(chk_actions_t chkwhat, X509 *cert) -{ - int i; - - if (chkwhat == CHK_NOT_BEFORE || chkwhat == CHK_BOTH) { - i = X509_cmp_time(X509_get_notBefore(cert), NULL); - if (i == 0) - return (CHKERR_TIME_BEFORE_BAD); - if (i > 0) - return (CHKERR_TIME_IS_BEFORE); - - /* The current time is after the 'not before' time */ - } - - if (chkwhat == CHK_NOT_AFTER || chkwhat == CHK_BOTH) { - i = X509_cmp_time(X509_get_notAfter(cert), NULL); - if (i == 0) - return (CHKERR_TIME_AFTER_BAD); - if (i < 0) - return (CHKERR_TIME_HAS_EXPIRED); - } - - return (CHKERR_TIME_OK); -} - -/* - * find_attr - Look for a given attribute of the type associated with the NID. - * - * Arguments: - * nid - NID for the attribute to be found (either NID_friendlyName or - * NID_locakKeyId) - * str - ASN1_STRING-type structure containing the value to be found, - * FriendlyName expects a ASN1_BMPSTRING and localKeyID uses a - * ASN1_STRING. - * kl - Points to a stack of private keys. - * pkey - Points at a location where the address of the matching private - * key will be stored. - * cl - Points to a stack of client certs with matching private keys. - * cert - Points to locaiton where the address of the matching client cert - * will be returned - * - * This function is designed to process lists of certs and private keys. - * This is made complex because these the attributes are stored differently - * for certs and for keys. For certs, only a few attributes are retained. - * FriendlyName is stored in the aux structure, under the name 'alias'. - * LocalKeyId is also stored in the aux structure, under the name 'keyid'. - * A pkey structure has a stack of attributes. - * - * The basic approach is: - * - If there there is no stack of certs but a stack of private keys exists, - * search the stack of keys for a match. Alternately, if there is a stack - * of certs and no private keys, search the certs. - * - * - If there are both certs and keys, assume that the matching certs and - * keys are in their respective stacks, with matching entries in the same - * order. Search for the name or keyid in the stack of certs. If it is - * not found, then this function returns 0 (nothing found). - * - * - Once a cert is found, verify that the key actually matches by - * comparing the private key with the public key (in the cert). - * If they don't match, return an error. - * - * A pointer to cert and/or pkey which matches the name or keyid is stored - * in the return arguments. - * - * Returns: - * 0 - No matches were found. - * > 0 - Bits set based on FOUND_* definitions, indicating what was found. - * This can be FOUND_PKEY, FOUND_CERT or (FOUND_PKEY | FOUND_CERT). - */ -static int -find_attr(int nid, ASN1_STRING *str, STACK_OF(EVP_PKEY) *kl, EVP_PKEY **pkey, - STACK_OF(X509) *cl, X509 **cert) -{ - ASN1_UTF8STRING *ustr = NULL; - ASN1_STRING *s; - ASN1_TYPE *t; - EVP_PKEY *p; - uchar_t *fname = NULL; - X509 *x; - int found = 0; - int chkcerts; - int len; - int res; - int c = -1; - int k = -1; - - chkcerts = (cert != NULL || pkey != NULL) && cl != NULL; - if (chkcerts && nid == NID_friendlyName && - str->type == V_ASN1_BMPSTRING) { - ustr = ASN1_UTF8STRING_new(); - if (ustr == NULL) { - SUNWerr(SUNW_F_FINDATTR, SUNW_R_MEMORY_FAILURE); - return (0); - } - len = ASN1_STRING_to_UTF8(&fname, str); - if (fname == NULL) { - ASN1_UTF8STRING_free(ustr); - SUNWerr(SUNW_F_FINDATTR, SUNW_R_STR_CONVERT_ERR); - return (0); - } - - if (ASN1_STRING_set(ustr, fname, len) == 0) { - ASN1_UTF8STRING_free(ustr); - OPENSSL_free(fname); - SUNWerr(SUNW_F_FINDATTR, SUNW_R_MEMORY_FAILURE); - return (0); - } - } - - if (chkcerts) { - for (c = 0; c < sk_X509_num(cl); c++) { - res = -1; - x = sk_X509_value(cl, c); - if (nid == NID_friendlyName && ustr != NULL) { - if (x->aux == NULL || x->aux->alias == NULL) - continue; - s = x->aux->alias; - if (s != NULL && s->type == ustr->type && - s->data != NULL) { - res = ASN1_STRING_cmp(s, ustr); - } - } else { - if (x->aux == NULL || x->aux->keyid == NULL) - continue; - s = x->aux->keyid; - if (s != NULL && s->type == str->type && - s->data != NULL) { - res = ASN1_STRING_cmp(s, str); - } - } - if (res == 0) { - if (cert != NULL) - *cert = sk_X509_delete(cl, c); - found = FOUND_CERT; - break; - } - } - if (ustr != NULL) { - ASN1_UTF8STRING_free(ustr); - OPENSSL_free(fname); - } - } - - if (pkey != NULL && kl != NULL) { - /* - * Looking for pkey to match a cert? If so, assume that - * lists of certs and their matching pkeys are in the same - * order. Call X509_check_private_key() to verify this - * assumption. - */ - if (found != 0 && cert != NULL) { - k = c; - p = sk_EVP_PKEY_value(kl, k); - if (X509_check_private_key(x, p) != 0) { - if (pkey != NULL) - *pkey = sk_EVP_PKEY_delete(kl, k); - found |= FOUND_PKEY; - } - } else if (cert == NULL) { - for (k = 0; k < sk_EVP_PKEY_num(kl); k++) { - p = sk_EVP_PKEY_value(kl, k); - if (p == NULL || p->attributes == NULL) - continue; - - t = PKCS12_get_attr_gen(p->attributes, nid); - if (t != NULL || ASN1_STRING_cmp(str, - t->value.asn1_string) == 0) - continue; - - found |= FOUND_PKEY; - if (pkey != NULL) - *pkey = sk_EVP_PKEY_delete(kl, k); - break; - } - } - } - - return (found); -} - -/* - * set_results - Given two pointers to stacks of private keys, certs or CA - * CA certs, either copy the second stack to the first, or append the - * contents of the second to the first. - * - * Arguments: - * pkeys - Points to stack of pkeys - * work_kl - Points to working stack of pkeys - * certs - Points to stack of certs - * work_cl - Points to working stack of certs - * cacerts - Points to stack of CA certs - * work_ca - Points to working stack of CA certs - * xtrakeys - Points to stack of unmatcned pkeys - * work_xl - Points to working stack of unmatcned pkeys - * - * The arguments are in pairs. The first of each pair points to a stack - * of keys or certs. The second of the pair points at a 'working stack' - * of the same type of entities. Actions taken are as follows: - * - * - If either the first or second argument is NULL, or if there are no - * members in the second stack, there is nothing to do. - * - If the first argument points to a pointer which is NULL, then there - * is no existing stack for the first argument. Copy the stack pointer - * from the second argument to the first argument and NULL out the stack - * pointer for the second. - * - Otherwise, go through the elements of the second stack, removing each - * and adding it to the first stack. - * - * Returns: - * == -1 - An error occurred. Call ERR_get_error() to get error information. - * == 0 - No matching returns were found. - * > 0 - This is the arithmetic 'or' of the FOUND_* bits that indicate which - * of the requested entries were manipulated. - */ -static int -set_results(STACK_OF(EVP_PKEY) **pkeys, STACK_OF(EVP_PKEY) **work_kl, - STACK_OF(X509) **certs, STACK_OF(X509) **work_cl, - STACK_OF(X509) **cacerts, STACK_OF(X509) **work_ca, - STACK_OF(EVP_PKEY) **xtrakeys, STACK_OF(EVP_PKEY) **work_xl) -{ - int retval = 0; - - if (pkeys != NULL && work_kl != NULL && *work_kl != NULL && - sk_EVP_PKEY_num(*work_kl) > 0) { - if (*pkeys == NULL) { - *pkeys = *work_kl; - *work_kl = NULL; - } else { - if (sunw_append_keys(*pkeys, *work_kl) < 0) { - return (-1); - } - } - retval |= FOUND_PKEY; - } - if (certs != NULL && work_cl != NULL && *work_cl != NULL && - sk_X509_num(*work_cl) > 0) { - if (*certs == NULL) { - *certs = *work_cl; - *work_cl = NULL; - } else { - if (move_certs(*certs, *work_cl) < 0) { - return (-1); - } - } - retval |= FOUND_CERT; - } - - if (cacerts != NULL && work_ca != NULL && *work_ca != NULL && - sk_X509_num(*work_ca) > 0) { - if (*cacerts == NULL) { - *cacerts = *work_ca; - *work_ca = NULL; - } else { - if (move_certs(*cacerts, *work_ca) < 0) { - return (-1); - } - } - retval |= FOUND_CA_CERTS; - } - - if (xtrakeys != NULL && work_xl != NULL && *work_xl != NULL && - sk_EVP_PKEY_num(*work_xl) > 0) { - if (*xtrakeys == NULL) { - *xtrakeys = *work_xl; - *work_xl = NULL; - } else { - if (sunw_append_keys(*xtrakeys, *work_xl) < 0) { - return (-1); - } - } - retval |= FOUND_XPKEY; - } - - return (retval); -} diff --git a/usr/src/lib/libpkg/common/p12lib.h b/usr/src/lib/libpkg/common/p12lib.h deleted file mode 100644 index 3d80ddaa35..0000000000 --- a/usr/src/lib/libpkg/common/p12lib.h +++ /dev/null @@ -1,245 +0,0 @@ -/* - * ==================================================================== - * Copyright (c) 1999 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * licensing@OpenSSL.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). - * - */ - -/* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _P12LIB_H -#define _P12LIB_H - - -#include <openssl/pkcs12.h> -#include <openssl/pem.h> - -/* - * PKCS12 file routines borrowed from SNT's libwanboot. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* These declarations allow us to make stacks of EVP_PKEY objects */ -DECLARE_STACK_OF(EVP_PKEY) -#define sk_EVP_PKEY_new_null() SKM_sk_new_null(EVP_PKEY) -#define sk_EVP_PKEY_free(st) SKM_sk_free(EVP_PKEY, (st)) -#define sk_EVP_PKEY_num(st) SKM_sk_num(EVP_PKEY, (st)) -#define sk_EVP_PKEY_value(st, i) SKM_sk_value(EVP_PKEY, (st), (i)) -#define sk_EVP_PKEY_push(st, val) SKM_sk_push(EVP_PKEY, (st), (val)) -#define sk_EVP_PKEY_find(st, val) SKM_sk_find(EVP_PKEY, (st), (val)) -#define sk_EVP_PKEY_delete(st, i) SKM_sk_delete(EVP_PKEY, (st), (i)) -#define sk_EVP_PKEY_delete_ptr(st, ptr) SKM_sk_delete_ptr(EVP_PKEY, (st), (ptr)) -#define sk_EVP_PKEY_insert(st, val, i) SKM_sk_insert(EVP_PKEY, (st), (val), (i)) -#define sk_EVP_PKEY_pop_free(st, free_func) SKM_sk_pop_free(EVP_PKEY, (st), \ - (free_func)) -#define sk_EVP_PKEY_pop(st) SKM_sk_pop(EVP_PKEY, (st)) - -/* Error reporting routines required by OpenSSL */ -#define SUNW_LIB_NAME "SUNW_PKCS12" -#define SUNWerr(f, r) ERR_SUNW_error((f), (r), __FILE__, __LINE__) - -/* Error codes for the SUNW functions. */ -/* OpenSSL prefers codes to start at 100 */ - -/* Function codes. */ -typedef enum { - SUNW_F_USE_X509CERT = 100, - SUNW_F_USE_PKEY, - SUNW_F_USE_TASTORE, - SUNW_F_USE_CERTFILE, - SUNW_F_USE_KEYFILE, - SUNW_F_USE_TRUSTFILE, - SUNW_F_READ_FILE, - SUNW_F_DOPARSE, - SUNW_F_PKCS12_PARSE, - SUNW_F_PKCS12_CONTENTS, - SUNW_F_PARSE_ONE_BAG, - SUNW_F_PKCS12_CREATE, - SUNW_F_SPLIT_CERTS, - SUNW_F_FIND_LOCALKEYID, - SUNW_F_SET_LOCALKEYID, - SUNW_F_SET_FNAME, - SUNW_F_GET_LOCALKEYID, - SUNW_F_GET_PKEY_FNAME, - SUNW_F_APPEND_KEYS, - SUNW_F_PEM_CONTENTS, - SUNW_F_PEM_INFO, - SUNW_F_ASC2BMPSTRING, - SUNW_F_UTF82ASCSTR, - SUNW_F_FINDATTR, - SUNW_F_TYPE2ATTRIB, - SUNW_F_MOVE_CERTS, - SUNW_F_FIND_FNAME, - SUNW_F_PARSE_OUTER, - SUNW_F_CHECKFILE -} sunw_err_func_t; - -/* Reason codes. */ -typedef enum { - SUNW_R_INVALID_ARG = 100, - SUNW_R_MEMORY_FAILURE, - SUNW_R_MAC_VERIFY_FAILURE, - SUNW_R_MAC_CREATE_FAILURE, - SUNW_R_BAD_FILETYPE, - SUNW_R_BAD_PKEY, - SUNW_R_BAD_PKEYTYPE, - SUNW_R_PKEY_READ_ERR, - SUNW_R_NO_TRUST_ANCHOR, - SUNW_R_READ_TRUST_ERR, - SUNW_R_ADD_TRUST_ERR, - SUNW_R_PKCS12_PARSE_ERR, - SUNW_R_PKCS12_CREATE_ERR, - SUNW_R_PARSE_BAG_ERR, - SUNW_R_MAKE_BAG_ERR, - SUNW_R_BAD_CERTTYPE, - SUNW_R_PARSE_CERT_ERR, - SUNW_R_BAD_LKID, - SUNW_R_SET_LKID_ERR, - SUNW_R_BAD_FNAME, - SUNW_R_SET_FNAME_ERR, - SUNW_R_BAD_TRUST, - SUNW_R_BAD_BAGTYPE, - SUNW_R_CERT_ERR, - SUNW_R_PKEY_ERR, - SUNW_R_READ_ERR, - SUNW_R_ADD_ATTR_ERR, - SUNW_R_STR_CONVERT_ERR, - SUNW_R_PKCS12_EMPTY_ERR, - SUNW_R_PASSWORD_ERR -} sunw_err_reason_t; - -/* - * Type of checking to perform when calling sunw_check_cert_times - */ -typedef enum { - CHK_NOT_BEFORE = 1, /* Check 'not before' date */ - CHK_NOT_AFTER, /* Check 'not after' date */ - CHK_BOTH /* Check both dates */ -} chk_actions_t; - -/* - * Return type for sunw_check_cert_times - */ -typedef enum { - CHKERR_TIME_OK = 0, /* Current time meets requested checks */ - CHKERR_TIME_BEFORE_BAD, /* 'not before' field is invalid */ - CHKERR_TIME_AFTER_BAD, /* 'not after' field is invalid */ - CHKERR_TIME_IS_BEFORE, /* Current time is before 'not before' */ - CHKERR_TIME_HAS_EXPIRED /* Current time is after 'not after' */ -} chk_errs_t; - -/* - * This type indicates what to do with an attribute being returned. - */ -typedef enum { - GETDO_COPY = 1, /* Simply return the value of the attribute */ - GETDO_DEL /* Delete the attribute at the same time. */ -} getdo_actions_t; - -/* - * For sunw_pkcs12_parse, the following are values for bits that indicate - * various types of searches/matching to do. Any of these values can be - * OR'd together. However, the order in which an attempt will be made - * to satisfy them is the order in which they are listed below. The - * exception is DO_NONE. It should not be OR'd with any other value. - */ -#define DO_NONE 0x00 /* Don't even try to match */ -#define DO_FIND_KEYID 0x01 /* 1st cert, key with matching localkeyid */ -#define DO_FIND_FN 0x02 /* 1st cert, key with matching friendlyname */ -#define DO_FIRST_PAIR 0x04 /* Return first matching cert/key pair found */ -#define DO_LAST_PAIR 0x08 /* Return last matching cert/key pair found */ -#define DO_UNMATCHING 0x10 /* Return first cert and/or key */ - -/* Bits returned, which indicate what values were found. */ -#define FOUND_PKEY 0x01 /* Found one or more private key */ -#define FOUND_CERT 0x02 /* Found one or more client certificate */ -#define FOUND_CA_CERTS 0x04 /* Added at least one cert to the CA list */ -#define FOUND_XPKEY 0x08 /* Found at least one private key which does */ - /* not match a certificate in the certs list */ - -/* p12lib.c */ -PKCS12 *sunw_PKCS12_create(const char *, STACK_OF(EVP_PKEY) *, - STACK_OF(X509) *, STACK_OF(X509) *); - -int sunw_split_certs(STACK_OF(EVP_PKEY) *, STACK_OF(X509) *, - STACK_OF(X509) **, STACK_OF(EVP_PKEY) **); - -void sunw_evp_pkey_free(EVP_PKEY *); -int sunw_set_localkeyid(const char *, int, EVP_PKEY *, X509 *); -int sunw_get_pkey_localkeyid(getdo_actions_t, EVP_PKEY *, char **, int *); -int sunw_get_pkey_fname(getdo_actions_t, EVP_PKEY *, char **); -int sunw_find_localkeyid(char *, int, STACK_OF(EVP_PKEY) *, - STACK_OF(X509) *, EVP_PKEY **, X509 **); -int sunw_find_fname(char *, STACK_OF(EVP_PKEY) *, STACK_OF(X509) *, - EVP_PKEY **, X509 **); -int sunw_set_fname(const char *, EVP_PKEY *, X509 *); -int sunw_check_keys(X509 *, EVP_PKEY *); - -chk_errs_t sunw_check_cert_times(chk_actions_t, X509 *); -extern void ERR_SUNW_error(int function, int reason, char *file, int line); -extern void ERR_load_SUNW_strings(void); -int sunw_PKCS12_contents(PKCS12 *, const char *, - STACK_OF(EVP_PKEY) **, STACK_OF(X509) **); -int sunw_get_cert_fname(getdo_actions_t, X509 *, char **); -int sunw_PEM_contents(FILE *, pem_password_cb, void *, - STACK_OF(EVP_PKEY) **, STACK_OF(X509) **); - -#ifdef __cplusplus -} -#endif - -#endif /* _P12LIB_H */ diff --git a/usr/src/lib/libpkg/common/path_valid.c b/usr/src/lib/libpkg/common/path_valid.c new file mode 100644 index 0000000000..c320685cdb --- /dev/null +++ b/usr/src/lib/libpkg/common/path_valid.c @@ -0,0 +1,61 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright (c) 2017 Peter Tribble. + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + +#include <limits.h> +#include <string.h> +#include <sys/types.h> + +/* + * Name: path_valid + * Description: Checks a string for being a valid path + * + * Arguments: path - path to validate + * + * Returns : B_TRUE - success, B_FALSE otherwise. + * B_FALSE means path was null, too long (>PATH_MAX), + * or too short (<1) + */ +boolean_t +path_valid(char *path) +{ + if (path == NULL) { + return (B_FALSE); + } else if (strlen(path) > PATH_MAX) { + return (B_FALSE); + } else if (strlen(path) >= 1) { + return (B_TRUE); + } else { + /* path < 1 */ + return (B_FALSE); + } +} diff --git a/usr/src/lib/libpkg/common/pkgerr.c b/usr/src/lib/libpkg/common/pkgerr.c deleted file mode 100644 index 6828d88968..0000000000 --- a/usr/src/lib/libpkg/common/pkgerr.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - - -/* - * Module: pkgerr.c - * Description: - * Module for handling error messages that come from libpkg libraries. - */ - -#include <stdio.h> -#include <string.h> -#include <sys/types.h> -#include <locale.h> -#include <libintl.h> -#include <stdlib.h> -#include <sys/varargs.h> -#include "pkgerr.h" - -/* max length of any formatted error message */ -#define MAX_ERRMSGLEN 1024 - -/* private structures (not visible outside this file) */ -struct _pkg_err_struct { - int nerrs; - char **msgs; - PKG_ERR_CODE *errs; -}; - -/* ---------------------- public functions ----------------------- */ - -PKG_ERR -*pkgerr_new() -{ - PKG_ERR *newerr; - - newerr = (PKG_ERR *)malloc(sizeof (PKG_ERR)); - newerr->nerrs = 0; - newerr->msgs = NULL; - newerr->errs = NULL; - return (newerr); -} - -/*PRINTFLIKE3*/ -void -pkgerr_add(PKG_ERR *err, PKG_ERR_CODE code, char *fmt, ...) -{ - char errmsgbuf[1024]; - va_list ap; - - va_start(ap, fmt); - (void) vsnprintf(errmsgbuf, MAX_ERRMSGLEN, fmt, ap); - va_end(ap); - - err->nerrs++; - - err->msgs = (char **)realloc(err->msgs, - err->nerrs * sizeof (char *)); - err->errs = (PKG_ERR_CODE *)realloc(err->errs, - err->nerrs * sizeof (PKG_ERR_CODE)); - err->msgs[err->nerrs - 1] = strdup(errmsgbuf); - err->errs[err->nerrs - 1] = code; -} - -void -pkgerr_clear(PKG_ERR *err) -{ - int i; - - for (i = 0; i < err->nerrs; i++) { - free(err->msgs[i]); - } - - free(err->msgs); - free(err->errs); - err->msgs = NULL; - err->errs = NULL; - err->nerrs = 0; -} - -int -pkgerr_num(PKG_ERR *err) -{ - return (err->nerrs); -} - -char -*pkgerr_get(PKG_ERR *err, int pos) -{ - if (pos < 0 || pos > (err->nerrs - 1)) { - return (NULL); - } - - return (err->msgs[pos]); -} - -void -pkgerr_free(PKG_ERR *err) -{ - pkgerr_clear(err); - free(err); -} diff --git a/usr/src/lib/libpkg/common/pkgerr.h b/usr/src/lib/libpkg/common/pkgerr.h deleted file mode 100644 index 10e0e219d9..0000000000 --- a/usr/src/lib/libpkg/common/pkgerr.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _PKGERR_H -#define _PKGERR_H - - -/* - * Module: pkgerr.h - * Description: - * - * Implements error routines to handle the creation, - * management, and destruction of error objects, which - * hold error messages and codes returned from libpkg - * routines that support the objects defined herein. - */ - -#include <stdio.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Public Definitions - */ - -typedef enum { - PKGERR_OK = 0, - PKGERR_EXIST, - PKGERR_READ, - PKGERR_CORRUPT, - PKGERR_PARSE, - PKGERR_BADPASS, - PKGERR_BADALIAS, - PKGERR_INTERNAL, - PKGERR_UNSUP, - PKGERR_NOALIAS, - PKGERR_NOALIASMATCH, - PKGERR_MULTIPLE, - PKGERR_INCOMPLETE, - PKGERR_NOPRIVKEY, - PKGERR_NOPUBKEY, - PKGERR_NOCACERT, - PKGERR_NOMEM, - PKGERR_CHAIN, - PKGERR_LOCKED, - PKGERR_WRITE, - PKGERR_UNLOCK, - PKGERR_TIME, - PKGERR_DUPLICATE, - PKGERR_WEB, - PKGERR_VERIFY -} PKG_ERR_CODE; - -/* - * Public Structures - */ - -/* external reference to PKG_ERR object (contents private) */ -typedef PKG_ERR_CODE pkg_err_t; - -typedef struct _pkg_err_struct PKG_ERR; - -/* - * Public Methods - */ - -PKG_ERR *pkgerr_new(); -void pkgerr_add(PKG_ERR *, PKG_ERR_CODE, char *, ...); -void pkgerr_clear(PKG_ERR *); -int pkgerr_dump(PKG_ERR *, FILE *); -int pkgerr_num(PKG_ERR *); -char *pkgerr_get(PKG_ERR *, int); -void pkgerr_free(PKG_ERR *); - -#ifdef __cplusplus -} -#endif - -#endif /* _PKGERR_H */ diff --git a/usr/src/lib/libpkg/common/pkglib.h b/usr/src/lib/libpkg/common/pkglib.h index 4e4bdabf91..31f392fe95 100644 --- a/usr/src/lib/libpkg/common/pkglib.h +++ b/usr/src/lib/libpkg/common/pkglib.h @@ -20,6 +20,10 @@ */ /* + * Copyright (c) 2017 Peter Tribble. + */ + +/* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -40,12 +44,6 @@ extern "C" { #include <stdio.h> #include <pkgdev.h> #include <pkgstrct.h> -#include <openssl/bio.h> -#include <openssl/x509.h> -#include <netdb.h> -#include <boot_http.h> -#include "pkgerr.h" -#include "keystore.h" #include "cfext.h" /* @@ -355,33 +353,13 @@ struct dstr { #define SMALL_DIVISOR 4 #define MED_DIVISOR 5 #define LARGE_DIVISOR 10 -#define MED_DWNLD (10 * 1024 * 1024) /* 10 MB */ -#define LARGE_DWNLD (5 * MED_DWNLD) /* 50 MB */ - -#define HTTP "http://" -#define HTTPS "https://" #define PKGADD "pkgadd" -/* Settings for network admin defaults */ - -#define NET_TIMEOUT_DEFAULT 60 -#define NET_RETRIES_DEFAULT 3 -#define NET_TIMEOUT_MIN 1 /* 1 second */ -#define NET_TIMEOUT_MAX (5 * 60) /* 5 minutes */ -#define NET_RETRIES_MIN 1 -#define NET_RETRIES_MAX 10 -#define AUTH_NOCHECK 0 -#define AUTH_QUIT 1 - /* package header magic tokens */ #define HDR_PREFIX "# PaCkAgE DaTaStReAm" #define HDR_SUFFIX "# end of header" -/* name of security files */ -#define PKGSEC "/var/sadm/security" -#define SIGNATURE_FILENAME "signature" - #define GROUP "/etc/group" #define PASSWD "/etc/passwd" @@ -435,9 +413,6 @@ extern int ds_getpkg(char *device, int n, char *dstdir); extern int ds_ginit(char *device); extern boolean_t ds_fd_open(void); extern int ds_init(char *device, char **pkg, char *norewind); -extern int BIO_ds_dump_header(PKG_ERR *, BIO *); -extern int BIO_ds_dump(PKG_ERR *, char *, BIO *); -extern int BIO_dump_cmd(char *cmd, BIO *bio); extern int ds_next(char *, char *); extern int ds_readbuf(char *device); extern int epclose(FILE *pp); @@ -464,7 +439,7 @@ extern int pkghead(char *device); extern int pkgmount(struct pkgdev *devp, char *pkg, int part, int nparts, int getvolflg); extern int pkgtrans(char *device1, char *device2, char **pkg, - int options, keystore_handle_t, char *); + int options); extern int pkgumount(struct pkgdev *devp); extern int ppkgmap(struct cfent *ept, FILE *fp); extern int putcfile(struct cfent *ept, FILE *fp); @@ -474,9 +449,6 @@ extern void set_memalloc_failure_func(void (*)(int)); extern void *xmalloc(size_t size); extern void *xrealloc(void *ptr, size_t size); extern char *xstrdup(char *str); -extern void set_passphrase_prompt(char *); -extern void set_passphrase_passarg(char *); -extern int pkg_passphrase_cb(char *, int, int, void *); extern int srchcfile(struct cfent *ept, char *path, PKGserver server); extern struct group *cgrgid(gid_t gid); @@ -503,7 +475,6 @@ extern int mappath(int flag, char *path); extern int mapvar(int flag, char *varname); /*PRINTFLIKE1*/ extern void progerr(char *fmt, ...); -extern void pkgerr(PKG_ERR *); extern void rpterr(void); extern void tputcfent(struct cfent *ept, FILE *fp); extern void set_nonABI_symlinks(void); @@ -511,15 +482,6 @@ extern int nonABI_symlinks(void); extern void disable_attribute_check(void); extern int get_disable_attribute_check(void); -/* security.c */ -extern void sec_init(void); -extern char *get_subject_display_name(X509 *); -extern char *get_issuer_display_name(X509 *); -extern char *get_serial_num(X509 *); -extern char *get_fingerprint(X509 *, const EVP_MD *); -extern int get_cert_chain(PKG_ERR *, X509 *, STACK_OF(X509) *, - STACK_OF(X509) *, STACK_OF(X509) **); - /* pkgstr.c */ void pkgstrConvertUllToTimeString_r(unsigned long long a_time, char *a_buf, int a_bufLen); @@ -567,6 +529,9 @@ extern int vfpWriteToFile(VFP_T *a_vfp, char *a_path); boolean_t enable_local_fs(void); boolean_t restore_local_fs(void); +/* path_valid.c */ +extern boolean_t path_valid(char *); + /* pkgserv.c */ extern PKGserver pkgopenserver(const char *, const char *, boolean_t); extern void pkgcloseserver(PKGserver); diff --git a/usr/src/lib/libpkg/common/pkglibmsgs.h b/usr/src/lib/libpkg/common/pkglibmsgs.h index 4b811ca6ae..342b836d73 100644 --- a/usr/src/lib/libpkg/common/pkglibmsgs.h +++ b/usr/src/lib/libpkg/common/pkglibmsgs.h @@ -20,6 +20,10 @@ */ /* + * Copyright (c) 2017 Peter Tribble. + */ + +/* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -54,8 +58,6 @@ extern "C" { /* pkgtrans messages */ #define MSG_TRANSFER "Transferring <%s> package instance\n" -#define MSG_STORE_ACC "Retrieving signature certificates from <%s>\n" -#define MSG_SIGNING "Generating digital signature for signer <%s>\n" #define MSG_RENAME "\t... instance renamed <%s> on destination\n" #define ERR_TRANSFER "unable to complete package transfer" @@ -90,124 +92,6 @@ extern "C" { #define MSG_OPEN "- open of <%s> failed, errno=%d" #define MSG_STATVFS "- statvfs(%s) failed, errno=%d" -/* security problems */ -#define ERR_PARSE "unable to parse keystore <%s>, invalid " \ - "format or corrupt" -#define ERR_BADPASS "Invalid password. Password does not " \ - "decrypt keystore" - -#define MSG_PASSWD_FILE "Password file <%s> cannot be read" -#define MSG_PASSWD_AGAIN "For Verification" -#define MSG_PASSWD_NOMATCH "Passwords do not match" -#define MSG_BADPASSARG "Password retrieval method <%s> invalid" -#define MSG_NOPASS "Cannot get passphrase using " \ - "retrieval method <%s>" - -#define ERR_MISMATCHPASS "<%s> encrypted with different password " \ - " than <%s>, keystore <%s> corrupt" - -#define MSG_CHSIGDIR "- unable to change directory to <%s/%s>" -#define MSG_MKSIGDIR "- unable to make directory <%s/%s>" -#define ERR_CANTSIGN "- destination device must be datastream in order to" \ - " sign contents" -#define ERR_STORE "unable to find or use store <%s> from application " \ - "<%s>:<%s>" - -#define ERR_NO_KEYSTORE "unable to open keystore <%s> for reading" -#define ERR_NOT_REG "<%s> is not a regular file" -#define ERR_KEYSTORE_CORRUPT "Keystore file <%s> is corrupt or unparseable" -#define ERR_KEYSTORE_REPAIR "unable to repair keystore <%s>" -#define ERR_KEYSTORE_LOCKED_READ "unable to lock keystore file <%s> " \ - "for reading, try again later" -#define ERR_KEYSTORE_LOCKED "unable to lock keystore <%s> for exclusive " \ - "access" -#define ERR_KEYSTORE_UNLOCK "unable to unlock keystore <%s> for " \ - "application <%s>" -#define ERR_KEYSTORE_WRITE "unable to open keystore <%s> for writing" -#define ERR_KEYSTORE_REMOVE "unable to delete keystore file <%s>" -#define ERR_KEYSTORE_READ "unable to open keystore <%s> for reading" -#define ERR_KEYSTORE_OPEN "unable to open keystore <%s>:<%s>" -#define ERR_KEYSTORE_FORM "unable to form PKCS12 keystore file for " \ - "writing to <%s>" - -#define ERR_KEYSTORE_NOPUBCERTS "unable to find any public key certificates " \ - "in keystore file <%s>" - -#define ERR_KEYSTORE_NOPRIVKEYS "unable to find any private keys in keystore "\ - "file <%s>" - -#define ERR_KEYSTORE_NOCACERTS "unable to find any trusted certificates in "\ - "file <%s>" - -#define ERR_KEYSTORE_NOTRUST "unable to find any trusted certificates in "\ - "keystore" - -#define ERR_KEYSTORE_NOMATCH "unable to find certificate and key pair " \ - "with alias <%s> in keystore" - -#define ERR_KEYSTORE_DUPLICATECERT "Certificate with alias <%s> " \ - "already exists in keystore" -#define ERR_KEYSTORE_DUPLICATEKEY "Private key with alias <%s> already" \ - " exists in keystore" -#define ERR_KEYSTORE_NO_ALIAS "Keystore certificate <%s> has no recorded " \ - "alias, must be deleted from keystore" -#define ERR_KEYSTORE_NOCERT "No certificate with alias <%s> found in " \ - "keystore <%s>" -#define ERR_KEYSTORE_NOCERTKEY "No certificates or private keys with alias " \ - "<%s> found in keystore <%s>" - -#define ERR_KEYSTORE_INTERNAL "Internal Error file %s line %d" - -#define ERR_CURR_TIME "Cannot determine current time from system" -#define ERR_CERT_TIME "Certificate <%s> has expired or is not yet valid.\n" \ - "Current time: <%s>\n Certificate valid: <%s> - <%s>" -#define ERR_MISMATCHED_KEYS "Private key does not match public key in " \ - "certificate <%s>" -#define ERR_CERT_TIME_BAD "Certificate has corrupt validity dates, " \ - "cannot process" -#define ERR_TRUSTSTORE "unable to find or use trusted certificate " \ - "store <%s> from application <%s>:<%s>" - -#define ERR_STORE_PW "unable to read password from <%s>" - -#define ERR_SEC "unable to sign package contents using <%s> " \ - "private key" - -#define ERR_NOGEN "unable to generate digital signature" - -#define ERR_STORE_PW "unable to read password from <%s>" -#define ERR_CORRUPTSIG "Invalid or corrupt signature in datastream <%s>" -#define ERR_CORRUPTSIG_TYPE "Wrong PKCS7 signature type in datastream <%s>" -#define ERR_CORRUPTSIG_DT "Signature found but not detached in " \ - "datastream <%s>" -#define ERR_KEYSTORE "invalid or corrupt PKCS12 file <%s>." -#define ERR_KEYSTORE_NOCERTS "Store <%s> contains no certificates" -#define ERR_KEYSTORE_NOKEYS "Store <%s> contains no private keys" -#define ERR_SIG_INT "Internal error during signature verification." -#define MSG_VERIFY "## Verifying signature for signer <%s>" -#define MSG_VERIFY_OK "## Signature for signer <%s> verified." -#define ERR_VERIFY "Signature verification failed." -#define ERR_VERIFY_SIG "Signature verification failed while verifying " \ - "certificate <subject=%s, issuer=%s>:<%s>." -#define ERR_VERIFY_ISSUER "Could not find issuer certificate for signer <%s>" -#define ERR_OPENSIG "Signature found in datastream but cannot be " \ - " opened: <%s>" - -#define ERR_SIGFOUND "signature found in datastream <%s>, you must " \ - "specify a keystore with -k" -#define ERR_DSINIT "could not process datastream from <%s>" - -#define MSG_KEYSTORE_AL "Keystore Alias" -#define MSG_KEYSTORE_SN "Serial Number" -#define MSG_KEYSTORE_FP "Fingerprint" -#define MSG_KEYSTORE_CN "Common Name" -#define MSG_KEYSTORE_IN "Issuer Common Name" -#define MSG_KEYSTORE_VD "Validity Dates" -#define MSG_KEYSTORE_TY "Certificate Type" -#define MSG_KEYSTORE_TRUSTED "Trusted Certificate" -#define MSG_KEYSTORE_UNTRUSTED "Signing Certificate" -#define MSG_KEYSTORE_UNKNOWN "Unknown" - /* parameter errors */ #define ERR_LEN "length of parameter <%s> value exceeds limit" #define ERR_ASCII "parameter <%s> must be ascii" @@ -337,92 +221,7 @@ extern "C" { #define ERR_SETUID "setuid(%d) failed." #define ERR_EX_FAIL "exec of %s failed, errno=%d" -/* pkgweb errors */ -#define MSG_DWNLD "\n## Downloading..." -#define ERR_DWNLD_FAILED "\n## After %d retries, unable to complete transfer" -#define MSG_DWNLD_TIMEOUT "\n## Timed out, retrying..." -#define MSG_DWNLD_CONNREF "\n## Connection to <%s> refused, retrying..." -#define MSG_DWNLD_HOSTDWN "\n## <%s> not responding, retrying..." -#define MSG_DWNLD_PART "\n## Found partially downloaded file <%s> of " \ - "size <%ld> bytes. To force a complete " \ - "re-download, delete this file and try again" -#define MSG_DWNLD_PREV "\n## Using previously spooled package datastream <%s>" -#define MSG_DWNLD_CONT "\n## Continuing previously attempted download..." -#define MSG_DWNLD_COMPLETE "## Download Complete\n" - -#define ERR_DWNLD_NO_CONT "unable to open partially downloaded file <%s> " \ - "for appending" -#define ERR_BAD_PATH "unable to locate keystore." -#define ERR_EMPTYPATH "No valid path exists for the keystore file." -#define ERR_RETRIES "The number of server retries is not a valid " \ - "value. Please specify a value within the range of %d - %d." -#define ERR_TIMEOUT "The network timeout value is not a valid " \ - "value. Please specify a value within the range of %d - %d." -#define ERR_PARSE_URL "unable to parse the url <%s>." -#define ERR_MEM "unable to allocate memory." -#define ERR_HTTPS_PASSWD "unable set password for HTTPS connection." -#define ERR_HTTPS_CA "unable to set CA file for HTTPS connection." -#define ERR_HTTP "Failure occurred with http(s) negotiation: <%s>" -#define ERR_WRITE "Cannot write to file <%s> : <%s>" -#define ERR_READ "Cannot read from file <%s> : <%s>" -#define ERR_SVR_RESP "unable to establish a connection with the http(s) server." -#define ERR_INIT_CONN "unable to establish a connection with <%s>." -#define ERR_INIT_SESS "unable to intialize download session for <%s>." -#define ERR_INIT_CONN_PROXY "unable to establish a connection with <%s> " \ - "using <%s> as the proxy" -#define ERR_CLOSE_CONN "unable to close the connection with <%s>." -#define ERR_NO_HEAD_VAL "HTTP Response did not include header <%s>." -/* CSTYLED */ -#define ERR_BAD_HEAD_VAL "HTTP Header value \"<%s>: <%s>\" unusable or " \ - "unparseable." -#define ERR_BAD_CONTENT "The package <%s> attempting to be installed " \ - "is illegal." -#define ERR_DWNLD "unable to download package datastream from <%s>." -#define ERR_OPEN_TMP "unable to open temporary file for writing." -#define ERR_WRITE_TMP "unable to write to temporary file." -#define ERR_DISK_SPACE "Not enough disk space is available to download " \ - "package to\n%s. %llukb needed, %llukb available." -#define ERR_CERTS "unable to find a valid certificate in <%s>." -#define ERR_CERTCHAIN "unable to build certificate chain for subject <%s>:<%s>." -#define ERR_ILL_ENV "The environment variable <%s=%s> is illegal" -#define ERR_BAD_PROXY "Invalid proxy specification: <%s>" -#define ERR_TMPDIR "unable to find temporary directory <%s>" #define ERR_MEM "unable to allocate memory." -#define ERR_NO_DWNLD_DIR "No download directory available." -#define MSG_OCSP_VERIFY "## Contacting OCSP Responder <%s> for " \ - "certificate <%s> status" -#define MSG_OCSP_VERIFY_PROXY "## Contacting OCSP Responder <%s> through " \ - "proxy <%s:%d> for certificate <%s> status" -#define ERR_OCSP_PARSE "OCSP Responder URL <%s> invalid or unparseable" -#define ERR_OCSP_RESP_PARSE "OCSP Response <%s> unparseable or empty" -#define ERR_OCSP_RESP_NOTOK "OCSP Request failed. Expected status " \ - "<%d>, got <%d>, Reason=<%s>" -#define WRN_OCSP_RESP_NONCE "WARNING: Invalid or no nonce found in " \ - "OCSP response." -#define ERR_OCSP_RESP_TYPE "OCSP response message type invalid: <%s>, " \ - "expecting <%s>" -#define ERR_OCSP_CONNECT "Cannot connect to OCSP Responder <%s> port <%d>" -#define ERR_OCSP_SEND "Cannot send OCSP request to OCSP Responder <%s>" -#define ERR_OCSP_READ "Cannot read OCSP response from OCSP Responder <%s>" -#define ERR_OCSP_RESPONDER "OCSP Responder cannot process OCSP Request" -#define ERR_OCSP_UNSUP "Unsupported OCSP Option <%s>" -#define ERR_OCSP_VERIFY_NOTIME "Cannot access system time() to determine " \ - "OCSP Response validity" -#define ERR_OCSP_VERIFY_SIG "OCSP Response, signed by <%s>, cannot be " \ - "verified: <%s>" -#define ERR_OCSP_VERIFY_FAIL "unable to validate response from OCSP " \ - "Responder <%s>" -#define ERR_OCSP_VERIFY_NO_STATUS "OCSP Responder did not supply validity " \ - "of certificate <%s> " -#define ERR_OCSP_VERIFY_VALIDITY_NOTBEFORE "OCSP Response is only valid " \ - "after <%s>. Current time is <%s>." -#define ERR_OCSP_VERIFY_VALIDITY "OCSP Response is only valid from <%s> " \ - "to <%s>. Current time is <%s>." -#define ERR_OCSP_VERIFY_STATUS "OCSP Responder indicates certificate <%s> " \ - "status is <%s>" -#define ERR_OCSP_VERIFY "OCSP Responder rejected certificate, or did not " \ - "recognize" -#define ERR_OCSP_NO_URI "No OCSP Responder URL" #define MSG_BASE_USED "Using <%s> as the package base directory." diff --git a/usr/src/lib/libpkg/common/pkgserv.c b/usr/src/lib/libpkg/common/pkgserv.c index 785f275dfc..7d1c3b8ad0 100644 --- a/usr/src/lib/libpkg/common/pkgserv.c +++ b/usr/src/lib/libpkg/common/pkgserv.c @@ -20,6 +20,10 @@ */ /* + * Copyright (c) 2017 Peter Tribble. + */ + +/* * Copyright 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -506,6 +510,7 @@ pkgcmd(PKGserver srv, void *cmd, size_t len, char **result, size_t *rlen, } /* Error return */ if (da.data_size == sizeof (int)) { + /* LINTED */ int x = *(int *)da.data_ptr; if (x != 0) { if (result == NULL || da.rbuf != *result) diff --git a/usr/src/lib/libpkg/common/pkgtrans.c b/usr/src/lib/libpkg/common/pkgtrans.c index a717360580..cfc4009b08 100644 --- a/usr/src/lib/libpkg/common/pkgtrans.c +++ b/usr/src/lib/libpkg/common/pkgtrans.c @@ -20,6 +20,10 @@ */ /* + * Copyright (c) 2017 Peter Tribble. + */ + +/* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -46,11 +50,6 @@ #include <dirent.h> #include <signal.h> #include <devmgmt.h> -#include <openssl/pkcs12.h> -#include <openssl/x509.h> -#include <openssl/pkcs7.h> -#include <openssl/err.h> -#include <openssl/pem.h> #include <note.h> #include "pkginfo.h" #include "pkgstrct.h" @@ -58,9 +57,7 @@ #include "pkgdev.h" #include "pkglib.h" #include "pkglibmsgs.h" -#include "keystore.h" #include "pkglocale.h" -#include "pkgerr.h" extern char *pkgdir; /* pkgparam.c */ @@ -113,12 +110,9 @@ static int cat_and_count(struct dm_buf *, char *); static int ckoverwrite(char *dir, char *inst, int options); static int pkgxfer(char *srcinst, int options); -static int wdsheader(struct dm_buf *, char *src, char *device, - char **pkg, PKCS7 *); +static int wdsheader(struct dm_buf *, char *device, char **pkg); static struct dm_buf *genheader(char *, char **); -static int dump_hdr_and_pkgs(BIO *, struct dm_buf *, char **); - extern int ds_fd; /* open file descriptor for data stream WHERE? */ static char *root_names[] = { @@ -170,8 +164,7 @@ pkghead(char *device) } /* check for datastream */ - if (n = pkgtrans(device, (char *)0, allpkg, PT_SILENT|PT_INFO_ONLY, - NULL, NULL)) { + if (n = pkgtrans(device, (char *)0, allpkg, PT_SILENT|PT_INFO_ONLY)) { cleanup(); return (n); } @@ -239,90 +232,12 @@ rd_map_size(FILE *fp, int *npts, int *maxpsz, int *cmpsize) /* will return 0, 1, 3, or 99 */ static int -_pkgtrans(char *device1, char *device2, char **pkg, int options, - keystore_handle_t keystore, char *keystore_alias) +_pkgtrans(char *device1, char *device2, char **pkg, int options) { - BIO *p7_bio = NULL; - EVP_PKEY *privkey = NULL; - PKCS7 *sec_pkcs7 = NULL; - PKCS7_SIGNER_INFO *sec_signerinfo = NULL; - PKG_ERR *err; - STACK_OF(X509) *cacerts = NULL; - STACK_OF(X509) *clcerts = NULL; - STACK_OF(X509) *sec_chain = NULL; - X509 *pubcert = NULL; - boolean_t making_sig = B_FALSE; char *src, *dst; int errflg, i, n; struct dm_buf *hdr; - making_sig = (keystore != NULL) ? B_TRUE : B_FALSE; - - if (making_sig) { - - /* new error object */ - err = pkgerr_new(); - - /* find matching cert and key */ - if (find_key_cert_pair(err, keystore, - keystore_alias, &privkey, &pubcert) != 0) { - pkgerr(err); - pkgerr_free(err); - return (1); - } - - /* get CA certificates */ - if (find_ca_certs(err, keystore, &cacerts) != 0) { - pkgerr(err); - pkgerr_free(err); - return (1); - } - - /* get CL (aka "chain") certificates */ - if (find_cl_certs(err, keystore, &clcerts) != 0) { - pkgerr(err); - pkgerr_free(err); - return (1); - } - - /* initialize PKCS7 object to be filled in later */ - sec_pkcs7 = PKCS7_new(); - (void) PKCS7_set_type(sec_pkcs7, NID_pkcs7_signed); - sec_signerinfo = PKCS7_add_signature(sec_pkcs7, - pubcert, privkey, EVP_sha1()); - - if (sec_signerinfo == NULL) { - progerr(gettext(ERR_SEC), keystore_alias); - ERR_print_errors_fp(stderr); - pkgerr_free(err); - return (1); - } - - /* add signer cert into signature */ - (void) PKCS7_add_certificate(sec_pkcs7, pubcert); - - /* attempt to resolve cert chain starting at the signer cert */ - if (get_cert_chain(err, pubcert, clcerts, cacerts, - &sec_chain) != 0) { - pkgerr(err); - pkgerr_free(err); - return (1); - } - - /* - * add the verification chain of certs into the signature. - * The first cert is the user cert, which we don't need, - * since it's baked in already, so skip it - */ - for (i = 1; i < sk_X509_num(sec_chain); i++) { - (void) PKCS7_add_certificate(sec_pkcs7, - sk_X509_value(sec_chain, i)); - } - - pkgerr_free(err); - err = NULL; - } - if (signal_received > 0) { return (1); } @@ -417,17 +332,6 @@ _pkgtrans(char *device1, char *device2, char **pkg, int options, logerr(pkg_gt(MSG_TWODSTREAM)); return (1); } - } else { - /* - * output device isn't a stream. If we're making a signed - * package, then fail, since we can't make signed, - * non-stream pkgs - */ - if (making_sig) { - progerr(pkg_gt(ERR_TRANSFER)); - logerr(pkg_gt(ERR_CANTSIGN)); - return (1); - } } if ((srcdev.dirname && dstdev.dirname) && @@ -531,59 +435,13 @@ _pkgtrans(char *device1, char *device2, char **pkg, int options, cleanup(); return (1); } - if (making_sig) { - /* start up signature data stream */ - (void) PKCS7_content_new(sec_pkcs7, NID_pkcs7_data); - (void) PKCS7_set_detached(sec_pkcs7, 1); - p7_bio = PKCS7_dataInit(sec_pkcs7, NULL); - - /* - * Here we generate all the data that will go into - * the package, and send it through the signature - * generator, essentially calculating the signature - * of the entire package so we can place it in the - * header. Otherwise we'd have to place it at the end - * of the pkg, which would break the ABI - */ - if (!(options & PT_SILENT)) { - (void) fprintf(stderr, pkg_gt(MSG_SIGNING), - get_subject_display_name(pubcert)); - } - if (dump_hdr_and_pkgs(p7_bio, hdr, pkg) != 0) { - progerr(gettext(ERR_NOGEN)); - logerr(pkg_gt(MSG_GETVOL)); - cleanup(); - return (1); - - } - - BIO_flush(p7_bio); - /* - * now generate PKCS7 signature - */ - if (!PKCS7_dataFinal(sec_pkcs7, p7_bio)) { - progerr(gettext(ERR_NOGEN)); - logerr(pkg_gt(MSG_GETVOL)); - cleanup(); - return (1); - } - - (void) BIO_free(p7_bio); - } - - /* write out header to stream, which includes signature */ - if (wdsheader(hdr, src, ods_name, pkg, sec_pkcs7)) { + /* write out header to stream */ + if (wdsheader(hdr, ods_name, pkg)) { cleanup(); return (1); } - if (sec_pkcs7 != NULL) { - /* nuke in-memory signature for safety */ - PKCS7_free(sec_pkcs7); - sec_pkcs7 = NULL; - } - ds_volno = 1; /* number of volumes in datastream */ pinput = hdrbuf.text_buffer; /* skip past first line in header */ @@ -630,8 +488,7 @@ _pkgtrans(char *device1, char *device2, char **pkg, int options, } int -pkgtrans(char *device1, char *device2, char **pkg, int options, - keystore_handle_t keystore, char *keystore_alias) +pkgtrans(char *device1, char *device2, char **pkg, int options) { int r; struct sigaction nact; @@ -683,7 +540,7 @@ pkgtrans(char *device1, char *device2, char **pkg, int options, * perform the package translation */ - r = _pkgtrans(device1, device2, pkg, options, keystore, keystore_alias); + r = _pkgtrans(device1, device2, pkg, options); /* * reset signal handlers @@ -922,20 +779,12 @@ genheader(char *src, char **pkg) } static int -wdsheader(struct dm_buf *hdr, char *src, char *device, char **pkg, PKCS7 *sig) +wdsheader(struct dm_buf *hdr, char *device, char **pkg) { - FILE *fp; - char path[PATH_MAX], tmp_entry[ENTRY_MAX], - tmp_file[L_tmpnam+1]; - char srcpath[PATH_MAX]; + char tmp_entry[ENTRY_MAX], tmp_file[L_tmpnam+1]; int i, n; int list_fd; int block_cnt; - int len; - char cwd[MAXPATHLEN + 1]; - boolean_t making_sig = B_FALSE; - - making_sig = (sig != NULL) ? B_TRUE : B_FALSE; (void) ds_close(0); if (dstdev.pathname) @@ -982,161 +831,32 @@ wdsheader(struct dm_buf *hdr, char *src, char *device, char **pkg, PKCS7 *sig) * Create a cpio-compatible list of the requisite files in * the temporary file. */ - if (!making_sig) { - for (i = 0; pkg[i]; i++) { - register ssize_t entry_size; - - /* - * Copy pkginfo and pkgmap filenames into the - * temporary string allowing for the first line - * as a special case. - */ - entry_size = sprintf(tmp_entry, - (i == 0) ? "%s/%s\n%s/%s" : "\n%s/%s\n%s/%s", - pkg[i], PKGINFO, pkg[i], PKGMAP); - - if (write(list_fd, tmp_entry, - entry_size) != entry_size) { - progerr(pkg_gt(ERR_TRANSFER)); - logerr(pkg_gt(MSG_NOTMPFIL), tmp_file); - (void) close(list_fd); - ecleanup(); - return (1); - } - } - - } else { + for (i = 0; pkg[i]; i++) { register ssize_t entry_size; /* - * if we're making a signature, we must make a - * temporary area full of symlinks to the requisite - * files, plus an extra entry for the signature, so - * that cpio will put all files and signature in the - * same archive in a single invocation of cpio. + * Copy pkginfo and pkgmap filenames into the + * temporary string allowing for the first line + * as a special case. */ - tmpsymdir = xstrdup(tmpnam(NULL)); + entry_size = sprintf(tmp_entry, + (i == 0) ? "%s/%s\n%s/%s" : "\n%s/%s\n%s/%s", + pkg[i], PKGINFO, pkg[i], PKGMAP); - if (mkdir(tmpsymdir, S_IRWXU)) { - progerr(pkg_gt(ERR_TRANSFER)); - logerr(pkg_gt(MSG_MKDIR), tmpsymdir); - return (1); - } - - /* generate the signature */ - if (((len = snprintf(path, PATH_MAX, "%s/%s", - tmpsymdir, SIGNATURE_FILENAME)) >= PATH_MAX) || - len < 0) { - progerr(pkg_gt(ERR_TRANSFER)); - logerr(pkg_gt(MSG_NOTMPFIL), tmpsymdir); - cleanup(); - return (1); - } - - if ((fp = fopen(path, "w")) == NULL) { - progerr(pkg_gt(ERR_TRANSFER)); - logerr(pkg_gt(MSG_NOTMPFIL), path); - cleanup(); - return (1); - } - (void) PEM_write_PKCS7(fp, sig); - (void) fclose(fp); - - for (i = 0; pkg[i]; i++) { - (void) snprintf(path, sizeof (path), - "%s/%s", tmpsymdir, pkg[i]); - if (mkdir(path, 0755)) { - progerr(pkg_gt(ERR_TRANSFER)); - logerr(pkg_gt(MSG_MKDIR), path); - cleanup(); - return (1); - } - (void) snprintf(path, sizeof (path), - "%s/%s/%s", tmpsymdir, pkg[i], PKGINFO); - (void) snprintf(srcpath, sizeof (srcpath), - "%s/%s/%s", src, pkg[i], PKGINFO); - if (symlink(srcpath, path) != 0) { - progerr(pkg_gt(ERR_TRANSFER)); - logerr(pkg_gt(MSG_SYMLINK), path, srcpath); - cleanup(); - return (1); - } - - (void) snprintf(path, sizeof (path), - "%s/%s/%s", tmpsymdir, pkg[i], PKGMAP); - (void) snprintf(srcpath, sizeof (srcpath), - "%s/%s/%s", src, pkg[i], PKGMAP); - if (symlink(srcpath, path) != 0) { - progerr(pkg_gt(ERR_TRANSFER)); - logerr(pkg_gt(MSG_SYMLINK), path, srcpath); - cleanup(); - return (1); - } - - /* - * Copy pkginfo and pkgmap filenames into the - * temporary string allowing for the first line - * as a special case. - */ - entry_size = snprintf(tmp_entry, sizeof (tmp_entry), - (i == 0) ? "%s/%s\n%s/%s" : "\n%s/%s\n%s/%s", - pkg[i], PKGINFO, pkg[i], PKGMAP); - - if (write(list_fd, tmp_entry, - entry_size) != entry_size) { - progerr(pkg_gt(ERR_TRANSFER)); - logerr(pkg_gt(MSG_NOTMPFIL), tmp_file); - (void) close(list_fd); - ecleanup(); - cleanup(); - return (1); - } - } - - /* add signature to list of files */ - entry_size = snprintf(tmp_entry, sizeof (tmp_entry), "\n%s", - SIGNATURE_FILENAME); - if (write(list_fd, tmp_entry, entry_size) != entry_size) { + if (write(list_fd, tmp_entry, + entry_size) != entry_size) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOTMPFIL), tmp_file); (void) close(list_fd); ecleanup(); - cleanup(); return (1); } } (void) lseek(list_fd, 0, SEEK_SET); - if (!making_sig) { - (void) snprintf(tmp_entry, sizeof (tmp_entry), - "%s -ocD -C %d", CPIOPROC, (int)BLK_SIZE); - } else { - /* - * when making a signature, we must make sure to follow - * symlinks during the cpio so that we don't archive - * the links themselves - */ - (void) snprintf(tmp_entry, sizeof (tmp_entry), - "%s -ocDL -C %d", CPIOPROC, (int)BLK_SIZE); - } - - if (making_sig) { - /* save cwd and change to symlink dir for cpio invocation */ - if (getcwd(cwd, MAXPATHLEN + 1) == NULL) { - logerr(pkg_gt(ERR_GETWD)); - progerr(pkg_gt(ERR_TRANSFER)); - cleanup(); - return (1); - } - - if (chdir(tmpsymdir)) { - progerr(pkg_gt(ERR_TRANSFER)); - logerr(pkg_gt(MSG_CHDIR), tmpsymdir); - cleanup(); - return (1); - } - } + (void) snprintf(tmp_entry, sizeof (tmp_entry), + "%s -ocD -C %d", CPIOPROC, (int)BLK_SIZE); if (n = esystem(tmp_entry, list_fd, ds_fd)) { rpterr(); @@ -1151,15 +871,6 @@ wdsheader(struct dm_buf *hdr, char *src, char *device, char **pkg, PKCS7 *sig) (void) close(list_fd); (void) unlink(tmp_file); - if (making_sig) { - /* change to back to src dir for subsequent operations */ - if (chdir(cwd)) { - progerr(pkg_gt(ERR_TRANSFER)); - logerr(pkg_gt(MSG_CHDIR), cwd); - cleanup(); - return (1); - } - } return (0); } @@ -1679,135 +1390,6 @@ pkgxfer(char *srcinst, int options) return (0); } -/* - * Name: pkgdump - * Description: Dump a cpio archive of a package's contents to a BIO. - * - * Arguments: srcinst - Name of package, which resides on the - * device pointed to by the static 'srcdev' variable, - * to dump. - * bio - BIO object to dump data to - * - * Returns : 0 - success - * nonzero - failure. errors printed to screen. - */ -static int -pkgdump(char *srcinst, BIO *bio) -{ - FILE *fp; - char *src; - char temp[MAXPATHLEN], - srcdir[MAXPATHLEN], - cmd[CMDSIZE]; - int i, n, part, nparts, maxpartsize, iscomp; - - /* - * when this routine is entered, the entire package - * is already available at 'src' - including the - * pkginfo/pkgmap files and the objects as well. - */ - - /* read the pkgmap to get it's size information */ - if ((fp = fopen(PKGMAP, "r")) == NULL) { - progerr(pkg_gt(ERR_TRANSFER)); - logerr(pkg_gt(MSG_NOPKGMAP), srcinst); - return (1); - } - - nparts = 1; - if (!rd_map_size(fp, &nparts, &maxpartsize, &compressedsize)) - return (1); - else - (void) fclose(fp); - - /* make sure the first volume is available */ - if (srcdev.mount) { - src = srcdev.dirname; - (void) snprintf(srcdir, MAXPATHLEN, "%s/%s", src, srcinst); - if (ckvolseq(srcdir, 1, nparts)) { - progerr(pkg_gt(ERR_TRANSFER)); - logerr(pkg_gt(MSG_SEQUENCE)); - return (1); - } - } - - /* - * form cpio command that will output the contents of all of - * this package's parts - */ - for (part = 1; part <= nparts; /* void */) { - - if (part == 1) { - (void) snprintf(cmd, CMDSIZE, "find %s %s", - PKGINFO, PKGMAP); - if (nparts && (isdir(INSTALL) == 0)) { - (void) strlcat(cmd, " ", sizeof (cmd)); - (void) strlcat(cmd, INSTALL, sizeof (cmd)); - } - } else - (void) snprintf(cmd, CMDSIZE, "find %s", PKGINFO); - - if (nparts > 1) { - (void) snprintf(temp, MAXPATHLEN, "%s.%d", RELOC, part); - if (iscpio(temp, &iscomp) || isdir(temp) == 0) { - (void) strlcat(cmd, " ", CMDSIZE); - (void) strlcat(cmd, temp, CMDSIZE); - } - (void) snprintf(temp, MAXPATHLEN, "%s.%d", ROOT, part); - if (iscpio(temp, &iscomp) || isdir(temp) == 0) { - (void) strlcat(cmd, " ", CMDSIZE); - (void) strlcat(cmd, temp, CMDSIZE); - } - (void) snprintf(temp, MAXPATHLEN, "%s.%d", - ARCHIVE, part); - if (isdir(temp) == 0) { - (void) strlcat(cmd, " ", CMDSIZE); - (void) strlcat(cmd, temp, CMDSIZE); - } - } else if (nparts) { - for (i = 0; reloc_names[i] != NULL; i++) { - if (iscpio(reloc_names[i], &iscomp) || - isdir(reloc_names[i]) == 0) { - (void) strlcat(cmd, " ", CMDSIZE); - (void) strlcat(cmd, reloc_names[i], - CMDSIZE); - } - } - for (i = 0; root_names[i] != NULL; i++) { - if (iscpio(root_names[i], &iscomp) || - isdir(root_names[i]) == 0) { - (void) strlcat(cmd, " ", CMDSIZE); - (void) strlcat(cmd, root_names[i], - CMDSIZE); - } - } - if (isdir(ARCHIVE) == 0) { - (void) strlcat(cmd, " ", CMDSIZE); - (void) strlcat(cmd, ARCHIVE, CMDSIZE); - } - } - - (void) snprintf(cmd + strlen(cmd), - sizeof (cmd) - strlen(cmd), - " -print | %s -ocD -C %d", - CPIOPROC, (int)BLK_SIZE); - /* - * execute the command, dumping all standard output - * to the BIO. - */ - n = BIO_dump_cmd(cmd, bio); - if (n != 0) { - rpterr(); - progerr(pkg_gt(ERR_TRANSFER)); - logerr(pkg_gt(MSG_CMDFAIL), cmd, n); - return (1); - } - - part++; - } - return (0); -} - static void sigtrap(int signo) { @@ -1845,129 +1427,3 @@ cleanup(void) (void) pkgumount(&dstdev); (void) ds_close(1); } - -/* - * Name: dump_hdr_and_pkgs - * Description: Dumps datastream header and each package's contents - * to the supplied BIO - * - * Arguments: bio - BIO object to dump data to - * hdr - Header for the datastream being dumped - * pkglist - NULL-terminated list of packages - * to dump. The location of the packages are stored - * in the static 'srcdev' variable. - * - * Returns : 0 - success - * nonzero - failure. errors printed to screen. - */ -static int -dump_hdr_and_pkgs(BIO *bio, struct dm_buf *hdr, char **pkglist) -{ - int block_cnt, i; - char srcdir[MAXPATHLEN]; - char cwd[MAXPATHLEN + 1]; - char *src; - - /* write out the header to the signature stream */ - for (block_cnt = 0; block_cnt < hdr->allocation; - block_cnt += BLK_SIZE) { - (void) BIO_write(bio, (hdr->text_buffer + block_cnt), BLK_SIZE); - } - - /* save current directory */ - if (getcwd(cwd, MAXPATHLEN + 1) == NULL) { - logerr(pkg_gt(ERR_GETWD)); - progerr(pkg_gt(ERR_TRANSFER)); - return (1); - } - - /* now write out each package's contents */ - for (i = 0; pkglist[i]; i++) { - /* - * change to the source dir, so we can find and dump - * the package(s) bits into the BIO - * - */ - src = srcdev.dirname; - - /* change to the package source directory */ - (void) snprintf(srcdir, MAXPATHLEN, "%s/%s", src, pkglist[i]); - if (chdir(srcdir)) { - progerr(pkg_gt(ERR_TRANSFER)); - logerr(pkg_gt(MSG_CHDIR), srcdir); - return (1); - } - - if (pkgdump(pkglist[i], bio)) { - pkglist[i] = NULL; - return (1); - } - } - - /* change back to directory we were in upon entering this routine */ - if (chdir(cwd)) { - progerr(pkg_gt(ERR_TRANSFER)); - logerr(pkg_gt(MSG_CHDIR), cwd); - return (1); - } - - return (0); -} - -/* - * Name: BIO_dump_cmd - * Description: Dump the output of invoking a command - * to a BIO. - * - * Arguments: cmd - Command to invoke - * bio - BIO to dump output of command to - * only 'stdout' is dumped. - * Returns : 0 - success - * nonzero - failure. errors printed to screen. - */ -int -BIO_dump_cmd(char *cmd, BIO *bio) -{ - char buf[BLK_SIZE]; - FILE *fp; - int rc; - - /* start up the process */ - if ((fp = epopen(cmd, "r")) == NULL) { - rpterr(); - return (1); - } - - /* read output in chunks, transfer to BIO */ - while (fread(buf, BLK_SIZE, 1, fp) == 1) { - if (BIO_write(bio, buf, BLK_SIZE) != BLK_SIZE) { - (void) sighold(SIGINT); - (void) sighold(SIGHUP); - (void) epclose(fp); - (void) sigrelse(SIGINT); - (void) sigrelse(SIGHUP); - rpterr(); - return (1); - } - } - - /* done with stream, make sure no errors were encountered */ - if (ferror(fp)) { - (void) epclose(fp); - rpterr(); - return (1); - } - - /* done, close stream, report any errors */ - (void) sighold(SIGINT); - (void) sighold(SIGHUP); - rc = epclose(fp); - (void) sigrelse(SIGINT); - (void) sigrelse(SIGHUP); - if (rc != 0) { - rpterr(); - return (1); - } - - return (rc); -} diff --git a/usr/src/lib/libpkg/common/pkgweb.c b/usr/src/lib/libpkg/common/pkgweb.c deleted file mode 100644 index bcda3e53f2..0000000000 --- a/usr/src/lib/libpkg/common/pkgweb.c +++ /dev/null @@ -1,3240 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ -/* All Rights Reserved */ - - -#include <stdio.h> -#include <limits.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <pkglocs.h> -#include <locale.h> -#include <libintl.h> -#include <libgen.h> -#include <signal.h> -#include <sys/stat.h> -#include <sys/statvfs.h> -#include <sys/types.h> -#include <fcntl.h> -#include <dirent.h> -#include <boot_http.h> -#include <errno.h> -#include <ctype.h> -#include <openssl/pkcs7.h> -#include <openssl/ocsp.h> -#include <openssl/pkcs12.h> -#include <openssl/err.h> -#include <openssl/x509.h> -#include <openssl/pem.h> -#include <openssl/evp.h> -#include <openssl/rand.h> -#include <openssl/x509v3.h> -#include "pkglib.h" -#include "pkglibmsgs.h" -#include "pkglocale.h" -#include "keystore.h" -#include "pkgweb.h" -#include "pkgerr.h" -#include "p12lib.h" - -/* fixed format when making an OCSP request */ -#define OCSP_REQUEST_FORMAT \ - "POST %s HTTP/1.0\r\n" \ - "Content-Type: application/ocsp-request\r\n" \ - "Content-Length: %d\r\n\r\n" - -/* - * no security is afforded by using this phrase to "encrypt" CA certificates, - * but it might aid in debugging and has to be non-null - */ -#define WEB_CA_PHRASE "schizophrenic" - -/* This one needs the ': ' at the end */ -#define CONTENT_TYPE_HDR "Content-Type" -#define CONTENT_DISPOSITION_HDR "Content-Disposition" -#define CONTENT_OCSP_RESP "application/ocsp-response" -#define CONTENT_LENGTH_HDR "Content-Length" -#define LAST_MODIFIED_HDR "Last-Modified" -#define OCSP_BUFSIZ 1024 - -/* - * default amount of time that is allowed for error when checking - * OCSP response validity. - * For example, if this is set to 5 minutes, then if a response - * is issued that is valid from 12:00 to 1:00, then we will - * accept it if the local time is between 11:55 and 1:05. - * This takes care of not-quite-synchronized server and client clocks. - */ -#define OCSP_VALIDITY_PERIOD (5 * 60) - -/* this value is defined by getpassphrase(3c) manpage */ -#define MAX_PHRASELEN 257 - -/* Max length of "enter password again" prompt message */ -#define MAX_VERIFY_MSGLEN 1024 - -/* local prototypes */ -static boolean_t remove_dwnld_file(char *); -static boolean_t get_ENV_proxyport(PKG_ERR *, ushort_t *); -static boolean_t make_link(char *, char *); -static WebStatus web_send_request(PKG_ERR *, int, int, int); -static boolean_t web_eval_headers(PKG_ERR *); -static WebStatus web_get_file(PKG_ERR *, char *, int, char **); -static boolean_t ck_dwnld_dir_space(PKG_ERR *, char *, ulong_t); -static WebStatus web_connect(PKG_ERR *); -static boolean_t web_setup(PKG_ERR *); -static boolean_t check_dwnld_dir(PKG_ERR *, char *); -static boolean_t parse_url_proxy(PKG_ERR *, char *, char *, ushort_t); -static boolean_t web_disconnect(void); -static char *get_unique_filename(char *, char *); -static boolean_t get_ENV_proxy(PKG_ERR *, char **); -static char *condense_lastmodified(char *); -static int web_verify(int, X509_STORE_CTX *); -static int get_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); -static boolean_t get_ocsp_uri(X509 *, char **); -static OCSPStatus ocsp_verify(PKG_ERR *, X509 *, X509 *, char *, url_hport_t *, - STACK_OF(X509) *); -static char *get_time_string(ASN1_GENERALIZEDTIME *); -static char *write_ca_file(PKG_ERR *, char *, STACK_OF(X509) *, char *); -static boolean_t _get_random_info(void *, int); -static boolean_t init_session(void); -static void progress_setup(int, ulong_t); -static void progress_report(int, ulong_t); -static void progress_finish(int); -static char *replace_token(char *, char, char); -static void dequote(char *); -static void trim(char *); - - -/* - * structure used to hold data passed back to the - * X509 verify callback routine in validate_signature() - */ -typedef struct { - url_hport_t *proxy; - PKG_ERR *err; - STACK_OF(X509) *cas; -} verify_cb_data_t; - -/* Progress bar variables */ -static ulong_t const_increment, const_divider, completed, const_completed; - -/* current network backoff wait period */ -static int cur_backoff = 0; - -/* download session context handle */ -static WEB_SESSION *ps; - -static int webpkg_install = 0; -static char *prompt = NULL; -static char *passarg = NULL; - - -/* ~~~~~~~~~~~~~~ Public Functions ~~~~~~~~~~~~~~~~~~~ */ - -/* - * Name: set_prompt - * Description: Specifies the prompt to use with the pkglib - * passphrase callback routine. - * - * Arguments: newprompt - The prompt to display - * - * Returns : NONE - */ -void -set_passphrase_prompt(char *newprompt) -{ - prompt = newprompt; -} - -/* - * Name: set_passarg - * Description: Specifies the passphrase retrieval method - * to use with the pkglib - * passphrase callback routine. - * - * Arguments: newpassarg - The new password retrieval arg - * - * Returns : NONE - */ -void -set_passphrase_passarg(char *newpassarg) -{ - passarg = newpassarg; -} - -/* - * Name: get_proxy_port - * Description: Resolves proxy specification - * - * Arguments: err - where to record any errors. - * proxy - Location to store result - if *proxy is not - * null, then it will be validated, but not changed - * - * Returns : B_TRUE - success, B_FALSE otherwise - * on success, *proxy and *port are set to either - * the user-supplied proxy and port, or the - * ones found in the environment variables - * HTTPPROXY and/or HTTPROXYPORT - */ -boolean_t -get_proxy_port(PKG_ERR *err, char **proxy, ushort_t *port) -{ - if (*proxy != NULL) { - if (!path_valid(*proxy)) { - /* bad proxy supplied */ - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_BAD_PROXY), *proxy); - return (B_FALSE); - } - if (!get_ENV_proxyport(err, port)) { - /* env set, but bad */ - return (B_FALSE); - } - } else { - if (!get_ENV_proxy(err, proxy)) { - /* environment variable set, but bad */ - return (B_FALSE); - } - if ((*proxy != NULL) && !path_valid(*proxy)) { - /* env variable set, but bad */ - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_BAD_PROXY), *proxy); - return (B_FALSE); - } - if (!get_ENV_proxyport(err, port)) { - /* env variable set, but bad */ - return (B_FALSE); - } - } - return (B_TRUE); -} - -/* - * Name: path_valid - * Description: Checks a string for being a valid path - * - * Arguments: path - path to validate - * - * Returns : B_TRUE - success, B_FALSE otherwise. - * B_FALSE means path was null, too long (>PATH_MAX), - * or too short (<1) - */ -boolean_t -path_valid(char *path) -{ - if (path == NULL) { - return (B_FALSE); - } else if (strlen(path) > PATH_MAX) { - return (B_FALSE); - } else if (strlen(path) >= 1) { - return (B_TRUE); - } else { - /* path < 1 */ - return (B_FALSE); - } -} - -/* - * Name: web_cleanup - * Description: Deletes temp files, closes, frees memory taken - * by 'ps' static structure - * - * Arguments: none - * - * Returns : none - */ -void -web_cleanup(void) -{ - PKG_ERR *err; - - if (ps == NULL) - return; - - err = pkgerr_new(); - - if (ps->keystore) { - (void) close_keystore(err, ps->keystore, NULL); - } - - ps->keystore = NULL; - - pkgerr_free(err); - - if (ps->uniqfile) { - (void) remove_dwnld_file(ps->uniqfile); - free(ps->uniqfile); - ps->uniqfile = NULL; - } - if (ps->link) { - (void) remove_dwnld_file(ps->link); - free(ps->link); - ps->link = NULL; - } - if (ps->dwnld_dir) { - (void) rmdir(ps->dwnld_dir); - ps->dwnld_dir = NULL; - } - if (ps->errstr) { - free(ps->errstr); - ps->errstr = NULL; - } - - if (ps->content) { - free(ps->content); - ps->content = NULL; - } - - if (ps->resp) { - http_free_respinfo(ps->resp); - ps->resp = NULL; - } - - if (ps) { - free(ps); - ps = NULL; - } -} - -/* - * Name: web_session_control - * Description: Downloads an arbitrary URL and saves to disk. - * - * Arguments: err - where to record any errors. - * url - URL pointing to content to download - can be - * http:// or https:// - * dwnld_dir - Directory to download into - * keystore - keystore to use for accessing trusted - * certs when downloading using SSL - * proxy - HTTP proxy to use, or NULL for no proxy - * proxy_port - HTTP proxy port to use, ignored - * if proxy is NULL - * passarg - method to retrieve password - * retries - # of times to retry download before - * giving up - * timeout - how long to wait before retrying, - * when download is interrupted - * nointeract - if non-zero, do not output - * download progress to screen - * - * Returns : B_TRUE - success, B_FALSE otherwise - */ -boolean_t -web_session_control(PKG_ERR *err, char *url, char *dwnld_dir, - keystore_handle_t keystore, char *proxy, ushort_t proxy_port, - int retries, int timeout, int nointeract, char **fname) -{ - int i; - boolean_t ret = B_TRUE; - boolean_t retrieved = B_FALSE; - - if (!init_session()) { - ret = B_FALSE; - goto cleanup; - } - - if (!parse_url_proxy(err, url, proxy, proxy_port)) { - ret = B_FALSE; - goto cleanup; - } - - ps->timeout = timeout; - - if (keystore != NULL) - ps->keystore = keystore; - - if (dwnld_dir != NULL) - ps->dwnld_dir = xstrdup(dwnld_dir); - else { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_NO_DWNLD_DIR)); - ret = B_FALSE; - goto cleanup; - } - - if (!check_dwnld_dir(err, dwnld_dir)) { - ret = B_FALSE; - goto cleanup; - } - - for (i = 0; i < retries && !retrieved; i++) { - if (!web_setup(err)) { - ret = B_FALSE; - goto cleanup; - } - - switch (web_connect(err)) { - /* time out and wait a little bit for these failures */ - case WEB_OK: - /* were able to connect */ - reset_backoff(); - break; - case WEB_TIMEOUT: - echo_out(nointeract, gettext(MSG_DWNLD_TIMEOUT)); - (void) web_disconnect(); - backoff(); - continue; - - case WEB_CONNREFUSED: - echo_out(nointeract, gettext(MSG_DWNLD_CONNREF), - ps->url.hport.hostname); - (void) web_disconnect(); - backoff(); - continue; - case WEB_HOSTDOWN: - echo_out(nointeract, gettext(MSG_DWNLD_HOSTDWN), - ps->url.hport.hostname); - (void) web_disconnect(); - backoff(); - continue; - - default: - /* every other failure is a hard failure, so bail */ - ret = B_FALSE; - goto cleanup; - } - - switch (web_send_request(err, HTTP_REQ_TYPE_HEAD, - ps->data.cur_pos, ps->data.content_length)) { - case WEB_OK: - /* were able to connect */ - reset_backoff(); - break; - case WEB_TIMEOUT: - echo_out(nointeract, gettext(MSG_DWNLD_TIMEOUT)); - (void) web_disconnect(); - backoff(); - continue; - - case WEB_CONNREFUSED: - echo_out(nointeract, gettext(MSG_DWNLD_CONNREF), - ps->url.hport.hostname); - (void) web_disconnect(); - backoff(); - continue; - case WEB_HOSTDOWN: - echo_out(nointeract, gettext(MSG_DWNLD_HOSTDWN), - ps->url.hport.hostname); - (void) web_disconnect(); - backoff(); - continue; - default: - /* every other case is failure, so bail */ - ret = B_FALSE; - goto cleanup; - } - - if (!web_eval_headers(err)) { - ret = B_FALSE; - goto cleanup; - } - - switch (web_get_file(err, dwnld_dir, nointeract, fname)) { - case WEB_OK: - /* were able to retrieve file */ - retrieved = B_TRUE; - reset_backoff(); - break; - - case WEB_TIMEOUT: - echo_out(nointeract, gettext(MSG_DWNLD_TIMEOUT)); - (void) web_disconnect(); - backoff(); - continue; - - case WEB_CONNREFUSED: - echo_out(nointeract, gettext(MSG_DWNLD_CONNREF), - ps->url.hport.hostname); - (void) web_disconnect(); - backoff(); - continue; - case WEB_HOSTDOWN: - echo_out(nointeract, gettext(MSG_DWNLD_HOSTDWN), - ps->url.hport.hostname); - (void) web_disconnect(); - backoff(); - continue; - default: - /* every other failure is a hard failure, so bail */ - ret = B_FALSE; - goto cleanup; - } - } - - if (!retrieved) { - /* max retries attempted */ - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_DWNLD_FAILED), retries); - ret = B_FALSE; - } -cleanup: - (void) web_disconnect(); - if (!ret) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_DWNLD), url); - } - return (ret); -} - -/* - * Name: get_signature - * Description: retrieves signature from signed package. - * - * Arguments: err - where to record any errors. - * ids_name - name of package stream, for error reporting - * devp - Device on which package resides that we - * result - where to store resulting PKCS7 signature - * - * Returns : B_TRUE - package is signed and signature returned OR - * package is not signed, in which case result is NULL - * - * B_FALSE - there were problems accessing signature, - * and it is unknown whether it is signed or not. Errors - * recorded in 'err'. - */ -boolean_t -get_signature(PKG_ERR *err, char *ids_name, struct pkgdev *devp, PKCS7 **result) -{ - char path[PATH_MAX]; - int len, fd = -1; - struct stat buf; - FILE *fp = NULL; - boolean_t ret = B_TRUE; - BIO *sig_in = NULL; - PKCS7 *p7 = NULL; - - /* - * look for signature. If one was in the stream, - * it is now extracted - */ - if (((len = snprintf(path, PATH_MAX, "%s/%s", devp->dirname, - SIGNATURE_FILENAME)) >= PATH_MAX) || (len < 0)) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN), ids_name); - ret = B_FALSE; - goto cleanup; - } - - if ((fd = open(path, O_RDONLY|O_NONBLOCK)) == -1) { - /* - * only if the signature is non-existant - * do we "pass" - */ - if (errno != ENOENT) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_OPENSIG), - strerror(errno)); - ret = B_FALSE; - goto cleanup; - } - } else { - /* found sig file. parse it. */ - if (fstat(fd, &buf) == -1) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_OPENSIG), strerror(errno)); - ret = B_FALSE; - goto cleanup; - } - - if (!S_ISREG(buf.st_mode)) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_OPENSIG), - (gettext(ERR_NOT_REG))); - ret = B_FALSE; - goto cleanup; - } - - if ((fp = fdopen(fd, "r")) == NULL) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_OPENSIG), strerror(errno)); - ret = B_FALSE; - goto cleanup; - } - - /* - * read in signature. If it's invalid, we - * punt, unless we're ignoring it - */ - if ((sig_in = BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_OPENSIG), strerror(errno)); - goto cleanup; - } - - if ((p7 = PEM_read_bio_PKCS7(sig_in, - NULL, NULL, NULL)) == NULL) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_CORRUPTSIG), - ids_name); - ret = B_FALSE; - goto cleanup; - } - *result = p7; - p7 = NULL; - } - -cleanup: - if (sig_in) - (void) BIO_free(sig_in); - if (fp) - (void) fclose(fp); - if (fd != -1) - (void) close(fd); - if (p7) - (void) PKCS7_free(p7); - - return (ret); -} - -/* - * Name: echo_out - * Description: Conditionally output a message to stdout - * - * Arguments: nointeract - if non-zero, do not output anything - * fmt - print format - * ... - print arguments - * - * Returns : none - */ -/*PRINTFLIKE2*/ -void -echo_out(int nointeract, char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - - if (nointeract) - return; - - (void) vfprintf(stdout, fmt, ap); - - va_end(ap); - - (void) putc('\n', stdout); -} - -/* - * Name: strip_port - * Description: Returns "port" portion of a "hostname:port" string - * - * Arguments: proxy - full "hostname:port" string pointer - * - * Returns : the "port" portion of a "hostname:port" string, - * converted to a decimal integer, or (int)0 - * if string contains no :port suffix. - */ -ushort_t -strip_port(char *proxy) -{ - char *tmp_port; - - if ((tmp_port = strpbrk(proxy, ":")) != NULL) - return (atoi(tmp_port)); - else - return (0); -} - -/* - * Name: set_web_install - * Description: Sets flag indicating we are doing a web-based install - * - * Arguments: none - * - * Returns : none - */ -void -set_web_install(void) -{ - webpkg_install++; -} - -/* - * Name: is_web_install - * Description: Determines whether we are doing a web-based install - * - * Arguments: none - * - * Returns : non-zero if we are doing a web-based install, 0 otherwise - */ -int -is_web_install(void) -{ - return (webpkg_install); -} - -/* ~~~~~~~~~~~~~~ Private Functions ~~~~~~~~~~~~~~~~~~~ */ - -/* - * Name: web_disconnect - * Description: Disconnects connection to web server - * - * Arguments: none - * - * Returns : B_TRUE - successful disconnect, B_FALSE otherwise - * Temp certificiate files are deleted, - * if one was used to initiate the connection - * (such as when using SSL) - */ -static boolean_t -web_disconnect(void) -{ - if (ps->certfile) { - (void) unlink(ps->certfile); - } - if (http_srv_disconnect(ps->hps) == 0) - if (http_srv_close(ps->hps) == 0) - return (B_TRUE); - - return (B_FALSE); -} - -/* - * Name: check_dwnld_dir - * Description: Creates temp download directory - * - * Arguments: err - where to record any errors. - * dwnld_dir - name of directory to create - * - * Returns : B_TRUE - success, B_FALSE otherwise - * on success, directory is created with - * safe permissions - */ -static boolean_t -check_dwnld_dir(PKG_ERR *err, char *dwnld_dir) -{ - DIR *dirp; - - /* - * Check the directory passed in. If it doesn't exist, create it - * with strict permissions - */ - if ((dirp = opendir(dwnld_dir)) == NULL) { - if (mkdir(dwnld_dir, 0744) == -1) { - pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTEMP), - dwnld_dir); - return (B_FALSE); - } - } - if (dirp) { - (void) closedir(dirp); - } - return (B_TRUE); -} - -/* - * Name: ds_validate_signature - * Description: Validates signature found in a package datastream - * - * Arguments: err - where to record any errors. - * pkgdev - Package context handle of package to verify - * pkgs - Null-terminated List of package name to verify - * ids_name - Pathname to stream to validate - * p7 - PKCS7 signature decoded from stream header - * cas - List of trusted CA certificates - * proxy - Proxy to use when doing online validation (OCSP) - * nointeract - if non-zero, do not output to screen - * - * Returns : B_TRUE - success, B_FALSE otherwise - * success means signature was completely validated, - * and contents of stream checked against signature. - */ -boolean_t -ds_validate_signature(PKG_ERR *err, struct pkgdev *pkgdev, char **pkgs, - char *ids_name, PKCS7 *p7, STACK_OF(X509) *cas, - url_hport_t *proxy, int nointeract) -{ - BIO *p7_bio; - boolean_t ret = B_TRUE; - - /* make sure it's a Signed PKCS7 message */ - if (!PKCS7_type_is_signed(p7)) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_CORRUPTSIG_TYPE), - ids_name); - ret = B_FALSE; - goto cleanup; - } - - /* initialize PKCS7 object to be filled in */ - if (!PKCS7_get_detached(p7)) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_CORRUPTSIG_DT), - ids_name); - ret = B_FALSE; - goto cleanup; - } - - /* dump header and packages into BIO to calculate the message digest */ - if ((p7_bio = PKCS7_dataInit(p7, NULL)) == NULL) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_CORRUPTSIG), - ids_name); - ret = B_FALSE; - goto cleanup; - } - - if ((BIO_ds_dump_header(err, p7_bio) != 0) || - (BIO_ds_dump(err, ids_name, p7_bio) != 0)) { - ret = B_FALSE; - goto cleanup; - } - (void) BIO_flush(p7_bio); - - /* validate the stream and its signature */ - if (!validate_signature(err, ids_name, p7_bio, p7, cas, - proxy, nointeract)) { - ret = B_FALSE; - goto cleanup; - } - - /* reset device stream (really bad performance for tapes) */ - (void) ds_close(1); - (void) ds_init(ids_name, pkgs, pkgdev->norewind); - -cleanup: - return (ret); -} - - -/* - * Name: validate_signature - * Description: Validates signature of an arbitrary stream of bits - * - * Arguments: err - where to record any errors. - * name - Descriptive name of object being validated, - * for good error reporting messages - * indata - BIO object to read stream bits from - * p7 - PKCS7 signature of stream - * cas - List of trusted CA certificates - * proxy - Proxy to use when doing online validation (OCSP) - * nointeract - if non-zero, do not output to screen - * - * Returns : B_TRUE - success, B_FALSE otherwise - * success means signature was completely validated, - * and contents of stream checked against signature. - */ -boolean_t -validate_signature(PKG_ERR *err, char *name, BIO *indata, PKCS7 *p7, - STACK_OF(X509) *cas, url_hport_t *proxy, int nointeract) -{ - STACK_OF(PKCS7_SIGNER_INFO) *sec_sinfos = NULL; - - PKCS7_SIGNER_INFO *signer = NULL; - X509_STORE *sec_truststore = NULL; - X509_STORE_CTX *ctx = NULL; - X509 *signer_cert = NULL, *issuer = NULL; - STACK_OF(X509) *chaincerts = NULL; - int i, k; - unsigned long errcode; - const char *err_data = NULL; - const char *err_reason = NULL; - char *err_string; - int err_flags; - verify_cb_data_t verify_data; - char *signer_sname; - char *signer_iname; - PKCS7_ISSUER_AND_SERIAL *ias; - boolean_t ret = B_TRUE; - - /* only support signed PKCS7 signatures */ - if (!PKCS7_type_is_signed(p7)) { - PKCS7err(PKCS7_F_PKCS7_DATAVERIFY, PKCS7_R_WRONG_PKCS7_TYPE); - ret = B_FALSE; - goto cleanup; - } - - /* initialize temporary internal trust store used for verification */ - sec_truststore = X509_STORE_new(); - - for (i = 0; i < sk_X509_num(cas); i++) { - if (X509_STORE_add_cert(sec_truststore, - sk_X509_value(cas, i)) == 0) { - pkgerr_add(err, PKGERR_VERIFY, gettext(ERR_MEM)); - ret = B_FALSE; - goto cleanup; - } - } - - /* get signers from the signature */ - if ((sec_sinfos = PKCS7_get_signer_info(p7)) == NULL) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_CORRUPTSIG), name); - ret = B_FALSE; - goto cleanup; - } - - /* verify each signer found in the PKCS7 signature */ - for (k = 0; k < sk_PKCS7_SIGNER_INFO_num(sec_sinfos); k++) { - signer = sk_PKCS7_SIGNER_INFO_value(sec_sinfos, k); - signer_cert = PKCS7_cert_from_signer_info(p7, signer); - signer_sname = get_subject_display_name(signer_cert); - signer_iname = get_issuer_display_name(signer_cert); - - echo_out(nointeract, gettext(MSG_VERIFY), signer_sname); - - /* find the issuer of the current cert */ - chaincerts = p7->d.sign->cert; - ias = signer->issuer_and_serial; - issuer = X509_find_by_issuer_and_serial(chaincerts, - ias->issuer, ias->serial); - - /* were we not able to find the issuer cert */ - if (issuer == NULL) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_VERIFY_ISSUER), - signer_iname, signer_sname); - ret = B_FALSE; - goto cleanup; - } - - /* Lets verify */ - if ((ctx = X509_STORE_CTX_new()) == NULL) { - pkgerr_add(err, PKGERR_VERIFY, gettext(ERR_MEM)); - ret = B_FALSE; - goto cleanup; - } - (void) X509_STORE_CTX_init(ctx, sec_truststore, - issuer, chaincerts); - (void) X509_STORE_CTX_set_purpose(ctx, - X509_PURPOSE_ANY); - - /* callback will perform OCSP on certificates with OCSP data */ - X509_STORE_CTX_set_verify_cb(ctx, web_verify); - - /* pass needed data into callback through the app_data handle */ - verify_data.proxy = proxy; - verify_data.cas = cas; - verify_data.err = err; - (void) X509_STORE_CTX_set_app_data(ctx, &verify_data); - - /* first verify the certificate chain */ - i = X509_verify_cert(ctx); - if (i <= 0 && ctx->error != X509_V_ERR_CERT_HAS_EXPIRED) { - signer_sname = - get_subject_display_name(ctx->current_cert); - signer_iname = - get_issuer_display_name(ctx->current_cert); - /* if the verify context holds an error, print it */ - if (ctx->error != X509_V_OK) { - pkgerr_add(err, PKGERR_VERIFY, - gettext(ERR_VERIFY_SIG), signer_sname, - signer_iname, - (char *)X509_verify_cert_error_string(ctx->error)); - } else { - /* some other error. print them all. */ - while ((errcode = ERR_get_error_line_data(NULL, - NULL, &err_data, &err_flags)) != 0) { - size_t errsz; - err_reason = - ERR_reason_error_string(errcode); - if (err_reason == NULL) { - err_reason = - gettext(ERR_SIG_INT); - } - - if (!(err_flags & ERR_TXT_STRING)) { - err_data = - gettext(ERR_SIG_INT); - } - errsz = strlen(err_reason) + - strlen(err_data) + 3; - err_string = xmalloc(errsz); - (void) snprintf(err_string, errsz, - "%s: %s", err_reason, err_data); - pkgerr_add(err, PKGERR_VERIFY, - gettext(ERR_VERIFY_SIG), - signer_sname, signer_iname, - err_string); - free(err_string); - } - } - ret = B_FALSE; - goto cleanup; - } - - /* now verify the signature */ - i = PKCS7_signatureVerify(indata, p7, signer, issuer); - - if (i <= 0) { - /* print out any OpenSSL-specific errors */ - signer_sname = - get_subject_display_name(ctx->current_cert); - signer_iname = - get_subject_display_name(ctx->current_cert); - while ((errcode = ERR_get_error_line_data(NULL, - NULL, &err_data, &err_flags)) != 0) { - err_reason = - ERR_reason_error_string(errcode); - if (err_reason == NULL) { - err_reason = - gettext(ERR_SIG_INT); - } - - if (!(err_flags & ERR_TXT_STRING)) { - err_data = - gettext(ERR_SIG_INT); - } - pkgerr_add(err, PKGERR_VERIFY, - gettext(ERR_VERIFY_SIG), signer_sname, - signer_iname, err_reason); - pkgerr_add(err, PKGERR_VERIFY, - gettext(ERR_VERIFY_SIG), signer_sname, - signer_iname, err_data); - } - ret = B_FALSE; - goto cleanup; - } - - echo_out(nointeract, gettext(MSG_VERIFY_OK), signer_sname); - } - - /* signature(s) verified successfully */ -cleanup: - if (ctx) - X509_STORE_CTX_cleanup(ctx); - return (ret); -} - -/* - * Name: web_verify - * Description: Callback used by PKCS7_dataVerify when - * verifying a certificate chain. - * - * Arguments: err - where to record any errors. - * ctx - The context handle of the current verification operation - * - * Returns : B_TRUE - success, B_FALSE otherwise - * if it's '0' (not OK) we simply return it, since the - * verification operation has already determined that the - * cert is invalid. if 'ok' is non-zero, then we do our - * checks, and return 0 or 1 based on if the cert is - * invalid or valid. - */ -static int -web_verify(int ok, X509_STORE_CTX *ctx) -{ - X509 *curr_cert; - X509 *curr_issuer; - char *uri; - url_hport_t *proxy; - PKG_ERR *err = NULL; - STACK_OF(X509) *cas; - if (!ok) { - /* don't override a verify failure */ - return (ok); - } - - - /* get app data supplied through callback context */ - err = ((verify_cb_data_t *)X509_STORE_CTX_get_app_data(ctx))->err; - proxy = ((verify_cb_data_t *)X509_STORE_CTX_get_app_data(ctx))->proxy; - cas = ((verify_cb_data_t *)X509_STORE_CTX_get_app_data(ctx))->cas; - - /* Check revocation status */ - curr_cert = X509_STORE_CTX_get_current_cert(ctx); - - /* this shouldn't happen */ - if (curr_cert == NULL) { - pkgerr_add(err, PKGERR_INTERNAL, gettext(ERR_PKG_INTERNAL), - __FILE__, __LINE__); - return (0); - } - - /* don't perform OCSP unless cert has required OCSP extensions */ - if (get_ocsp_uri(curr_cert, &uri)) { - if (get_issuer(&curr_issuer, ctx, curr_cert) <= 0) { - /* no issuer! */ - pkgerr_add(err, PKGERR_INTERNAL, - gettext(ERR_PKG_INTERNAL), - __FILE__, __LINE__); - return (0); - } - - /* - * ok we have the current cert - * and its issuer. Do the OCSP check - */ - - /* - * OCSP extensions are, by, RFC 2459, never critical - * extensions, therefore, we only fail if we were able - * to explicitly contact an OCSP responder, and that - * responder did not indicate the cert was valid. We - * also fail if user-supplied data could not be parsed - * or we run out of memory. We succeeed for "soft" - * failures, such as not being able to connect to the - * OCSP responder, or trying to use if the OCSP URI - * indicates SSL must be used (which we do not - * support) - */ - switch (ocsp_verify(err, curr_cert, curr_issuer, - uri, proxy, cas)) { - case OCSPMem: /* Ran out of memory */ - case OCSPInternal: /* Some internal error */ - case OCSPVerify: /* OCSP responder indicated fail */ - return (0); - } - /* all other cases are success, or soft failures */ - pkgerr_clear(err); - } - - return (ok); -} - -/* - * Name: get_time_string - * Description: Generates a human-readable string from an ASN1_GENERALIZED_TIME - * - * Arguments: intime - The time to convert - * - * Returns : A pointer to a static string representing the passed-in time. - */ -static char -*get_time_string(ASN1_GENERALIZEDTIME *intime) -{ - - static char time[ATTR_MAX]; - BIO *mem; - char *p; - - if (intime == NULL) { - return (NULL); - } - if ((mem = BIO_new(BIO_s_mem())) == NULL) { - return (NULL); - } - - if (ASN1_GENERALIZEDTIME_print(mem, intime) == 0) { - (void) BIO_free(mem); - return (NULL); - } - - if (BIO_gets(mem, time, ATTR_MAX) <= 0) { - (void) BIO_free(mem); - return (NULL); - } - - (void) BIO_free(mem); - - /* trim the end of the string */ - for (p = time + strlen(time) - 1; isspace(*p); p--) { - *p = '\0'; - } - - return (time); -} - -/* - * Name: get_ocsp_uri - * Description: Examines an X509 certificate and retrieves the embedded - * OCSP Responder URI if one exists. - * - * Arguments: cert - The cert to inspect - * uri - pointer where the newly-allocated URI is placed, if found - * - * Returns : Success if the URI was found. Appropriate status otherwise. - */ -static boolean_t -get_ocsp_uri(X509 *cert, char **uri) -{ - AUTHORITY_INFO_ACCESS *aia; - ACCESS_DESCRIPTION *ad; - int i; - - if (getenv("PKGWEB_TEST_OCSP")) { - *uri = xstrdup(getenv("PKGWEB_TEST_OCSP")); - return (B_TRUE); - } - - /* get the X509v3 extension holding the OCSP URI */ - if ((aia = X509_get_ext_d2i(cert, NID_info_access, - NULL, NULL)) != NULL) { - for (i = 0; i < sk_ACCESS_DESCRIPTION_num(aia); i++) { - ad = sk_ACCESS_DESCRIPTION_value(aia, i); - if (OBJ_obj2nid(ad->method) == NID_ad_OCSP) { - if (ad->location->type == GEN_URI) { - *uri = - xstrdup((char *)ASN1_STRING_data(ad->location->d.ia5)); - return (B_TRUE); - } - } - } - } - - /* no URI was found */ - return (B_FALSE); -} - -/* - * Name: ocsp_verify - * Description: Attempts to contact an OCSP Responder and ascertain the validity - * of an X509 certificate. - * - * Arguments: err - Error object to add error messages to - * cert - The cert to validate - * issuer - The certificate of the issuer of 'cert' - * uri - The OCSP Responder URI - * cas - The trusted CA certificates used to verify the - * signed OCSP response - * Returns : Success - The OCSP Responder reported a 'good' - * status for the cert otherwise, appropriate - * error is returned. - */ -static OCSPStatus -ocsp_verify(PKG_ERR *err, X509 *cert, X509 *issuer, - char *uri, url_hport_t *proxy, STACK_OF(X509) *cas) -{ - OCSP_CERTID *id; - OCSP_REQUEST *req; - OCSP_RESPONSE *resp; - OCSP_BASICRESP *bs; - BIO *cbio, *mem; - char ocspbuf[OCSP_BUFSIZ]; - char *host = NULL, *portstr = NULL, *path = "/", *p, *q, *r; - int port, status, reason; - int len, retval, respcode, use_ssl = 0; - ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd; - char *subjname; - time_t currtime; - char currtimestr[ATTR_MAX]; - unsigned long errcode; - const char *err_reason; - - subjname = get_subject_display_name(cert); - - /* parse the URI into its constituent parts */ - if (OCSP_parse_url(uri, &host, &portstr, &path, &use_ssl) == NULL) { - pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_PARSE), uri); - return (OCSPParse); - } - - /* we don't currently support SSL-based OCSP Responders */ - if (use_ssl) { - pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_UNSUP), uri); - return (OCSPUnsupported); - } - - /* default port if none specified */ - if (portstr == NULL) { - port = (int)URL_DFLT_SRVR_PORT; - } else { - port = (int)strtoul(portstr, &r, 10); - if (*r != '\0') { - pkgerr_add(err, PKGERR_PARSE, - gettext(ERR_OCSP_PARSE), uri); - return (OCSPParse); - } - } - - /* allocate new request structure */ - if ((req = OCSP_REQUEST_new()) == NULL) { - pkgerr_add(err, PKGERR_PARSE, gettext(ERR_MEM)); - return (OCSPMem); - } - - /* convert cert and issuer fields into OCSP request data */ - if ((id = OCSP_cert_to_id(NULL, cert, issuer)) == NULL) { - pkgerr_add(err, PKGERR_PARSE, gettext(ERR_PKG_INTERNAL), - __FILE__, __LINE__); - return (OCSPInternal); - } - - /* fill out request structure with request data */ - if ((OCSP_request_add0_id(req, id)) == NULL) { - pkgerr_add(err, PKGERR_PARSE, gettext(ERR_PKG_INTERNAL), - __FILE__, __LINE__); - return (OCSPInternal); - } - - /* add nonce */ - (void) OCSP_request_add1_nonce(req, NULL, -1); - - /* connect to host, or proxy */ - if (proxy != NULL) { - if ((cbio = BIO_new_connect(proxy->hostname)) == NULL) { - pkgerr_add(err, PKGERR_PARSE, gettext(ERR_MEM)); - return (OCSPMem); - } - - /* - * BIO_set_conn_int_port takes an int *, so let's give it one - * rather than an ushort_t * - */ - port = proxy->port; - (void) BIO_set_conn_int_port(cbio, &port); - if (BIO_do_connect(cbio) <= 0) { - pkgerr_add(err, PKGERR_PARSE, - gettext(ERR_OCSP_CONNECT), - proxy->hostname, port); - return (OCSPConnect); - } - } else { - if ((cbio = BIO_new_connect(host)) == NULL) { - pkgerr_add(err, PKGERR_PARSE, gettext(ERR_MEM)); - return (OCSPMem); - } - - (void) BIO_set_conn_int_port(cbio, &port); - if (BIO_do_connect(cbio) <= 0) { - pkgerr_add(err, PKGERR_PARSE, - gettext(ERR_OCSP_CONNECT), - host, port); - return (OCSPConnect); - } - } - - /* calculate length of binary request data */ - len = i2d_OCSP_REQUEST(req, NULL); - - /* send the request headers */ - if (proxy != NULL) { - retval = BIO_printf(cbio, OCSP_REQUEST_FORMAT, uri, len); - } else { - retval = BIO_printf(cbio, OCSP_REQUEST_FORMAT, path, len); - } - - if (retval <= 0) { - pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_SEND), host); - return (OCSPRequest); - } - - /* send the request binary data */ - if (i2d_OCSP_REQUEST_bio(cbio, req) <= 0) { - pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_SEND), host); - return (OCSPRequest); - } - - /* - * read the response into a memory BIO, so we can 'gets' - * (socket bio's don't support BIO_gets) - */ - if ((mem = BIO_new(BIO_s_mem())) == NULL) { - pkgerr_add(err, PKGERR_PARSE, gettext(ERR_MEM)); - return (OCSPMem); - } - - while ((len = BIO_read(cbio, ocspbuf, OCSP_BUFSIZ))) { - if (len < 0) { - pkgerr_add(err, PKGERR_PARSE, - gettext(ERR_OCSP_READ), host); - return (OCSPRequest); - } - if (BIO_write(mem, ocspbuf, len) != len) { - pkgerr_add(err, PKGERR_PARSE, gettext(ERR_MEM)); - return (OCSPMem); - } - } - - /* now get the first line of the response */ - if (BIO_gets(mem, ocspbuf, OCSP_BUFSIZ) <= 0) { - pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_RESP_PARSE)); - return (OCSPRequest); - } - - /* parse the header response */ - /* it should look like "HTTP/x.x 200 OK" */ - - /* skip past the protocol info */ - for (p = ocspbuf; (*p != '\0') && !isspace(*p); p++) - continue; - - /* skip past whitespace betwen protocol and start of response code */ - while ((*p != '\0') && isspace(*p)) { - p++; - } - - if (*p == '\0') { - /* premature end */ - pkgerr_add(err, PKGERR_PARSE, - gettext(ERR_OCSP_RESP_PARSE), ocspbuf); - return (OCSPRequest); - } - - /* find end of response code */ - for (q = p; (*q != NULL) && !isspace(*q); q++) - continue; - - /* mark end of response code */ - *q++ = '\0'; - - /* parse response code */ - respcode = strtoul(p, &r, 10); - if (*r != '\0') { - pkgerr_add(err, PKGERR_PARSE, - gettext(ERR_OCSP_RESP_PARSE), ocspbuf); - return (OCSPRequest); - } - - /* now find beginning of the response string */ - while ((*q != NULL) && isspace(*q)) { - q++; - } - - /* trim whitespace from end of message */ - for (r = (q + strlen(q) - 1); isspace(*r); r--) { - *r = '\0'; - } - - /* response must be OK */ - if (respcode != 200) { - pkgerr_add(err, PKGERR_PARSE, - gettext(ERR_OCSP_RESP_NOTOK), 200, - respcode, q); - return (OCSPRequest); - } - - /* read headers, looking for content-type or a blank line */ - while (BIO_gets(mem, ocspbuf, OCSP_BUFSIZ) > 0) { - - /* if we get a content type, make sure it's the right type */ - if (ci_strneq(ocspbuf, CONTENT_TYPE_HDR, - strlen(CONTENT_TYPE_HDR))) { - - /* look for the delimiting : */ - p = strchr(ocspbuf + strlen(CONTENT_TYPE_HDR), ':'); - - if (p == NULL) { - pkgerr_add(err, PKGERR_PARSE, - gettext(ERR_OCSP_RESP_PARSE), ocspbuf); - return (OCSPResponder); - } - - /* skip over ':' */ - p++; - - /* find beginning of the content type */ - while ((*p != NULL) && isspace(*p)) { - p++; - } - - if (!ci_strneq(p, CONTENT_OCSP_RESP, - strlen(CONTENT_OCSP_RESP))) { - /* response is not right type */ - pkgerr_add(err, PKGERR_PARSE, - gettext(ERR_OCSP_RESP_TYPE), - p, CONTENT_OCSP_RESP); - return (OCSPResponder); - } - - /* continue with next header line */ - continue; - } - - /* scan looking for a character */ - for (p = ocspbuf; (*p != '\0') && isspace(*p); p++) { - continue; - } - /* - * if we got to the end of the line with - * no chars, then this is a blank line - */ - if (*p == '\0') { - break; - } - } - - - if (*p != '\0') { - /* last line was not blank */ - pkgerr_add(err, PKGERR_PARSE, - gettext(ERR_OCSP_RESP_PARSE), ocspbuf); - return (OCSPResponder); - } - - /* now read in the binary response */ - if ((resp = d2i_OCSP_RESPONSE_bio(mem, NULL)) == NULL) { - pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_READ), host); - return (OCSPResponder); - } - - /* free temp BIOs */ - (void) BIO_free(mem); - (void) BIO_free_all(cbio); - cbio = NULL; - - /* make sure request was successful */ - if (OCSP_response_status(resp) != OCSP_RESPONSE_STATUS_SUCCESSFUL) { - pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_RESP_NOTOK), - OCSP_RESPONSE_STATUS_SUCCESSFUL, - OCSP_response_status(resp), - OCSP_response_status_str(OCSP_response_status(resp))); - return (OCSPResponder); - } - - /* parse binary response into internal structure */ - if ((bs = OCSP_response_get1_basic(resp)) == NULL) { - pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_READ), host); - return (OCSPParse); - } - - /* - * From here to the end of the code, the return values - * should be hard failures - */ - - /* verify the response, warn if no nonce */ - if (OCSP_check_nonce(req, bs) <= 0) { - logerr(pkg_gt(WRN_OCSP_RESP_NONCE)); - } - - if (OCSP_basic_verify(bs, cas, NULL, OCSP_TRUSTOTHER) <= 0) { - while ((errcode = ERR_get_error()) != NULL) { - err_reason = ERR_reason_error_string(errcode); - if (err_reason == NULL) { - err_reason = - gettext(ERR_SIG_INT); - } - pkgerr_add(err, PKGERR_PARSE, (char *)err_reason); - } - pkgerr_add(err, PKGERR_PARSE, gettext(ERR_OCSP_VERIFY_FAIL), - uri); - return (OCSPVerify); - } - - /* check the validity of our certificate */ - if (OCSP_resp_find_status(bs, id, &status, &reason, - &rev, &thisupd, &nextupd) == NULL) { - pkgerr_add(err, PKGERR_PARSE, - gettext(ERR_OCSP_VERIFY_NO_STATUS), subjname); - return (OCSPVerify); - } - - if ((currtime = time(NULL)) == (time_t)-1) { - pkgerr_add(err, PKGERR_PARSE, - gettext(ERR_OCSP_VERIFY_NOTIME)); - return (OCSPVerify); - } - - (void) strlcpy(currtimestr, ctime(&currtime), ATTR_MAX); - - /* trim end */ - for (r = currtimestr + strlen(currtimestr) - 1; - isspace(*r); r--) { - *r = '\0'; - } - - if (!OCSP_check_validity(thisupd, nextupd, - OCSP_VALIDITY_PERIOD, -1)) { - if (nextupd != NULL) { - pkgerr_add(err, PKGERR_PARSE, - gettext(ERR_OCSP_VERIFY_VALIDITY), - get_time_string(thisupd), get_time_string(nextupd), - currtimestr); - } else { - pkgerr_add(err, PKGERR_PARSE, - gettext(ERR_OCSP_VERIFY_VALIDITY), - get_time_string(thisupd), - currtimestr); - } - return (OCSPVerify); - } - - if (status != V_OCSP_CERTSTATUS_GOOD) { - pkgerr_add(err, PKGERR_PARSE, - gettext(ERR_OCSP_VERIFY_STATUS), subjname, - OCSP_cert_status_str(status)); - return (OCSPVerify); - } - - /* everythign checks out */ - return (OCSPSuccess); -} - -/* - * Name: get_issuer - * Description: Attempts to find the issuing certificate for a given certificate - * This will look in both the list of trusted certificates found in - * the X509_STORE_CTX structure, as well as the list of untrusted - * chain certificates found in the X509_STORE_CTX structure. - * Arguments: - * issuer - The resulting issuer cert is placed here, if found - * ctx - The current verification context - * x - The certificate whose issuer we are looking for - * Returns : Success - The issuer cert was found and placed in *issuer. - * otherwise, appropriate error is returned. - */ -static int -get_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x) -{ - int i, ok; - - /* - * first look in the list of trusted - * certs, using the context's method to do so - */ - if ((ok = ctx->get_issuer(issuer, ctx, x)) > 0) { - return (ok); - } - - if (ctx->untrusted != NULL) { - /* didn't find it in trusted certs, look through untrusted */ - for (i = 0; i < sk_X509_num(ctx->untrusted); i++) { - if (X509_check_issued(sk_X509_value(ctx->untrusted, i), - x) == X509_V_OK) { - *issuer = sk_X509_value(ctx->untrusted, i); - return (1); - } - } - } - *issuer = NULL; - return (0); -} - -/* - * Name: parse_url_proxy - * Description: Parses URL and optional proxy specification, populates static - * 'ps' structure - * - * Arguments: err - where to record any errors. - * url - URL to parse - * proxy - proxy to parse, or NULL for no proxy - * proxy_port - Default proxy port to use if no proxy - * port specified in 'proxy' - * - * Returns : B_TRUE - success, B_FALSE otherwise - * on success, 'ps->url' and 'ps->proxy' are populated - * with parsed data. - */ -static boolean_t -parse_url_proxy(PKG_ERR *err, char *url, char *proxy, ushort_t proxy_port) -{ - boolean_t ret = B_TRUE; - if (!path_valid(url)) { - ret = B_FALSE; - goto cleanup; - } - - if (url_parse(url, &ps->url) != URL_PARSE_SUCCESS) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_PARSE_URL), url); - ret = B_FALSE; - goto cleanup; - } - - if (proxy != NULL) { - if (url_parse_hostport(proxy, &ps->proxy, proxy_port) - != URL_PARSE_SUCCESS) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_BAD_PROXY), proxy); - ret = B_FALSE; - goto cleanup; - } - } - -cleanup: - return (ret); -} - -/* - * Name: web_setup - * Description: Initializes http library settings - * - * Arguments: err - where to record any errors. - * - * Returns : B_TRUE - success, B_FALSE otherwise - */ -static boolean_t -web_setup(PKG_ERR *err) -{ - boolean_t ret = B_TRUE; - static boolean_t keepalive = B_TRUE; - - if ((ps->hps = http_srv_init(&ps->url)) == NULL) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_INIT_SESS), ps->url); - ret = B_FALSE; - goto cleanup; - } - - if (getenv("WEBPKG_DEBUG") != NULL) { - http_set_verbose(B_TRUE); - } - - if (ps->proxy.hostname[0] != '\0' && - http_set_proxy(ps->hps, &ps->proxy) != 0) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_INIT_SESS), ps->url); - ret = B_FALSE; - goto cleanup; - } - if (http_set_keepalive(ps->hps, keepalive) != 0) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_INIT_SESS), ps->url); - ret = B_FALSE; - goto cleanup; - } - if (http_set_socket_read_timeout(ps->hps, ps->timeout) != 0) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_INIT_SESS), ps->url); - ret = B_FALSE; - goto cleanup; - } - if (http_set_random_file(ps->hps, RANDOM) != 0) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_INIT_SESS), ps->url); - ret = B_FALSE; - goto cleanup; - } - - (void) http_set_p12_format(B_TRUE); - -cleanup: - return (ret); -} - -/* - * Name: web_connect - * Description: Makes connection with URL stored in static 'ps' structure. - * - * Arguments: err - where to record any errors. - * - * Returns : WEB_OK - connection successful - * WEB_VERIFY_SETUP - Unable to complete necessary - * SSL setup - * WEB_CONNREFUSED - Connection was refused to web site - * WEB_HOSTDOWN - Host was not responding to request - * WEB_NOCONNECT - Some other connection failure - */ -static WebStatus -web_connect(PKG_ERR *err) -{ - STACK_OF(X509) *sec_cas = NULL; - char *path; - WebStatus ret = WEB_OK; - ulong_t errcode; - uint_t errsrc; - int my_errno = 0; - const char *libhttperr = NULL; - - if (ps->url.https == B_TRUE) { - /* get CA certificates */ - if (find_ca_certs(err, ps->keystore, &sec_cas) != 0) { - ret = WEB_VERIFY_SETUP; - goto cleanup; - } - - if (sk_X509_num(sec_cas) < 1) { - /* no trusted websites */ - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_KEYSTORE_NOTRUST)); - ret = WEB_VERIFY_SETUP; - goto cleanup; - } - - /* - * write out all CA certs to temp file. libwanboot should - * have an interface for giving it a list of trusted certs - * through an in-memory structure, but currently that does - * not exist - */ - if ((path = write_ca_file(err, ps->dwnld_dir, sec_cas, - WEB_CA_PHRASE)) == NULL) { - ret = WEB_VERIFY_SETUP; - goto cleanup; - } - - ps->certfile = path; - if (http_set_password(ps->hps, WEB_CA_PHRASE) != 0) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_HTTPS_PASSWD)); - ret = WEB_VERIFY_SETUP; - goto cleanup; - } - - if (http_set_certificate_authority_file(path) != 0) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_HTTPS_CA)); - ret = WEB_VERIFY_SETUP; - goto cleanup; - } - } - - if (http_srv_connect(ps->hps) != 0) { - while ((errcode = http_get_lasterr(ps->hps, &errsrc)) != 0) { - /* Have an error - is it EINTR? */ - if (errsrc == ERRSRC_SYSTEM) { - my_errno = errcode; - break; - } else if (libhttperr == NULL) { - /* save the first non-system error message */ - libhttperr = http_errorstr(errsrc, errcode); - } - } - switch (my_errno) { - case EINTR: - case ETIMEDOUT: - /* Timed out. Try, try again */ - ret = WEB_TIMEOUT; - break; - case ECONNREFUSED: - ret = WEB_CONNREFUSED; - break; - case EHOSTDOWN: - ret = WEB_HOSTDOWN; - break; - default: - /* some other fatal error */ - ret = WEB_NOCONNECT; - if (libhttperr == NULL) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_INIT_CONN), - ps->url.hport.hostname); - } else { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_HTTP), libhttperr); - } - break; - } - } -cleanup: - return (ret); -} - -/* - * Name: write_ca_file - * Description: Writes out a PKCS12 file containing all trusted certs - * found in keystore recorded in static 'ps' structure - * - * This routine is used because the libwanboot library's - * HTTPS routines cannot accept trusted certificates - * through an in-memory structure, when initiating an - * SSL connection. They must be in a PKCS12, which is - * admittedly a poor interface. - * - * Arguments: err - where to record any errors. - * tmpdir - Directory to write certificate file in - * cacerts - Certs to write out - * passwd - password used to encrypt certs - * - * Returns : path to resulting file, if successfullly written, - * otherwise NULL. - */ -static char -*write_ca_file(PKG_ERR *err, char *tmpdir, STACK_OF(X509) *cacerts, - char *passwd) -{ - int fd, len; - FILE *fp; - PKCS12 *p12 = NULL; - char *ret = NULL; - static char tmp_file[PATH_MAX] = ""; - struct stat buf; - - if (!path_valid(tmpdir)) { - pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTEMP), tmpdir); - goto cleanup; - } - - /* mkstemp replaces XXXXXX with a unique string */ - if (((len = snprintf(tmp_file, PATH_MAX, "%s/%sXXXXXX", tmpdir, - "cert")) < 0) || - (len >= PATH_MAX)) { - pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTEMP), tmpdir); - goto cleanup; - } - - if ((fd = mkstemp(tmp_file)) == -1) { - pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTMPFIL), tmp_file); - goto cleanup; - } - - if (fstat(fd, &buf) == -1) { - pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTMPFIL), tmp_file); - goto cleanup; - } - - if (!S_ISREG(buf.st_mode)) { - pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTMPFIL), tmp_file); - goto cleanup; - } - - if ((fp = fdopen(fd, "w")) == NULL) { - pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTMPFIL), tmp_file); - goto cleanup; - } - - if ((p12 = sunw_PKCS12_create(passwd, NULL, NULL, cacerts)) == NULL) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_KEYSTORE_FORM), tmp_file); - goto cleanup; - } - - if (i2d_PKCS12_fp(fp, p12) == 0) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_KEYSTORE_FORM), tmp_file); - goto cleanup; - } - - (void) fflush(fp); - (void) fclose(fp); - (void) close(fd); - fp = NULL; - fd = -1; - ret = tmp_file; - -cleanup: - if (p12 != NULL) - PKCS12_free(p12); - if (fp != NULL) - (void) fclose(fp); - if (fd != -1) { - (void) close(fd); - (void) unlink(tmp_file); - } - - return (ret); -} - -/* - * Name: web_send_request - * Description: Sends an HTTP request for a file to the - * web server being communicated with in the static - * 'ps' structure - * - * Arguments: err - where to record any errors. - * request_type - HTTP_REQ_TYPE_HEAD to send an HTTP HEAD request, - * or HTTP_REQ_TYPE_GET to send an HTTP GET request - * cp - - * Returns : WEB_OK - request sent successfully - * WEB_CONNREFUSED - Connection was refused to web site - * WEB_HOSTDOWN - Host was not responding to request - * WEB_NOCONNECT - Some other connection failure - */ -static WebStatus -web_send_request(PKG_ERR *err, int request_type, int cp, int ep) -{ - WebStatus ret = WEB_OK; - ulong_t errcode; - uint_t errsrc; - int my_errno = 0; - const char *libhttperr = NULL; - switch (request_type) { - case HTTP_REQ_TYPE_HEAD: - if ((http_head_request(ps->hps, ps->url.abspath)) != 0) { - while ((errcode = http_get_lasterr(ps->hps, - &errsrc)) != 0) { - /* Have an error - is it EINTR? */ - if (errsrc == ERRSRC_SYSTEM) { - my_errno = errcode; - break; - } else if (libhttperr == NULL) { - /* save first non-system error message */ - libhttperr = - http_errorstr(errsrc, errcode); - } - } - switch (my_errno) { - case EINTR: - case ETIMEDOUT: - /* Timed out. Try, try again */ - ret = WEB_TIMEOUT; - break; - case ECONNREFUSED: - ret = WEB_CONNREFUSED; - break; - case EHOSTDOWN: - ret = WEB_HOSTDOWN; - break; - default: - /* some other fatal error */ - ret = WEB_NOCONNECT; - if (libhttperr == NULL) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_INIT_CONN), - ps->url.hport.hostname); - } else { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_HTTP), libhttperr); - } - break; - } - goto cleanup; - } - break; - - case HTTP_REQ_TYPE_GET: - if (cp && ep) { - if (http_get_range_request(ps->hps, ps->url.abspath, - cp, ep - cp) != 0) { - while ((errcode = http_get_lasterr(ps->hps, - &errsrc)) != 0) { - /* Have an error - is it EINTR? */ - if (errsrc == ERRSRC_SYSTEM) { - my_errno = errcode; - break; - } else { - /* - * save first non-system - * error message - */ - libhttperr = - http_errorstr(errsrc, - errcode); - } - } - switch (my_errno) { - case EINTR: - case ETIMEDOUT: - /* Timed out. Try, try again */ - ret = WEB_TIMEOUT; - break; - case ECONNREFUSED: - ret = WEB_CONNREFUSED; - break; - case EHOSTDOWN: - ret = WEB_HOSTDOWN; - break; - default: - /* some other fatal error */ - ret = WEB_NOCONNECT; - if (libhttperr == NULL) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_INIT_CONN), - ps->url.hport.hostname); - } else { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_HTTP), - libhttperr); - } - break; - } - goto cleanup; - } - - if (!web_eval_headers(err)) { - ret = WEB_NOCONNECT; - goto cleanup; - } - } else { - if ((http_get_request(ps->hps, ps->url.abspath)) - != 0) { - while ((errcode = http_get_lasterr(ps->hps, - &errsrc)) != 0) { - /* Have an error - is it EINTR? */ - if (errsrc == ERRSRC_SYSTEM) { - my_errno = errcode; - break; - } else { - /* - * save the first non-system - * error message - */ - libhttperr = - http_errorstr(errsrc, - errcode); - } - } - switch (my_errno) { - case EINTR: - case ETIMEDOUT: - /* Timed out. Try, try again */ - ret = WEB_TIMEOUT; - break; - case ECONNREFUSED: - ret = WEB_CONNREFUSED; - break; - case EHOSTDOWN: - ret = WEB_HOSTDOWN; - break; - default: - /* some other fatal error */ - ret = WEB_NOCONNECT; - if (libhttperr == NULL) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_INIT_CONN), - ps->url.hport.hostname); - } else { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_HTTP), - libhttperr); - } - break; - } - goto cleanup; - } - - if (!web_eval_headers(err)) { - ret = WEB_NOCONNECT; - goto cleanup; - } - } - break; - default: - pkgerr_add(err, PKGERR_INTERNAL, gettext(ERR_PKG_INTERNAL), - __FILE__, __LINE__); - } - -cleanup: - return (ret); -} - -/* - * Name: web_eval_headers - * Description: Evaluates HTTP headers returned during an HTTP request. - * This must be called before calling - * http_get_header_value(). - * - * Arguments: err - where to record any errors. - * - * Returns : B_TRUE - success, B_FALSE otherwise - */ -static boolean_t -web_eval_headers(PKG_ERR *err) -{ - const char *http_err; - ulong_t herr; - uint_t errsrc; - - if (http_process_headers(ps->hps, &ps->resp) != 0) { - if ((ps->resp != NULL) && (ps->resp->statusmsg != NULL)) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_HTTP), - ps->resp->statusmsg); - } - - herr = http_get_lasterr(ps->hps, &errsrc); - http_err = http_errorstr(errsrc, herr); - pkgerr_add(err, PKGERR_WEB, gettext(ERR_HTTP), - http_err); - return (B_FALSE); - } - return (B_TRUE); -} - -/* - * Name: web_get_file - * Description: Downloads the file URL from the website, all of - * which are recorded in the static 'ps' struct - * - * Arguments: err - where to record any errors. - * dwnld_dir - Directory to download file into - * device - Where to store path to resulting - * file - * nointeract - if non-zero, do not output - * progress - * fname - name of downloaded file link in the dwnld_dir - * - * Returns : WEB_OK - download successful - * WEB_CONNREFUSED - Connection was refused to web site - * WEB_HOSTDOWN - Host was not responding to request - * WEB_GET_FAIL - Unable to initialize download - * state (temp file creation, header parsing, etc) - * WEB_NOCONNECT - Some other connection failure - */ -static WebStatus -web_get_file(PKG_ERR *err, char *dwnld_dir, int nointeract, char **fname) -{ - int i, fd; - int n = 0; - ulong_t abs_pos = 0; - char *head_val = NULL; - char *lastmod_val = NULL; - char *bname = NULL; - struct stat status; - WebStatus ret = WEB_OK; - WebStatus req_ret; - ulong_t errcode; - uint_t errsrc; - int my_errno = 0; - const char *libhttperr = NULL; - char *disp; - char tmp_file[PATH_MAX]; - int len; - - ps->data.prev_cont_length = - ps->data.content_length = - ps->data.cur_pos = 0; - - if ((head_val = http_get_header_value(ps->hps, - CONTENT_LENGTH_HDR)) != NULL) { - ps->data.content_length = atol(head_val); - } else { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_NO_HEAD_VAL), - CONTENT_LENGTH_HDR); - ret = WEB_GET_FAIL; - goto cleanup; - } - - free(head_val); - head_val = NULL; - - if ((head_val = http_get_header_value(ps->hps, - CONTENT_DISPOSITION_HDR)) != NULL) { - /* "inline; parm=val; parm=val */ - if ((disp = strtok(head_val, "; \t\n\f\r")) != NULL) { - /* disp = "inline" */ - while ((disp = strtok(NULL, "; \t\n\f\r")) != NULL) { - /* disp = "parm=val" */ - if (ci_strneq(disp, "filename=", 9)) { - bname = xstrdup(basename(disp + 9)); - trim(bname); - dequote(bname); - } - } - } - free(head_val); - head_val = NULL; - } - - if (bname == NULL) { - /* - * couldn't determine filename from header value, - * so take basename of URL - */ - if ((bname = get_endof_string(ps->url.abspath, '/')) == NULL) { - /* URL is bad */ - pkgerr_add(err, PKGERR_PARSE, - gettext(ERR_PARSE_URL), ps->url.abspath); - ret = WEB_GET_FAIL; - goto cleanup; - } - } - - *fname = bname; - - if ((head_val = http_get_header_value(ps->hps, LAST_MODIFIED_HDR)) - != NULL) { - - if ((lastmod_val = condense_lastmodified(head_val)) == NULL) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_BAD_HEAD_VAL), - LAST_MODIFIED_HDR, head_val); - ret = WEB_GET_FAIL; - goto cleanup; - } - free(head_val); - head_val = NULL; - - if ((ps->uniqfile = get_unique_filename(dwnld_dir, - lastmod_val)) == NULL) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_OPEN_TMP)); - ret = WEB_GET_FAIL; - goto cleanup; - } - - free(lastmod_val); - lastmod_val = NULL; - - if ((fd = open(ps->uniqfile, - O_NONBLOCK|O_RDWR|O_APPEND|O_CREAT|O_EXCL, - 640)) == -1) { - - /* - * A partial downloaded file - * already exists, so open it. - */ - if ((fd = open(ps->uniqfile, - O_NONBLOCK|O_RDWR|O_APPEND)) != -1) { - if (fstat(fd, &status) == -1 || - !S_ISREG(status.st_mode)) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_DWNLD_NO_CONT), - ps->uniqfile); - ret = WEB_GET_FAIL; - goto cleanup; - } else { - echo_out(nointeract, - gettext(MSG_DWNLD_PART), - ps->uniqfile, - status.st_size); - ps->data.prev_cont_length = - status.st_size; - } - } else { - /* unable to open partial file */ - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_DWNLD_NO_CONT), - ps->uniqfile); - ret = WEB_GET_FAIL; - goto cleanup; - } - } - } else { - /* - * no "Last-Modified" header, so this file is not eligible for - * spooling and "resuming last download" operations - */ - ps->spool = B_FALSE; - - /* mkstemp replaces XXXXXX with a unique string */ - if (((len = snprintf(tmp_file, PATH_MAX, - "%s/%sXXXXXX", dwnld_dir, "stream")) < 0) || - (len >= PATH_MAX)) { - pkgerr_add(err, PKGERR_WEB, - gettext(MSG_NOTEMP), dwnld_dir); - ret = WEB_GET_FAIL; - goto cleanup; - } - - if ((fd = mkstemp(tmp_file)) == -1) { - pkgerr_add(err, PKGERR_WEB, - gettext(MSG_NOTMPFIL), tmp_file); - ret = WEB_GET_FAIL; - goto cleanup; - } - - if (fstat(fd, &status) == -1 || - !S_ISREG(status.st_mode)) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_DWNLD_NO_CONT), - ps->uniqfile); - ret = WEB_GET_FAIL; - goto cleanup; - } - - ps->data.prev_cont_length = 0; - ps->uniqfile = xstrdup(tmp_file); - } - - /* File has already been completely downloaded */ - if (ps->data.prev_cont_length == ps->data.content_length) { - echo_out(nointeract, gettext(MSG_DWNLD_PREV), ps->uniqfile); - ps->data.cur_pos = ps->data.prev_cont_length; - if (!make_link(dwnld_dir, bname)) { - pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTEMP), - dwnld_dir); - ret = WEB_GET_FAIL; - goto cleanup; - } - /* we're done, so cleanup and return success */ - goto cleanup; - } else if (ps->data.prev_cont_length != 0) { - ps->data.cur_pos = ps->data.prev_cont_length; - } - - if (!ck_dwnld_dir_space(err, dwnld_dir, - (ps->data.prev_cont_length != 0) ? - (ps->data.content_length - ps->data.cur_pos) : - ps->data.content_length)) { - ret = WEB_GET_FAIL; - goto cleanup; - } - - if ((req_ret = web_send_request(err, HTTP_REQ_TYPE_GET, - ps->data.cur_pos, ps->data.content_length)) != WEB_OK) { - ret = req_ret; - goto cleanup; - } - - if (ps->data.prev_cont_length != 0) - echo_out(nointeract, gettext(MSG_DWNLD_CONT)); - else - echo_out(nointeract, gettext(MSG_DWNLD)); - - progress_setup(nointeract, ps->data.content_length); - - /* Download the file a BLOCK at a time */ - while (ps->data.cur_pos < ps->data.content_length) { - progress_report(nointeract, abs_pos); - i = ((ps->data.content_length - ps->data.cur_pos) < BLOCK) ? - (ps->data.content_length - ps->data.cur_pos) - : BLOCK; - if ((n = http_read_body(ps->hps, ps->content, i)) <= 0) { - while ((errcode = http_get_lasterr(ps->hps, - &errsrc)) != 0) { - /* Have an error - is it EINTR? */ - if (errsrc == ERRSRC_SYSTEM) { - my_errno = errcode; - break; - } else { - /* - * save first non-system - * error message - */ - libhttperr = - http_errorstr(errsrc, errcode); - } - } - switch (my_errno) { - case EINTR: - case ETIMEDOUT: - /* Timed out. Try, try again */ - ret = WEB_TIMEOUT; - break; - case ECONNREFUSED: - ret = WEB_CONNREFUSED; - break; - case EHOSTDOWN: - ret = WEB_HOSTDOWN; - break; - default: - /* some other fatal error */ - ret = WEB_NOCONNECT; - if (libhttperr == NULL) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_INIT_CONN), - ps->url.hport.hostname); - } else { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_HTTP), libhttperr); - } - break; - } - goto cleanup; - } - if ((n = write(fd, ps->content, n)) == 0) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_WRITE), - ps->uniqfile, strerror(errno)); - ret = WEB_GET_FAIL; - goto cleanup; - } - ps->data.cur_pos += n; - abs_pos += n; - } - - progress_finish(nointeract); - echo_out(nointeract, gettext(MSG_DWNLD_COMPLETE)); - - if (!make_link(dwnld_dir, bname)) { - pkgerr_add(err, PKGERR_WEB, gettext(MSG_NOTEMP), - dwnld_dir); - ret = WEB_GET_FAIL; - goto cleanup; - } - -cleanup: - sync(); - if (fd != -1) { - (void) close(fd); - } - - if (head_val != NULL) - free(head_val); - - if (lastmod_val != NULL) - free(lastmod_val); - - return (ret); -} - -/* - * Name: make_link - * Description: Create new link to file being downloaded - * - * Arguments: dwnld_dir - directory in which downloaded file exists - * bname - name of link - * - * Returns : B_TRUE - success, B_FALSE otherwise - */ -static boolean_t -make_link(char *dwnld_dir, char *bname) -{ - int len; - - if ((ps->link = (char *)xmalloc(PATH_MAX)) == NULL) - return (B_FALSE); - if (((len = snprintf(ps->link, PATH_MAX, "%s/%s", - dwnld_dir, bname)) < 0) || - len >= PATH_MAX) - return (B_FALSE); - - (void) link(ps->uniqfile, ps->link); - - return (B_TRUE); -} - -/* - * Name: get_startof_string - * Description: searches string for token, returns a newly-allocated - * substring of the given string up to, but not - * including, token. for example - * get_startof_string("abcd", 'c') will return "ab" - * - * Arguments: path - path to split - * token - character to split on - * - * Returns : substring of 'path', up to, but not including, - * token, if token appears in path. Otherwise, - * returns NULL. - */ -char * -get_startof_string(char *path, char token) -{ - char *p, *p2; - - if (path == NULL) - return (NULL); - - p = xstrdup(path); - - p2 = strchr(p, token); - if (p2 == NULL) { - free(p); - return (NULL); - } else { - *p2 = '\0'; - return (p); - } -} - -/* - * Name: get_endof_string - * Description: searches string for token, returns a - * newly-allocated substring of the given string, - * starting at character following token, to end of - * string. - * - * for example get_end_string("abcd", 'c') - * will return "d" - * - * Arguments: path - path to split - * token - character to split on - * - * Returns : substring of 'path', beginning at character - * following token, to end of string, if - * token appears in path. Otherwise, - * returns NULL. - */ -char * -get_endof_string(char *path, char token) -{ - char *p, *p2; - - if (path == NULL) - return (NULL); - - p = xstrdup(path); - - if ((p2 = strrchr(p, token)) == NULL) { - return (NULL); - } - - return (p2 + 1); -} - -/* - * Name: progress_setup - * Description: Initialize session for reporting progress - * - * Arguments: nointeract - if non-zero, do not do anything - * ulong_t - size of job to report progress for - * - * Returns : none - */ -static void -progress_setup(int nointeract, ulong_t size_of_load) -{ - ulong_t divisor; - ulong_t term_width = TERM_WIDTH; - - if (nointeract) - return; - - if (size_of_load > MED_DWNLD && size_of_load < LARGE_DWNLD) - divisor = MED_DIVISOR; - else if (size_of_load > LARGE_DWNLD) { - term_width = TERM_WIDTH - 8; - divisor = LARGE_DIVISOR; - } else - divisor = SMALL_DIVISOR; - - const_increment = size_of_load / term_width; - const_divider = size_of_load / divisor; - const_completed = 100 / divisor; -} - -/* - * Name: progress_report - * Description: Report progress for current progress context, - * to stderr - * - * Arguments: nointeract - if non-zero, do not do anything - * position - how far along in the job to report. - * This should be <= size used during progress_setup - * - * Returns : none - */ -static void -progress_report(int nointeract, ulong_t position) -{ - static ulong_t increment; - static ulong_t divider; - - if (nointeract) - return; - - if (position == 0) { - increment = const_increment; - divider = const_divider; - } - if (position > increment && position < divider) { - (void) putc('.', stderr); - increment += const_increment; - } else if (position > divider) { - completed += const_completed; - (void) fprintf(stderr, "%ld%c", completed, '%'); - increment += const_increment; - divider += const_divider; - } -} - -/* - * Name: progress_finish - * Description: Finalize session for reporting progress. - * "100%" is reported to screen - * - * Arguments: nointeract - if non-zero, do not do anything - * - * Returns : none - */ -static void -progress_finish(int nointeract) -{ - if (nointeract) - return; - - (void) fprintf(stderr, "%d%c\n", 100, '%'); -} - -/* - * Name: init_session - * Description: Initializes static 'ps' structure with default - * values - * - * Arguments: none - * - * Returns : B_TRUE - success, B_FALSE otherwise - */ -static boolean_t -init_session(void) -{ - if ((ps = (WEB_SESSION *) - xmalloc(sizeof (WEB_SESSION))) == NULL) { - return (B_FALSE); - } - (void) memset(ps, 0, sizeof (*ps)); - - if ((ps->content = (char *)xmalloc(BLOCK)) == NULL) { - return (B_FALSE); - } - - (void) memset(ps->content, 0, BLOCK); - - ps->data.cur_pos = 0UL; - ps->data.content_length = 0UL; - ps->url.https = B_FALSE; - ps->uniqfile = NULL; - ps->link = NULL; - ps->dwnld_dir = NULL; - ps->spool = B_TRUE; - ps->errstr = NULL; - ps->keystore = NULL; - - return (B_TRUE); -} - -/* - * Name: ck_downld_dir_space - * Description: Verify enough space exists in directory to hold file - * - * Arguments: err - where to record any errors. - * dwnld_dir - Directory to check available space in - * bytes_needed - How many bytes are need - * - * Returns : B_TRUE - enough space exists in dwnld_dir to hold - * bytes_needed bytes, otherwise B_FALSE - */ -static boolean_t -ck_dwnld_dir_space(PKG_ERR *err, char *dwnld_dir, ulong_t bytes_needed) -{ - u_longlong_t bytes_avail; - u_longlong_t block_pad; - struct statvfs64 status; - - if (statvfs64(dwnld_dir, &status)) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_TMPDIR), dwnld_dir); - return (B_FALSE); - } - - block_pad = (status.f_frsize ? status.f_frsize : status.f_bsize); - bytes_avail = status.f_bavail * block_pad; - - if ((((u_longlong_t)bytes_needed) + block_pad) > bytes_avail) { - pkgerr_add(err, PKGERR_WEB, gettext(ERR_DISK_SPACE), - dwnld_dir, - (((u_longlong_t)bytes_needed) + block_pad) / 1024ULL, - bytes_avail / 1024ULL); - return (B_FALSE); - } - - return (B_TRUE); -} - -/* - * Description: - * This function returns a unique file name based on the parts of the - * URI. This is done to enable partially downloaded files to be resumed. - * Arguments: - * dir - The directory that should contain the filename. - * last_modified - A string representing the date of last modification, - * used as part of generating unique name - * Returns: - * A valid filename or NULL. - */ - -static char * -get_unique_filename(char *dir, char *last_modified) -{ - char *buf, *buf2, *beg_str; - int len; - - if ((buf = (char *)xmalloc(PATH_MAX)) == NULL) { - return (NULL); - } - if ((buf2 = (char *)xmalloc(PATH_MAX)) == NULL) { - return (NULL); - } - - /* prepare strings for being cat'ed onto */ - buf[0] = buf2[0] = '\0'; - /* - * No validation of the path is done here. We just construct the path - * and it must be validated later - */ - - if (dir) { - if (((len = snprintf(buf2, PATH_MAX, "%s/", dir)) < 0) || - (len >= PATH_MAX)) - return (NULL); - } else { - return (NULL); - } - - if (ps->url.abspath) - if (strlcat(buf, ps->url.abspath, PATH_MAX) >= PATH_MAX) - return (NULL); - if (ps->url.hport.hostname) - if (isdigit((int)ps->url.hport.hostname[0])) { - if (strlcat(buf, ps->url.hport.hostname, PATH_MAX) - >= PATH_MAX) - return (NULL); - } else { - if ((beg_str = - get_startof_string(ps->url.hport.hostname, '.')) - != NULL) - if (strlcat(buf, beg_str, PATH_MAX) >= PATH_MAX) - return (NULL); - } - if (last_modified != NULL) - if (strlcat(buf, last_modified, PATH_MAX) >= PATH_MAX) - return (NULL); - - if ((buf = replace_token(buf, '/', '_')) != NULL) { - if (strlcat(buf2, buf, PATH_MAX) >= PATH_MAX) { - return (NULL); - } else { - if (buf) free(buf); - return (buf2); - } - } else { - if (buf) free(buf); - if (buf2) free(buf2); - return (NULL); - } -} - -/* - * Description: - * Removes token(s) consisting of one character from any path. - * Arguments: - * path - The path to search for the token in. - * token - The token to search for - * Returns: - * The path with all tokens removed or NULL. - */ -static char * -replace_token(char *path, char oldtoken, char newtoken) -{ - char *newpath, *p; - - if ((path == NULL) || (oldtoken == '\0') || (newtoken == '\0')) { - return (NULL); - } - - newpath = xstrdup(path); - - for (p = newpath; *p != '\0'; p++) { - if (*p == oldtoken) { - *p = newtoken; - } - } - - return (newpath); -} - -/* - * Name: trim - * Description: Trims whitespace from a string - * has been registered) - * Scope: private - * Arguments: string - string to trim. It is assumed - * this string is writable up to it's entire - * length. - * Returns: none - */ -static void -trim(char *str) -{ - int len, i; - if (str == NULL) { - return; - } - - len = strlen(str); - /* strip from front */ - while (isspace(*str)) { - for (i = 0; i < len; i++) { - str[i] = str[i+1]; - } - } - - /* strip from back */ - len = strlen(str); - while (isspace(str[len-1])) { - len--; - } - str[len] = '\0'; -} - -/* - * Description: - * Resolves double quotes - * Arguments: - * str - The string to resolve - * Returns: - * None - */ -static void -dequote(char *str) -{ - char *cp; - - if ((str == NULL) || (str[0] != '"')) { - /* no quotes */ - return; - } - - /* remove first quote */ - (void) memmove(str, str + 1, strlen(str) - 1); - - /* - * scan string looking for ending quote. - * escaped quotes like \" don't count - */ - cp = str; - - while (*cp != '\0') { - switch (*cp) { - case '\\': - /* found an escaped character */ - /* make sure end of string is not '\' */ - if (*++cp != '\0') { - cp++; - } - break; - - case '"': - *cp = '\0'; - break; - default: - cp++; - } - } -} - -/* - * Name: get_ENV_proxy - * Description: Retrieves setting of proxy env variable - * - * Arguments: err - where to record any errors. - * proxy - where to store proxy - * - * Returns : B_TRUE - http proxy was found and valid, stored in proxy - * B_FALSE - error, errors recorded in err - */ -static boolean_t -get_ENV_proxy(PKG_ERR *err, char **proxy) -{ - char *buf; - - if ((buf = getenv("HTTPPROXY")) != NULL) { - if (!path_valid(buf)) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_ILL_ENV), "HTTPPROXY", buf); - return (B_FALSE); - } else { - *proxy = buf; - return (B_TRUE); - } - } else { - /* try the other env variable */ - if ((buf = getenv("http_proxy")) != NULL) { - if (!path_valid(buf)) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_ILL_ENV), "http_proxy", buf); - return (B_FALSE); - } - if (!strneq(buf, "http://", 7)) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_ILL_ENV), "http_proxy", buf); - return (B_FALSE); - } - - /* skip over the http:// part of the proxy "url" */ - *proxy = buf + 7; - return (B_TRUE); - } - } - - /* either the env variable(s) were set and valid, or not set */ - return (B_TRUE); -} - -/* - * Name: get_ENV_proxyport - * Description: Retrieves setting of PROXYPORT env variable - * - * Arguments: err - where to record any errors. - * port - where to store resulting port - * - * Returns : B_TRUE - string found in PROXYPORT variable, converted - * to decimal integer, if it exists - * and is valid. Or, PROXYPORT not set, port set to 1. - * B_FALSE - env variable set, but invalid - * (not a number for example) - */ -static boolean_t -get_ENV_proxyport(PKG_ERR *err, ushort_t *port) -{ - char *buf; - ushort_t newport; - buf = getenv("HTTPPROXYPORT"); - if (buf != NULL) { - if (!path_valid(buf)) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_ILL_ENV), "HTTPPROXYPORT", buf); - return (B_FALSE); - } - if ((newport = atoi(buf)) == 0) { - pkgerr_add(err, PKGERR_WEB, - gettext(ERR_ILL_ENV), "HTTPPROXYPORT", buf); - return (B_FALSE); - } - *port = newport; - return (B_TRUE); - } else { - *port = 1; - return (B_TRUE); - } -} - -/* - * Name: remove_dwnld_file - * Description: Removes newly-downloaded file if completely downloaded. - * - * Arguments: path - path to file to remove - * - * Returns : B_TRUE - success, B_FALSE otherwise - * if it's '0' (not OK) we simply return it, since the - * verification operation has already determined that the - * cert is invalid. if 'ok' is non-zero, then we do our - * checks, and return 0 or 1 based on if the cert is - * invalid or valid. - */ -static boolean_t -remove_dwnld_file(char *path) -{ - if (path && path != NULL) { - /* - * Only remove the downloaded file if it has been completely - * downloaded, or is not eligible for spooling - */ - if ((!ps->spool) || - (ps->data.cur_pos >= ps->data.content_length)) { - (void) unlink(path); - } - } else { - return (B_FALSE); - } - return (B_TRUE); -} - -/* - * Name: condense_lastmodifided - * Description: generates a substring of a last-modified string, - * and removes colons. - * - * Arguments: last_modified - string of the form - * "Wed, 23 Oct 2002 21:59:45 GMT" - * - * Returns : - * new string, consisting of hours/minutes/seconds only, - * sans any colons. - */ -char * -condense_lastmodified(char *last_modified) -{ - char *p, *p2; - - /* - * Last-Modified: Wed, 23 Oct 2002 21:59:45 GMT - * Strip the hours, minutes and seconds, without the ':'s, from - * the above string, void of the ':". - */ - - if (last_modified == NULL) - return (NULL); - - if ((p = xstrdup(last_modified)) == NULL) - return (NULL); - p2 = (strstr(p, ":") - 2); - p2[8] = '\0'; - return (replace_token(p2, ':', '_')); -} - -/* - * Name: backoff - * Description: sleeps for a certain # of seconds after a network - * failure. - * Scope: public - * Arguments: none - * Returns: none - */ -void -backoff() -{ - static boolean_t initted = B_FALSE; - int backoff; - long seed; - - if (!initted) { - /* seed the rng */ - (void) _get_random_info(&seed, sizeof (seed)); - srand48(seed); - initted = B_TRUE; - } - - backoff = (int)(drand48() * (double)cur_backoff); - (void) sleep(backoff); - if (cur_backoff < MAX_BACKOFF) { - /* - * increase maximum time we might wait - * next time so as to fall off over - * time. - */ - cur_backoff *= BACKOFF_FACTOR; - } -} - -/* - * Name: reset_backoff - * Description: notifies the backoff service that whatever was - * being backoff succeeded. - * Scope: public - * Arguments: none - * Returns: none - */ -void -reset_backoff() -{ - cur_backoff = MIN_BACKOFF; -} - -/* - * Name: _get_random_info - * Description: generate an amount of random bits. Currently - * only a small amount (a long long) can be - * generated at one time. - * Scope: private - * Arguments: buf - [RO, *RW] (char *) - * Buffer to copy bits into - * size - amount to copy - * Returns: B_TRUE on success, B_FALSE otherwise. The buffer is filled - * with the amount of bytes of random data specified. - */ -static boolean_t -_get_random_info(void *buf, int size) -{ - struct timeval tv; - typedef struct { - long low_time; - long hostid; - } randomness; - randomness r; - - /* if the RANDOM file exists, use it */ - if (access(RANDOM, R_OK) == 0) { - if ((RAND_load_file(RANDOM, 1024 * 1024)) > 0) { - if (RAND_bytes((uchar_t *)buf, size) == 1) { - /* success */ - return (B_TRUE); - } - } - } - - /* couldn't use RANDOM file, so fallback to time of day and hostid */ - (void) gettimeofday(&tv, (struct timezone *)0); - - /* Wouldn't it be nice if we could hash these */ - r.low_time = tv.tv_usec; - r.hostid = gethostid(); - - if (sizeof (r) < size) { - /* - * Can't copy correctly - */ - return (B_FALSE); - } - (void) memcpy(buf, &r, size); - return (B_TRUE); -} - -/* - * Name: pkg_passphrase_cb - * Description: Default callback that applications can use when - * a passphrase is needed. This routine collects - * a passphrase from the user using the given - * passphrase retrieval method set with - * set_passphrase_passarg(). If the method - * indicates an interactive prompt, then the - * prompt set with set_passphrase_prompt() - * is displayed. - * - * Arguments: buf - Buffer to copy passphrase into - * size - Max amount to copy to buf - * rw - Whether this passphrase is needed - * to read something off disk, or - * write something to disk. Applications - * typically want to ask twice when getting - * a passphrase for writing something. - * data - application-specific data. In this - * callback, data is a pointer to - * a keystore_passphrase_data structure. - * - * Returns: Length of passphrase collected, or -1 on error. - * Errors recorded in 'err' object in the *data. - */ -int -pkg_passphrase_cb(char *buf, int size, int rw, void *data) -{ - BIO *pwdbio = NULL; - char passphrase_copy[MAX_PHRASELEN + 1]; - PKG_ERR *err; - int passlen; - char *ws; - char prompt_copy[MAX_VERIFY_MSGLEN]; - char *passphrase; - char *arg; - - err = ((keystore_passphrase_data *)data)->err; - - if (passarg == NULL) { - arg = "console"; - } else { - arg = passarg; - } - - /* default method of collecting password is by prompting */ - if (ci_streq(arg, "console")) { - if ((passphrase = getpassphrase(prompt)) == NULL) { - pkgerr_add(err, PKGERR_BADPASS, - gettext(MSG_NOPASS), arg); - return (-1); - } - - if (rw) { - /* - * if the password is being supplied for - * writing something to disk, verify it first - */ - - /* make a copy (getpassphrase overwrites) */ - (void) strlcpy(passphrase_copy, passphrase, - MAX_PHRASELEN + 1); - - if (((passlen = snprintf(prompt_copy, - MAX_VERIFY_MSGLEN, "%s: %s", - gettext(MSG_PASSWD_AGAIN), - prompt)) < 0) || - (passlen >= (MAX_PHRASELEN + 1))) { - pkgerr_add(err, PKGERR_BADPASS, - gettext(MSG_NOPASS), arg); - return (-1); - } - - if ((passphrase = - getpassphrase(prompt_copy)) == NULL) { - pkgerr_add(err, PKGERR_BADPASS, - gettext(MSG_NOPASS), arg); - return (-1); - } - - if (!streq(passphrase_copy, passphrase)) { - pkgerr_add(err, PKGERR_READ, - gettext(MSG_PASSWD_NOMATCH)); - return (-1); - } - } - } else if (ci_strneq(arg, "pass:", 5)) { - passphrase = arg + 5; - } else if (ci_strneq(arg, "env:", 4)) { - passphrase = getenv(arg + 4); - } else if (ci_strneq(arg, "file:", 5)) { - - /* open file for reading */ - if ((pwdbio = BIO_new_file(arg + 5, "r")) == NULL) { - pkgerr_add(err, PKGERR_EXIST, - gettext(MSG_PASSWD_FILE), arg + 5); - return (-1); - } - - /* read first line */ - if (((passlen = BIO_gets(pwdbio, buf, size)) < 1) || - (passlen > size)) { - pkgerr_add(err, PKGERR_READ, gettext(MSG_PASSWD_FILE), - arg + 5); - return (-1); - } - BIO_free_all(pwdbio); - pwdbio = NULL; - - if (passlen == size) { - /* - * password was maximum length, so there is - * no null terminator. null-terminate it - */ - buf[size - 1] = '\0'; - } - - /* first newline found is end of passwd, so nuke it */ - if ((ws = strchr(buf, '\n')) != NULL) { - *ws = '\0'; - } - return (strlen(buf)); - } else { - /* unrecognized passphrase */ - pkgerr_add(err, PKGERR_BADPASS, - gettext(MSG_BADPASSARG), arg); - return (-1); - } - - if (passphrase == NULL) { - /* unable to collect passwd from given source */ - pkgerr_add(err, PKGERR_BADPASS, - gettext(MSG_NOPASS), arg); - return (-1); - } - - (void) strlcpy(buf, passphrase, size); - return (strlen(buf)); -} diff --git a/usr/src/lib/libpkg/common/pkgweb.h b/usr/src/lib/libpkg/common/pkgweb.h deleted file mode 100644 index fe9dc372d9..0000000000 --- a/usr/src/lib/libpkg/common/pkgweb.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright 2009 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _PKGWEB_H -#define _PKGWEB_H - - -#ifdef __cplusplus -extern "C" { -#endif - -#include <netdb.h> -#include <boot_http.h> - -/* shortest backoff delay possible (in seconds) */ -#define MIN_BACKOFF 1 - -/* how much to increase backoff time after each failure */ -#define BACKOFF_FACTOR 2 - -/* Maximum amount of backoff for a heavy network or flaky server */ -#define MAX_BACKOFF 128 - -typedef enum { - HTTP_REQ_TYPE_HEAD, - HTTP_REQ_TYPE_GET -} HTTPRequestType; - -typedef enum { - OCSPSuccess, - OCSPMem, - OCSPParse, - OCSPConnect, - OCSPRequest, - OCSPResponder, - OCSPUnsupported, - OCSPVerify, - OCSPInternal, - OCSPNoURI -} OCSPStatus; - -typedef enum { - none, - web_http, - web_https, - web_ftp -} WebScheme; - -typedef enum { - WEB_OK, - WEB_TIMEOUT, - WEB_CONNREFUSED, - WEB_HOSTDOWN, - WEB_VERIFY_SETUP, - WEB_NOCONNECT, - WEB_GET_FAIL -} WebStatus; - -typedef struct { - ulong_t prev_cont_length; - ulong_t content_length; - ulong_t cur_pos; -} DwnldData; - -typedef struct { - keystore_handle_t keystore; - char *certfile; - char *uniqfile; - char *link; - char *errstr; - char *dwnld_dir; - boolean_t spool; - void *content; - int timeout; - url_hport_t proxy; - url_t url; - DwnldData data; - http_respinfo_t *resp; - boot_http_ver_t *http_vers; - http_handle_t *hps; -} WEB_SESSION; - -extern boolean_t web_session_control(PKG_ERR *, char *, char *, - keystore_handle_t, char *, ushort_t, int, int, int, char **); -extern boolean_t get_signature(PKG_ERR *, char *, struct pkgdev *, - PKCS7 **); -extern boolean_t validate_signature(PKG_ERR *, char *, BIO *, PKCS7 *, - STACK_OF(X509) *, url_hport_t *, int); -extern boolean_t ds_validate_signature(PKG_ERR *, struct pkgdev *, char **, - char *, PKCS7 *, STACK_OF(X509) *, url_hport_t *, int); -extern boolean_t get_proxy_port(PKG_ERR *, char **, ushort_t *); -extern boolean_t path_valid(char *); -extern void web_cleanup(void); -extern ushort_t strip_port(char *proxy); -extern void set_web_install(void); -extern int is_web_install(void); -extern void echo_out(int, char *, ...); -extern void backoff(void); -extern void reset_backoff(void); -extern char *get_endof_string(char *, char); -extern char *get_startof_string(char *, char); - -#ifdef __cplusplus -} -#endif - -#endif /* _PKGWEB_H */ diff --git a/usr/src/lib/libpkg/common/progerr.c b/usr/src/lib/libpkg/common/progerr.c index e239dd8bda..567d77b581 100644 --- a/usr/src/lib/libpkg/common/progerr.c +++ b/usr/src/lib/libpkg/common/progerr.c @@ -20,6 +20,10 @@ */ /* + * Copyright (c) 2017 Peter Tribble. + */ + +/* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -36,7 +40,6 @@ #include <stdlib.h> #include <errno.h> #include "pkglocale.h" -#include "pkgerr.h" static char *ProgName = NULL; /* Set via set_prog_name() */ @@ -94,17 +97,6 @@ progerr(char *fmt, ...) (void) fprintf(stderr, "\n"); } -void -pkgerr(PKG_ERR *err) -{ - int i; - - for (i = 0; i < pkgerr_num(err); i++) { - progerr("%s", pkgerr_get(err, i)); - } -} - - /* * set_memalloc_failure_func() * Allows an appliation to specify the function to be called when diff --git a/usr/src/lib/libpkg/common/security.c b/usr/src/lib/libpkg/common/security.c deleted file mode 100644 index 9f2070c0c6..0000000000 --- a/usr/src/lib/libpkg/common/security.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - - -/* - * Module: security.c - * Description: - * Module for handling certificates and various - * utilities to access their data. - */ - -#include <stdio.h> -#include <string.h> -#include <errno.h> -#include <ctype.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <limits.h> -#include <pkgstrct.h> -#include <pkginfo.h> -#include <locale.h> -#include <libintl.h> -#include <unistd.h> -#include <stdlib.h> - -#include <openssl/bio.h> -#include <openssl/pkcs12.h> -#include <openssl/pkcs7.h> -#include <openssl/x509.h> -#include <openssl/err.h> -#include <openssl/ssl.h> -#include "pkgerr.h" -#include "pkglib.h" -#include "pkglibmsgs.h" -#include "pkglocale.h" -#include "p12lib.h" - -/* length of allowable passwords */ -#define MAX_PASSLEN 128 - -/* - * Name: init_security - * Description: Initializes structures, libraries, for security operations - * Arguments: none - * Returns: 0 if we couldn't initialize, non-zero otherwise - */ -void -sec_init(void) -{ - OpenSSL_add_all_algorithms(); - SSL_load_error_strings(); - ERR_load_SUNW_strings(); - (void) SSL_library_init(); -} - -/* - * get_cert_chain - Builds a chain of certificates, from a given - * user certificate to a trusted certificate. - * - * Arguments: - * err - Error object to add errors to - * cert - User cert to start with - * cas - Trusted certs to use as trust anchors - * chain - The resulting chain of certs (in the form of an - * ordered set) is placed here. - * - * Returns: - * 0 - Success - chain is stored in 'chain'. - * non-zero - Failure, errors recorded in err - */ -int -get_cert_chain(PKG_ERR *err, X509 *cert, STACK_OF(X509) *clcerts, - STACK_OF(X509) *cas, STACK_OF(X509) **chain) -{ - X509_STORE_CTX *store_ctx = NULL; - X509_STORE *ca_store = NULL; - X509 *ca_cert = NULL; - int i; - int ret = 0; - - if ((ca_store = X509_STORE_new()) == NULL) { - pkgerr_add(err, PKGERR_NOMEM, - gettext(ERR_MEM)); - ret = 1; - goto cleanup; - } - - /* add all ca certs into the store */ - for (i = 0; i < sk_X509_num(cas); i++) { - /* LINTED pointer cast may result in improper alignment */ - ca_cert = sk_X509_value(cas, i); - if (X509_STORE_add_cert(ca_store, ca_cert) == 0) { - pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM)); - ret = 1; - goto cleanup; - } - } - - /* initialize context object used during the chain resolution */ - - if ((store_ctx = X509_STORE_CTX_new()) == NULL) { - pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM)); - ret = 1; - goto cleanup; - } - - (void) X509_STORE_CTX_init(store_ctx, ca_store, cert, clcerts); - /* attempt to verify the cert, which builds the cert chain */ - if (X509_verify_cert(store_ctx) <= 0) { - pkgerr_add(err, PKGERR_CHAIN, - gettext(ERR_CERTCHAIN), - get_subject_display_name(cert), - X509_verify_cert_error_string(store_ctx->error)); - ret = 1; - goto cleanup; - } - *chain = X509_STORE_CTX_get1_chain(store_ctx); - -cleanup: - if (ca_store != NULL) - (void) X509_STORE_free(ca_store); - if (store_ctx != NULL) { - (void) X509_STORE_CTX_cleanup(store_ctx); - (void) X509_STORE_CTX_free(store_ctx); - } - - return (ret); -} - -/* - * Name: get_subject_name - * Description: Retrieves a name used for identifying a certificate's subject. - * - * Arguments: cert - The certificate to get the name from - * - * Returns : A static buffer containing the common name (CN) of the - * subject of the cert. - * - * if the CN is not available, returns a string with the entire - * X509 distinguished name. - */ -char -*get_subject_display_name(X509 *cert) -{ - - X509_NAME *xname; - static char sname[ATTR_MAX]; - - xname = X509_get_subject_name(cert); - if (X509_NAME_get_text_by_NID(xname, - NID_commonName, sname, - ATTR_MAX) <= 0) { - (void) strncpy(sname, - X509_NAME_oneline(xname, - NULL, 0), ATTR_MAX); - sname[ATTR_MAX - 1] = '\0'; - } - return (sname); -} - -/* - * Name: get_display_name - * Description: Retrieves a name used for identifying a certificate's issuer. - * - * Arguments: cert - The certificate to get the name from - * - * Returns : A static buffer containing the common name (CN) - * of the issuer of the cert. - * - * if the CN is not available, returns a string with the entire - * X509 distinguished name. - */ -char -*get_issuer_display_name(X509 *cert) -{ - - X509_NAME *xname; - static char sname[ATTR_MAX]; - - xname = X509_get_issuer_name(cert); - if (X509_NAME_get_text_by_NID(xname, - NID_commonName, sname, - ATTR_MAX) <= 0) { - (void) strncpy(sname, - X509_NAME_oneline(xname, - NULL, 0), ATTR_MAX); - sname[ATTR_MAX - 1] = '\0'; - } - return (sname); -} - - -/* - * Name: get_serial_num - * Description: Retrieves the serial number of an X509 cert - * - * Arguments: cert - The certificate to get the data from - * - * Returns : A static buffer containing the serial number - * of the cert - * - * if the SN is not available, returns NULL - */ -char -*get_serial_num(X509 *cert) -{ - static char sn_str[ATTR_MAX]; - ASN1_INTEGER *sn; - - if ((sn = X509_get_serialNumber(cert)) != 0) { - return (NULL); - } else { - (void) snprintf(sn_str, ATTR_MAX, "%ld", - ASN1_INTEGER_get(sn)); - } - - return (sn_str); -} - -/* - * Name: get_fingerprint - * Description: Generates a fingerprint string given - * a digest algorithm with which to calculate - * the fingerprint - * - * Arguments: cert - The certificate to get the data from - * Arguments: alg - The algorithm to use to calculate the fingerprint - * - * Returns : A static buffer containing the digest - * NULL if cert is NULL, or digest cannot be calculated - */ -char -*get_fingerprint(X509 *cert, const EVP_MD *alg) -{ - static char fp_str[ATTR_MAX]; - char tmp[ATTR_MAX] = ""; - unsigned int n; - unsigned char md[EVP_MAX_MD_SIZE]; - int i; - - if (!X509_digest(cert, alg, md, &n)) { - return (NULL); - } - - /* start with empty string */ - fp_str[0] = '\0'; - - for (i = 0; i < (int)n; i++) { - /* form a byte of the fingerprint */ - (void) snprintf(tmp, ATTR_MAX, "%02X:", md[i]); - /* cat it onto the end of the result */ - (void) strlcat(fp_str, tmp, ATTR_MAX); - } - - /* nuke trailing ':' */ - fp_str[strlen(fp_str) - 1] = '\0'; - - return (fp_str); -} |