xref: /titanic_51/usr/src/lib/libpkg/common/keystore.c (revision 4656d4747c8743290bfbe910c64cd75eb4e4af8d)
15c51f124SMoriah Waterland /*
25c51f124SMoriah Waterland  * CDDL HEADER START
35c51f124SMoriah Waterland  *
45c51f124SMoriah Waterland  * The contents of this file are subject to the terms of the
55c51f124SMoriah Waterland  * Common Development and Distribution License (the "License").
65c51f124SMoriah Waterland  * You may not use this file except in compliance with the License.
75c51f124SMoriah Waterland  *
85c51f124SMoriah Waterland  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95c51f124SMoriah Waterland  * or http://www.opensolaris.org/os/licensing.
105c51f124SMoriah Waterland  * See the License for the specific language governing permissions
115c51f124SMoriah Waterland  * and limitations under the License.
125c51f124SMoriah Waterland  *
135c51f124SMoriah Waterland  * When distributing Covered Code, include this CDDL HEADER in each
145c51f124SMoriah Waterland  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155c51f124SMoriah Waterland  * If applicable, add the following below this CDDL HEADER, with the
165c51f124SMoriah Waterland  * fields enclosed by brackets "[]" replaced with your own identifying
175c51f124SMoriah Waterland  * information: Portions Copyright [yyyy] [name of copyright owner]
185c51f124SMoriah Waterland  *
195c51f124SMoriah Waterland  * CDDL HEADER END
205c51f124SMoriah Waterland  */
215c51f124SMoriah Waterland 
225c51f124SMoriah Waterland /*
235c51f124SMoriah Waterland  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
245c51f124SMoriah Waterland  * Use is subject to license terms.
255c51f124SMoriah Waterland  */
265c51f124SMoriah Waterland 
275c51f124SMoriah Waterland /*
285c51f124SMoriah Waterland  * Module:	keystore.c
295c51f124SMoriah Waterland  * Description:	This module contains the structure definitions for processing
305c51f124SMoriah Waterland  *		package keystore files.
315c51f124SMoriah Waterland  */
325c51f124SMoriah Waterland 
335c51f124SMoriah Waterland #include <errno.h>
345c51f124SMoriah Waterland #include <fcntl.h>
355c51f124SMoriah Waterland #include <unistd.h>
365c51f124SMoriah Waterland #include <strings.h>
375c51f124SMoriah Waterland #include <libintl.h>
385c51f124SMoriah Waterland #include <time.h>
395c51f124SMoriah Waterland #include <ctype.h>
405c51f124SMoriah Waterland #include <sys/types.h>
415c51f124SMoriah Waterland #include <sys/stat.h>
425c51f124SMoriah Waterland #include <openssl/evp.h>
435c51f124SMoriah Waterland #include <openssl/x509.h>
445c51f124SMoriah Waterland #include <openssl/pkcs12.h>
455c51f124SMoriah Waterland #include <openssl/asn1.h>
465c51f124SMoriah Waterland #include <openssl/pem.h>
475c51f124SMoriah Waterland #include <openssl/err.h>
485c51f124SMoriah Waterland #include <openssl/safestack.h>
495c51f124SMoriah Waterland #include <openssl/stack.h>
505c51f124SMoriah Waterland #include "p12lib.h"
515c51f124SMoriah Waterland #include "pkgerr.h"
525c51f124SMoriah Waterland #include "keystore.h"
535c51f124SMoriah Waterland #include "pkglib.h"
545c51f124SMoriah Waterland #include "pkglibmsgs.h"
555c51f124SMoriah Waterland 
565c51f124SMoriah Waterland typedef struct keystore_t {
575c51f124SMoriah Waterland 	boolean_t		dirty;
585c51f124SMoriah Waterland 	boolean_t		new;
595c51f124SMoriah Waterland 	char			*path;
605c51f124SMoriah Waterland 	char			*passphrase;
615c51f124SMoriah Waterland 	/* truststore handles */
625c51f124SMoriah Waterland 	int			cafd;
635c51f124SMoriah Waterland 	STACK_OF(X509)		*cacerts;
645c51f124SMoriah Waterland 	char			*capath;
655c51f124SMoriah Waterland 
665c51f124SMoriah Waterland 	/* user certificate handles */
675c51f124SMoriah Waterland 	STACK_OF(X509)		*clcerts;
685c51f124SMoriah Waterland 	char			*clpath;
695c51f124SMoriah Waterland 
705c51f124SMoriah Waterland 	/* private key handles */
715c51f124SMoriah Waterland 	STACK_OF(EVP_PKEY)	*pkeys;
725c51f124SMoriah Waterland 	char			*keypath;
735c51f124SMoriah Waterland } keystore_t;
745c51f124SMoriah Waterland 
755c51f124SMoriah Waterland /* local routines */
765c51f124SMoriah Waterland static keystore_t	*new_keystore(void);
775c51f124SMoriah Waterland static void		free_keystore(keystore_t *);
785c51f124SMoriah Waterland static boolean_t	verify_keystore_integrity(PKG_ERR *, keystore_t *);
795c51f124SMoriah Waterland static boolean_t	check_password(PKCS12 *, char *);
805c51f124SMoriah Waterland static boolean_t	resolve_paths(PKG_ERR *, char *, char *,
815c51f124SMoriah Waterland     long, keystore_t *);
825c51f124SMoriah Waterland static boolean_t	lock_keystore(PKG_ERR *, long, keystore_t *);
835c51f124SMoriah Waterland 
845c51f124SMoriah Waterland static boolean_t	unlock_keystore(PKG_ERR *, keystore_t *);
855c51f124SMoriah Waterland static boolean_t	read_keystore(PKG_ERR *, keystore_t *,
865c51f124SMoriah Waterland     keystore_passphrase_cb);
875c51f124SMoriah Waterland static boolean_t	write_keystore(PKG_ERR *, keystore_t *,
885c51f124SMoriah Waterland     keystore_passphrase_cb);
895c51f124SMoriah Waterland static boolean_t	write_keystore_file(PKG_ERR *, char *, PKCS12 *);
905c51f124SMoriah Waterland static boolean_t	clear_keystore_file(PKG_ERR *, char *);
915c51f124SMoriah Waterland static PKCS12		*read_keystore_file(PKG_ERR *, char *);
925c51f124SMoriah Waterland static char		*get_time_string(ASN1_TIME *);
935c51f124SMoriah Waterland 
945c51f124SMoriah Waterland /* locking routines */
955c51f124SMoriah Waterland static boolean_t	restore_keystore_file(PKG_ERR *, char *);
965c51f124SMoriah Waterland static int		file_lock(int, int, int);
975c51f124SMoriah Waterland static int		file_unlock(int);
985c51f124SMoriah Waterland static boolean_t	file_lock_test(int, int);
995c51f124SMoriah Waterland static boolean_t	file_empty(char *);
1005c51f124SMoriah Waterland static boolean_t	get_keystore_passwd(PKG_ERR *err, PKCS12 *p12,
1015c51f124SMoriah Waterland     keystore_passphrase_cb cb, keystore_t *keystore);
1025c51f124SMoriah Waterland static boolean_t	wait_restore(int, char *, char *, char *);
1035c51f124SMoriah Waterland 
1045c51f124SMoriah Waterland #define	KEYSTORE_PERMS	(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
1055c51f124SMoriah Waterland 
1065c51f124SMoriah Waterland /* wait on other keystore access for 1 minute before giving up */
1075c51f124SMoriah Waterland #define	LOCK_TIMEOUT	60
1085c51f124SMoriah Waterland 
1095c51f124SMoriah Waterland /*
1105c51f124SMoriah Waterland  * print_certs  - prints certificates out of a keystore, to a file.
1115c51f124SMoriah Waterland  *
1125c51f124SMoriah Waterland  * Arguments:
1135c51f124SMoriah Waterland  * err - Error object to append errors to
1145c51f124SMoriah Waterland  * keystore - Keystore on which to operate
1155c51f124SMoriah Waterland  * alias - Name of certificate to print, NULL means print all
1165c51f124SMoriah Waterland  * format - Format in which to print certificates
1175c51f124SMoriah Waterland  * outfile - Where to print certificates
1185c51f124SMoriah Waterland  *
1195c51f124SMoriah Waterland  * Returns:
1205c51f124SMoriah Waterland  *   0 - Success
1215c51f124SMoriah Waterland  *   non-zero - Failure, errors added to err
1225c51f124SMoriah Waterland  */
1235c51f124SMoriah Waterland int
1245c51f124SMoriah Waterland print_certs(PKG_ERR *err, keystore_handle_t keystore_h, char *alias,
1255c51f124SMoriah Waterland     keystore_encoding_format_t format, FILE *outfile)
1265c51f124SMoriah Waterland {
1275c51f124SMoriah Waterland 	int		i;
1285c51f124SMoriah Waterland 	X509		*cert;
1295c51f124SMoriah Waterland 	char		*fname = NULL;
1305c51f124SMoriah Waterland 	boolean_t	found = B_FALSE;
1315c51f124SMoriah Waterland 	keystore_t	*keystore = keystore_h;
1325c51f124SMoriah Waterland 
1335c51f124SMoriah Waterland 	if (keystore->clcerts != NULL) {
1345c51f124SMoriah Waterland 		/* print out each client cert */
1355c51f124SMoriah Waterland 		for (i = 0; i < sk_X509_num(keystore->clcerts); i++) {
1365c51f124SMoriah Waterland 			cert = sk_X509_value(keystore->clcerts, i);
1375c51f124SMoriah Waterland 			(void) sunw_get_cert_fname(GETDO_COPY, cert,
1385c51f124SMoriah Waterland 			    &fname);
1395c51f124SMoriah Waterland 
1405c51f124SMoriah Waterland 			if (fname == NULL) {
1415c51f124SMoriah Waterland 				/* no name recorded, keystore is corrupt */
1425c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_CORRUPT,
1435c51f124SMoriah Waterland 				    gettext(ERR_KEYSTORE_NO_ALIAS),
1445c51f124SMoriah Waterland 				    get_subject_display_name(cert));
1455c51f124SMoriah Waterland 				return (1);
1465c51f124SMoriah Waterland 			}
1475c51f124SMoriah Waterland 
1485c51f124SMoriah Waterland 			if ((alias != NULL) && (!streq(alias, fname))) {
1495c51f124SMoriah Waterland 				/* name does not match, skip it */
1505c51f124SMoriah Waterland 				(void) OPENSSL_free(fname);
1515c51f124SMoriah Waterland 				fname = NULL;
1525c51f124SMoriah Waterland 				continue;
1535c51f124SMoriah Waterland 			} else {
1545c51f124SMoriah Waterland 				found = B_TRUE;
1555c51f124SMoriah Waterland 				(void) print_cert(err, cert, format,
1565c51f124SMoriah Waterland 				    fname, B_FALSE, outfile);
1575c51f124SMoriah Waterland 				(void) OPENSSL_free(fname);
1585c51f124SMoriah Waterland 				fname = NULL;
1595c51f124SMoriah Waterland 			}
1605c51f124SMoriah Waterland 		}
1615c51f124SMoriah Waterland 	}
1625c51f124SMoriah Waterland 
1635c51f124SMoriah Waterland 	if (fname != NULL) {
1645c51f124SMoriah Waterland 	    (void) OPENSSL_free(fname);
1655c51f124SMoriah Waterland 	    fname = NULL;
1665c51f124SMoriah Waterland 	}
1675c51f124SMoriah Waterland 
1685c51f124SMoriah Waterland 	if (keystore->cacerts != NULL) {
1695c51f124SMoriah Waterland 		/* print out each trusted cert */
1705c51f124SMoriah Waterland 		for (i = 0; i < sk_X509_num(keystore->cacerts); i++) {
1715c51f124SMoriah Waterland 			cert = sk_X509_value(keystore->cacerts, i);
1725c51f124SMoriah Waterland 			(void) sunw_get_cert_fname(GETDO_COPY,
1735c51f124SMoriah Waterland 			    cert, &fname);
1745c51f124SMoriah Waterland 
1755c51f124SMoriah Waterland 			if (fname == NULL) {
1765c51f124SMoriah Waterland 				/* no name recorded, keystore is corrupt */
1775c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_CORRUPT,
1785c51f124SMoriah Waterland 				    gettext(ERR_KEYSTORE_NO_ALIAS),
1795c51f124SMoriah Waterland 				    get_subject_display_name(cert));
1805c51f124SMoriah Waterland 				return (1);
1815c51f124SMoriah Waterland 			}
1825c51f124SMoriah Waterland 
1835c51f124SMoriah Waterland 			if ((alias != NULL) && (!streq(alias, fname))) {
1845c51f124SMoriah Waterland 				/* name does not match, skip it */
1855c51f124SMoriah Waterland 				(void) OPENSSL_free(fname);
1865c51f124SMoriah Waterland 				fname = NULL;
1875c51f124SMoriah Waterland 				continue;
1885c51f124SMoriah Waterland 			} else {
1895c51f124SMoriah Waterland 				found = B_TRUE;
1905c51f124SMoriah Waterland 				(void) print_cert(err, cert, format,
1915c51f124SMoriah Waterland 				    fname, B_TRUE, outfile);
1925c51f124SMoriah Waterland 				(void) OPENSSL_free(fname);
1935c51f124SMoriah Waterland 				fname = NULL;
1945c51f124SMoriah Waterland 			}
1955c51f124SMoriah Waterland 		}
1965c51f124SMoriah Waterland 	}
1975c51f124SMoriah Waterland 
1985c51f124SMoriah Waterland 	if (fname != NULL) {
1995c51f124SMoriah Waterland 	    (void) OPENSSL_free(fname);
2005c51f124SMoriah Waterland 	    fname = NULL;
2015c51f124SMoriah Waterland 	}
2025c51f124SMoriah Waterland 
2035c51f124SMoriah Waterland 	if (found) {
2045c51f124SMoriah Waterland 		return (0);
2055c51f124SMoriah Waterland 	} else {
2065c51f124SMoriah Waterland 		/* no certs printed */
2075c51f124SMoriah Waterland 		if (alias != NULL) {
2085c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_NOALIASMATCH,
2095c51f124SMoriah Waterland 			    gettext(ERR_KEYSTORE_NOCERT),
2105c51f124SMoriah Waterland 			    alias, keystore->path);
2115c51f124SMoriah Waterland 		} else {
2125c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_NOPUBKEY,
2135c51f124SMoriah Waterland 			    gettext(ERR_KEYSTORE_NOPUBCERTS),
2145c51f124SMoriah Waterland 			    keystore->path);
2155c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_NOCACERT,
2165c51f124SMoriah Waterland 			    gettext(ERR_KEYSTORE_NOCACERTS),
2175c51f124SMoriah Waterland 			    keystore->path);
2185c51f124SMoriah Waterland 		}
2195c51f124SMoriah Waterland 		return (1);
2205c51f124SMoriah Waterland 	}
2215c51f124SMoriah Waterland }
2225c51f124SMoriah Waterland 
2235c51f124SMoriah Waterland /*
2245c51f124SMoriah Waterland  * print_cert  - prints a single certificate, to a file
2255c51f124SMoriah Waterland  *
2265c51f124SMoriah Waterland  * Arguments:
2275c51f124SMoriah Waterland  * err - Error object to append errors to
2285c51f124SMoriah Waterland  * x - The certificate to print
2295c51f124SMoriah Waterland  * alias - Name of certificate to print
2305c51f124SMoriah Waterland  * format - Format in which to print certificate
2315c51f124SMoriah Waterland  * outfile - Where to print certificate
2325c51f124SMoriah Waterland  *
2335c51f124SMoriah Waterland  * Returns:
2345c51f124SMoriah Waterland  *   0 - Success
2355c51f124SMoriah Waterland  *   non-zero - Failure, errors added to err
2365c51f124SMoriah Waterland  */
2375c51f124SMoriah Waterland int print_cert(PKG_ERR *err, X509 *x,
2385c51f124SMoriah Waterland     keystore_encoding_format_t format, char *alias, boolean_t is_trusted,
2395c51f124SMoriah Waterland     FILE *outfile)
2405c51f124SMoriah Waterland {
2415c51f124SMoriah Waterland 
2425c51f124SMoriah Waterland 	char *vdb_str;
2435c51f124SMoriah Waterland 	char *vda_str;
2445c51f124SMoriah Waterland 	char vd_str[ATTR_MAX];
2455c51f124SMoriah Waterland 	int ret = 0;
2465c51f124SMoriah Waterland 	char *cn_str, *icn_str, *typ_str;
2475c51f124SMoriah Waterland 	char *tmp;
2485c51f124SMoriah Waterland 	char *md5_fp;
2495c51f124SMoriah Waterland 	char *sha1_fp;
2505c51f124SMoriah Waterland 	int len;
2515c51f124SMoriah Waterland 
2525c51f124SMoriah Waterland 	/* need to localize the word "Fingerprint", hence these pointers */
2535c51f124SMoriah Waterland 	char md5_label[ATTR_MAX];
2545c51f124SMoriah Waterland 	char sha1_label[ATTR_MAX];
2555c51f124SMoriah Waterland 
2565c51f124SMoriah Waterland 	if (is_trusted) {
2575c51f124SMoriah Waterland 		typ_str = gettext(MSG_KEYSTORE_TRUSTED);
2585c51f124SMoriah Waterland 	} else {
2595c51f124SMoriah Waterland 		typ_str = gettext(MSG_KEYSTORE_UNTRUSTED);
2605c51f124SMoriah Waterland 	}
2615c51f124SMoriah Waterland 
2625c51f124SMoriah Waterland 	if ((cn_str = get_subject_display_name(x)) == NULL) {
2635c51f124SMoriah Waterland 		cn_str = gettext(MSG_KEYSTORE_UNKNOWN);
2645c51f124SMoriah Waterland 	}
2655c51f124SMoriah Waterland 
2665c51f124SMoriah Waterland 	if ((icn_str = get_issuer_display_name(x)) == NULL) {
2675c51f124SMoriah Waterland 		icn_str = gettext(MSG_KEYSTORE_UNKNOWN);
2685c51f124SMoriah Waterland 	}
2695c51f124SMoriah Waterland 
2705c51f124SMoriah Waterland 	vdb_str = xstrdup(get_time_string(X509_get_notBefore(x)));
2715c51f124SMoriah Waterland 	vda_str = xstrdup(get_time_string(X509_get_notAfter(x)));
2725c51f124SMoriah Waterland 	if (((len = snprintf(vd_str, ATTR_MAX, "<%s> - <%s>",
2735c51f124SMoriah Waterland 	    vdb_str, vda_str)) < 0) || (len >= ATTR_MAX)) {
2745c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN), vdb_str);
2755c51f124SMoriah Waterland 		ret = 1;
2765c51f124SMoriah Waterland 		goto cleanup;
2775c51f124SMoriah Waterland 	}
2785c51f124SMoriah Waterland 
2795c51f124SMoriah Waterland 	if ((tmp = get_fingerprint(x, EVP_md5())) == NULL) {
2805c51f124SMoriah Waterland 		md5_fp = gettext(MSG_KEYSTORE_UNKNOWN);
2815c51f124SMoriah Waterland 	} else {
2825c51f124SMoriah Waterland 		/*
2835c51f124SMoriah Waterland 		 * make a copy, otherwise the next call to get_fingerprint
2845c51f124SMoriah Waterland 		 * will overwrite this one
2855c51f124SMoriah Waterland 		 */
2865c51f124SMoriah Waterland 		md5_fp = xstrdup(tmp);
2875c51f124SMoriah Waterland 	}
2885c51f124SMoriah Waterland 
2895c51f124SMoriah Waterland 	if ((tmp = get_fingerprint(x, EVP_sha1())) == NULL) {
2905c51f124SMoriah Waterland 		sha1_fp = gettext(MSG_KEYSTORE_UNKNOWN);
2915c51f124SMoriah Waterland 	} else {
2925c51f124SMoriah Waterland 		sha1_fp = xstrdup(tmp);
2935c51f124SMoriah Waterland 	}
2945c51f124SMoriah Waterland 
2955c51f124SMoriah Waterland 	(void) snprintf(md5_label, ATTR_MAX, "%s %s",
2965c51f124SMoriah Waterland 	    OBJ_nid2sn(EVP_MD_type(EVP_md5())),
2975c51f124SMoriah Waterland 	    /* i18n: 14 characters max */
2985c51f124SMoriah Waterland 	    gettext(MSG_KEYSTORE_FP));
2995c51f124SMoriah Waterland 
3005c51f124SMoriah Waterland 	(void) snprintf(sha1_label, ATTR_MAX, "%s %s",
3015c51f124SMoriah Waterland 	    OBJ_nid2sn(EVP_MD_type(EVP_sha1())),
3025c51f124SMoriah Waterland 	    /* i18n: 14 characters max */
3035c51f124SMoriah Waterland 	    gettext(MSG_KEYSTORE_FP));
3045c51f124SMoriah Waterland 
3055c51f124SMoriah Waterland 	switch (format) {
3065c51f124SMoriah Waterland 	case KEYSTORE_FORMAT_PEM:
3075c51f124SMoriah Waterland 		(void) PEM_write_X509(outfile, x);
3085c51f124SMoriah Waterland 		break;
3095c51f124SMoriah Waterland 	case KEYSTORE_FORMAT_DER:
3105c51f124SMoriah Waterland 		(void) i2d_X509_fp(outfile, x);
3115c51f124SMoriah Waterland 		break;
3125c51f124SMoriah Waterland 	case KEYSTORE_FORMAT_TEXT:
3135c51f124SMoriah Waterland 		(void) fprintf(outfile, "%18s: %s\n",
3145c51f124SMoriah Waterland 		    /* i18n: 18 characters max */
3155c51f124SMoriah Waterland 		    gettext(MSG_KEYSTORE_AL), alias);
3165c51f124SMoriah Waterland 		(void) fprintf(outfile, "%18s: %s\n",
3175c51f124SMoriah Waterland 		    /* i18n: 18 characters max */
3185c51f124SMoriah Waterland 		    gettext(MSG_KEYSTORE_CN), cn_str);
3195c51f124SMoriah Waterland 		(void) fprintf(outfile, "%18s: %s\n",
3205c51f124SMoriah Waterland 		    /* i18n: 18 characters max */
3215c51f124SMoriah Waterland 		    gettext(MSG_KEYSTORE_TY), typ_str);
3225c51f124SMoriah Waterland 		(void) fprintf(outfile, "%18s: %s\n",
3235c51f124SMoriah Waterland 		    /* i18n: 18 characters max */
3245c51f124SMoriah Waterland 		    gettext(MSG_KEYSTORE_IN), icn_str);
3255c51f124SMoriah Waterland 		(void) fprintf(outfile, "%18s: %s\n",
3265c51f124SMoriah Waterland 		    /* i18n: 18 characters max */
3275c51f124SMoriah Waterland 		    gettext(MSG_KEYSTORE_VD), vd_str);
3285c51f124SMoriah Waterland 		(void) fprintf(outfile, "%18s: %s\n", md5_label, md5_fp);
3295c51f124SMoriah Waterland 		(void) fprintf(outfile, "%18s: %s\n", sha1_label, sha1_fp);
3305c51f124SMoriah Waterland 		(void) fprintf(outfile, "\n");
3315c51f124SMoriah Waterland 		break;
3325c51f124SMoriah Waterland 	default:
3335c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_INTERNAL,
3345c51f124SMoriah Waterland 		    gettext(ERR_KEYSTORE_INTERNAL),
3355c51f124SMoriah Waterland 		    __FILE__, __LINE__);
3365c51f124SMoriah Waterland 		ret = 1;
3375c51f124SMoriah Waterland 		goto cleanup;
3385c51f124SMoriah Waterland 	}
3395c51f124SMoriah Waterland 
3405c51f124SMoriah Waterland cleanup:
3415c51f124SMoriah Waterland 	if (md5_fp != NULL)
3425c51f124SMoriah Waterland 		free(md5_fp);
3435c51f124SMoriah Waterland 	if (sha1_fp != NULL)
3445c51f124SMoriah Waterland 		free(sha1_fp);
3455c51f124SMoriah Waterland 	if (vda_str != NULL)
3465c51f124SMoriah Waterland 		free(vda_str);
3475c51f124SMoriah Waterland 	if (vdb_str != NULL)
3485c51f124SMoriah Waterland 		free(vdb_str);
3495c51f124SMoriah Waterland 	return (ret);
3505c51f124SMoriah Waterland }
3515c51f124SMoriah Waterland 
3525c51f124SMoriah Waterland /*
3535c51f124SMoriah Waterland  * open_keystore - Initialize new keystore object for
3545c51f124SMoriah Waterland  * impending access.
3555c51f124SMoriah Waterland  *
3565c51f124SMoriah Waterland  * Arguments:
3575c51f124SMoriah Waterland  * err - Error object to append errors to
3585c51f124SMoriah Waterland  * keystore_file - Base filename or directory of keystore
3595c51f124SMoriah Waterland  * app - Application making request
3605c51f124SMoriah Waterland  * passwd - Password used to decrypt keystore
3615c51f124SMoriah Waterland  * flags - Control flags used to control access mode and behavior
3625c51f124SMoriah Waterland  * result - Resulting keystore object stored here on success
3635c51f124SMoriah Waterland  *
3645c51f124SMoriah Waterland  * Returns:
3655c51f124SMoriah Waterland  *   0 - Success - result contains a pointer to the opened keystore
3665c51f124SMoriah Waterland  *   non-zero - Failure, errors added to err
3675c51f124SMoriah Waterland  */
3685c51f124SMoriah Waterland int
3695c51f124SMoriah Waterland open_keystore(PKG_ERR *err, char *keystore_file, char *app,
3705c51f124SMoriah Waterland     keystore_passphrase_cb cb, long flags, keystore_handle_t *result)
3715c51f124SMoriah Waterland {
3725c51f124SMoriah Waterland 	int ret = 0;
3735c51f124SMoriah Waterland 	keystore_t	*tmpstore;
3745c51f124SMoriah Waterland 
3755c51f124SMoriah Waterland 	tmpstore = new_keystore();
3765c51f124SMoriah Waterland 
3775c51f124SMoriah Waterland 	tmpstore->dirty = B_FALSE;
3785c51f124SMoriah Waterland 	tmpstore->new = B_FALSE;
3795c51f124SMoriah Waterland 	tmpstore->path = xstrdup(keystore_file);
3805c51f124SMoriah Waterland 
3815c51f124SMoriah Waterland 	if (!resolve_paths(err, keystore_file, app, flags, tmpstore)) {
3825c51f124SMoriah Waterland 		/* unable to determine keystore paths */
3835c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_CORRUPT, gettext(ERR_KEYSTORE_REPAIR),
3845c51f124SMoriah Waterland 		    keystore_file);
3855c51f124SMoriah Waterland 		ret = 1;
3865c51f124SMoriah Waterland 		goto cleanup;
3875c51f124SMoriah Waterland 	}
3885c51f124SMoriah Waterland 
3895c51f124SMoriah Waterland 	if (!verify_keystore_integrity(err, tmpstore)) {
3905c51f124SMoriah Waterland 		/* unable to repair keystore */
3915c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_CORRUPT, gettext(ERR_KEYSTORE_REPAIR),
3925c51f124SMoriah Waterland 		    keystore_file);
3935c51f124SMoriah Waterland 		ret = 1;
3945c51f124SMoriah Waterland 		goto cleanup;
3955c51f124SMoriah Waterland 	}
3965c51f124SMoriah Waterland 
3975c51f124SMoriah Waterland 	if (!lock_keystore(err, flags, tmpstore)) {
3985c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_LOCKED, gettext(ERR_KEYSTORE_LOCKED),
3995c51f124SMoriah Waterland 		    keystore_file);
4005c51f124SMoriah Waterland 		ret = 1;
4015c51f124SMoriah Waterland 		goto cleanup;
4025c51f124SMoriah Waterland 	}
4035c51f124SMoriah Waterland 
4045c51f124SMoriah Waterland 	/* now that we have locked the keystore, go ahead and read it */
4055c51f124SMoriah Waterland 	if (!read_keystore(err, tmpstore, cb)) {
4065c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_READ, gettext(ERR_PARSE),
4075c51f124SMoriah Waterland 		    keystore_file);
4085c51f124SMoriah Waterland 		ret = 1;
4095c51f124SMoriah Waterland 		goto cleanup;
4105c51f124SMoriah Waterland 	}
4115c51f124SMoriah Waterland 
4125c51f124SMoriah Waterland 	*result = tmpstore;
4135c51f124SMoriah Waterland 	tmpstore = NULL;
4145c51f124SMoriah Waterland 
4155c51f124SMoriah Waterland cleanup:
4165c51f124SMoriah Waterland 	if (tmpstore != NULL)
4175c51f124SMoriah Waterland 		free_keystore(tmpstore);
4185c51f124SMoriah Waterland 	return (ret);
4195c51f124SMoriah Waterland }
4205c51f124SMoriah Waterland 
4215c51f124SMoriah Waterland /*
4225c51f124SMoriah Waterland  * new_keystore - Allocates and initializes a Keystore object
4235c51f124SMoriah Waterland  *
4245c51f124SMoriah Waterland  * Arguments:
4255c51f124SMoriah Waterland  * NONE
4265c51f124SMoriah Waterland  *
4275c51f124SMoriah Waterland  * Returns:
4285c51f124SMoriah Waterland  *   NULL - out of memory
4295c51f124SMoriah Waterland  *   otherwise, returns a pointer to the newly allocated object,
4305c51f124SMoriah Waterland  *   which should be freed with free_keystore() when no longer
4315c51f124SMoriah Waterland  *   needed.
4325c51f124SMoriah Waterland  */
4335c51f124SMoriah Waterland static keystore_t
4345c51f124SMoriah Waterland *new_keystore(void)
4355c51f124SMoriah Waterland {
4365c51f124SMoriah Waterland 	keystore_t *tmpstore;
4375c51f124SMoriah Waterland 
4385c51f124SMoriah Waterland 	if ((tmpstore = (keystore_t *)malloc(sizeof (keystore_t))) == NULL) {
4395c51f124SMoriah Waterland 		return (NULL);
4405c51f124SMoriah Waterland 	}
4415c51f124SMoriah Waterland 	tmpstore->dirty = B_FALSE;
4425c51f124SMoriah Waterland 	tmpstore->new = B_FALSE;
4435c51f124SMoriah Waterland 	tmpstore->path = NULL;
4445c51f124SMoriah Waterland 	tmpstore->passphrase = NULL;
4455c51f124SMoriah Waterland 	tmpstore->cafd = -1;
4465c51f124SMoriah Waterland 	tmpstore->cacerts = NULL;
4475c51f124SMoriah Waterland 	tmpstore->capath = NULL;
4485c51f124SMoriah Waterland 	tmpstore->clcerts = NULL;
4495c51f124SMoriah Waterland 	tmpstore->clpath = NULL;
4505c51f124SMoriah Waterland 	tmpstore->pkeys = NULL;
4515c51f124SMoriah Waterland 	tmpstore->keypath = NULL;
4525c51f124SMoriah Waterland 
4535c51f124SMoriah Waterland 	return (tmpstore);
4545c51f124SMoriah Waterland }
4555c51f124SMoriah Waterland 
4565c51f124SMoriah Waterland /*
4575c51f124SMoriah Waterland  * free_keystore - Deallocates a Keystore object
4585c51f124SMoriah Waterland  *
4595c51f124SMoriah Waterland  * Arguments:
4605c51f124SMoriah Waterland  * keystore - The keystore to deallocate
4615c51f124SMoriah Waterland  *
4625c51f124SMoriah Waterland  * Returns:
4635c51f124SMoriah Waterland  *   NONE
4645c51f124SMoriah Waterland  */
4655c51f124SMoriah Waterland static void
4665c51f124SMoriah Waterland free_keystore(keystore_t *keystore)
4675c51f124SMoriah Waterland {
4685c51f124SMoriah Waterland 	if (keystore->path != NULL)
4695c51f124SMoriah Waterland 		free(keystore->path);
4705c51f124SMoriah Waterland 	if (keystore->capath != NULL)
4715c51f124SMoriah Waterland 		free(keystore->capath);
4725c51f124SMoriah Waterland 	if (keystore->passphrase != NULL)
4735c51f124SMoriah Waterland 		free(keystore->passphrase);
4745c51f124SMoriah Waterland 	if (keystore->clpath != NULL)
4755c51f124SMoriah Waterland 		free(keystore->clpath);
4765c51f124SMoriah Waterland 	if (keystore->keypath != NULL)
4775c51f124SMoriah Waterland 		free(keystore->keypath);
4785c51f124SMoriah Waterland 
4795c51f124SMoriah Waterland 	if (keystore->pkeys != NULL) {
4805c51f124SMoriah Waterland 		sk_EVP_PKEY_pop_free(keystore->pkeys,
4815c51f124SMoriah Waterland 		    sunw_evp_pkey_free);
4825c51f124SMoriah Waterland 	}
4835c51f124SMoriah Waterland 	if (keystore->clcerts != NULL)
4845c51f124SMoriah Waterland 		sk_X509_free(keystore->clcerts);
4855c51f124SMoriah Waterland 	if (keystore->cacerts != NULL)
4865c51f124SMoriah Waterland 		sk_X509_free(keystore->cacerts);
4875c51f124SMoriah Waterland 	free(keystore);
4885c51f124SMoriah Waterland }
4895c51f124SMoriah Waterland 
4905c51f124SMoriah Waterland /*
4915c51f124SMoriah Waterland  * close_keystore - Writes keystore to disk if needed, then
4925c51f124SMoriah Waterland  * unlocks and closes keystore.
4935c51f124SMoriah Waterland  *
4945c51f124SMoriah Waterland  * Arguments:
4955c51f124SMoriah Waterland  * err - Error object to append errors to
4965c51f124SMoriah Waterland  * keystore - Keystore which should be closed
4975c51f124SMoriah Waterland  * passwd - Password used to encrypt keystore
4985c51f124SMoriah Waterland  *
4995c51f124SMoriah Waterland  * Returns:
5005c51f124SMoriah Waterland  *   0 - Success - keystore is committed to disk, and unlocked
5015c51f124SMoriah Waterland  *   non-zero - Failure, errors added to err
5025c51f124SMoriah Waterland  */
5035c51f124SMoriah Waterland int
5045c51f124SMoriah Waterland close_keystore(PKG_ERR *err, keystore_handle_t keystore_h,
5055c51f124SMoriah Waterland     keystore_passphrase_cb cb)
5065c51f124SMoriah Waterland {
5075c51f124SMoriah Waterland 	int ret = 0;
5085c51f124SMoriah Waterland 	keystore_t *keystore = keystore_h;
5095c51f124SMoriah Waterland 
5105c51f124SMoriah Waterland 	if (keystore->dirty) {
5115c51f124SMoriah Waterland 		/* write out the keystore first */
5125c51f124SMoriah Waterland 		if (!write_keystore(err, keystore, cb)) {
5135c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_WRITE,
5145c51f124SMoriah Waterland 			    gettext(ERR_KEYSTORE_WRITE),
5155c51f124SMoriah Waterland 			    keystore->path);
5165c51f124SMoriah Waterland 			ret = 1;
5175c51f124SMoriah Waterland 			goto cleanup;
5185c51f124SMoriah Waterland 		}
5195c51f124SMoriah Waterland 	}
5205c51f124SMoriah Waterland 
5215c51f124SMoriah Waterland 	if (!unlock_keystore(err, keystore)) {
5225c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_UNLOCK, gettext(ERR_KEYSTORE_UNLOCK),
5235c51f124SMoriah Waterland 		    keystore->path);
5245c51f124SMoriah Waterland 		ret = 1;
5255c51f124SMoriah Waterland 		goto cleanup;
5265c51f124SMoriah Waterland 	}
5275c51f124SMoriah Waterland 
5285c51f124SMoriah Waterland 	free_keystore(keystore);
5295c51f124SMoriah Waterland cleanup:
5305c51f124SMoriah Waterland 	return (ret);
5315c51f124SMoriah Waterland }
5325c51f124SMoriah Waterland 
5335c51f124SMoriah Waterland /*
5345c51f124SMoriah Waterland  * merge_ca_cert - Adds a trusted certificate (trust anchor) to a keystore.
5355c51f124SMoriah Waterland  * certificate checked for validity dates and non-duplicity.
5365c51f124SMoriah Waterland  *
5375c51f124SMoriah Waterland  * Arguments:
5385c51f124SMoriah Waterland  * err - Error object to add errors to
5395c51f124SMoriah Waterland  * cacert - Certificate which to merge into keystore
5405c51f124SMoriah Waterland  * keystore - The keystore into which the certificate is merged
5415c51f124SMoriah Waterland  *
5425c51f124SMoriah Waterland  * Returns:
5435c51f124SMoriah Waterland  *   0 - Success - Certificate passes validity, and
5445c51f124SMoriah Waterland  *		is merged into keystore
5455c51f124SMoriah Waterland  * non-zero - Failure, errors recorded in err
5465c51f124SMoriah Waterland  */
5475c51f124SMoriah Waterland int
5485c51f124SMoriah Waterland merge_ca_cert(PKG_ERR *err, X509 *cacert, keystore_handle_t keystore_h)
5495c51f124SMoriah Waterland {
5505c51f124SMoriah Waterland 
5515c51f124SMoriah Waterland 	int		ret = 0;
5525c51f124SMoriah Waterland 	X509		*existing = NULL;
5535c51f124SMoriah Waterland 	char		*fname;
5545c51f124SMoriah Waterland 	keystore_t	*keystore = keystore_h;
5555c51f124SMoriah Waterland 
5565c51f124SMoriah Waterland 	/* check validity dates */
5575c51f124SMoriah Waterland 	if (check_cert(err, cacert) != 0) {
5585c51f124SMoriah Waterland 		ret = 1;
5595c51f124SMoriah Waterland 		goto cleanup;
5605c51f124SMoriah Waterland 	}
5615c51f124SMoriah Waterland 
5625c51f124SMoriah Waterland 	/* create the certificate's friendlyName */
5635c51f124SMoriah Waterland 	fname = get_subject_display_name(cacert);
5645c51f124SMoriah Waterland 
5655c51f124SMoriah Waterland 	if (sunw_set_fname(fname, NULL, cacert) != 0) {
5665c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM));
5675c51f124SMoriah Waterland 		ret = 1;
5685c51f124SMoriah Waterland 		goto cleanup;
5695c51f124SMoriah Waterland 	}
5705c51f124SMoriah Waterland 
5715c51f124SMoriah Waterland 	/* merge certificate into the keystore */
5725c51f124SMoriah Waterland 	if (keystore->cacerts == NULL) {
5735c51f124SMoriah Waterland 		/* no existing truststore, so make a new one */
5745c51f124SMoriah Waterland 		if ((keystore->cacerts = sk_X509_new_null()) == NULL) {
5755c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM));
5765c51f124SMoriah Waterland 			ret = 1;
5775c51f124SMoriah Waterland 			goto cleanup;
5785c51f124SMoriah Waterland 		}
5795c51f124SMoriah Waterland 	} else {
5805c51f124SMoriah Waterland 		/* existing truststore, make sure there's no duplicate */
5815c51f124SMoriah Waterland 		if (sunw_find_fname(fname, NULL, keystore->cacerts,
5825c51f124SMoriah Waterland 		    NULL, &existing) < 0) {
5835c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_INTERNAL,
5845c51f124SMoriah Waterland 			    gettext(ERR_KEYSTORE_INTERNAL),
5855c51f124SMoriah Waterland 			    __FILE__, __LINE__);
5865c51f124SMoriah Waterland 			ERR_print_errors_fp(stderr);
5875c51f124SMoriah Waterland 			ret = 1;
5885c51f124SMoriah Waterland 			goto cleanup;
5895c51f124SMoriah Waterland 			/* could not search properly! */
5905c51f124SMoriah Waterland 		}
5915c51f124SMoriah Waterland 		if (existing != NULL) {
5925c51f124SMoriah Waterland 			/* whoops, found one already */
5935c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_DUPLICATE,
5945c51f124SMoriah Waterland 			    gettext(ERR_KEYSTORE_DUPLICATECERT), fname);
5955c51f124SMoriah Waterland 			ret = 1;
5965c51f124SMoriah Waterland 			goto cleanup;
5975c51f124SMoriah Waterland 		}
5985c51f124SMoriah Waterland 	}
5995c51f124SMoriah Waterland 
6005c51f124SMoriah Waterland 	(void) sk_X509_push(keystore->cacerts, cacert);
6015c51f124SMoriah Waterland 	keystore->dirty = B_TRUE;
6025c51f124SMoriah Waterland cleanup:
6035c51f124SMoriah Waterland 	if (existing != NULL)
6045c51f124SMoriah Waterland 		X509_free(existing);
6055c51f124SMoriah Waterland 	return (ret);
6065c51f124SMoriah Waterland }
6075c51f124SMoriah Waterland 
6085c51f124SMoriah Waterland /*
6095c51f124SMoriah Waterland  * find_key_cert_pair - Searches a keystore for a matching
6105c51f124SMoriah Waterland  * public key certificate and private key, given an alias.
6115c51f124SMoriah Waterland  *
6125c51f124SMoriah Waterland  * Arguments:
6135c51f124SMoriah Waterland  * err - Error object to add errors to
6145c51f124SMoriah Waterland  * ks - Keystore to search
6155c51f124SMoriah Waterland  * alias - Name to used to match certificate's alias
6165c51f124SMoriah Waterland  * key - Resulting key is placed here
6175c51f124SMoriah Waterland  * cert - Resulting cert is placed here
6185c51f124SMoriah Waterland  *
6195c51f124SMoriah Waterland  * Returns:
6205c51f124SMoriah Waterland  *   0 - Success - Matching cert/key pair placed in key and cert.
6215c51f124SMoriah Waterland  * non-zero - Failure, errors recorded in err
6225c51f124SMoriah Waterland  */
6235c51f124SMoriah Waterland int
6245c51f124SMoriah Waterland find_key_cert_pair(PKG_ERR *err, keystore_handle_t ks_h, char *alias,
6255c51f124SMoriah Waterland     EVP_PKEY **key, X509 **cert)
6265c51f124SMoriah Waterland {
6275c51f124SMoriah Waterland 	X509		*tmpcert = NULL;
6285c51f124SMoriah Waterland 	EVP_PKEY	*tmpkey = NULL;
6295c51f124SMoriah Waterland 	int		ret = 0;
6305c51f124SMoriah Waterland 	int		items_found;
6315c51f124SMoriah Waterland 	keystore_t	*ks = ks_h;
6325c51f124SMoriah Waterland 
6335c51f124SMoriah Waterland 	if (key == NULL || cert == NULL) {
6345c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_NOPUBKEY,
6355c51f124SMoriah Waterland 		    gettext(ERR_KEYSTORE_NOPUBCERTS), ks->path);
6365c51f124SMoriah Waterland 		ret = 1;
6375c51f124SMoriah Waterland 		goto cleanup;
6385c51f124SMoriah Waterland 	}
6395c51f124SMoriah Waterland 
6405c51f124SMoriah Waterland 	if (ks->clcerts == NULL) {
6415c51f124SMoriah Waterland 		/* no public certs */
6425c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_NOPUBKEY,
6435c51f124SMoriah Waterland 		    gettext(ERR_KEYSTORE_NOCERTS), ks->path);
6445c51f124SMoriah Waterland 		ret = 1;
6455c51f124SMoriah Waterland 		goto cleanup;
6465c51f124SMoriah Waterland 	}
6475c51f124SMoriah Waterland 	if (ks->pkeys == NULL) {
6485c51f124SMoriah Waterland 		/* no private keys */
6495c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_NOPRIVKEY,
6505c51f124SMoriah Waterland 		    gettext(ERR_KEYSTORE_NOKEYS), ks->path);
6515c51f124SMoriah Waterland 		ret = 1;
6525c51f124SMoriah Waterland 		goto cleanup;
6535c51f124SMoriah Waterland 	}
6545c51f124SMoriah Waterland 
6555c51f124SMoriah Waterland 	/* try the easy case first */
6565c51f124SMoriah Waterland 	if ((sk_EVP_PKEY_num(ks->pkeys) == 1) &&
6575c51f124SMoriah Waterland 	    (sk_X509_num(ks->clcerts) == 1)) {
6585c51f124SMoriah Waterland 		tmpkey = sk_EVP_PKEY_value(ks->pkeys, 0);
6595c51f124SMoriah Waterland 		tmpcert = sk_X509_value(ks->clcerts, 0);
6605c51f124SMoriah Waterland 		if (sunw_check_keys(tmpcert, tmpkey)) {
6615c51f124SMoriah Waterland 			/*
6625c51f124SMoriah Waterland 			 * only one private key and public key cert, and they
6635c51f124SMoriah Waterland 			 * match, so use them
6645c51f124SMoriah Waterland 			 */
6655c51f124SMoriah Waterland 			*key = tmpkey;
6665c51f124SMoriah Waterland 			tmpkey = NULL;
6675c51f124SMoriah Waterland 			*cert = tmpcert;
6685c51f124SMoriah Waterland 			tmpcert = NULL;
6695c51f124SMoriah Waterland 			goto cleanup;
6705c51f124SMoriah Waterland 		}
6715c51f124SMoriah Waterland 	}
6725c51f124SMoriah Waterland 
6735c51f124SMoriah Waterland 	/* Attempt to find the right pair given the alias */
6745c51f124SMoriah Waterland 	items_found = sunw_find_fname(alias, ks->pkeys, ks->clcerts,
6755c51f124SMoriah Waterland 	    &tmpkey, &tmpcert);
6765c51f124SMoriah Waterland 
6775c51f124SMoriah Waterland 	if ((items_found < 0) ||
6785c51f124SMoriah Waterland 	    (items_found & (FOUND_PKEY | FOUND_CERT)) == 0) {
6795c51f124SMoriah Waterland 		/* no key/cert pair found. bail. */
6805c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_BADALIAS,
6815c51f124SMoriah Waterland 		    gettext(ERR_KEYSTORE_NOMATCH), alias);
6825c51f124SMoriah Waterland 		ret = 1;
6835c51f124SMoriah Waterland 		goto cleanup;
6845c51f124SMoriah Waterland 	}
6855c51f124SMoriah Waterland 
6865c51f124SMoriah Waterland 	/* success */
6875c51f124SMoriah Waterland 	*key = tmpkey;
6885c51f124SMoriah Waterland 	tmpkey = NULL;
6895c51f124SMoriah Waterland 	*cert = tmpcert;
6905c51f124SMoriah Waterland 	tmpcert = NULL;
6915c51f124SMoriah Waterland 
6925c51f124SMoriah Waterland cleanup:
6935c51f124SMoriah Waterland 
6945c51f124SMoriah Waterland 	if (tmpcert != NULL)
6955c51f124SMoriah Waterland 		(void) X509_free(tmpcert);
6965c51f124SMoriah Waterland 
6975c51f124SMoriah Waterland 	if (tmpkey != NULL)
6985c51f124SMoriah Waterland 		sunw_evp_pkey_free(tmpkey);
6995c51f124SMoriah Waterland 
7005c51f124SMoriah Waterland 	return (ret);
7015c51f124SMoriah Waterland }
7025c51f124SMoriah Waterland 
7035c51f124SMoriah Waterland /*
7045c51f124SMoriah Waterland  * find_ca_certs - Searches a keystore for trusted certificates
7055c51f124SMoriah Waterland  *
7065c51f124SMoriah Waterland  * Arguments:
7075c51f124SMoriah Waterland  * err - Error object to add errors to
7085c51f124SMoriah Waterland  * ks - Keystore to search
7095c51f124SMoriah Waterland  * cacerts - resulting set of trusted certs are placed here
7105c51f124SMoriah Waterland  *
7115c51f124SMoriah Waterland  * Returns:
7125c51f124SMoriah Waterland  *   0 - Success - trusted cert list returned in cacerts
7135c51f124SMoriah Waterland  * non-zero - Failure, errors recorded in err
7145c51f124SMoriah Waterland  */
7155c51f124SMoriah Waterland int
7165c51f124SMoriah Waterland find_ca_certs(PKG_ERR *err, keystore_handle_t ks_h, STACK_OF(X509) **cacerts)
7175c51f124SMoriah Waterland {
7185c51f124SMoriah Waterland 
7195c51f124SMoriah Waterland 	keystore_t	*ks = ks_h;
7205c51f124SMoriah Waterland 
7215c51f124SMoriah Waterland 	/* easy */
7225c51f124SMoriah Waterland 	if (cacerts == NULL) {
7235c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_INTERNAL,
7245c51f124SMoriah Waterland 		    gettext(ERR_KEYSTORE_INTERNAL), __FILE__, __LINE__);
7255c51f124SMoriah Waterland 		return (1);
7265c51f124SMoriah Waterland 	}
7275c51f124SMoriah Waterland 
7285c51f124SMoriah Waterland 	*cacerts = ks->cacerts;
7295c51f124SMoriah Waterland 	return (0);
7305c51f124SMoriah Waterland }
7315c51f124SMoriah Waterland 
7325c51f124SMoriah Waterland /*
7335c51f124SMoriah Waterland  * find_cl_certs - Searches a keystore for user certificates
7345c51f124SMoriah Waterland  *
7355c51f124SMoriah Waterland  * Arguments:
7365c51f124SMoriah Waterland  * err - Error object to add errors to
7375c51f124SMoriah Waterland  * ks - Keystore to search
7385c51f124SMoriah Waterland  * cacerts - resulting set of user certs are placed here
7395c51f124SMoriah Waterland  *
7405c51f124SMoriah Waterland  * No matching of any kind is performed.
7415c51f124SMoriah Waterland  * Returns:
7425c51f124SMoriah Waterland  *   0 - Success - trusted cert list returned in cacerts
7435c51f124SMoriah Waterland  * non-zero - Failure, errors recorded in err
7445c51f124SMoriah Waterland  */
7455c51f124SMoriah Waterland /* ARGSUSED */
7465c51f124SMoriah Waterland int
7475c51f124SMoriah Waterland find_cl_certs(PKG_ERR *err, keystore_handle_t ks_h, STACK_OF(X509) **clcerts)
7485c51f124SMoriah Waterland {
7495c51f124SMoriah Waterland 	keystore_t	*ks = ks_h;
7505c51f124SMoriah Waterland 
7515c51f124SMoriah Waterland 	/* easy */
7525c51f124SMoriah Waterland 	*clcerts = ks->clcerts;
7535c51f124SMoriah Waterland 	return (0);
7545c51f124SMoriah Waterland }
7555c51f124SMoriah Waterland 
7565c51f124SMoriah Waterland 
7575c51f124SMoriah Waterland /*
7585c51f124SMoriah Waterland  * merge_cert_and_key - Adds a user certificate and matching
7595c51f124SMoriah Waterland  * private key to a keystore.
7605c51f124SMoriah Waterland  * certificate checked for validity dates and non-duplicity.
7615c51f124SMoriah Waterland  *
7625c51f124SMoriah Waterland  * Arguments:
7635c51f124SMoriah Waterland  * err - Error object to add errors to
7645c51f124SMoriah Waterland  * cert - Certificate which to merge into keystore
7655c51f124SMoriah Waterland  * key - matching private key to 'cert'
7665c51f124SMoriah Waterland  * alias - Name which to store the cert and key under
7675c51f124SMoriah Waterland  * keystore - The keystore into which the certificate is merged
7685c51f124SMoriah Waterland  *
7695c51f124SMoriah Waterland  * Returns:
7705c51f124SMoriah Waterland  *   0 - Success - Certificate passes validity, and
7715c51f124SMoriah Waterland  *		is merged into keystore, along with key
7725c51f124SMoriah Waterland  * non-zero - Failure, errors recorded in err
7735c51f124SMoriah Waterland  */
7745c51f124SMoriah Waterland int
7755c51f124SMoriah Waterland merge_cert_and_key(PKG_ERR *err, X509 *cert, EVP_PKEY *key, char *alias,
7765c51f124SMoriah Waterland     keystore_handle_t keystore_h)
7775c51f124SMoriah Waterland {
7785c51f124SMoriah Waterland 	X509		*existingcert = NULL;
7795c51f124SMoriah Waterland 	EVP_PKEY	*existingkey = NULL;
7805c51f124SMoriah Waterland 	int		ret = 0;
7815c51f124SMoriah Waterland 	keystore_t	*keystore = keystore_h;
7825c51f124SMoriah Waterland 
7835c51f124SMoriah Waterland 	/* check validity dates */
7845c51f124SMoriah Waterland 	if (check_cert(err, cert) != 0) {
7855c51f124SMoriah Waterland 		ret = 1;
7865c51f124SMoriah Waterland 		goto cleanup;
7875c51f124SMoriah Waterland 	}
7885c51f124SMoriah Waterland 
7895c51f124SMoriah Waterland 	/* set the friendlyName of the key and cert to the supplied alias */
7905c51f124SMoriah Waterland 	if (sunw_set_fname(alias, key, cert) != 0) {
7915c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM));
7925c51f124SMoriah Waterland 		ret = 1;
7935c51f124SMoriah Waterland 		goto cleanup;
7945c51f124SMoriah Waterland 	}
7955c51f124SMoriah Waterland 
7965c51f124SMoriah Waterland 	/* merge certificate and key into the keystore */
7975c51f124SMoriah Waterland 	if (keystore->clcerts == NULL) {
7985c51f124SMoriah Waterland 		/* no existing truststore, so make a new one */
7995c51f124SMoriah Waterland 		if ((keystore->clcerts = sk_X509_new_null()) == NULL) {
8005c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM));
8015c51f124SMoriah Waterland 			ret = 1;
8025c51f124SMoriah Waterland 			goto cleanup;
8035c51f124SMoriah Waterland 		}
8045c51f124SMoriah Waterland 	} else {
8055c51f124SMoriah Waterland 		/* existing certstore, make sure there's no duplicate */
8065c51f124SMoriah Waterland 		if (sunw_find_fname(alias, NULL, keystore->clcerts,
8075c51f124SMoriah Waterland 		    NULL, &existingcert) < 0) {
8085c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_INTERNAL,
8095c51f124SMoriah Waterland 			    gettext(ERR_KEYSTORE_INTERNAL),
8105c51f124SMoriah Waterland 			    __FILE__, __LINE__);
8115c51f124SMoriah Waterland 			ERR_print_errors_fp(stderr);
8125c51f124SMoriah Waterland 			ret = 1;
8135c51f124SMoriah Waterland 			goto cleanup;
8145c51f124SMoriah Waterland 			/* could not search properly! */
8155c51f124SMoriah Waterland 		}
8165c51f124SMoriah Waterland 		if (existingcert != NULL) {
8175c51f124SMoriah Waterland 			/* whoops, found one already */
8185c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_DUPLICATE,
8195c51f124SMoriah Waterland 			    gettext(ERR_KEYSTORE_DUPLICATECERT), alias);
8205c51f124SMoriah Waterland 			ret = 1;
8215c51f124SMoriah Waterland 			goto cleanup;
8225c51f124SMoriah Waterland 		}
8235c51f124SMoriah Waterland 	}
8245c51f124SMoriah Waterland 
8255c51f124SMoriah Waterland 	if (keystore->pkeys == NULL) {
8265c51f124SMoriah Waterland 		/* no existing keystore, so make a new one */
8275c51f124SMoriah Waterland 		if ((keystore->pkeys = sk_EVP_PKEY_new_null()) == NULL) {
8285c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM));
8295c51f124SMoriah Waterland 			ret = 1;
8305c51f124SMoriah Waterland 			goto cleanup;
8315c51f124SMoriah Waterland 		}
8325c51f124SMoriah Waterland 	} else {
8335c51f124SMoriah Waterland 		/* existing keystore, so make sure there's no duplicate entry */
8345c51f124SMoriah Waterland 		if (sunw_find_fname(alias, keystore->pkeys, NULL,
8355c51f124SMoriah Waterland 		    &existingkey, NULL) < 0) {
8365c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_INTERNAL,
8375c51f124SMoriah Waterland 			    gettext(ERR_KEYSTORE_INTERNAL),
8385c51f124SMoriah Waterland 			    __FILE__, __LINE__);
8395c51f124SMoriah Waterland 			ERR_print_errors_fp(stderr);
8405c51f124SMoriah Waterland 			ret = 1;
8415c51f124SMoriah Waterland 			goto cleanup;
8425c51f124SMoriah Waterland 			/* could not search properly! */
8435c51f124SMoriah Waterland 		}
8445c51f124SMoriah Waterland 		if (existingkey != NULL) {
8455c51f124SMoriah Waterland 			/* whoops, found one already */
8465c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_DUPLICATE,
8475c51f124SMoriah Waterland 			    gettext(ERR_KEYSTORE_DUPLICATEKEY), alias);
8485c51f124SMoriah Waterland 			ret = 1;
8495c51f124SMoriah Waterland 			goto cleanup;
8505c51f124SMoriah Waterland 		}
8515c51f124SMoriah Waterland 	}
8525c51f124SMoriah Waterland 
8535c51f124SMoriah Waterland 	(void) sk_X509_push(keystore->clcerts, cert);
8545c51f124SMoriah Waterland 	(void) sk_EVP_PKEY_push(keystore->pkeys, key);
8555c51f124SMoriah Waterland 	keystore->dirty = B_TRUE;
8565c51f124SMoriah Waterland cleanup:
8575c51f124SMoriah Waterland 	if (existingcert != NULL)
8585c51f124SMoriah Waterland 		(void) X509_free(existingcert);
8595c51f124SMoriah Waterland 	if (existingkey != NULL)
8605c51f124SMoriah Waterland 		(void) sunw_evp_pkey_free(existingkey);
8615c51f124SMoriah Waterland 	return (ret);
8625c51f124SMoriah Waterland }
8635c51f124SMoriah Waterland 
8645c51f124SMoriah Waterland /*
8655c51f124SMoriah Waterland  * delete_cert_and_keys - Deletes one or more certificates
8665c51f124SMoriah Waterland  *  and matching private keys from a keystore.
8675c51f124SMoriah Waterland  *
8685c51f124SMoriah Waterland  * Arguments:
8695c51f124SMoriah Waterland  * err - Error object to add errors to
8705c51f124SMoriah Waterland  * ks - The keystore from which certs and keys are deleted
8715c51f124SMoriah Waterland  * alias - Name which to search for certificates and keys
8725c51f124SMoriah Waterland  *	to delete
8735c51f124SMoriah Waterland  *
8745c51f124SMoriah Waterland  * Returns:
8755c51f124SMoriah Waterland  *   0 - Success - All trusted certs which match 'alias'
8765c51f124SMoriah Waterland  *		are deleted.  All user certificates
8775c51f124SMoriah Waterland  *		which match 'alias' are deleted, along
8785c51f124SMoriah Waterland  *		with the matching private key.
8795c51f124SMoriah Waterland  * non-zero - Failure, errors recorded in err
8805c51f124SMoriah Waterland  */
8815c51f124SMoriah Waterland int
8825c51f124SMoriah Waterland delete_cert_and_keys(PKG_ERR *err, keystore_handle_t ks_h, char *alias)
8835c51f124SMoriah Waterland {
8845c51f124SMoriah Waterland 	X509		*existingcert;
8855c51f124SMoriah Waterland 	EVP_PKEY	*existingkey;
8865c51f124SMoriah Waterland 	int		i;
8875c51f124SMoriah Waterland 	char		*fname = NULL;
8885c51f124SMoriah Waterland 	boolean_t	found = B_FALSE;
8895c51f124SMoriah Waterland 	keystore_t	*ks = ks_h;
8905c51f124SMoriah Waterland 
8915c51f124SMoriah Waterland 	/* delete any and all client certs with the supplied name */
8925c51f124SMoriah Waterland 	if (ks->clcerts != NULL) {
8935c51f124SMoriah Waterland 		for (i = 0; i < sk_X509_num(ks->clcerts); i++) {
8945c51f124SMoriah Waterland 			existingcert = sk_X509_value(ks->clcerts, i);
8955c51f124SMoriah Waterland 			if (sunw_get_cert_fname(GETDO_COPY,
8965c51f124SMoriah Waterland 			    existingcert, &fname) >= 0) {
8975c51f124SMoriah Waterland 				if (streq(fname, alias)) {
8985c51f124SMoriah Waterland 					/* match, so nuke it */
8995c51f124SMoriah Waterland 					existingcert =
9005c51f124SMoriah Waterland 					    sk_X509_delete(ks->clcerts, i);
9015c51f124SMoriah Waterland 					X509_free(existingcert);
9025c51f124SMoriah Waterland 					existingcert = NULL;
9035c51f124SMoriah Waterland 					found = B_TRUE;
9045c51f124SMoriah Waterland 				}
9055c51f124SMoriah Waterland 				(void) OPENSSL_free(fname);
9065c51f124SMoriah Waterland 				fname = NULL;
9075c51f124SMoriah Waterland 			}
9085c51f124SMoriah Waterland 		}
9095c51f124SMoriah Waterland 		if (sk_X509_num(ks->clcerts) <= 0) {
9105c51f124SMoriah Waterland 			/* we deleted all the client certs */
9115c51f124SMoriah Waterland 			sk_X509_free(ks->clcerts);
9125c51f124SMoriah Waterland 			ks->clcerts = NULL;
9135c51f124SMoriah Waterland 		}
9145c51f124SMoriah Waterland 	}
9155c51f124SMoriah Waterland 
9165c51f124SMoriah Waterland 	/* and now the private keys */
9175c51f124SMoriah Waterland 	if (ks->pkeys != NULL) {
9185c51f124SMoriah Waterland 		for (i = 0; i < sk_EVP_PKEY_num(ks->pkeys); i++) {
9195c51f124SMoriah Waterland 			existingkey = sk_EVP_PKEY_value(ks->pkeys, i);
9205c51f124SMoriah Waterland 			if (sunw_get_pkey_fname(GETDO_COPY,
9215c51f124SMoriah Waterland 			    existingkey, &fname) >= 0) {
9225c51f124SMoriah Waterland 				if (streq(fname, alias)) {
9235c51f124SMoriah Waterland 					/* match, so nuke it */
9245c51f124SMoriah Waterland 					existingkey =
9255c51f124SMoriah Waterland 					    sk_EVP_PKEY_delete(ks->pkeys, i);
9265c51f124SMoriah Waterland 					sunw_evp_pkey_free(existingkey);
9275c51f124SMoriah Waterland 					existingkey = NULL;
9285c51f124SMoriah Waterland 					found = B_TRUE;
9295c51f124SMoriah Waterland 				}
9305c51f124SMoriah Waterland 				(void) OPENSSL_free(fname);
9315c51f124SMoriah Waterland 				fname = NULL;
9325c51f124SMoriah Waterland 			}
9335c51f124SMoriah Waterland 		}
9345c51f124SMoriah Waterland 		if (sk_EVP_PKEY_num(ks->pkeys) <= 0) {
9355c51f124SMoriah Waterland 			/* we deleted all the private keys */
9365c51f124SMoriah Waterland 			sk_EVP_PKEY_free(ks->pkeys);
9375c51f124SMoriah Waterland 			ks->pkeys = NULL;
9385c51f124SMoriah Waterland 		}
9395c51f124SMoriah Waterland 	}
9405c51f124SMoriah Waterland 
9415c51f124SMoriah Waterland 	/* finally, remove any trust anchors that match */
9425c51f124SMoriah Waterland 
9435c51f124SMoriah Waterland 	if (ks->cacerts != NULL) {
9445c51f124SMoriah Waterland 		for (i = 0; i < sk_X509_num(ks->cacerts); i++) {
9455c51f124SMoriah Waterland 			existingcert = sk_X509_value(ks->cacerts, i);
9465c51f124SMoriah Waterland 			if (sunw_get_cert_fname(GETDO_COPY,
9475c51f124SMoriah Waterland 			    existingcert, &fname) >= 0) {
9485c51f124SMoriah Waterland 				if (streq(fname, alias)) {
9495c51f124SMoriah Waterland 					/* match, so nuke it */
9505c51f124SMoriah Waterland 					existingcert =
9515c51f124SMoriah Waterland 					    sk_X509_delete(ks->cacerts, i);
9525c51f124SMoriah Waterland 					X509_free(existingcert);
9535c51f124SMoriah Waterland 					existingcert = NULL;
9545c51f124SMoriah Waterland 					found = B_TRUE;
9555c51f124SMoriah Waterland 				}
9565c51f124SMoriah Waterland 				(void) OPENSSL_free(fname);
9575c51f124SMoriah Waterland 				fname = NULL;
9585c51f124SMoriah Waterland 			}
9595c51f124SMoriah Waterland 		}
9605c51f124SMoriah Waterland 		if (sk_X509_num(ks->cacerts) <= 0) {
9615c51f124SMoriah Waterland 			/* we deleted all the CA certs */
9625c51f124SMoriah Waterland 			sk_X509_free(ks->cacerts);
9635c51f124SMoriah Waterland 			ks->cacerts = NULL;
9645c51f124SMoriah Waterland 		}
9655c51f124SMoriah Waterland 	}
9665c51f124SMoriah Waterland 
9675c51f124SMoriah Waterland 	if (found) {
9685c51f124SMoriah Waterland 		ks->dirty = B_TRUE;
9695c51f124SMoriah Waterland 		return (0);
9705c51f124SMoriah Waterland 	} else {
9715c51f124SMoriah Waterland 		/* no certs or keys deleted */
9725c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_NOALIASMATCH,
9735c51f124SMoriah Waterland 		    gettext(ERR_KEYSTORE_NOCERTKEY),
9745c51f124SMoriah Waterland 		    alias, ks->path);
9755c51f124SMoriah Waterland 		return (1);
9765c51f124SMoriah Waterland 	}
9775c51f124SMoriah Waterland }
9785c51f124SMoriah Waterland 
9795c51f124SMoriah Waterland /*
9805c51f124SMoriah Waterland  * check_cert - Checks certificate validity.  This routine
9815c51f124SMoriah Waterland  * checks that the current time falls within the period
9825c51f124SMoriah Waterland  * of validity for the cert.
9835c51f124SMoriah Waterland  *
9845c51f124SMoriah Waterland  * Arguments:
9855c51f124SMoriah Waterland  * err - Error object to add errors to
9865c51f124SMoriah Waterland  * cert - The certificate to check
9875c51f124SMoriah Waterland  *
9885c51f124SMoriah Waterland  * Returns:
9895c51f124SMoriah Waterland  *   0 - Success - Certificate checks out
9905c51f124SMoriah Waterland  * non-zero - Failure, errors and reasons recorded in err
9915c51f124SMoriah Waterland  */
9925c51f124SMoriah Waterland int
9935c51f124SMoriah Waterland check_cert(PKG_ERR *err, X509 *cert)
9945c51f124SMoriah Waterland {
9955c51f124SMoriah Waterland 	char			currtimestr[ATTR_MAX];
9965c51f124SMoriah Waterland 	time_t			currtime;
997*4656d474SGarrett D'Amore 	char			*r;
9985c51f124SMoriah Waterland 	/* get current time */
9995c51f124SMoriah Waterland 	if ((currtime = time(NULL)) == (time_t)-1) {
10005c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_TIME, gettext(ERR_CURR_TIME));
10015c51f124SMoriah Waterland 		return (1);
10025c51f124SMoriah Waterland 	}
10035c51f124SMoriah Waterland 
10045c51f124SMoriah Waterland 	(void) strlcpy(currtimestr, ctime(&currtime), ATTR_MAX);
10055c51f124SMoriah Waterland 
10065c51f124SMoriah Waterland 	/* trim whitespace from end of time string */
10075c51f124SMoriah Waterland 	for (r = (currtimestr + strlen(currtimestr) - 1); isspace(*r); r--) {
10085c51f124SMoriah Waterland 		*r = '\0';
10095c51f124SMoriah Waterland 	}
10105c51f124SMoriah Waterland 	/* check  validity of cert */
10115c51f124SMoriah Waterland 	switch (sunw_check_cert_times(CHK_BOTH, cert)) {
10125c51f124SMoriah Waterland 	case CHKERR_TIME_OK:
10135c51f124SMoriah Waterland 		/* Current time meets requested checks */
10145c51f124SMoriah Waterland 		break;
10155c51f124SMoriah Waterland 	case CHKERR_TIME_BEFORE_BAD:
10165c51f124SMoriah Waterland 		/* 'not before' field is invalid */
10175c51f124SMoriah Waterland 	case CHKERR_TIME_AFTER_BAD:
10185c51f124SMoriah Waterland 		/* 'not after' field is invalid */
10195c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_TIME, gettext(ERR_CERT_TIME_BAD));
10205c51f124SMoriah Waterland 		return (1);
10215c51f124SMoriah Waterland 	case CHKERR_TIME_IS_BEFORE:
10225c51f124SMoriah Waterland 		/* Current time is before 'not before' */
10235c51f124SMoriah Waterland 	case CHKERR_TIME_HAS_EXPIRED:
10245c51f124SMoriah Waterland 		/*
10255c51f124SMoriah Waterland 		 * Ignore expiration time since the trust cert used to
10265c51f124SMoriah Waterland 		 * verify the certs used to sign Sun patches is already
10275c51f124SMoriah Waterland 		 * expired. Once the patches get resigned with the new
10285c51f124SMoriah Waterland 		 * cert we will check expiration against the time the
10295c51f124SMoriah Waterland 		 * patch was signed and not the time it is installed.
10305c51f124SMoriah Waterland 		 */
10315c51f124SMoriah Waterland 		return (0);
10325c51f124SMoriah Waterland 	default:
10335c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_INTERNAL,
10345c51f124SMoriah Waterland 		    gettext(ERR_KEYSTORE_INTERNAL),
10355c51f124SMoriah Waterland 		    __FILE__, __LINE__);
10365c51f124SMoriah Waterland 		return (1);
10375c51f124SMoriah Waterland 	}
10385c51f124SMoriah Waterland 
10395c51f124SMoriah Waterland 	/* all checks ok */
10405c51f124SMoriah Waterland 	return (0);
10415c51f124SMoriah Waterland }
10425c51f124SMoriah Waterland 
10435c51f124SMoriah Waterland /*
10445c51f124SMoriah Waterland  * check_cert - Checks certificate validity.  This routine
10455c51f124SMoriah Waterland  * checks everything that check_cert checks, and additionally
10465c51f124SMoriah Waterland  * verifies that the private key and corresponding public
10475c51f124SMoriah Waterland  * key are indeed a pair.
10485c51f124SMoriah Waterland  *
10495c51f124SMoriah Waterland  * Arguments:
10505c51f124SMoriah Waterland  * err - Error object to add errors to
10515c51f124SMoriah Waterland  * cert - The certificate to check
10525c51f124SMoriah Waterland  * key - the key to check
10535c51f124SMoriah Waterland  * Returns:
10545c51f124SMoriah Waterland  *   0 - Success - Certificate checks out
10555c51f124SMoriah Waterland  * non-zero - Failure, errors and reasons recorded in err
10565c51f124SMoriah Waterland  */
10575c51f124SMoriah Waterland int
10585c51f124SMoriah Waterland check_cert_and_key(PKG_ERR *err, X509 *cert, EVP_PKEY *key)
10595c51f124SMoriah Waterland {
10605c51f124SMoriah Waterland 
10615c51f124SMoriah Waterland 	/* check validity dates */
10625c51f124SMoriah Waterland 	if (check_cert(err, cert) != 0) {
10635c51f124SMoriah Waterland 		return (1);
10645c51f124SMoriah Waterland 	}
10655c51f124SMoriah Waterland 
10665c51f124SMoriah Waterland 	/* check key pair match */
10675c51f124SMoriah Waterland 	if (sunw_check_keys(cert, key) == 0) {
10685c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_VERIFY, gettext(ERR_MISMATCHED_KEYS),
10695c51f124SMoriah Waterland 		    get_subject_display_name(cert));
10705c51f124SMoriah Waterland 		return (1);
10715c51f124SMoriah Waterland 	}
10725c51f124SMoriah Waterland 
10735c51f124SMoriah Waterland 	/* all checks OK */
10745c51f124SMoriah Waterland 	return (0);
10755c51f124SMoriah Waterland }
10765c51f124SMoriah Waterland 
10775c51f124SMoriah Waterland /* ------------------ private functions ---------------------- */
10785c51f124SMoriah Waterland 
10795c51f124SMoriah Waterland /*
10805c51f124SMoriah Waterland  * verify_keystore_integrity - Searches for the remnants
10815c51f124SMoriah Waterland  * of a failed or aborted keystore modification, and
10825c51f124SMoriah Waterland  * cleans up the files, retstores the keystore to a known
10835c51f124SMoriah Waterland  * state.
10845c51f124SMoriah Waterland  *
10855c51f124SMoriah Waterland  * Arguments:
10865c51f124SMoriah Waterland  * err - Error object to add errors to
10875c51f124SMoriah Waterland  * keystore_file - Base directory or filename of keystore
10885c51f124SMoriah Waterland  * app - Application making request
10895c51f124SMoriah Waterland  *
10905c51f124SMoriah Waterland  * Returns:
10915c51f124SMoriah Waterland  *   0 - Success - Keystore is restored, or untouched in the
10925c51f124SMoriah Waterland  *		case that cleanup was unnecessary
10935c51f124SMoriah Waterland  * non-zero - Failure, errors and reasons recorded in err
10945c51f124SMoriah Waterland  */
10955c51f124SMoriah Waterland static boolean_t
10965c51f124SMoriah Waterland verify_keystore_integrity(PKG_ERR *err, keystore_t *keystore)
10975c51f124SMoriah Waterland {
10985c51f124SMoriah Waterland 	if (keystore->capath != NULL) {
10995c51f124SMoriah Waterland 		if (!restore_keystore_file(err, keystore->capath)) {
11005c51f124SMoriah Waterland 			return (B_FALSE);
11015c51f124SMoriah Waterland 		}
11025c51f124SMoriah Waterland 	}
11035c51f124SMoriah Waterland 	if (keystore->clpath != NULL) {
11045c51f124SMoriah Waterland 		if (!restore_keystore_file(err, keystore->clpath)) {
11055c51f124SMoriah Waterland 			return (B_FALSE);
11065c51f124SMoriah Waterland 		}
11075c51f124SMoriah Waterland 	}
11085c51f124SMoriah Waterland 	if (keystore->keypath != NULL) {
11095c51f124SMoriah Waterland 		if (!restore_keystore_file(err, keystore->keypath)) {
11105c51f124SMoriah Waterland 			return (B_FALSE);
11115c51f124SMoriah Waterland 		}
11125c51f124SMoriah Waterland 	}
11135c51f124SMoriah Waterland 	return (B_TRUE);
11145c51f124SMoriah Waterland }
11155c51f124SMoriah Waterland 
11165c51f124SMoriah Waterland /*
11175c51f124SMoriah Waterland  * restore_keystore_file - restores a keystore file to
11185c51f124SMoriah Waterland  * a known state.
11195c51f124SMoriah Waterland  *
11205c51f124SMoriah Waterland  * Keystore files can possibly be corrupted by a variety
11215c51f124SMoriah Waterland  * of error conditions during reading/writing.  This
11225c51f124SMoriah Waterland  * routine, along with write_keystore_file, tries to
11235c51f124SMoriah Waterland  * maintain keystore integrity by writing the files
11245c51f124SMoriah Waterland  * out in a particular order, minimizing the time period
11255c51f124SMoriah Waterland  * that the keystore is in an indeterminate state.
11265c51f124SMoriah Waterland  *
11275c51f124SMoriah Waterland  * With the current implementation, there are some failures
11285c51f124SMoriah Waterland  * that are wholly unrecoverable, such as disk corruption.
11295c51f124SMoriah Waterland  * These routines attempt to minimize the risk, but not
11305c51f124SMoriah Waterland  * eliminate it.  When better, atomic operations are available
11315c51f124SMoriah Waterland  * (such as a trued atabase with commit, rollback, and
11325c51f124SMoriah Waterland  * guaranteed atomicity), this implementation should use that.
11335c51f124SMoriah Waterland  *
11345c51f124SMoriah Waterland  * Arguments:
11355c51f124SMoriah Waterland  * err - Error object to add errors to
11365c51f124SMoriah Waterland  * keystore_file - keystore file path to restore.
11375c51f124SMoriah Waterland  *
11385c51f124SMoriah Waterland  * Returns:
11395c51f124SMoriah Waterland  *   0 - Success - Keystore file is restored, or untouched in the
11405c51f124SMoriah Waterland  *		case that cleanup was unnecessary
11415c51f124SMoriah Waterland  * non-zero - Failure, errors and reasons recorded in err
11425c51f124SMoriah Waterland  */
11435c51f124SMoriah Waterland /* ARGSUSED */
11445c51f124SMoriah Waterland static boolean_t
11455c51f124SMoriah Waterland restore_keystore_file(PKG_ERR *err, char *keystore_file)
11465c51f124SMoriah Waterland {
11475c51f124SMoriah Waterland 	char	newpath[MAXPATHLEN];
11485c51f124SMoriah Waterland 	char	backuppath[MAXPATHLEN];
11495c51f124SMoriah Waterland 	int	newfd;
11505c51f124SMoriah Waterland 	struct stat buf;
11515c51f124SMoriah Waterland 	int len;
11525c51f124SMoriah Waterland 
11535c51f124SMoriah Waterland 	if (((len = snprintf(newpath, MAXPATHLEN, "%s.new",
11545c51f124SMoriah Waterland 	    keystore_file)) < 0) ||
11555c51f124SMoriah Waterland 	    (len >= ATTR_MAX)) {
11565c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN), keystore_file);
11575c51f124SMoriah Waterland 		return (B_FALSE);
11585c51f124SMoriah Waterland 	}
11595c51f124SMoriah Waterland 
11605c51f124SMoriah Waterland 	if (((len = snprintf(backuppath, MAXPATHLEN, "%s.bak",
11615c51f124SMoriah Waterland 	    keystore_file)) < 0) ||
11625c51f124SMoriah Waterland 	    (len >= ATTR_MAX)) {
11635c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN), keystore_file);
11645c51f124SMoriah Waterland 		return (B_FALSE);
11655c51f124SMoriah Waterland 	}
11665c51f124SMoriah Waterland 
11675c51f124SMoriah Waterland 	if ((newfd = open(newpath, O_RDWR|O_NONBLOCK, 0)) != -1) {
11685c51f124SMoriah Waterland 		if (fstat(newfd, &buf) != -1) {
11695c51f124SMoriah Waterland 			if (S_ISREG(buf.st_mode)) {
11705c51f124SMoriah Waterland 				/*
11715c51f124SMoriah Waterland 				 * restore the file, waiting on it
11725c51f124SMoriah Waterland 				 * to be free for locking, or for
11735c51f124SMoriah Waterland 				 * it to disappear
11745c51f124SMoriah Waterland 				 */
11755c51f124SMoriah Waterland 				if (!wait_restore(newfd, keystore_file,
11765c51f124SMoriah Waterland 				    newpath, backuppath)) {
11775c51f124SMoriah Waterland 					pkgerr_add(err, PKGERR_WRITE,
11785c51f124SMoriah Waterland 					    gettext(ERR_WRITE),
11795c51f124SMoriah Waterland 					    newpath, strerror(errno));
11805c51f124SMoriah Waterland 					(void) close(newfd);
11815c51f124SMoriah Waterland 					return (B_FALSE);
11825c51f124SMoriah Waterland 				} else {
11835c51f124SMoriah Waterland 					return (B_TRUE);
11845c51f124SMoriah Waterland 				}
11855c51f124SMoriah Waterland 			} else {
11865c51f124SMoriah Waterland 				/* "new" file is not a regular file */
11875c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_WRITE,
11885c51f124SMoriah Waterland 				    gettext(ERR_NOT_REG), newpath);
11895c51f124SMoriah Waterland 				(void) close(newfd);
11905c51f124SMoriah Waterland 				return (B_FALSE);
11915c51f124SMoriah Waterland 			}
11925c51f124SMoriah Waterland 		} else {
11935c51f124SMoriah Waterland 			/* couldn't stat "new" file */
11945c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_WRITE,
11955c51f124SMoriah Waterland 			    gettext(ERR_WRITE), newpath,
11965c51f124SMoriah Waterland 			    strerror(errno));
11975c51f124SMoriah Waterland 			(void) close(newfd);
11985c51f124SMoriah Waterland 			return (B_FALSE);
11995c51f124SMoriah Waterland 		}
12005c51f124SMoriah Waterland 	} else {
12015c51f124SMoriah Waterland 		/* "new" file doesn't exist */
12025c51f124SMoriah Waterland 		return (B_TRUE);
12035c51f124SMoriah Waterland 	}
12045c51f124SMoriah Waterland }
12055c51f124SMoriah Waterland 
12065c51f124SMoriah Waterland static boolean_t
12075c51f124SMoriah Waterland wait_restore(int newfd, char *keystore_file,
12085c51f124SMoriah Waterland     char *origpath, char *backuppath)
12095c51f124SMoriah Waterland {
12105c51f124SMoriah Waterland 	struct stat buf;
12115c51f124SMoriah Waterland 	FILE *newstream;
12125c51f124SMoriah Waterland 	PKCS12 *p12;
12135c51f124SMoriah Waterland 
12145c51f124SMoriah Waterland 	(void) alarm(LOCK_TIMEOUT);
12155c51f124SMoriah Waterland 	if (file_lock(newfd, F_WRLCK, 1) == -1) {
12165c51f124SMoriah Waterland 		/* could not lock file */
12175c51f124SMoriah Waterland 		(void) alarm(0);
12185c51f124SMoriah Waterland 		return (B_FALSE);
12195c51f124SMoriah Waterland 	}
12205c51f124SMoriah Waterland 	(void) alarm(0);
12215c51f124SMoriah Waterland 
12225c51f124SMoriah Waterland 	if (fstat(newfd, &buf) != -1) {
12235c51f124SMoriah Waterland 		if (S_ISREG(buf.st_mode)) {
12245c51f124SMoriah Waterland 			/*
12255c51f124SMoriah Waterland 			 * The new file still
12265c51f124SMoriah Waterland 			 * exists, with no
12275c51f124SMoriah Waterland 			 * owner.  It must be
12285c51f124SMoriah Waterland 			 * the result of an
12295c51f124SMoriah Waterland 			 * aborted update.
12305c51f124SMoriah Waterland 			 */
12315c51f124SMoriah Waterland 			newstream = fdopen(newfd, "r");
12325c51f124SMoriah Waterland 			if ((p12 =
12335c51f124SMoriah Waterland 			    d2i_PKCS12_fp(newstream,
12345c51f124SMoriah Waterland 				NULL)) != NULL) {
12355c51f124SMoriah Waterland 				/*
12365c51f124SMoriah Waterland 				 * The file
12375c51f124SMoriah Waterland 				 * appears
12385c51f124SMoriah Waterland 				 * complete.
12395c51f124SMoriah Waterland 				 * Replace the
12405c51f124SMoriah Waterland 				 * exsisting
12415c51f124SMoriah Waterland 				 * keystore
12425c51f124SMoriah Waterland 				 * file with
12435c51f124SMoriah Waterland 				 * this one
12445c51f124SMoriah Waterland 				 */
12455c51f124SMoriah Waterland 				(void) rename(keystore_file, backuppath);
12465c51f124SMoriah Waterland 				(void) rename(origpath, keystore_file);
12475c51f124SMoriah Waterland 				PKCS12_free(p12);
12485c51f124SMoriah Waterland 			} else {
12495c51f124SMoriah Waterland 				/* The file is not complete.  Remove it */
12505c51f124SMoriah Waterland 				(void) remove(origpath);
12515c51f124SMoriah Waterland 			}
12525c51f124SMoriah Waterland 			/* remove backup file */
12535c51f124SMoriah Waterland 			(void) remove(backuppath);
12545c51f124SMoriah Waterland 			(void) fclose(newstream);
12555c51f124SMoriah Waterland 			(void) close(newfd);
12565c51f124SMoriah Waterland 			return (B_TRUE);
12575c51f124SMoriah Waterland 		} else {
12585c51f124SMoriah Waterland 			/*
12595c51f124SMoriah Waterland 			 * new file exists, but is not a
12605c51f124SMoriah Waterland 			 * regular file
12615c51f124SMoriah Waterland 			 */
12625c51f124SMoriah Waterland 			(void) close(newfd);
12635c51f124SMoriah Waterland 			return (B_FALSE);
12645c51f124SMoriah Waterland 		}
12655c51f124SMoriah Waterland 	} else {
12665c51f124SMoriah Waterland 		/*
12675c51f124SMoriah Waterland 		 * could not stat file.  Unless
12685c51f124SMoriah Waterland 		 * the reason was that the file
12695c51f124SMoriah Waterland 		 * is now gone, this is an error
12705c51f124SMoriah Waterland 		 */
12715c51f124SMoriah Waterland 		if (errno != ENOENT) {
12725c51f124SMoriah Waterland 			(void) close(newfd);
12735c51f124SMoriah Waterland 			return (B_FALSE);
12745c51f124SMoriah Waterland 		}
12755c51f124SMoriah Waterland 		/*
12765c51f124SMoriah Waterland 		 * otherwise, file is gone.  The process
12775c51f124SMoriah Waterland 		 * that held the lock must have
12785c51f124SMoriah Waterland 		 * successfully cleaned up and
12795c51f124SMoriah Waterland 		 * exited with a valid keystore
12805c51f124SMoriah Waterland 		 * state
12815c51f124SMoriah Waterland 		 */
12825c51f124SMoriah Waterland 		(void) close(newfd);
12835c51f124SMoriah Waterland 		return (B_TRUE);
12845c51f124SMoriah Waterland 	}
12855c51f124SMoriah Waterland }
12865c51f124SMoriah Waterland 
12875c51f124SMoriah Waterland /*
12885c51f124SMoriah Waterland  * resolve_paths - figure out if we are dealing with a single-file
12895c51f124SMoriah Waterland  * or multi-file keystore
12905c51f124SMoriah Waterland  *
12915c51f124SMoriah Waterland  * The flags tell resolve_paths how to behave:
12925c51f124SMoriah Waterland  *
12935c51f124SMoriah Waterland  * KEYSTORE_PATH_SOFT
12945c51f124SMoriah Waterland  * If the keystore file does not exist at <base>/<app> then
12955c51f124SMoriah Waterland  * use <base> as the path to the keystore.  This can be used,
12965c51f124SMoriah Waterland  * for example, to access an app-specific keystore iff it
12975c51f124SMoriah Waterland  * exists, otherwise revert back to an app-generic keystore.
12985c51f124SMoriah Waterland  *
12995c51f124SMoriah Waterland  * KEYSTORE_PATH_HARD
13005c51f124SMoriah Waterland  * Always use the keystore located at <keystore_path>/<app>.
13015c51f124SMoriah Waterland  * In read/write mode, if the files do not exist, then
13025c51f124SMoriah Waterland  * they will be created.  This is used to avoid falling
13035c51f124SMoriah Waterland  * back to an app-generic keystore path when the app-specific
13045c51f124SMoriah Waterland  * one does not exist.
13055c51f124SMoriah Waterland  *
13065c51f124SMoriah Waterland  * Arguments:
13075c51f124SMoriah Waterland  * err - Error object to add errors to
13085c51f124SMoriah Waterland  * keystore_file - base keystore file path to lock
13095c51f124SMoriah Waterland  * app - Application making requests
13105c51f124SMoriah Waterland  * flags - Control flags (see above description)
13115c51f124SMoriah Waterland  * keystore - object which is being locked
13125c51f124SMoriah Waterland  *
13135c51f124SMoriah Waterland  * Returns:
13145c51f124SMoriah Waterland  *   B_TRUE - Success - Keystore file is locked, paths to
13155c51f124SMoriah Waterland  *		appropriate files placed in keystore.
13165c51f124SMoriah Waterland  *   B_FALSE - Failure, errors and reasons recorded in err
13175c51f124SMoriah Waterland  */
13185c51f124SMoriah Waterland static boolean_t
13195c51f124SMoriah Waterland resolve_paths(PKG_ERR *err, char *keystore_file, char *app,
13205c51f124SMoriah Waterland     long flags, keystore_t *keystore)
13215c51f124SMoriah Waterland {
13225c51f124SMoriah Waterland 	char			storepath[PATH_MAX];
13235c51f124SMoriah Waterland 	struct stat		buf;
13245c51f124SMoriah Waterland 	boolean_t		multi = B_FALSE;
13255c51f124SMoriah Waterland 	int			fd1, fd2, len;
13265c51f124SMoriah Waterland 
13275c51f124SMoriah Waterland 	/*
13285c51f124SMoriah Waterland 	 * figure out whether we are dealing with a single-file keystore
13295c51f124SMoriah Waterland 	 * or a multi-file keystore
13305c51f124SMoriah Waterland 	 */
13315c51f124SMoriah Waterland 	if (app != NULL) {
13325c51f124SMoriah Waterland 		if (((len = snprintf(storepath, PATH_MAX, "%s/%s",
13335c51f124SMoriah Waterland 		    keystore_file, app)) < 0) ||
13345c51f124SMoriah Waterland 		    (len >= ATTR_MAX)) {
13355c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN),
13365c51f124SMoriah Waterland 			    keystore_file);
13375c51f124SMoriah Waterland 			return (B_FALSE);
13385c51f124SMoriah Waterland 		}
13395c51f124SMoriah Waterland 
13405c51f124SMoriah Waterland 		if (((fd1 = open(storepath, O_NONBLOCK|O_RDONLY)) == -1) ||
13415c51f124SMoriah Waterland 		    (fstat(fd1, &buf) == -1) ||
13425c51f124SMoriah Waterland 		    !S_ISDIR(buf.st_mode)) {
13435c51f124SMoriah Waterland 			/*
13445c51f124SMoriah Waterland 			 * app-specific does not exist
13455c51f124SMoriah Waterland 			 * fallback to app-generic, if flags say we can
13465c51f124SMoriah Waterland 			 */
13475c51f124SMoriah Waterland 			if ((flags & KEYSTORE_PATH_MASK) ==
13485c51f124SMoriah Waterland 			    KEYSTORE_PATH_SOFT) {
13495c51f124SMoriah Waterland 
13505c51f124SMoriah Waterland 				if (((fd2 = open(keystore_file,
13515c51f124SMoriah Waterland 				    O_NONBLOCK|O_RDONLY)) != -1) &&
13525c51f124SMoriah Waterland 				    (fstat(fd2, &buf) != -1)) {
13535c51f124SMoriah Waterland 					if (S_ISDIR(buf.st_mode)) {
13545c51f124SMoriah Waterland 						/*
13555c51f124SMoriah Waterland 						 * app-generic dir
13565c51f124SMoriah Waterland 						 * exists, so use it
13575c51f124SMoriah Waterland 						 * as a multi-file
13585c51f124SMoriah Waterland 						 * keystore
13595c51f124SMoriah Waterland 						 */
13605c51f124SMoriah Waterland 						multi = B_TRUE;
13615c51f124SMoriah Waterland 						app = NULL;
13625c51f124SMoriah Waterland 					} else if (S_ISREG(buf.st_mode)) {
13635c51f124SMoriah Waterland 						/*
13645c51f124SMoriah Waterland 						 * app-generic file exists, so
13655c51f124SMoriah Waterland 						 * use it as a single file ks
13665c51f124SMoriah Waterland 						 */
13675c51f124SMoriah Waterland 						multi = B_FALSE;
13685c51f124SMoriah Waterland 						app = NULL;
13695c51f124SMoriah Waterland 					}
13705c51f124SMoriah Waterland 				}
13715c51f124SMoriah Waterland 			}
13725c51f124SMoriah Waterland 		}
13735c51f124SMoriah Waterland 		if (fd1 != -1)
13745c51f124SMoriah Waterland 			(void) close(fd1);
13755c51f124SMoriah Waterland 		if (fd2 != -1)
13765c51f124SMoriah Waterland 			(void) close(fd2);
13775c51f124SMoriah Waterland 	} else {
13785c51f124SMoriah Waterland 		if (((fd1 = open(keystore_file,
13795c51f124SMoriah Waterland 		    O_NONBLOCK|O_RDONLY)) != -1) &&
13805c51f124SMoriah Waterland 		    (fstat(fd1, &buf) != -1) &&
13815c51f124SMoriah Waterland 		    S_ISDIR(buf.st_mode)) {
13825c51f124SMoriah Waterland 			/*
13835c51f124SMoriah Waterland 			 * app-generic dir exists, so use
13845c51f124SMoriah Waterland 			 * it as a multi-file keystore
13855c51f124SMoriah Waterland 			 */
13865c51f124SMoriah Waterland 			multi = B_TRUE;
13875c51f124SMoriah Waterland 		}
13885c51f124SMoriah Waterland 		if (fd1 != -1)
13895c51f124SMoriah Waterland 			(void) close(fd1);
13905c51f124SMoriah Waterland 	}
13915c51f124SMoriah Waterland 
13925c51f124SMoriah Waterland 	if (app != NULL) {
13935c51f124SMoriah Waterland 		/* app-specific keystore */
13945c51f124SMoriah Waterland 		(void) snprintf(storepath, PATH_MAX, "%s/%s/%s",
13955c51f124SMoriah Waterland 		    keystore_file, app, TRUSTSTORE);
13965c51f124SMoriah Waterland 		keystore->capath = xstrdup(storepath);
13975c51f124SMoriah Waterland 		(void) snprintf(storepath, PATH_MAX, "%s/%s/%s",
13985c51f124SMoriah Waterland 		    keystore_file, app, CERTSTORE);
13995c51f124SMoriah Waterland 		keystore->clpath = xstrdup(storepath);
14005c51f124SMoriah Waterland 		(void) snprintf(storepath, PATH_MAX, "%s/%s/%s",
14015c51f124SMoriah Waterland 		    keystore_file, app, KEYSTORE);
14025c51f124SMoriah Waterland 		keystore->keypath = xstrdup(storepath);
14035c51f124SMoriah Waterland 	} else {
14045c51f124SMoriah Waterland 		/* app-generic keystore */
14055c51f124SMoriah Waterland 		if (!multi) {
14065c51f124SMoriah Waterland 			/* single-file app-generic keystore */
14075c51f124SMoriah Waterland 			keystore->capath = xstrdup(keystore_file);
14085c51f124SMoriah Waterland 			keystore->keypath = NULL;
14095c51f124SMoriah Waterland 			keystore->clpath = NULL;
14105c51f124SMoriah Waterland 		} else {
14115c51f124SMoriah Waterland 			/* multi-file app-generic keystore */
14125c51f124SMoriah Waterland 			(void) snprintf(storepath, PATH_MAX, "%s/%s",
14135c51f124SMoriah Waterland 			    keystore_file, TRUSTSTORE);
14145c51f124SMoriah Waterland 			keystore->capath = xstrdup(storepath);
14155c51f124SMoriah Waterland 			(void) snprintf(storepath, PATH_MAX, "%s/%s",
14165c51f124SMoriah Waterland 			    keystore_file, CERTSTORE);
14175c51f124SMoriah Waterland 			keystore->clpath = xstrdup(storepath);
14185c51f124SMoriah Waterland 			(void) snprintf(storepath, PATH_MAX, "%s/%s",
14195c51f124SMoriah Waterland 			    keystore_file, KEYSTORE);
14205c51f124SMoriah Waterland 			keystore->keypath = xstrdup(storepath);
14215c51f124SMoriah Waterland 		}
14225c51f124SMoriah Waterland 	}
14235c51f124SMoriah Waterland 
14245c51f124SMoriah Waterland 	return (B_TRUE);
14255c51f124SMoriah Waterland }
14265c51f124SMoriah Waterland 
14275c51f124SMoriah Waterland /*
14285c51f124SMoriah Waterland  * lock_keystore - Locks a keystore for shared (read-only)
14295c51f124SMoriah Waterland  * or exclusive (read-write) access.
14305c51f124SMoriah Waterland  *
14315c51f124SMoriah Waterland  * The flags tell lock_keystore how to behave:
14325c51f124SMoriah Waterland  *
14335c51f124SMoriah Waterland  * KEYSTORE_ACCESS_READONLY
14345c51f124SMoriah Waterland  * opens keystore read-only.  Attempts to modify results in an error
14355c51f124SMoriah Waterland  *
14365c51f124SMoriah Waterland  * KEYSTORE_ACCESS_READWRITE
14375c51f124SMoriah Waterland  * opens keystore read-write
14385c51f124SMoriah Waterland  *
14395c51f124SMoriah Waterland  * KEYSTORE_PATH_SOFT
14405c51f124SMoriah Waterland  * If the keystore file does not exist at <base>/<app> then
14415c51f124SMoriah Waterland  * use <base> as the path to the keystore.  This can be used,
14425c51f124SMoriah Waterland  * for example, to access an app-specific keystore iff it
14435c51f124SMoriah Waterland  * exists, otherwise revert back to an app-generic keystore.
14445c51f124SMoriah Waterland  *
14455c51f124SMoriah Waterland  * KEYSTORE_PATH_HARD
14465c51f124SMoriah Waterland  * Always use the keystore located at <keystore_path>/<app>.
14475c51f124SMoriah Waterland  * In read/write mode, if the files do not exist, then
14485c51f124SMoriah Waterland  * they will be created.  This is used to avoid falling
14495c51f124SMoriah Waterland  * back to an app-generic keystore path when the app-specific
14505c51f124SMoriah Waterland  * one does not exist.
14515c51f124SMoriah Waterland  *
14525c51f124SMoriah Waterland  * Arguments:
14535c51f124SMoriah Waterland  * err - Error object to add errors to
14545c51f124SMoriah Waterland  * flags - Control flags (see above description)
14555c51f124SMoriah Waterland  * keystore - object which is being locked
14565c51f124SMoriah Waterland  *
14575c51f124SMoriah Waterland  * Returns:
14585c51f124SMoriah Waterland  *   0 - Success - Keystore file is locked, paths to
14595c51f124SMoriah Waterland  *		appropriate files placed in keystore.
14605c51f124SMoriah Waterland  * non-zero - Failure, errors and reasons recorded in err
14615c51f124SMoriah Waterland  */
14625c51f124SMoriah Waterland static boolean_t
14635c51f124SMoriah Waterland lock_keystore(PKG_ERR *err, long flags, keystore_t *keystore)
14645c51f124SMoriah Waterland {
14655c51f124SMoriah Waterland 	boolean_t		ret = B_TRUE;
14665c51f124SMoriah Waterland 	struct stat		buf;
14675c51f124SMoriah Waterland 
14685c51f124SMoriah Waterland 	switch (flags & KEYSTORE_ACCESS_MASK) {
14695c51f124SMoriah Waterland 	case KEYSTORE_ACCESS_READONLY:
14705c51f124SMoriah Waterland 		if ((keystore->cafd =
14715c51f124SMoriah Waterland 		    open(keystore->capath, O_NONBLOCK|O_RDONLY)) == -1) {
14725c51f124SMoriah Waterland 			if (errno == ENOENT) {
14735c51f124SMoriah Waterland 				/*
14745c51f124SMoriah Waterland 				 * no keystore.  try to create an
14755c51f124SMoriah Waterland 				 * empty one so we can lock on it and
14765c51f124SMoriah Waterland 				 * prevent others from gaining
14775c51f124SMoriah Waterland 				 * exclusive access.  It will be
14785c51f124SMoriah Waterland 				 * deleted when the keystore is closed.
14795c51f124SMoriah Waterland 				 */
14805c51f124SMoriah Waterland 				if ((keystore->cafd =
14815c51f124SMoriah Waterland 				    open(keystore->capath,
14825c51f124SMoriah Waterland 					O_NONBLOCK|O_RDWR|O_CREAT|O_EXCL,
14835c51f124SMoriah Waterland 					S_IRUSR|S_IWUSR)) == -1) {
14845c51f124SMoriah Waterland 					pkgerr_add(err, PKGERR_READ,
14855c51f124SMoriah Waterland 					    gettext(ERR_NO_KEYSTORE),
14865c51f124SMoriah Waterland 					    keystore->capath);
14875c51f124SMoriah Waterland 					ret = B_FALSE;
14885c51f124SMoriah Waterland 					goto cleanup;
14895c51f124SMoriah Waterland 				}
14905c51f124SMoriah Waterland 			} else {
14915c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_READ,
14925c51f124SMoriah Waterland 				    gettext(ERR_KEYSTORE_OPEN),
14935c51f124SMoriah Waterland 				    keystore->capath, strerror(errno));
14945c51f124SMoriah Waterland 				ret = B_FALSE;
14955c51f124SMoriah Waterland 				goto cleanup;
14965c51f124SMoriah Waterland 			}
14975c51f124SMoriah Waterland 		}
14985c51f124SMoriah Waterland 		if (fstat(keystore->cafd, &buf) != -1) {
14995c51f124SMoriah Waterland 			if (S_ISREG(buf.st_mode)) {
15005c51f124SMoriah Waterland 				if (file_lock(keystore->cafd, F_RDLCK,
15015c51f124SMoriah Waterland 				    0) == -1) {
15025c51f124SMoriah Waterland 					pkgerr_add(err, PKGERR_LOCKED,
15035c51f124SMoriah Waterland 					    gettext(ERR_KEYSTORE_LOCKED_READ),
15045c51f124SMoriah Waterland 					    keystore->capath);
15055c51f124SMoriah Waterland 					ret = B_FALSE;
15065c51f124SMoriah Waterland 					goto cleanup;
15075c51f124SMoriah Waterland 				}
15085c51f124SMoriah Waterland 			} else {
15095c51f124SMoriah Waterland 				/* ca file not a regular file! */
15105c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_READ,
15115c51f124SMoriah Waterland 				    gettext(ERR_NOT_REG),
15125c51f124SMoriah Waterland 				    keystore->capath);
15135c51f124SMoriah Waterland 				ret = B_FALSE;
15145c51f124SMoriah Waterland 				goto cleanup;
15155c51f124SMoriah Waterland 			}
15165c51f124SMoriah Waterland 		} else {
15175c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_READ,
15185c51f124SMoriah Waterland 			    gettext(ERR_KEYSTORE_OPEN),
15195c51f124SMoriah Waterland 			    keystore->capath, strerror(errno));
15205c51f124SMoriah Waterland 			ret = B_FALSE;
15215c51f124SMoriah Waterland 			goto cleanup;
15225c51f124SMoriah Waterland 		}
15235c51f124SMoriah Waterland 		break;
15245c51f124SMoriah Waterland 	case KEYSTORE_ACCESS_READWRITE:
15255c51f124SMoriah Waterland 
15265c51f124SMoriah Waterland 		if ((keystore->cafd = open(keystore->capath,
15275c51f124SMoriah Waterland 		    O_RDWR|O_NONBLOCK)) == -1) {
15285c51f124SMoriah Waterland 			/* does not exist.  try to create an empty one */
15295c51f124SMoriah Waterland 			if (errno == ENOENT) {
15305c51f124SMoriah Waterland 				if ((keystore->cafd =
15315c51f124SMoriah Waterland 				    open(keystore->capath,
15325c51f124SMoriah Waterland 					O_NONBLOCK|O_RDWR|O_CREAT|O_EXCL,
15335c51f124SMoriah Waterland 					S_IRUSR|S_IWUSR)) == -1) {
15345c51f124SMoriah Waterland 					pkgerr_add(err, PKGERR_READ,
15355c51f124SMoriah Waterland 					    gettext(ERR_KEYSTORE_WRITE),
15365c51f124SMoriah Waterland 					    keystore->capath);
15375c51f124SMoriah Waterland 					ret = B_FALSE;
15385c51f124SMoriah Waterland 					goto cleanup;
15395c51f124SMoriah Waterland 				}
15405c51f124SMoriah Waterland 			} else {
15415c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_READ,
15425c51f124SMoriah Waterland 				    gettext(ERR_KEYSTORE_OPEN),
15435c51f124SMoriah Waterland 				    keystore->capath, strerror(errno));
15445c51f124SMoriah Waterland 				ret = B_FALSE;
15455c51f124SMoriah Waterland 				goto cleanup;
15465c51f124SMoriah Waterland 			}
15475c51f124SMoriah Waterland 		}
15485c51f124SMoriah Waterland 		if (fstat(keystore->cafd, &buf) != -1) {
15495c51f124SMoriah Waterland 			if (S_ISREG(buf.st_mode)) {
15505c51f124SMoriah Waterland 				if (file_lock(keystore->cafd, F_WRLCK,
15515c51f124SMoriah Waterland 				    0) == -1) {
15525c51f124SMoriah Waterland 					pkgerr_add(err, PKGERR_LOCKED,
15535c51f124SMoriah Waterland 					    gettext(ERR_KEYSTORE_LOCKED),
15545c51f124SMoriah Waterland 					    keystore->capath);
15555c51f124SMoriah Waterland 					ret = B_FALSE;
15565c51f124SMoriah Waterland 					goto cleanup;
15575c51f124SMoriah Waterland 				}
15585c51f124SMoriah Waterland 			} else {
15595c51f124SMoriah Waterland 				/* ca file not a regular file! */
15605c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_READ,
15615c51f124SMoriah Waterland 				    gettext(ERR_NOT_REG),
15625c51f124SMoriah Waterland 				    keystore->capath);
15635c51f124SMoriah Waterland 				ret = B_FALSE;
15645c51f124SMoriah Waterland 				goto cleanup;
15655c51f124SMoriah Waterland 			}
15665c51f124SMoriah Waterland 		} else {
15675c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_READ,
15685c51f124SMoriah Waterland 			    gettext(ERR_KEYSTORE_OPEN),
15695c51f124SMoriah Waterland 			    keystore->capath, strerror(errno));
15705c51f124SMoriah Waterland 			ret = B_FALSE;
15715c51f124SMoriah Waterland 			goto cleanup;
15725c51f124SMoriah Waterland 		}
15735c51f124SMoriah Waterland 
15745c51f124SMoriah Waterland 		break;
15755c51f124SMoriah Waterland 	default:
15765c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_INTERNAL,
15775c51f124SMoriah Waterland 		    gettext(ERR_KEYSTORE_INTERNAL),
15785c51f124SMoriah Waterland 		    __FILE__, __LINE__);
15795c51f124SMoriah Waterland 		ret = B_FALSE;
15805c51f124SMoriah Waterland 		goto cleanup;
15815c51f124SMoriah Waterland 	}
15825c51f124SMoriah Waterland 
15835c51f124SMoriah Waterland cleanup:
15845c51f124SMoriah Waterland 	if (!ret) {
15855c51f124SMoriah Waterland 		if (keystore->cafd > 0) {
15865c51f124SMoriah Waterland 			(void) file_unlock(keystore->cafd);
15875c51f124SMoriah Waterland 			(void) close(keystore->cafd);
15885c51f124SMoriah Waterland 			keystore->cafd = -1;
15895c51f124SMoriah Waterland 		}
15905c51f124SMoriah Waterland 
15915c51f124SMoriah Waterland 		if (keystore->capath != NULL)
15925c51f124SMoriah Waterland 			free(keystore->capath);
15935c51f124SMoriah Waterland 		if (keystore->clpath != NULL)
15945c51f124SMoriah Waterland 			free(keystore->clpath);
15955c51f124SMoriah Waterland 		if (keystore->keypath != NULL)
15965c51f124SMoriah Waterland 			free(keystore->keypath);
15975c51f124SMoriah Waterland 		keystore->capath = NULL;
15985c51f124SMoriah Waterland 		keystore->clpath = NULL;
15995c51f124SMoriah Waterland 		keystore->keypath = NULL;
16005c51f124SMoriah Waterland 	}
16015c51f124SMoriah Waterland 
16025c51f124SMoriah Waterland 	return (ret);
16035c51f124SMoriah Waterland }
16045c51f124SMoriah Waterland 
16055c51f124SMoriah Waterland /*
16065c51f124SMoriah Waterland  * unlock_keystore - Unocks a keystore
16075c51f124SMoriah Waterland  *
16085c51f124SMoriah Waterland  * Arguments:
16095c51f124SMoriah Waterland  * err - Error object to add errors to
16105c51f124SMoriah Waterland  * keystore - keystore object to unlock
16115c51f124SMoriah Waterland  * Returns:
16125c51f124SMoriah Waterland  *   0 - Success - Keystore files are unlocked, files are closed,
16135c51f124SMoriah Waterland  * non-zero - Failure, errors and reasons recorded in err
16145c51f124SMoriah Waterland  */
16155c51f124SMoriah Waterland /* ARGSUSED */
16165c51f124SMoriah Waterland static boolean_t
16175c51f124SMoriah Waterland unlock_keystore(PKG_ERR *err, keystore_t *keystore)
16185c51f124SMoriah Waterland {
16195c51f124SMoriah Waterland 
16205c51f124SMoriah Waterland 	/*
16215c51f124SMoriah Waterland 	 * Release lock on the CA file.
16225c51f124SMoriah Waterland 	 * Delete file if it is empty
16235c51f124SMoriah Waterland 	 */
16245c51f124SMoriah Waterland 	if (file_empty(keystore->capath)) {
16255c51f124SMoriah Waterland 		(void) remove(keystore->capath);
16265c51f124SMoriah Waterland 	}
16275c51f124SMoriah Waterland 
16285c51f124SMoriah Waterland 	(void) file_unlock(keystore->cafd);
16295c51f124SMoriah Waterland 	(void) close(keystore->cafd);
16305c51f124SMoriah Waterland 	return (B_TRUE);
16315c51f124SMoriah Waterland }
16325c51f124SMoriah Waterland 
16335c51f124SMoriah Waterland /*
16345c51f124SMoriah Waterland  * read_keystore - Reads keystore files of disk, parses
16355c51f124SMoriah Waterland  * into internal structures.
16365c51f124SMoriah Waterland  *
16375c51f124SMoriah Waterland  * Arguments:
16385c51f124SMoriah Waterland  * err - Error object to add errors to
16395c51f124SMoriah Waterland  * keystore - keystore object to read into
16405c51f124SMoriah Waterland  * cb - callback to get password, if required
16415c51f124SMoriah Waterland  * Returns:
16425c51f124SMoriah Waterland  *   0 - Success - Keystore files are read, and placed
16435c51f124SMoriah Waterland  * into keystore structure.
16445c51f124SMoriah Waterland  * non-zero - Failure, errors and reasons recorded in err
16455c51f124SMoriah Waterland  */
16465c51f124SMoriah Waterland static boolean_t
16475c51f124SMoriah Waterland read_keystore(PKG_ERR *err, keystore_t *keystore, keystore_passphrase_cb cb)
16485c51f124SMoriah Waterland {
16495c51f124SMoriah Waterland 	boolean_t	ret = B_TRUE;
16505c51f124SMoriah Waterland 	PKCS12		*p12 = NULL;
16515c51f124SMoriah Waterland 	boolean_t	ca_empty;
16525c51f124SMoriah Waterland 	boolean_t	have_passwd = B_FALSE;
16535c51f124SMoriah Waterland 	boolean_t	cl_empty = B_TRUE;
16545c51f124SMoriah Waterland 	boolean_t	key_empty = B_TRUE;
16555c51f124SMoriah Waterland 
16565c51f124SMoriah Waterland 	ca_empty = file_empty(keystore->capath);
16575c51f124SMoriah Waterland 
16585c51f124SMoriah Waterland 	if (keystore->clpath != NULL)
16595c51f124SMoriah Waterland 		cl_empty = file_empty(keystore->clpath);
16605c51f124SMoriah Waterland 	if (keystore->keypath != NULL)
16615c51f124SMoriah Waterland 		key_empty = file_empty(keystore->keypath);
16625c51f124SMoriah Waterland 
16635c51f124SMoriah Waterland 	if (ca_empty && cl_empty && key_empty) {
16645c51f124SMoriah Waterland 	    keystore->new = B_TRUE;
16655c51f124SMoriah Waterland 	}
16665c51f124SMoriah Waterland 
16675c51f124SMoriah Waterland 	if (!ca_empty) {
16685c51f124SMoriah Waterland 		/* first read the ca file */
16695c51f124SMoriah Waterland 		if ((p12 = read_keystore_file(err,
16705c51f124SMoriah Waterland 		    keystore->capath)) == NULL) {
16715c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_CORRUPT,
16725c51f124SMoriah Waterland 			    gettext(ERR_KEYSTORE_CORRUPT), keystore->capath);
16735c51f124SMoriah Waterland 			ret = B_FALSE;
16745c51f124SMoriah Waterland 			goto cleanup;
16755c51f124SMoriah Waterland 		}
16765c51f124SMoriah Waterland 
16775c51f124SMoriah Waterland 		/* Get password, using callback if necessary */
16785c51f124SMoriah Waterland 		if (!have_passwd) {
16795c51f124SMoriah Waterland 			if (!get_keystore_passwd(err, p12, cb, keystore)) {
16805c51f124SMoriah Waterland 				ret = B_FALSE;
16815c51f124SMoriah Waterland 				goto cleanup;
16825c51f124SMoriah Waterland 			}
16835c51f124SMoriah Waterland 			have_passwd = B_TRUE;
16845c51f124SMoriah Waterland 		}
16855c51f124SMoriah Waterland 
16865c51f124SMoriah Waterland 		/* decrypt and parse keystore file */
16875c51f124SMoriah Waterland 		if (sunw_PKCS12_contents(p12, keystore->passphrase,
16885c51f124SMoriah Waterland 		    &keystore->pkeys, &keystore->cacerts) < 0) {
16895c51f124SMoriah Waterland 			/* could not parse the contents */
16905c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_CORRUPT,
16915c51f124SMoriah Waterland 			    gettext(ERR_KEYSTORE_CORRUPT), keystore->capath);
16925c51f124SMoriah Waterland 			ret = B_FALSE;
16935c51f124SMoriah Waterland 			goto cleanup;
16945c51f124SMoriah Waterland 		}
16955c51f124SMoriah Waterland 
16965c51f124SMoriah Waterland 		PKCS12_free(p12);
16975c51f124SMoriah Waterland 		p12 = NULL;
16985c51f124SMoriah Waterland 	} else {
16995c51f124SMoriah Waterland 
17005c51f124SMoriah Waterland 		/*
17015c51f124SMoriah Waterland 		 * truststore is empty, so we don't have any trusted
17025c51f124SMoriah Waterland 		 * certs
17035c51f124SMoriah Waterland 		 */
17045c51f124SMoriah Waterland 		keystore->cacerts = NULL;
17055c51f124SMoriah Waterland 	}
17065c51f124SMoriah Waterland 
17075c51f124SMoriah Waterland 	/*
17085c51f124SMoriah Waterland 	 * if there is no cl file or key file, use the cl's and key's found
17095c51f124SMoriah Waterland 	 * in the ca file
17105c51f124SMoriah Waterland 	 */
17115c51f124SMoriah Waterland 	if (keystore->clpath == NULL && !ca_empty) {
17125c51f124SMoriah Waterland 		if (sunw_split_certs(keystore->pkeys, keystore->cacerts,
17135c51f124SMoriah Waterland 		    &keystore->clcerts, NULL) < 0) {
17145c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_CORRUPT,
17155c51f124SMoriah Waterland 			    gettext(ERR_KEYSTORE_CORRUPT), keystore->capath);
17165c51f124SMoriah Waterland 			ret = B_FALSE;
17175c51f124SMoriah Waterland 			goto cleanup;
17185c51f124SMoriah Waterland 		}
17195c51f124SMoriah Waterland 	} else {
17205c51f124SMoriah Waterland 		/*
17215c51f124SMoriah Waterland 		 * files are in separate files.  read keys out of the keystore
17225c51f124SMoriah Waterland 		 * certs out of the certstore, if they are not empty
17235c51f124SMoriah Waterland 		 */
17245c51f124SMoriah Waterland 		if (!cl_empty) {
17255c51f124SMoriah Waterland 			if ((p12 = read_keystore_file(err,
17265c51f124SMoriah Waterland 			    keystore->clpath)) == NULL) {
17275c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_CORRUPT,
17285c51f124SMoriah Waterland 				    gettext(ERR_KEYSTORE_CORRUPT),
17295c51f124SMoriah Waterland 				    keystore->clpath);
17305c51f124SMoriah Waterland 				ret = B_FALSE;
17315c51f124SMoriah Waterland 				goto cleanup;
17325c51f124SMoriah Waterland 			}
17335c51f124SMoriah Waterland 
17345c51f124SMoriah Waterland 			/* Get password, using callback if necessary */
17355c51f124SMoriah Waterland 			if (!have_passwd) {
17365c51f124SMoriah Waterland 				if (!get_keystore_passwd(err, p12, cb,
17375c51f124SMoriah Waterland 				    keystore)) {
17385c51f124SMoriah Waterland 					ret = B_FALSE;
17395c51f124SMoriah Waterland 					goto cleanup;
17405c51f124SMoriah Waterland 				}
17415c51f124SMoriah Waterland 				have_passwd = B_TRUE;
17425c51f124SMoriah Waterland 			}
17435c51f124SMoriah Waterland 
17445c51f124SMoriah Waterland 			if (check_password(p12,
17455c51f124SMoriah Waterland 			    keystore->passphrase) == B_FALSE) {
17465c51f124SMoriah Waterland 				/*
17475c51f124SMoriah Waterland 				 * password in client cert file
17485c51f124SMoriah Waterland 				 * is different than
17495c51f124SMoriah Waterland 				 * the one in the other files!
17505c51f124SMoriah Waterland 				 */
17515c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_BADPASS,
17525c51f124SMoriah Waterland 				    gettext(ERR_MISMATCHPASS),
17535c51f124SMoriah Waterland 				    keystore->clpath,
17545c51f124SMoriah Waterland 				    keystore->capath, keystore->path);
17555c51f124SMoriah Waterland 				ret = B_FALSE;
17565c51f124SMoriah Waterland 				goto cleanup;
17575c51f124SMoriah Waterland 			}
17585c51f124SMoriah Waterland 
17595c51f124SMoriah Waterland 			if (sunw_PKCS12_contents(p12, keystore->passphrase,
17605c51f124SMoriah Waterland 			    NULL, &keystore->clcerts) < 0) {
17615c51f124SMoriah Waterland 				/* could not parse the contents */
17625c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_CORRUPT,
17635c51f124SMoriah Waterland 				    gettext(ERR_KEYSTORE_CORRUPT),
17645c51f124SMoriah Waterland 				    keystore->clpath);
17655c51f124SMoriah Waterland 				ret = B_FALSE;
17665c51f124SMoriah Waterland 				goto cleanup;
17675c51f124SMoriah Waterland 			}
17685c51f124SMoriah Waterland 
17695c51f124SMoriah Waterland 			PKCS12_free(p12);
17705c51f124SMoriah Waterland 			p12 = NULL;
17715c51f124SMoriah Waterland 		} else {
17725c51f124SMoriah Waterland 			keystore->clcerts = NULL;
17735c51f124SMoriah Waterland 		}
17745c51f124SMoriah Waterland 
17755c51f124SMoriah Waterland 		if (!key_empty) {
17765c51f124SMoriah Waterland 			if ((p12 = read_keystore_file(err,
17775c51f124SMoriah Waterland 			    keystore->keypath)) == NULL) {
17785c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_CORRUPT,
17795c51f124SMoriah Waterland 				    gettext(ERR_KEYSTORE_CORRUPT),
17805c51f124SMoriah Waterland 				    keystore->keypath);
17815c51f124SMoriah Waterland 				ret = B_FALSE;
17825c51f124SMoriah Waterland 				goto cleanup;
17835c51f124SMoriah Waterland 			}
17845c51f124SMoriah Waterland 
17855c51f124SMoriah Waterland 			/* Get password, using callback if necessary */
17865c51f124SMoriah Waterland 			if (!have_passwd) {
17875c51f124SMoriah Waterland 				if (!get_keystore_passwd(err, p12, cb,
17885c51f124SMoriah Waterland 				    keystore)) {
17895c51f124SMoriah Waterland 					ret = B_FALSE;
17905c51f124SMoriah Waterland 					goto cleanup;
17915c51f124SMoriah Waterland 				}
17925c51f124SMoriah Waterland 				have_passwd = B_TRUE;
17935c51f124SMoriah Waterland 			}
17945c51f124SMoriah Waterland 
17955c51f124SMoriah Waterland 			if (check_password(p12,
17965c51f124SMoriah Waterland 			    keystore->passphrase) == B_FALSE) {
17975c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_BADPASS,
17985c51f124SMoriah Waterland 				    gettext(ERR_MISMATCHPASS),
17995c51f124SMoriah Waterland 				    keystore->keypath,
18005c51f124SMoriah Waterland 				    keystore->capath, keystore->path);
18015c51f124SMoriah Waterland 				ret = B_FALSE;
18025c51f124SMoriah Waterland 				goto cleanup;
18035c51f124SMoriah Waterland 			}
18045c51f124SMoriah Waterland 
18055c51f124SMoriah Waterland 			if (sunw_PKCS12_contents(p12, keystore->passphrase,
18065c51f124SMoriah Waterland 			    &keystore->pkeys, NULL) < 0) {
18075c51f124SMoriah Waterland 				/* could not parse the contents */
18085c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_CORRUPT,
18095c51f124SMoriah Waterland 				    gettext(ERR_KEYSTORE_CORRUPT),
18105c51f124SMoriah Waterland 				    keystore->keypath);
18115c51f124SMoriah Waterland 				ret = B_FALSE;
18125c51f124SMoriah Waterland 				goto cleanup;
18135c51f124SMoriah Waterland 			}
18145c51f124SMoriah Waterland 
18155c51f124SMoriah Waterland 			PKCS12_free(p12);
18165c51f124SMoriah Waterland 			p12 = NULL;
18175c51f124SMoriah Waterland 		} else {
18185c51f124SMoriah Waterland 			keystore->pkeys = NULL;
18195c51f124SMoriah Waterland 		}
18205c51f124SMoriah Waterland 	}
18215c51f124SMoriah Waterland 
18225c51f124SMoriah Waterland cleanup:
18235c51f124SMoriah Waterland 	if (p12 != NULL)
18245c51f124SMoriah Waterland 		PKCS12_free(p12);
18255c51f124SMoriah Waterland 	return (ret);
18265c51f124SMoriah Waterland }
18275c51f124SMoriah Waterland 
18285c51f124SMoriah Waterland /*
18295c51f124SMoriah Waterland  * get_keystore_password - retrieves pasword used to
18305c51f124SMoriah Waterland  * decrypt PKCS12 structure.
18315c51f124SMoriah Waterland  *
18325c51f124SMoriah Waterland  * Arguments:
18335c51f124SMoriah Waterland  * err - Error object to add errors to
18345c51f124SMoriah Waterland  * p12 - PKCS12 structure which returned password should
18355c51f124SMoriah Waterland  * decrypt
18365c51f124SMoriah Waterland  * cb - callback to collect password.
18375c51f124SMoriah Waterland  * keystore - The keystore in which the PKCS12 structure
18385c51f124SMoriah Waterland  * will eventually populate.
18395c51f124SMoriah Waterland  * Returns:
18405c51f124SMoriah Waterland  *   B_TRUE - success.
18415c51f124SMoriah Waterland  *     keystore password is set in keystore->passphrase.
18425c51f124SMoriah Waterland  *   B_FALSE - failure, errors logged
18435c51f124SMoriah Waterland  */
18445c51f124SMoriah Waterland static boolean_t
18455c51f124SMoriah Waterland get_keystore_passwd(PKG_ERR *err, PKCS12 *p12, keystore_passphrase_cb cb,
18465c51f124SMoriah Waterland     keystore_t *keystore)
18475c51f124SMoriah Waterland {
18485c51f124SMoriah Waterland 	char				*passwd;
18495c51f124SMoriah Waterland 	char				passbuf[KEYSTORE_PASS_MAX + 1];
18505c51f124SMoriah Waterland 	keystore_passphrase_data	data;
18515c51f124SMoriah Waterland 
18525c51f124SMoriah Waterland 	/* see if no password is the right password */
18535c51f124SMoriah Waterland 	if (check_password(p12, "") == B_TRUE) {
18545c51f124SMoriah Waterland 		passwd = "";
18555c51f124SMoriah Waterland 	} else if (check_password(p12, NULL) == B_TRUE) {
18565c51f124SMoriah Waterland 		passwd = NULL;
18575c51f124SMoriah Waterland 	} else {
18585c51f124SMoriah Waterland 		/* oops, it's encrypted.  get password */
18595c51f124SMoriah Waterland 		data.err = err;
18605c51f124SMoriah Waterland 		if (cb(passbuf, KEYSTORE_PASS_MAX, 0,
18615c51f124SMoriah Waterland 		    &data) == -1) {
18625c51f124SMoriah Waterland 			/* could not get password */
18635c51f124SMoriah Waterland 			return (B_FALSE);
18645c51f124SMoriah Waterland 		}
18655c51f124SMoriah Waterland 
18665c51f124SMoriah Waterland 		if (check_password(p12, passbuf) == B_FALSE) {
18675c51f124SMoriah Waterland 				/* wrong password */
18685c51f124SMoriah Waterland 			pkgerr_add(err, PKGERR_BADPASS,
18695c51f124SMoriah Waterland 			    gettext(ERR_BADPASS));
18705c51f124SMoriah Waterland 			return (B_FALSE);
18715c51f124SMoriah Waterland 		}
18725c51f124SMoriah Waterland 
18735c51f124SMoriah Waterland 		/*
18745c51f124SMoriah Waterland 		 * make copy of password buffer, since it
18755c51f124SMoriah Waterland 		 * goes away upon return
18765c51f124SMoriah Waterland 		 */
18775c51f124SMoriah Waterland 		passwd = xstrdup(passbuf);
18785c51f124SMoriah Waterland 	}
18795c51f124SMoriah Waterland 	keystore->passphrase = passwd;
18805c51f124SMoriah Waterland 	return (B_TRUE);
18815c51f124SMoriah Waterland }
18825c51f124SMoriah Waterland 
18835c51f124SMoriah Waterland /*
18845c51f124SMoriah Waterland  * write_keystore - Writes keystore files to disk
18855c51f124SMoriah Waterland  *
18865c51f124SMoriah Waterland  * Arguments:
18875c51f124SMoriah Waterland  * err - Error object to add errors to
18885c51f124SMoriah Waterland  * keystore - keystore object to write from
18895c51f124SMoriah Waterland  * passwd - password used to encrypt keystore
18905c51f124SMoriah Waterland  * Returns:
18915c51f124SMoriah Waterland  *   0 - Success - Keystore contents are written out to
18925c51f124SMoriah Waterland  *   the same locations as read from
18935c51f124SMoriah Waterland  * non-zero - Failure, errors and reasons recorded in err
18945c51f124SMoriah Waterland  */
18955c51f124SMoriah Waterland static boolean_t
18965c51f124SMoriah Waterland write_keystore(PKG_ERR *err, keystore_t *keystore,
18975c51f124SMoriah Waterland     keystore_passphrase_cb cb)
18985c51f124SMoriah Waterland {
18995c51f124SMoriah Waterland 	PKCS12	*p12 = NULL;
19005c51f124SMoriah Waterland 	boolean_t ret = B_TRUE;
19015c51f124SMoriah Waterland 	keystore_passphrase_data data;
19025c51f124SMoriah Waterland 	char		passbuf[KEYSTORE_PASS_MAX + 1];
19035c51f124SMoriah Waterland 
19045c51f124SMoriah Waterland 	if (keystore->capath != NULL && keystore->clpath == NULL &&
19055c51f124SMoriah Waterland 	    keystore->keypath == NULL) {
19065c51f124SMoriah Waterland 
19075c51f124SMoriah Waterland 		/*
19085c51f124SMoriah Waterland 		 * keystore is a file.
19095c51f124SMoriah Waterland 		 * just write out a single file
19105c51f124SMoriah Waterland 		 */
19115c51f124SMoriah Waterland 		if ((keystore->pkeys == NULL) &&
19125c51f124SMoriah Waterland 		    (keystore->clcerts == NULL) &&
19135c51f124SMoriah Waterland 		    (keystore->cacerts == NULL)) {
19145c51f124SMoriah Waterland 			if (!clear_keystore_file(err, keystore->capath)) {
19155c51f124SMoriah Waterland 				/*
19165c51f124SMoriah Waterland 				 * no keys or certs to write out, so
19175c51f124SMoriah Waterland 				 * blank the ca file.  we do not
19185c51f124SMoriah Waterland 				 * delete it since it is used as a
19195c51f124SMoriah Waterland 				 * lock by lock_keystore() in
19205c51f124SMoriah Waterland 				 * subsequent invocations
19215c51f124SMoriah Waterland 				 */
19225c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_WRITE,
19235c51f124SMoriah Waterland 				    gettext(ERR_KEYSTORE_WRITE),
19245c51f124SMoriah Waterland 				    keystore->capath);
19255c51f124SMoriah Waterland 				ret = B_FALSE;
19265c51f124SMoriah Waterland 				goto cleanup;
19275c51f124SMoriah Waterland 			}
19285c51f124SMoriah Waterland 		} else {
19295c51f124SMoriah Waterland 			/*
19305c51f124SMoriah Waterland 			 * if the keystore is being created for the first time,
19315c51f124SMoriah Waterland 			 * prompt for a passphrase for encryption
19325c51f124SMoriah Waterland 			 */
19335c51f124SMoriah Waterland 			if (keystore->new) {
19345c51f124SMoriah Waterland 				data.err = err;
19355c51f124SMoriah Waterland 				if (cb(passbuf, KEYSTORE_PASS_MAX,
19365c51f124SMoriah Waterland 				    1, &data) == -1) {
19375c51f124SMoriah Waterland 					ret = B_FALSE;
19385c51f124SMoriah Waterland 					goto cleanup;
19395c51f124SMoriah Waterland 				}
19405c51f124SMoriah Waterland 			} else {
19415c51f124SMoriah Waterland 				/*
19425c51f124SMoriah Waterland 				 * use the one used when the keystore
19435c51f124SMoriah Waterland 				 * was read
19445c51f124SMoriah Waterland 				 */
1945*4656d474SGarrett D'Amore 				(void) strlcpy(passbuf, keystore->passphrase,
19465c51f124SMoriah Waterland 				    KEYSTORE_PASS_MAX);
19475c51f124SMoriah Waterland 			}
19485c51f124SMoriah Waterland 
19495c51f124SMoriah Waterland 			p12 = sunw_PKCS12_create(passbuf, keystore->pkeys,
19505c51f124SMoriah Waterland 			    keystore->clcerts, keystore->cacerts);
19515c51f124SMoriah Waterland 
19525c51f124SMoriah Waterland 			if (p12 == NULL) {
19535c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_WRITE,
19545c51f124SMoriah Waterland 				    gettext(ERR_KEYSTORE_FORM),
19555c51f124SMoriah Waterland 				    keystore->capath);
19565c51f124SMoriah Waterland 				ret = B_FALSE;
19575c51f124SMoriah Waterland 				goto cleanup;
19585c51f124SMoriah Waterland 			}
19595c51f124SMoriah Waterland 
19605c51f124SMoriah Waterland 			if (!write_keystore_file(err, keystore->capath, p12)) {
19615c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_WRITE,
19625c51f124SMoriah Waterland 				    gettext(ERR_KEYSTORE_WRITE),
19635c51f124SMoriah Waterland 				    keystore->capath);
19645c51f124SMoriah Waterland 				ret = B_FALSE;
19655c51f124SMoriah Waterland 				goto cleanup;
19665c51f124SMoriah Waterland 			}
19675c51f124SMoriah Waterland 		}
19685c51f124SMoriah Waterland 
19695c51f124SMoriah Waterland 	} else {
19705c51f124SMoriah Waterland 		/* files are seprate. Do one at a time */
19715c51f124SMoriah Waterland 
19725c51f124SMoriah Waterland 		/*
19735c51f124SMoriah Waterland 		 * if the keystore is being created for the first time,
19745c51f124SMoriah Waterland 		 * prompt for a passphrase for encryption
19755c51f124SMoriah Waterland 		 */
19765c51f124SMoriah Waterland 		if (keystore->new && ((keystore->pkeys != NULL) ||
19775c51f124SMoriah Waterland 		    (keystore->clcerts != NULL) ||
19785c51f124SMoriah Waterland 		    (keystore->cacerts != NULL))) {
19795c51f124SMoriah Waterland 			data.err = err;
19805c51f124SMoriah Waterland 			if (cb(passbuf, KEYSTORE_PASS_MAX,
19815c51f124SMoriah Waterland 			    1, &data) == -1) {
19825c51f124SMoriah Waterland 				ret = B_FALSE;
19835c51f124SMoriah Waterland 				goto cleanup;
19845c51f124SMoriah Waterland 			}
19855c51f124SMoriah Waterland 		} else {
19865c51f124SMoriah Waterland 			/* use the one used when the keystore was read */
1987*4656d474SGarrett D'Amore 			(void) strlcpy(passbuf, keystore->passphrase,
19885c51f124SMoriah Waterland 			    KEYSTORE_PASS_MAX);
19895c51f124SMoriah Waterland 		}
19905c51f124SMoriah Waterland 
19915c51f124SMoriah Waterland 		/* do private keys first */
19925c51f124SMoriah Waterland 		if (keystore->pkeys != NULL) {
19935c51f124SMoriah Waterland 			p12 = sunw_PKCS12_create(passbuf, keystore->pkeys,
19945c51f124SMoriah Waterland 			    NULL, NULL);
19955c51f124SMoriah Waterland 
19965c51f124SMoriah Waterland 			if (p12 == NULL) {
19975c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_WRITE,
19985c51f124SMoriah Waterland 				    gettext(ERR_KEYSTORE_FORM),
19995c51f124SMoriah Waterland 				    keystore->keypath);
20005c51f124SMoriah Waterland 				ret = B_FALSE;
20015c51f124SMoriah Waterland 				goto cleanup;
20025c51f124SMoriah Waterland 			}
20035c51f124SMoriah Waterland 
20045c51f124SMoriah Waterland 			if (!write_keystore_file(err, keystore->keypath,
20055c51f124SMoriah Waterland 			    p12)) {
20065c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_WRITE,
20075c51f124SMoriah Waterland 				    gettext(ERR_KEYSTORE_WRITE),
20085c51f124SMoriah Waterland 				    keystore->keypath);
20095c51f124SMoriah Waterland 				ret = B_FALSE;
20105c51f124SMoriah Waterland 				goto cleanup;
20115c51f124SMoriah Waterland 			}
20125c51f124SMoriah Waterland 
20135c51f124SMoriah Waterland 			PKCS12_free(p12);
20145c51f124SMoriah Waterland 		} else {
20155c51f124SMoriah Waterland 			if ((remove(keystore->keypath) != 0) &&
20165c51f124SMoriah Waterland 			    (errno != ENOENT)) {
20175c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_WRITE,
20185c51f124SMoriah Waterland 				    gettext(ERR_KEYSTORE_REMOVE),
20195c51f124SMoriah Waterland 				    keystore->keypath);
20205c51f124SMoriah Waterland 				ret = B_FALSE;
20215c51f124SMoriah Waterland 				goto cleanup;
20225c51f124SMoriah Waterland 			}
20235c51f124SMoriah Waterland 		}
20245c51f124SMoriah Waterland 
20255c51f124SMoriah Waterland 		/* do user certs next */
20265c51f124SMoriah Waterland 		if (keystore->clcerts != NULL) {
20275c51f124SMoriah Waterland 			p12 = sunw_PKCS12_create(passbuf, NULL,
20285c51f124SMoriah Waterland 			    keystore->clcerts, NULL);
20295c51f124SMoriah Waterland 
20305c51f124SMoriah Waterland 			if (p12 == NULL) {
20315c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_WRITE,
20325c51f124SMoriah Waterland 				    gettext(ERR_KEYSTORE_FORM),
20335c51f124SMoriah Waterland 				    keystore->clpath);
20345c51f124SMoriah Waterland 				ret = B_FALSE;
20355c51f124SMoriah Waterland 				goto cleanup;
20365c51f124SMoriah Waterland 			}
20375c51f124SMoriah Waterland 
20385c51f124SMoriah Waterland 			if (!write_keystore_file(err, keystore->clpath, p12)) {
20395c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_WRITE,
20405c51f124SMoriah Waterland 				    gettext(ERR_KEYSTORE_WRITE),
20415c51f124SMoriah Waterland 				    keystore->clpath);
20425c51f124SMoriah Waterland 				ret = B_FALSE;
20435c51f124SMoriah Waterland 				goto cleanup;
20445c51f124SMoriah Waterland 			}
20455c51f124SMoriah Waterland 
20465c51f124SMoriah Waterland 			PKCS12_free(p12);
20475c51f124SMoriah Waterland 		} else {
20485c51f124SMoriah Waterland 			if ((remove(keystore->clpath) != 0) &&
20495c51f124SMoriah Waterland 			    (errno != ENOENT)) {
20505c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_WRITE,
20515c51f124SMoriah Waterland 				    gettext(ERR_KEYSTORE_REMOVE),
20525c51f124SMoriah Waterland 				    keystore->clpath);
20535c51f124SMoriah Waterland 				ret = B_FALSE;
20545c51f124SMoriah Waterland 				goto cleanup;
20555c51f124SMoriah Waterland 			}
20565c51f124SMoriah Waterland 		}
20575c51f124SMoriah Waterland 
20585c51f124SMoriah Waterland 
20595c51f124SMoriah Waterland 		/* finally do CA cert file */
20605c51f124SMoriah Waterland 		if (keystore->cacerts != NULL) {
20615c51f124SMoriah Waterland 			p12 = sunw_PKCS12_create(passbuf, NULL,
20625c51f124SMoriah Waterland 			    NULL, keystore->cacerts);
20635c51f124SMoriah Waterland 
20645c51f124SMoriah Waterland 			if (p12 == NULL) {
20655c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_WRITE,
20665c51f124SMoriah Waterland 				    gettext(ERR_KEYSTORE_FORM),
20675c51f124SMoriah Waterland 				    keystore->capath);
20685c51f124SMoriah Waterland 				ret = B_FALSE;
20695c51f124SMoriah Waterland 				goto cleanup;
20705c51f124SMoriah Waterland 			}
20715c51f124SMoriah Waterland 
20725c51f124SMoriah Waterland 			if (!write_keystore_file(err, keystore->capath, p12)) {
20735c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_WRITE,
20745c51f124SMoriah Waterland 				    gettext(ERR_KEYSTORE_WRITE),
20755c51f124SMoriah Waterland 				    keystore->capath);
20765c51f124SMoriah Waterland 				ret = B_FALSE;
20775c51f124SMoriah Waterland 				goto cleanup;
20785c51f124SMoriah Waterland 			}
20795c51f124SMoriah Waterland 
20805c51f124SMoriah Waterland 			PKCS12_free(p12);
20815c51f124SMoriah Waterland 			p12 = NULL;
20825c51f124SMoriah Waterland 		} else {
20835c51f124SMoriah Waterland 			/*
20845c51f124SMoriah Waterland 			 * nothing to write out, so truncate the file
20855c51f124SMoriah Waterland 			 * (it will be deleted during close_keystore)
20865c51f124SMoriah Waterland 			 */
20875c51f124SMoriah Waterland 			if (!clear_keystore_file(err, keystore->capath)) {
20885c51f124SMoriah Waterland 				pkgerr_add(err, PKGERR_WRITE,
20895c51f124SMoriah Waterland 				    gettext(ERR_KEYSTORE_WRITE),
20905c51f124SMoriah Waterland 				    keystore->capath);
20915c51f124SMoriah Waterland 				ret = B_FALSE;
20925c51f124SMoriah Waterland 				goto cleanup;
20935c51f124SMoriah Waterland 			}
20945c51f124SMoriah Waterland 		}
20955c51f124SMoriah Waterland 	}
20965c51f124SMoriah Waterland 
20975c51f124SMoriah Waterland cleanup:
20985c51f124SMoriah Waterland 	if (p12 != NULL)
20995c51f124SMoriah Waterland 		PKCS12_free(p12);
21005c51f124SMoriah Waterland 
21015c51f124SMoriah Waterland 	return (ret);
21025c51f124SMoriah Waterland }
21035c51f124SMoriah Waterland 
21045c51f124SMoriah Waterland /*
21055c51f124SMoriah Waterland  * clear_keystore_file - Clears (zeros out) a keystore file.
21065c51f124SMoriah Waterland  *
21075c51f124SMoriah Waterland  * Arguments:
21085c51f124SMoriah Waterland  * err - Error object to add errors to
21095c51f124SMoriah Waterland  * dest - Path of keystore file to zero out.
21105c51f124SMoriah Waterland  * Returns:
21115c51f124SMoriah Waterland  *   0 - Success - Keystore file is truncated to zero length
21125c51f124SMoriah Waterland  * non-zero - Failure, errors and reasons recorded in err
21135c51f124SMoriah Waterland  */
21145c51f124SMoriah Waterland static boolean_t
21155c51f124SMoriah Waterland clear_keystore_file(PKG_ERR *err, char *dest)
21165c51f124SMoriah Waterland {
21175c51f124SMoriah Waterland 	int fd;
21185c51f124SMoriah Waterland 	struct stat buf;
21195c51f124SMoriah Waterland 
21205c51f124SMoriah Waterland 	fd = open(dest, O_RDWR|O_NONBLOCK);
21215c51f124SMoriah Waterland 	if (fd == -1) {
21225c51f124SMoriah Waterland 		/* can't open for writing */
21235c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_WRITE, gettext(MSG_OPEN),
21245c51f124SMoriah Waterland 		    errno);
21255c51f124SMoriah Waterland 		return (B_FALSE);
21265c51f124SMoriah Waterland 	}
21275c51f124SMoriah Waterland 
21285c51f124SMoriah Waterland 	if ((fstat(fd, &buf) == -1) || !S_ISREG(buf.st_mode)) {
21295c51f124SMoriah Waterland 		/* not a regular file */
21305c51f124SMoriah Waterland 		(void) close(fd);
21315c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_WRITE, gettext(ERR_NOT_REG),
21325c51f124SMoriah Waterland 		    dest);
21335c51f124SMoriah Waterland 		return (B_FALSE);
21345c51f124SMoriah Waterland 	}
21355c51f124SMoriah Waterland 
21365c51f124SMoriah Waterland 	if (ftruncate(fd, 0) == -1) {
21375c51f124SMoriah Waterland 		(void) close(fd);
21385c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_WRITE, gettext(ERR_WRITE),
21395c51f124SMoriah Waterland 		    dest, strerror(errno));
21405c51f124SMoriah Waterland 		return (B_FALSE);
21415c51f124SMoriah Waterland 	}
21425c51f124SMoriah Waterland 
21435c51f124SMoriah Waterland 	(void) close(fd);
21445c51f124SMoriah Waterland 	return (B_TRUE);
21455c51f124SMoriah Waterland }
21465c51f124SMoriah Waterland 
21475c51f124SMoriah Waterland /*
21485c51f124SMoriah Waterland  * write_keystore_file - Writes keystore file to disk.
21495c51f124SMoriah Waterland  *
21505c51f124SMoriah Waterland  * Keystore files can possibly be corrupted by a variety
21515c51f124SMoriah Waterland  * of error conditions during reading/writing.  This
21525c51f124SMoriah Waterland  * routine, along with restore_keystore_file, tries to
21535c51f124SMoriah Waterland  * maintain keystore integity by writing the files
21545c51f124SMoriah Waterland  * out in a particular order, minimizing the time period
21555c51f124SMoriah Waterland  * that the keystore is in an indeterminate state.
21565c51f124SMoriah Waterland  *
21575c51f124SMoriah Waterland  * With the current implementation, there are some failures
21585c51f124SMoriah Waterland  * that are wholly unrecoverable, such as disk corruption.
21595c51f124SMoriah Waterland  * These routines attempt to minimize the risk, but not
21605c51f124SMoriah Waterland  * eliminate it.  When better, atomic operations are available
21615c51f124SMoriah Waterland  * (such as a true database with commit, rollback, and
21625c51f124SMoriah Waterland  * guaranteed atomicity), this implementation should use that.
21635c51f124SMoriah Waterland  *
21645c51f124SMoriah Waterland  *
21655c51f124SMoriah Waterland  * Arguments:
21665c51f124SMoriah Waterland  * err - Error object to add errors to
21675c51f124SMoriah Waterland  * dest - Destination filename
21685c51f124SMoriah Waterland  * contents - Contents to write to the file
21695c51f124SMoriah Waterland  * Returns:
21705c51f124SMoriah Waterland  *   0 - Success - Keystore contents are written out to
21715c51f124SMoriah Waterland  *   the destination.
21725c51f124SMoriah Waterland  * non-zero - Failure, errors and reasons recorded in err
21735c51f124SMoriah Waterland  */
21745c51f124SMoriah Waterland static boolean_t
21755c51f124SMoriah Waterland write_keystore_file(PKG_ERR *err, char *dest, PKCS12 *contents)
21765c51f124SMoriah Waterland {
21775c51f124SMoriah Waterland 	FILE	*newfile = NULL;
21785c51f124SMoriah Waterland 	boolean_t	ret = B_TRUE;
21795c51f124SMoriah Waterland 	char	newpath[MAXPATHLEN];
21805c51f124SMoriah Waterland 	char	backuppath[MAXPATHLEN];
21815c51f124SMoriah Waterland 	struct stat buf;
21825c51f124SMoriah Waterland 	int fd;
21835c51f124SMoriah Waterland 
21845c51f124SMoriah Waterland 	(void) snprintf(newpath, MAXPATHLEN, "%s.new", dest);
21855c51f124SMoriah Waterland 	(void) snprintf(backuppath, MAXPATHLEN, "%s.bak", dest);
21865c51f124SMoriah Waterland 
21875c51f124SMoriah Waterland 	if ((fd = open(newpath, O_CREAT|O_EXCL|O_WRONLY|O_NONBLOCK,
21885c51f124SMoriah Waterland 	    S_IRUSR|S_IWUSR)) == -1) {
21895c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN),
21905c51f124SMoriah Waterland 		    newpath, strerror(errno));
21915c51f124SMoriah Waterland 		ret = B_FALSE;
21925c51f124SMoriah Waterland 		goto cleanup;
21935c51f124SMoriah Waterland 	}
21945c51f124SMoriah Waterland 
21955c51f124SMoriah Waterland 	if (fstat(fd, &buf) == -1) {
21965c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN),
21975c51f124SMoriah Waterland 		    newpath, strerror(errno));
21985c51f124SMoriah Waterland 		ret = B_FALSE;
21995c51f124SMoriah Waterland 		goto cleanup;
22005c51f124SMoriah Waterland 	}
22015c51f124SMoriah Waterland 
22025c51f124SMoriah Waterland 	if (!S_ISREG(buf.st_mode)) {
22035c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_READ, gettext(ERR_NOT_REG),
22045c51f124SMoriah Waterland 		    newpath);
22055c51f124SMoriah Waterland 		ret = B_FALSE;
22065c51f124SMoriah Waterland 		goto cleanup;
22075c51f124SMoriah Waterland 	}
22085c51f124SMoriah Waterland 
22095c51f124SMoriah Waterland 	if ((newfile = fdopen(fd, "w")) == NULL) {
22105c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN),
22115c51f124SMoriah Waterland 		    newpath, strerror(errno));
22125c51f124SMoriah Waterland 		ret = B_FALSE;
22135c51f124SMoriah Waterland 		goto cleanup;
22145c51f124SMoriah Waterland 	}
22155c51f124SMoriah Waterland 
22165c51f124SMoriah Waterland 	if (i2d_PKCS12_fp(newfile, contents) == 0) {
22175c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_WRITE, gettext(ERR_KEYSTORE_WRITE),
22185c51f124SMoriah Waterland 		    newpath);
22195c51f124SMoriah Waterland 		ret = B_FALSE;
22205c51f124SMoriah Waterland 		goto cleanup;
22215c51f124SMoriah Waterland 	}
22225c51f124SMoriah Waterland 
22235c51f124SMoriah Waterland 	/* flush, then close */
22245c51f124SMoriah Waterland 	(void) fflush(newfile);
22255c51f124SMoriah Waterland 	(void) fclose(newfile);
22265c51f124SMoriah Waterland 	newfile = NULL;
22275c51f124SMoriah Waterland 
22285c51f124SMoriah Waterland 	/* now back up the original file */
22295c51f124SMoriah Waterland 	(void) rename(dest, backuppath);
22305c51f124SMoriah Waterland 
22315c51f124SMoriah Waterland 	/* put new one in its place */
22325c51f124SMoriah Waterland 	(void) rename(newpath, dest);
22335c51f124SMoriah Waterland 
22345c51f124SMoriah Waterland 	/* remove backup */
22355c51f124SMoriah Waterland 	(void) remove(backuppath);
22365c51f124SMoriah Waterland 
22375c51f124SMoriah Waterland cleanup:
22385c51f124SMoriah Waterland 	if (newfile != NULL)
22395c51f124SMoriah Waterland 		(void) fclose(newfile);
22405c51f124SMoriah Waterland 	if (fd != -1)
22415c51f124SMoriah Waterland 		(void) close(fd);
22425c51f124SMoriah Waterland 
22435c51f124SMoriah Waterland 	return (ret);
22445c51f124SMoriah Waterland }
22455c51f124SMoriah Waterland 
22465c51f124SMoriah Waterland /*
22475c51f124SMoriah Waterland  * read_keystore_file - Reads single keystore file
22485c51f124SMoriah Waterland  * off disk in PKCS12 format.
22495c51f124SMoriah Waterland  *
22505c51f124SMoriah Waterland  * Arguments:
22515c51f124SMoriah Waterland  * err - Error object to add errors to
22525c51f124SMoriah Waterland  * file - File path to read
22535c51f124SMoriah Waterland  * Returns:
22545c51f124SMoriah Waterland  *   PKCS12 contents of file, or NULL if an error occurred.
22555c51f124SMoriah Waterland  *   errors recorded in 'err'.
22565c51f124SMoriah Waterland  */
22575c51f124SMoriah Waterland static PKCS12
22585c51f124SMoriah Waterland *read_keystore_file(PKG_ERR *err, char *file)
22595c51f124SMoriah Waterland {
22605c51f124SMoriah Waterland 	int fd;
22615c51f124SMoriah Waterland 	struct stat buf;
22625c51f124SMoriah Waterland 	FILE *newfile;
22635c51f124SMoriah Waterland 	PKCS12 *p12 = NULL;
22645c51f124SMoriah Waterland 
22655c51f124SMoriah Waterland 	if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) {
22665c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN),
22675c51f124SMoriah Waterland 		    file, strerror(errno));
22685c51f124SMoriah Waterland 		goto cleanup;
22695c51f124SMoriah Waterland 	}
22705c51f124SMoriah Waterland 
22715c51f124SMoriah Waterland 	if (fstat(fd, &buf) == -1) {
22725c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN),
22735c51f124SMoriah Waterland 		    file, strerror(errno));
22745c51f124SMoriah Waterland 		goto cleanup;
22755c51f124SMoriah Waterland 	}
22765c51f124SMoriah Waterland 
22775c51f124SMoriah Waterland 	if (!S_ISREG(buf.st_mode)) {
22785c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_READ, gettext(ERR_NOT_REG),
22795c51f124SMoriah Waterland 		    file);
22805c51f124SMoriah Waterland 		goto cleanup;
22815c51f124SMoriah Waterland 	}
22825c51f124SMoriah Waterland 
22835c51f124SMoriah Waterland 	if ((newfile = fdopen(fd, "r")) == NULL) {
22845c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN),
22855c51f124SMoriah Waterland 		    file, strerror(errno));
22865c51f124SMoriah Waterland 		goto cleanup;
22875c51f124SMoriah Waterland 	}
22885c51f124SMoriah Waterland 
22895c51f124SMoriah Waterland 	if ((p12 = d2i_PKCS12_fp(newfile, NULL)) == NULL) {
22905c51f124SMoriah Waterland 		pkgerr_add(err, PKGERR_CORRUPT,
22915c51f124SMoriah Waterland 		    gettext(ERR_KEYSTORE_CORRUPT), file);
22925c51f124SMoriah Waterland 		goto cleanup;
22935c51f124SMoriah Waterland 	}
22945c51f124SMoriah Waterland 
22955c51f124SMoriah Waterland cleanup:
22965c51f124SMoriah Waterland 	if (newfile != NULL)
22975c51f124SMoriah Waterland 		(void) fclose(newfile);
22985c51f124SMoriah Waterland 	if (fd != -1)
22995c51f124SMoriah Waterland 		(void) close(fd);
23005c51f124SMoriah Waterland 
23015c51f124SMoriah Waterland 	return (p12);
23025c51f124SMoriah Waterland }
23035c51f124SMoriah Waterland 
23045c51f124SMoriah Waterland 
23055c51f124SMoriah Waterland /*
23065c51f124SMoriah Waterland  * Locks the specified file.
23075c51f124SMoriah Waterland  */
23085c51f124SMoriah Waterland static int
23095c51f124SMoriah Waterland file_lock(int fd, int type, int wait)
23105c51f124SMoriah Waterland {
23115c51f124SMoriah Waterland 	struct flock lock;
23125c51f124SMoriah Waterland 
23135c51f124SMoriah Waterland 	lock.l_type = type;
23145c51f124SMoriah Waterland 	lock.l_start = 0;
23155c51f124SMoriah Waterland 	lock.l_whence = SEEK_SET;
23165c51f124SMoriah Waterland 	lock.l_len = 0;
23175c51f124SMoriah Waterland 
23185c51f124SMoriah Waterland 	if (!wait) {
23195c51f124SMoriah Waterland 		if (file_lock_test(fd, type)) {
23205c51f124SMoriah Waterland 			/*
23215c51f124SMoriah Waterland 			 * The caller would have to wait to get the
23225c51f124SMoriah Waterland 			 * lock on this file.
23235c51f124SMoriah Waterland 			 */
23245c51f124SMoriah Waterland 			return (-1);
23255c51f124SMoriah Waterland 		}
23265c51f124SMoriah Waterland 	}
23275c51f124SMoriah Waterland 
23285c51f124SMoriah Waterland 	return (fcntl(fd, F_SETLKW, &lock));
23295c51f124SMoriah Waterland }
23305c51f124SMoriah Waterland 
23315c51f124SMoriah Waterland /*
23325c51f124SMoriah Waterland  * Returns FALSE if the file is not locked; TRUE
23335c51f124SMoriah Waterland  * otherwise.
23345c51f124SMoriah Waterland  */
23355c51f124SMoriah Waterland static boolean_t
23365c51f124SMoriah Waterland file_lock_test(int fd, int type)
23375c51f124SMoriah Waterland {
23385c51f124SMoriah Waterland 	struct flock lock;
23395c51f124SMoriah Waterland 
23405c51f124SMoriah Waterland 	lock.l_type = type;
23415c51f124SMoriah Waterland 	lock.l_start = 0;
23425c51f124SMoriah Waterland 	lock.l_whence = SEEK_SET;
23435c51f124SMoriah Waterland 	lock.l_len = 0;
23445c51f124SMoriah Waterland 
23455c51f124SMoriah Waterland 	if (fcntl(fd, F_GETLK, &lock) != -1) {
23465c51f124SMoriah Waterland 		if (lock.l_type != F_UNLCK) {
23475c51f124SMoriah Waterland 			/*
23485c51f124SMoriah Waterland 			 * The caller would have to wait to get the
23495c51f124SMoriah Waterland 			 * lock on this file.
23505c51f124SMoriah Waterland 			 */
23515c51f124SMoriah Waterland 			return (B_TRUE);
23525c51f124SMoriah Waterland 		}
23535c51f124SMoriah Waterland 	}
23545c51f124SMoriah Waterland 
23555c51f124SMoriah Waterland 	/*
23565c51f124SMoriah Waterland 	 * The file is not locked.
23575c51f124SMoriah Waterland 	 */
23585c51f124SMoriah Waterland 	return (B_FALSE);
23595c51f124SMoriah Waterland }
23605c51f124SMoriah Waterland 
23615c51f124SMoriah Waterland /*
23625c51f124SMoriah Waterland  * Unlocks the specified file.
23635c51f124SMoriah Waterland  */
23645c51f124SMoriah Waterland static int
23655c51f124SMoriah Waterland file_unlock(int fd)
23665c51f124SMoriah Waterland {
23675c51f124SMoriah Waterland 	struct flock lock;
23685c51f124SMoriah Waterland 
23695c51f124SMoriah Waterland 	lock.l_type = F_UNLCK;
23705c51f124SMoriah Waterland 	lock.l_start = 0;
23715c51f124SMoriah Waterland 	lock.l_whence = SEEK_SET;
23725c51f124SMoriah Waterland 	lock.l_len = 0;
23735c51f124SMoriah Waterland 
23745c51f124SMoriah Waterland 	return (fcntl(fd, F_SETLK, &lock));
23755c51f124SMoriah Waterland }
23765c51f124SMoriah Waterland 
23775c51f124SMoriah Waterland /*
23785c51f124SMoriah Waterland  * Determines if file has a length of 0 or not
23795c51f124SMoriah Waterland  */
23805c51f124SMoriah Waterland static boolean_t
23815c51f124SMoriah Waterland file_empty(char *path)
23825c51f124SMoriah Waterland {
23835c51f124SMoriah Waterland 	struct stat	buf;
23845c51f124SMoriah Waterland 
23855c51f124SMoriah Waterland 	/* file is empty if size = 0 or it doesn't exist */
23865c51f124SMoriah Waterland 	if (lstat(path, &buf) == 0) {
23875c51f124SMoriah Waterland 		if (buf.st_size == 0) {
23885c51f124SMoriah Waterland 			return (B_TRUE);
23895c51f124SMoriah Waterland 		}
23905c51f124SMoriah Waterland 	} else {
23915c51f124SMoriah Waterland 		if (errno == ENOENT) {
23925c51f124SMoriah Waterland 			return (B_TRUE);
23935c51f124SMoriah Waterland 		}
23945c51f124SMoriah Waterland 	}
23955c51f124SMoriah Waterland 
23965c51f124SMoriah Waterland 	return (B_FALSE);
23975c51f124SMoriah Waterland }
23985c51f124SMoriah Waterland 
23995c51f124SMoriah Waterland /*
24005c51f124SMoriah Waterland  * Name:		get_time_string
24015c51f124SMoriah Waterland  * Description:	Generates a human-readable string from an ASN1_TIME
24025c51f124SMoriah Waterland  *
24035c51f124SMoriah Waterland  * Arguments:	intime - The time to convert
24045c51f124SMoriah Waterland  *
24055c51f124SMoriah Waterland  * Returns :	A pointer to a static string representing the passed-in time.
24065c51f124SMoriah Waterland  */
24075c51f124SMoriah Waterland static char
24085c51f124SMoriah Waterland *get_time_string(ASN1_TIME *intime)
24095c51f124SMoriah Waterland {
24105c51f124SMoriah Waterland 
24115c51f124SMoriah Waterland 	static char	time[ATTR_MAX];
24125c51f124SMoriah Waterland 	BIO		*mem;
24135c51f124SMoriah Waterland 	char	*p;
24145c51f124SMoriah Waterland 
24155c51f124SMoriah Waterland 	if (intime == NULL) {
24165c51f124SMoriah Waterland 		return (NULL);
24175c51f124SMoriah Waterland 	}
24185c51f124SMoriah Waterland 	if ((mem = BIO_new(BIO_s_mem())) == NULL) {
24195c51f124SMoriah Waterland 		return (NULL);
24205c51f124SMoriah Waterland 	}
24215c51f124SMoriah Waterland 
24225c51f124SMoriah Waterland 	if (ASN1_TIME_print(mem, intime) == 0) {
24235c51f124SMoriah Waterland 		(void) BIO_free(mem);
24245c51f124SMoriah Waterland 		return (NULL);
24255c51f124SMoriah Waterland 	}
24265c51f124SMoriah Waterland 
24275c51f124SMoriah Waterland 	if (BIO_gets(mem, time, ATTR_MAX) <= 0) {
24285c51f124SMoriah Waterland 		(void) BIO_free(mem);
24295c51f124SMoriah Waterland 		return (NULL);
24305c51f124SMoriah Waterland 	}
24315c51f124SMoriah Waterland 
24325c51f124SMoriah Waterland 	(void) BIO_free(mem);
24335c51f124SMoriah Waterland 
24345c51f124SMoriah Waterland 	/* trim the end of the string */
24355c51f124SMoriah Waterland 	for (p = time + strlen(time) - 1; isspace(*p); p--) {
24365c51f124SMoriah Waterland 		*p = '\0';
24375c51f124SMoriah Waterland 	}
24385c51f124SMoriah Waterland 
24395c51f124SMoriah Waterland 	return (time);
24405c51f124SMoriah Waterland }
24415c51f124SMoriah Waterland 
24425c51f124SMoriah Waterland /*
24435c51f124SMoriah Waterland  * check_password - do various password checks to see if the current password
24445c51f124SMoriah Waterland  *                  will work or we need to prompt for a new one.
24455c51f124SMoriah Waterland  *
24465c51f124SMoriah Waterland  * Arguments:
24475c51f124SMoriah Waterland  *   pass   - password to check
24485c51f124SMoriah Waterland  *
24495c51f124SMoriah Waterland  * Returns:
24505c51f124SMoriah Waterland  *   B_TRUE  - Password is OK.
24515c51f124SMoriah Waterland  *   B_FALSE - Password not valid.
24525c51f124SMoriah Waterland  */
24535c51f124SMoriah Waterland static boolean_t
24545c51f124SMoriah Waterland check_password(PKCS12 *p12, char *pass)
24555c51f124SMoriah Waterland {
24565c51f124SMoriah Waterland 	boolean_t ret = B_TRUE;
24575c51f124SMoriah Waterland 
24585c51f124SMoriah Waterland 	/*
24595c51f124SMoriah Waterland 	 * If password is zero length or NULL then try verifying both cases
24605c51f124SMoriah Waterland 	 * to determine which password is correct. The reason for this is that
24615c51f124SMoriah Waterland 	 * under PKCS#12 password based encryption no password and a zero
24625c51f124SMoriah Waterland 	 * length password are two different things...
24635c51f124SMoriah Waterland 	 */
24645c51f124SMoriah Waterland 
24655c51f124SMoriah Waterland 	/* Check the mac */
24665c51f124SMoriah Waterland 	if (pass == NULL || *pass == '\0') {
24675c51f124SMoriah Waterland 		if (PKCS12_verify_mac(p12, NULL, 0) == 0 &&
24685c51f124SMoriah Waterland 		    PKCS12_verify_mac(p12, "", 0) == 0)
24695c51f124SMoriah Waterland 			ret = B_FALSE;
24705c51f124SMoriah Waterland 	} else if (PKCS12_verify_mac(p12, pass, -1) == 0) {
24715c51f124SMoriah Waterland 		ret = B_FALSE;
24725c51f124SMoriah Waterland 	}
24735c51f124SMoriah Waterland 	return (ret);
24745c51f124SMoriah Waterland }
2475