xref: /onnv-gate/usr/src/lib/libpkg/common/keystore.c (revision 9781:ccf49524d5dc)
1*9781SMoriah.Waterland@Sun.COM /*
2*9781SMoriah.Waterland@Sun.COM  * CDDL HEADER START
3*9781SMoriah.Waterland@Sun.COM  *
4*9781SMoriah.Waterland@Sun.COM  * The contents of this file are subject to the terms of the
5*9781SMoriah.Waterland@Sun.COM  * Common Development and Distribution License (the "License").
6*9781SMoriah.Waterland@Sun.COM  * You may not use this file except in compliance with the License.
7*9781SMoriah.Waterland@Sun.COM  *
8*9781SMoriah.Waterland@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*9781SMoriah.Waterland@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*9781SMoriah.Waterland@Sun.COM  * See the License for the specific language governing permissions
11*9781SMoriah.Waterland@Sun.COM  * and limitations under the License.
12*9781SMoriah.Waterland@Sun.COM  *
13*9781SMoriah.Waterland@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*9781SMoriah.Waterland@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*9781SMoriah.Waterland@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*9781SMoriah.Waterland@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*9781SMoriah.Waterland@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*9781SMoriah.Waterland@Sun.COM  *
19*9781SMoriah.Waterland@Sun.COM  * CDDL HEADER END
20*9781SMoriah.Waterland@Sun.COM  */
21*9781SMoriah.Waterland@Sun.COM 
22*9781SMoriah.Waterland@Sun.COM /*
23*9781SMoriah.Waterland@Sun.COM  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*9781SMoriah.Waterland@Sun.COM  * Use is subject to license terms.
25*9781SMoriah.Waterland@Sun.COM  */
26*9781SMoriah.Waterland@Sun.COM 
27*9781SMoriah.Waterland@Sun.COM /*
28*9781SMoriah.Waterland@Sun.COM  * Module:	keystore.c
29*9781SMoriah.Waterland@Sun.COM  * Description:	This module contains the structure definitions for processing
30*9781SMoriah.Waterland@Sun.COM  *		package keystore files.
31*9781SMoriah.Waterland@Sun.COM  */
32*9781SMoriah.Waterland@Sun.COM 
33*9781SMoriah.Waterland@Sun.COM #include <errno.h>
34*9781SMoriah.Waterland@Sun.COM #include <fcntl.h>
35*9781SMoriah.Waterland@Sun.COM #include <unistd.h>
36*9781SMoriah.Waterland@Sun.COM #include <strings.h>
37*9781SMoriah.Waterland@Sun.COM #include <libintl.h>
38*9781SMoriah.Waterland@Sun.COM #include <time.h>
39*9781SMoriah.Waterland@Sun.COM #include <ctype.h>
40*9781SMoriah.Waterland@Sun.COM #include <sys/types.h>
41*9781SMoriah.Waterland@Sun.COM #include <sys/stat.h>
42*9781SMoriah.Waterland@Sun.COM #include <openssl/evp.h>
43*9781SMoriah.Waterland@Sun.COM #include <openssl/x509.h>
44*9781SMoriah.Waterland@Sun.COM #include <openssl/pkcs12.h>
45*9781SMoriah.Waterland@Sun.COM #include <openssl/asn1.h>
46*9781SMoriah.Waterland@Sun.COM #include <openssl/pem.h>
47*9781SMoriah.Waterland@Sun.COM #include <openssl/err.h>
48*9781SMoriah.Waterland@Sun.COM #include <openssl/safestack.h>
49*9781SMoriah.Waterland@Sun.COM #include <openssl/stack.h>
50*9781SMoriah.Waterland@Sun.COM #include "p12lib.h"
51*9781SMoriah.Waterland@Sun.COM #include "pkgerr.h"
52*9781SMoriah.Waterland@Sun.COM #include "keystore.h"
53*9781SMoriah.Waterland@Sun.COM #include "pkglib.h"
54*9781SMoriah.Waterland@Sun.COM #include "pkglibmsgs.h"
55*9781SMoriah.Waterland@Sun.COM 
56*9781SMoriah.Waterland@Sun.COM typedef struct keystore_t {
57*9781SMoriah.Waterland@Sun.COM 	boolean_t		dirty;
58*9781SMoriah.Waterland@Sun.COM 	boolean_t		new;
59*9781SMoriah.Waterland@Sun.COM 	char			*path;
60*9781SMoriah.Waterland@Sun.COM 	char			*passphrase;
61*9781SMoriah.Waterland@Sun.COM 	/* truststore handles */
62*9781SMoriah.Waterland@Sun.COM 	int			cafd;
63*9781SMoriah.Waterland@Sun.COM 	STACK_OF(X509)		*cacerts;
64*9781SMoriah.Waterland@Sun.COM 	char			*capath;
65*9781SMoriah.Waterland@Sun.COM 
66*9781SMoriah.Waterland@Sun.COM 	/* user certificate handles */
67*9781SMoriah.Waterland@Sun.COM 	STACK_OF(X509)		*clcerts;
68*9781SMoriah.Waterland@Sun.COM 	char			*clpath;
69*9781SMoriah.Waterland@Sun.COM 
70*9781SMoriah.Waterland@Sun.COM 	/* private key handles */
71*9781SMoriah.Waterland@Sun.COM 	STACK_OF(EVP_PKEY)	*pkeys;
72*9781SMoriah.Waterland@Sun.COM 	char			*keypath;
73*9781SMoriah.Waterland@Sun.COM } keystore_t;
74*9781SMoriah.Waterland@Sun.COM 
75*9781SMoriah.Waterland@Sun.COM /* local routines */
76*9781SMoriah.Waterland@Sun.COM static keystore_t	*new_keystore(void);
77*9781SMoriah.Waterland@Sun.COM static void		free_keystore(keystore_t *);
78*9781SMoriah.Waterland@Sun.COM static boolean_t	verify_keystore_integrity(PKG_ERR *, keystore_t *);
79*9781SMoriah.Waterland@Sun.COM static boolean_t	check_password(PKCS12 *, char *);
80*9781SMoriah.Waterland@Sun.COM static boolean_t	resolve_paths(PKG_ERR *, char *, char *,
81*9781SMoriah.Waterland@Sun.COM     long, keystore_t *);
82*9781SMoriah.Waterland@Sun.COM static boolean_t	lock_keystore(PKG_ERR *, long, keystore_t *);
83*9781SMoriah.Waterland@Sun.COM 
84*9781SMoriah.Waterland@Sun.COM static boolean_t	unlock_keystore(PKG_ERR *, keystore_t *);
85*9781SMoriah.Waterland@Sun.COM static boolean_t	read_keystore(PKG_ERR *, keystore_t *,
86*9781SMoriah.Waterland@Sun.COM     keystore_passphrase_cb);
87*9781SMoriah.Waterland@Sun.COM static boolean_t	write_keystore(PKG_ERR *, keystore_t *,
88*9781SMoriah.Waterland@Sun.COM     keystore_passphrase_cb);
89*9781SMoriah.Waterland@Sun.COM static boolean_t	write_keystore_file(PKG_ERR *, char *, PKCS12 *);
90*9781SMoriah.Waterland@Sun.COM static boolean_t	clear_keystore_file(PKG_ERR *, char *);
91*9781SMoriah.Waterland@Sun.COM static PKCS12		*read_keystore_file(PKG_ERR *, char *);
92*9781SMoriah.Waterland@Sun.COM static char		*get_time_string(ASN1_TIME *);
93*9781SMoriah.Waterland@Sun.COM 
94*9781SMoriah.Waterland@Sun.COM /* locking routines */
95*9781SMoriah.Waterland@Sun.COM static boolean_t	restore_keystore_file(PKG_ERR *, char *);
96*9781SMoriah.Waterland@Sun.COM static int		file_lock(int, int, int);
97*9781SMoriah.Waterland@Sun.COM static int		file_unlock(int);
98*9781SMoriah.Waterland@Sun.COM static boolean_t	file_lock_test(int, int);
99*9781SMoriah.Waterland@Sun.COM static boolean_t	file_empty(char *);
100*9781SMoriah.Waterland@Sun.COM static boolean_t	get_keystore_passwd(PKG_ERR *err, PKCS12 *p12,
101*9781SMoriah.Waterland@Sun.COM     keystore_passphrase_cb cb, keystore_t *keystore);
102*9781SMoriah.Waterland@Sun.COM static boolean_t	wait_restore(int, char *, char *, char *);
103*9781SMoriah.Waterland@Sun.COM 
104*9781SMoriah.Waterland@Sun.COM #define	KEYSTORE_PERMS	(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
105*9781SMoriah.Waterland@Sun.COM 
106*9781SMoriah.Waterland@Sun.COM /* wait on other keystore access for 1 minute before giving up */
107*9781SMoriah.Waterland@Sun.COM #define	LOCK_TIMEOUT	60
108*9781SMoriah.Waterland@Sun.COM 
109*9781SMoriah.Waterland@Sun.COM /*
110*9781SMoriah.Waterland@Sun.COM  * print_certs  - prints certificates out of a keystore, to a file.
111*9781SMoriah.Waterland@Sun.COM  *
112*9781SMoriah.Waterland@Sun.COM  * Arguments:
113*9781SMoriah.Waterland@Sun.COM  * err - Error object to append errors to
114*9781SMoriah.Waterland@Sun.COM  * keystore - Keystore on which to operate
115*9781SMoriah.Waterland@Sun.COM  * alias - Name of certificate to print, NULL means print all
116*9781SMoriah.Waterland@Sun.COM  * format - Format in which to print certificates
117*9781SMoriah.Waterland@Sun.COM  * outfile - Where to print certificates
118*9781SMoriah.Waterland@Sun.COM  *
119*9781SMoriah.Waterland@Sun.COM  * Returns:
120*9781SMoriah.Waterland@Sun.COM  *   0 - Success
121*9781SMoriah.Waterland@Sun.COM  *   non-zero - Failure, errors added to err
122*9781SMoriah.Waterland@Sun.COM  */
123*9781SMoriah.Waterland@Sun.COM int
print_certs(PKG_ERR * err,keystore_handle_t keystore_h,char * alias,keystore_encoding_format_t format,FILE * outfile)124*9781SMoriah.Waterland@Sun.COM print_certs(PKG_ERR *err, keystore_handle_t keystore_h, char *alias,
125*9781SMoriah.Waterland@Sun.COM     keystore_encoding_format_t format, FILE *outfile)
126*9781SMoriah.Waterland@Sun.COM {
127*9781SMoriah.Waterland@Sun.COM 	int		i;
128*9781SMoriah.Waterland@Sun.COM 	X509		*cert;
129*9781SMoriah.Waterland@Sun.COM 	char		*fname = NULL;
130*9781SMoriah.Waterland@Sun.COM 	boolean_t	found = B_FALSE;
131*9781SMoriah.Waterland@Sun.COM 	keystore_t	*keystore = keystore_h;
132*9781SMoriah.Waterland@Sun.COM 
133*9781SMoriah.Waterland@Sun.COM 	if (keystore->clcerts != NULL) {
134*9781SMoriah.Waterland@Sun.COM 		/* print out each client cert */
135*9781SMoriah.Waterland@Sun.COM 		for (i = 0; i < sk_X509_num(keystore->clcerts); i++) {
136*9781SMoriah.Waterland@Sun.COM 			cert = sk_X509_value(keystore->clcerts, i);
137*9781SMoriah.Waterland@Sun.COM 			(void) sunw_get_cert_fname(GETDO_COPY, cert,
138*9781SMoriah.Waterland@Sun.COM 			    &fname);
139*9781SMoriah.Waterland@Sun.COM 
140*9781SMoriah.Waterland@Sun.COM 			if (fname == NULL) {
141*9781SMoriah.Waterland@Sun.COM 				/* no name recorded, keystore is corrupt */
142*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_CORRUPT,
143*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_KEYSTORE_NO_ALIAS),
144*9781SMoriah.Waterland@Sun.COM 				    get_subject_display_name(cert));
145*9781SMoriah.Waterland@Sun.COM 				return (1);
146*9781SMoriah.Waterland@Sun.COM 			}
147*9781SMoriah.Waterland@Sun.COM 
148*9781SMoriah.Waterland@Sun.COM 			if ((alias != NULL) && (!streq(alias, fname))) {
149*9781SMoriah.Waterland@Sun.COM 				/* name does not match, skip it */
150*9781SMoriah.Waterland@Sun.COM 				(void) OPENSSL_free(fname);
151*9781SMoriah.Waterland@Sun.COM 				fname = NULL;
152*9781SMoriah.Waterland@Sun.COM 				continue;
153*9781SMoriah.Waterland@Sun.COM 			} else {
154*9781SMoriah.Waterland@Sun.COM 				found = B_TRUE;
155*9781SMoriah.Waterland@Sun.COM 				(void) print_cert(err, cert, format,
156*9781SMoriah.Waterland@Sun.COM 				    fname, B_FALSE, outfile);
157*9781SMoriah.Waterland@Sun.COM 				(void) OPENSSL_free(fname);
158*9781SMoriah.Waterland@Sun.COM 				fname = NULL;
159*9781SMoriah.Waterland@Sun.COM 			}
160*9781SMoriah.Waterland@Sun.COM 		}
161*9781SMoriah.Waterland@Sun.COM 	}
162*9781SMoriah.Waterland@Sun.COM 
163*9781SMoriah.Waterland@Sun.COM 	if (fname != NULL) {
164*9781SMoriah.Waterland@Sun.COM 	    (void) OPENSSL_free(fname);
165*9781SMoriah.Waterland@Sun.COM 	    fname = NULL;
166*9781SMoriah.Waterland@Sun.COM 	}
167*9781SMoriah.Waterland@Sun.COM 
168*9781SMoriah.Waterland@Sun.COM 	if (keystore->cacerts != NULL) {
169*9781SMoriah.Waterland@Sun.COM 		/* print out each trusted cert */
170*9781SMoriah.Waterland@Sun.COM 		for (i = 0; i < sk_X509_num(keystore->cacerts); i++) {
171*9781SMoriah.Waterland@Sun.COM 			cert = sk_X509_value(keystore->cacerts, i);
172*9781SMoriah.Waterland@Sun.COM 			(void) sunw_get_cert_fname(GETDO_COPY,
173*9781SMoriah.Waterland@Sun.COM 			    cert, &fname);
174*9781SMoriah.Waterland@Sun.COM 
175*9781SMoriah.Waterland@Sun.COM 			if (fname == NULL) {
176*9781SMoriah.Waterland@Sun.COM 				/* no name recorded, keystore is corrupt */
177*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_CORRUPT,
178*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_KEYSTORE_NO_ALIAS),
179*9781SMoriah.Waterland@Sun.COM 				    get_subject_display_name(cert));
180*9781SMoriah.Waterland@Sun.COM 				return (1);
181*9781SMoriah.Waterland@Sun.COM 			}
182*9781SMoriah.Waterland@Sun.COM 
183*9781SMoriah.Waterland@Sun.COM 			if ((alias != NULL) && (!streq(alias, fname))) {
184*9781SMoriah.Waterland@Sun.COM 				/* name does not match, skip it */
185*9781SMoriah.Waterland@Sun.COM 				(void) OPENSSL_free(fname);
186*9781SMoriah.Waterland@Sun.COM 				fname = NULL;
187*9781SMoriah.Waterland@Sun.COM 				continue;
188*9781SMoriah.Waterland@Sun.COM 			} else {
189*9781SMoriah.Waterland@Sun.COM 				found = B_TRUE;
190*9781SMoriah.Waterland@Sun.COM 				(void) print_cert(err, cert, format,
191*9781SMoriah.Waterland@Sun.COM 				    fname, B_TRUE, outfile);
192*9781SMoriah.Waterland@Sun.COM 				(void) OPENSSL_free(fname);
193*9781SMoriah.Waterland@Sun.COM 				fname = NULL;
194*9781SMoriah.Waterland@Sun.COM 			}
195*9781SMoriah.Waterland@Sun.COM 		}
196*9781SMoriah.Waterland@Sun.COM 	}
197*9781SMoriah.Waterland@Sun.COM 
198*9781SMoriah.Waterland@Sun.COM 	if (fname != NULL) {
199*9781SMoriah.Waterland@Sun.COM 	    (void) OPENSSL_free(fname);
200*9781SMoriah.Waterland@Sun.COM 	    fname = NULL;
201*9781SMoriah.Waterland@Sun.COM 	}
202*9781SMoriah.Waterland@Sun.COM 
203*9781SMoriah.Waterland@Sun.COM 	if (found) {
204*9781SMoriah.Waterland@Sun.COM 		return (0);
205*9781SMoriah.Waterland@Sun.COM 	} else {
206*9781SMoriah.Waterland@Sun.COM 		/* no certs printed */
207*9781SMoriah.Waterland@Sun.COM 		if (alias != NULL) {
208*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_NOALIASMATCH,
209*9781SMoriah.Waterland@Sun.COM 			    gettext(ERR_KEYSTORE_NOCERT),
210*9781SMoriah.Waterland@Sun.COM 			    alias, keystore->path);
211*9781SMoriah.Waterland@Sun.COM 		} else {
212*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_NOPUBKEY,
213*9781SMoriah.Waterland@Sun.COM 			    gettext(ERR_KEYSTORE_NOPUBCERTS),
214*9781SMoriah.Waterland@Sun.COM 			    keystore->path);
215*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_NOCACERT,
216*9781SMoriah.Waterland@Sun.COM 			    gettext(ERR_KEYSTORE_NOCACERTS),
217*9781SMoriah.Waterland@Sun.COM 			    keystore->path);
218*9781SMoriah.Waterland@Sun.COM 		}
219*9781SMoriah.Waterland@Sun.COM 		return (1);
220*9781SMoriah.Waterland@Sun.COM 	}
221*9781SMoriah.Waterland@Sun.COM }
222*9781SMoriah.Waterland@Sun.COM 
223*9781SMoriah.Waterland@Sun.COM /*
224*9781SMoriah.Waterland@Sun.COM  * print_cert  - prints a single certificate, to a file
225*9781SMoriah.Waterland@Sun.COM  *
226*9781SMoriah.Waterland@Sun.COM  * Arguments:
227*9781SMoriah.Waterland@Sun.COM  * err - Error object to append errors to
228*9781SMoriah.Waterland@Sun.COM  * x - The certificate to print
229*9781SMoriah.Waterland@Sun.COM  * alias - Name of certificate to print
230*9781SMoriah.Waterland@Sun.COM  * format - Format in which to print certificate
231*9781SMoriah.Waterland@Sun.COM  * outfile - Where to print certificate
232*9781SMoriah.Waterland@Sun.COM  *
233*9781SMoriah.Waterland@Sun.COM  * Returns:
234*9781SMoriah.Waterland@Sun.COM  *   0 - Success
235*9781SMoriah.Waterland@Sun.COM  *   non-zero - Failure, errors added to err
236*9781SMoriah.Waterland@Sun.COM  */
print_cert(PKG_ERR * err,X509 * x,keystore_encoding_format_t format,char * alias,boolean_t is_trusted,FILE * outfile)237*9781SMoriah.Waterland@Sun.COM int print_cert(PKG_ERR *err, X509 *x,
238*9781SMoriah.Waterland@Sun.COM     keystore_encoding_format_t format, char *alias, boolean_t is_trusted,
239*9781SMoriah.Waterland@Sun.COM     FILE *outfile)
240*9781SMoriah.Waterland@Sun.COM {
241*9781SMoriah.Waterland@Sun.COM 
242*9781SMoriah.Waterland@Sun.COM 	char *vdb_str;
243*9781SMoriah.Waterland@Sun.COM 	char *vda_str;
244*9781SMoriah.Waterland@Sun.COM 	char vd_str[ATTR_MAX];
245*9781SMoriah.Waterland@Sun.COM 	int ret = 0;
246*9781SMoriah.Waterland@Sun.COM 	char *cn_str, *icn_str, *typ_str;
247*9781SMoriah.Waterland@Sun.COM 	char *tmp;
248*9781SMoriah.Waterland@Sun.COM 	char *md5_fp;
249*9781SMoriah.Waterland@Sun.COM 	char *sha1_fp;
250*9781SMoriah.Waterland@Sun.COM 	int len;
251*9781SMoriah.Waterland@Sun.COM 
252*9781SMoriah.Waterland@Sun.COM 	/* need to localize the word "Fingerprint", hence these pointers */
253*9781SMoriah.Waterland@Sun.COM 	char md5_label[ATTR_MAX];
254*9781SMoriah.Waterland@Sun.COM 	char sha1_label[ATTR_MAX];
255*9781SMoriah.Waterland@Sun.COM 
256*9781SMoriah.Waterland@Sun.COM 	if (is_trusted) {
257*9781SMoriah.Waterland@Sun.COM 		typ_str = gettext(MSG_KEYSTORE_TRUSTED);
258*9781SMoriah.Waterland@Sun.COM 	} else {
259*9781SMoriah.Waterland@Sun.COM 		typ_str = gettext(MSG_KEYSTORE_UNTRUSTED);
260*9781SMoriah.Waterland@Sun.COM 	}
261*9781SMoriah.Waterland@Sun.COM 
262*9781SMoriah.Waterland@Sun.COM 	if ((cn_str = get_subject_display_name(x)) == NULL) {
263*9781SMoriah.Waterland@Sun.COM 		cn_str = gettext(MSG_KEYSTORE_UNKNOWN);
264*9781SMoriah.Waterland@Sun.COM 	}
265*9781SMoriah.Waterland@Sun.COM 
266*9781SMoriah.Waterland@Sun.COM 	if ((icn_str = get_issuer_display_name(x)) == NULL) {
267*9781SMoriah.Waterland@Sun.COM 		icn_str = gettext(MSG_KEYSTORE_UNKNOWN);
268*9781SMoriah.Waterland@Sun.COM 	}
269*9781SMoriah.Waterland@Sun.COM 
270*9781SMoriah.Waterland@Sun.COM 	vdb_str = xstrdup(get_time_string(X509_get_notBefore(x)));
271*9781SMoriah.Waterland@Sun.COM 	vda_str = xstrdup(get_time_string(X509_get_notAfter(x)));
272*9781SMoriah.Waterland@Sun.COM 	if (((len = snprintf(vd_str, ATTR_MAX, "<%s> - <%s>",
273*9781SMoriah.Waterland@Sun.COM 	    vdb_str, vda_str)) < 0) || (len >= ATTR_MAX)) {
274*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN), vdb_str);
275*9781SMoriah.Waterland@Sun.COM 		ret = 1;
276*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
277*9781SMoriah.Waterland@Sun.COM 	}
278*9781SMoriah.Waterland@Sun.COM 
279*9781SMoriah.Waterland@Sun.COM 	if ((tmp = get_fingerprint(x, EVP_md5())) == NULL) {
280*9781SMoriah.Waterland@Sun.COM 		md5_fp = gettext(MSG_KEYSTORE_UNKNOWN);
281*9781SMoriah.Waterland@Sun.COM 	} else {
282*9781SMoriah.Waterland@Sun.COM 		/*
283*9781SMoriah.Waterland@Sun.COM 		 * make a copy, otherwise the next call to get_fingerprint
284*9781SMoriah.Waterland@Sun.COM 		 * will overwrite this one
285*9781SMoriah.Waterland@Sun.COM 		 */
286*9781SMoriah.Waterland@Sun.COM 		md5_fp = xstrdup(tmp);
287*9781SMoriah.Waterland@Sun.COM 	}
288*9781SMoriah.Waterland@Sun.COM 
289*9781SMoriah.Waterland@Sun.COM 	if ((tmp = get_fingerprint(x, EVP_sha1())) == NULL) {
290*9781SMoriah.Waterland@Sun.COM 		sha1_fp = gettext(MSG_KEYSTORE_UNKNOWN);
291*9781SMoriah.Waterland@Sun.COM 	} else {
292*9781SMoriah.Waterland@Sun.COM 		sha1_fp = xstrdup(tmp);
293*9781SMoriah.Waterland@Sun.COM 	}
294*9781SMoriah.Waterland@Sun.COM 
295*9781SMoriah.Waterland@Sun.COM 	(void) snprintf(md5_label, ATTR_MAX, "%s %s",
296*9781SMoriah.Waterland@Sun.COM 	    OBJ_nid2sn(EVP_MD_type(EVP_md5())),
297*9781SMoriah.Waterland@Sun.COM 	    /* i18n: 14 characters max */
298*9781SMoriah.Waterland@Sun.COM 	    gettext(MSG_KEYSTORE_FP));
299*9781SMoriah.Waterland@Sun.COM 
300*9781SMoriah.Waterland@Sun.COM 	(void) snprintf(sha1_label, ATTR_MAX, "%s %s",
301*9781SMoriah.Waterland@Sun.COM 	    OBJ_nid2sn(EVP_MD_type(EVP_sha1())),
302*9781SMoriah.Waterland@Sun.COM 	    /* i18n: 14 characters max */
303*9781SMoriah.Waterland@Sun.COM 	    gettext(MSG_KEYSTORE_FP));
304*9781SMoriah.Waterland@Sun.COM 
305*9781SMoriah.Waterland@Sun.COM 	switch (format) {
306*9781SMoriah.Waterland@Sun.COM 	case KEYSTORE_FORMAT_PEM:
307*9781SMoriah.Waterland@Sun.COM 		(void) PEM_write_X509(outfile, x);
308*9781SMoriah.Waterland@Sun.COM 		break;
309*9781SMoriah.Waterland@Sun.COM 	case KEYSTORE_FORMAT_DER:
310*9781SMoriah.Waterland@Sun.COM 		(void) i2d_X509_fp(outfile, x);
311*9781SMoriah.Waterland@Sun.COM 		break;
312*9781SMoriah.Waterland@Sun.COM 	case KEYSTORE_FORMAT_TEXT:
313*9781SMoriah.Waterland@Sun.COM 		(void) fprintf(outfile, "%18s: %s\n",
314*9781SMoriah.Waterland@Sun.COM 		    /* i18n: 18 characters max */
315*9781SMoriah.Waterland@Sun.COM 		    gettext(MSG_KEYSTORE_AL), alias);
316*9781SMoriah.Waterland@Sun.COM 		(void) fprintf(outfile, "%18s: %s\n",
317*9781SMoriah.Waterland@Sun.COM 		    /* i18n: 18 characters max */
318*9781SMoriah.Waterland@Sun.COM 		    gettext(MSG_KEYSTORE_CN), cn_str);
319*9781SMoriah.Waterland@Sun.COM 		(void) fprintf(outfile, "%18s: %s\n",
320*9781SMoriah.Waterland@Sun.COM 		    /* i18n: 18 characters max */
321*9781SMoriah.Waterland@Sun.COM 		    gettext(MSG_KEYSTORE_TY), typ_str);
322*9781SMoriah.Waterland@Sun.COM 		(void) fprintf(outfile, "%18s: %s\n",
323*9781SMoriah.Waterland@Sun.COM 		    /* i18n: 18 characters max */
324*9781SMoriah.Waterland@Sun.COM 		    gettext(MSG_KEYSTORE_IN), icn_str);
325*9781SMoriah.Waterland@Sun.COM 		(void) fprintf(outfile, "%18s: %s\n",
326*9781SMoriah.Waterland@Sun.COM 		    /* i18n: 18 characters max */
327*9781SMoriah.Waterland@Sun.COM 		    gettext(MSG_KEYSTORE_VD), vd_str);
328*9781SMoriah.Waterland@Sun.COM 		(void) fprintf(outfile, "%18s: %s\n", md5_label, md5_fp);
329*9781SMoriah.Waterland@Sun.COM 		(void) fprintf(outfile, "%18s: %s\n", sha1_label, sha1_fp);
330*9781SMoriah.Waterland@Sun.COM 		(void) fprintf(outfile, "\n");
331*9781SMoriah.Waterland@Sun.COM 		break;
332*9781SMoriah.Waterland@Sun.COM 	default:
333*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_INTERNAL,
334*9781SMoriah.Waterland@Sun.COM 		    gettext(ERR_KEYSTORE_INTERNAL),
335*9781SMoriah.Waterland@Sun.COM 		    __FILE__, __LINE__);
336*9781SMoriah.Waterland@Sun.COM 		ret = 1;
337*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
338*9781SMoriah.Waterland@Sun.COM 	}
339*9781SMoriah.Waterland@Sun.COM 
340*9781SMoriah.Waterland@Sun.COM cleanup:
341*9781SMoriah.Waterland@Sun.COM 	if (md5_fp != NULL)
342*9781SMoriah.Waterland@Sun.COM 		free(md5_fp);
343*9781SMoriah.Waterland@Sun.COM 	if (sha1_fp != NULL)
344*9781SMoriah.Waterland@Sun.COM 		free(sha1_fp);
345*9781SMoriah.Waterland@Sun.COM 	if (vda_str != NULL)
346*9781SMoriah.Waterland@Sun.COM 		free(vda_str);
347*9781SMoriah.Waterland@Sun.COM 	if (vdb_str != NULL)
348*9781SMoriah.Waterland@Sun.COM 		free(vdb_str);
349*9781SMoriah.Waterland@Sun.COM 	return (ret);
350*9781SMoriah.Waterland@Sun.COM }
351*9781SMoriah.Waterland@Sun.COM 
352*9781SMoriah.Waterland@Sun.COM /*
353*9781SMoriah.Waterland@Sun.COM  * open_keystore - Initialize new keystore object for
354*9781SMoriah.Waterland@Sun.COM  * impending access.
355*9781SMoriah.Waterland@Sun.COM  *
356*9781SMoriah.Waterland@Sun.COM  * Arguments:
357*9781SMoriah.Waterland@Sun.COM  * err - Error object to append errors to
358*9781SMoriah.Waterland@Sun.COM  * keystore_file - Base filename or directory of keystore
359*9781SMoriah.Waterland@Sun.COM  * app - Application making request
360*9781SMoriah.Waterland@Sun.COM  * passwd - Password used to decrypt keystore
361*9781SMoriah.Waterland@Sun.COM  * flags - Control flags used to control access mode and behavior
362*9781SMoriah.Waterland@Sun.COM  * result - Resulting keystore object stored here on success
363*9781SMoriah.Waterland@Sun.COM  *
364*9781SMoriah.Waterland@Sun.COM  * Returns:
365*9781SMoriah.Waterland@Sun.COM  *   0 - Success - result contains a pointer to the opened keystore
366*9781SMoriah.Waterland@Sun.COM  *   non-zero - Failure, errors added to err
367*9781SMoriah.Waterland@Sun.COM  */
368*9781SMoriah.Waterland@Sun.COM int
open_keystore(PKG_ERR * err,char * keystore_file,char * app,keystore_passphrase_cb cb,long flags,keystore_handle_t * result)369*9781SMoriah.Waterland@Sun.COM open_keystore(PKG_ERR *err, char *keystore_file, char *app,
370*9781SMoriah.Waterland@Sun.COM     keystore_passphrase_cb cb, long flags, keystore_handle_t *result)
371*9781SMoriah.Waterland@Sun.COM {
372*9781SMoriah.Waterland@Sun.COM 	int ret = 0;
373*9781SMoriah.Waterland@Sun.COM 	keystore_t	*tmpstore;
374*9781SMoriah.Waterland@Sun.COM 
375*9781SMoriah.Waterland@Sun.COM 	tmpstore = new_keystore();
376*9781SMoriah.Waterland@Sun.COM 
377*9781SMoriah.Waterland@Sun.COM 	tmpstore->dirty = B_FALSE;
378*9781SMoriah.Waterland@Sun.COM 	tmpstore->new = B_FALSE;
379*9781SMoriah.Waterland@Sun.COM 	tmpstore->path = xstrdup(keystore_file);
380*9781SMoriah.Waterland@Sun.COM 
381*9781SMoriah.Waterland@Sun.COM 	if (!resolve_paths(err, keystore_file, app, flags, tmpstore)) {
382*9781SMoriah.Waterland@Sun.COM 		/* unable to determine keystore paths */
383*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_CORRUPT, gettext(ERR_KEYSTORE_REPAIR),
384*9781SMoriah.Waterland@Sun.COM 		    keystore_file);
385*9781SMoriah.Waterland@Sun.COM 		ret = 1;
386*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
387*9781SMoriah.Waterland@Sun.COM 	}
388*9781SMoriah.Waterland@Sun.COM 
389*9781SMoriah.Waterland@Sun.COM 	if (!verify_keystore_integrity(err, tmpstore)) {
390*9781SMoriah.Waterland@Sun.COM 		/* unable to repair keystore */
391*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_CORRUPT, gettext(ERR_KEYSTORE_REPAIR),
392*9781SMoriah.Waterland@Sun.COM 		    keystore_file);
393*9781SMoriah.Waterland@Sun.COM 		ret = 1;
394*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
395*9781SMoriah.Waterland@Sun.COM 	}
396*9781SMoriah.Waterland@Sun.COM 
397*9781SMoriah.Waterland@Sun.COM 	if (!lock_keystore(err, flags, tmpstore)) {
398*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_LOCKED, gettext(ERR_KEYSTORE_LOCKED),
399*9781SMoriah.Waterland@Sun.COM 		    keystore_file);
400*9781SMoriah.Waterland@Sun.COM 		ret = 1;
401*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
402*9781SMoriah.Waterland@Sun.COM 	}
403*9781SMoriah.Waterland@Sun.COM 
404*9781SMoriah.Waterland@Sun.COM 	/* now that we have locked the keystore, go ahead and read it */
405*9781SMoriah.Waterland@Sun.COM 	if (!read_keystore(err, tmpstore, cb)) {
406*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_READ, gettext(ERR_PARSE),
407*9781SMoriah.Waterland@Sun.COM 		    keystore_file);
408*9781SMoriah.Waterland@Sun.COM 		ret = 1;
409*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
410*9781SMoriah.Waterland@Sun.COM 	}
411*9781SMoriah.Waterland@Sun.COM 
412*9781SMoriah.Waterland@Sun.COM 	*result = tmpstore;
413*9781SMoriah.Waterland@Sun.COM 	tmpstore = NULL;
414*9781SMoriah.Waterland@Sun.COM 
415*9781SMoriah.Waterland@Sun.COM cleanup:
416*9781SMoriah.Waterland@Sun.COM 	if (tmpstore != NULL)
417*9781SMoriah.Waterland@Sun.COM 		free_keystore(tmpstore);
418*9781SMoriah.Waterland@Sun.COM 	return (ret);
419*9781SMoriah.Waterland@Sun.COM }
420*9781SMoriah.Waterland@Sun.COM 
421*9781SMoriah.Waterland@Sun.COM /*
422*9781SMoriah.Waterland@Sun.COM  * new_keystore - Allocates and initializes a Keystore object
423*9781SMoriah.Waterland@Sun.COM  *
424*9781SMoriah.Waterland@Sun.COM  * Arguments:
425*9781SMoriah.Waterland@Sun.COM  * NONE
426*9781SMoriah.Waterland@Sun.COM  *
427*9781SMoriah.Waterland@Sun.COM  * Returns:
428*9781SMoriah.Waterland@Sun.COM  *   NULL - out of memory
429*9781SMoriah.Waterland@Sun.COM  *   otherwise, returns a pointer to the newly allocated object,
430*9781SMoriah.Waterland@Sun.COM  *   which should be freed with free_keystore() when no longer
431*9781SMoriah.Waterland@Sun.COM  *   needed.
432*9781SMoriah.Waterland@Sun.COM  */
433*9781SMoriah.Waterland@Sun.COM static keystore_t
new_keystore(void)434*9781SMoriah.Waterland@Sun.COM *new_keystore(void)
435*9781SMoriah.Waterland@Sun.COM {
436*9781SMoriah.Waterland@Sun.COM 	keystore_t *tmpstore;
437*9781SMoriah.Waterland@Sun.COM 
438*9781SMoriah.Waterland@Sun.COM 	if ((tmpstore = (keystore_t *)malloc(sizeof (keystore_t))) == NULL) {
439*9781SMoriah.Waterland@Sun.COM 		return (NULL);
440*9781SMoriah.Waterland@Sun.COM 	}
441*9781SMoriah.Waterland@Sun.COM 	tmpstore->dirty = B_FALSE;
442*9781SMoriah.Waterland@Sun.COM 	tmpstore->new = B_FALSE;
443*9781SMoriah.Waterland@Sun.COM 	tmpstore->path = NULL;
444*9781SMoriah.Waterland@Sun.COM 	tmpstore->passphrase = NULL;
445*9781SMoriah.Waterland@Sun.COM 	tmpstore->cafd = -1;
446*9781SMoriah.Waterland@Sun.COM 	tmpstore->cacerts = NULL;
447*9781SMoriah.Waterland@Sun.COM 	tmpstore->capath = NULL;
448*9781SMoriah.Waterland@Sun.COM 	tmpstore->clcerts = NULL;
449*9781SMoriah.Waterland@Sun.COM 	tmpstore->clpath = NULL;
450*9781SMoriah.Waterland@Sun.COM 	tmpstore->pkeys = NULL;
451*9781SMoriah.Waterland@Sun.COM 	tmpstore->keypath = NULL;
452*9781SMoriah.Waterland@Sun.COM 
453*9781SMoriah.Waterland@Sun.COM 	return (tmpstore);
454*9781SMoriah.Waterland@Sun.COM }
455*9781SMoriah.Waterland@Sun.COM 
456*9781SMoriah.Waterland@Sun.COM /*
457*9781SMoriah.Waterland@Sun.COM  * free_keystore - Deallocates a Keystore object
458*9781SMoriah.Waterland@Sun.COM  *
459*9781SMoriah.Waterland@Sun.COM  * Arguments:
460*9781SMoriah.Waterland@Sun.COM  * keystore - The keystore to deallocate
461*9781SMoriah.Waterland@Sun.COM  *
462*9781SMoriah.Waterland@Sun.COM  * Returns:
463*9781SMoriah.Waterland@Sun.COM  *   NONE
464*9781SMoriah.Waterland@Sun.COM  */
465*9781SMoriah.Waterland@Sun.COM static void
free_keystore(keystore_t * keystore)466*9781SMoriah.Waterland@Sun.COM free_keystore(keystore_t *keystore)
467*9781SMoriah.Waterland@Sun.COM {
468*9781SMoriah.Waterland@Sun.COM 	if (keystore->path != NULL)
469*9781SMoriah.Waterland@Sun.COM 		free(keystore->path);
470*9781SMoriah.Waterland@Sun.COM 	if (keystore->capath != NULL)
471*9781SMoriah.Waterland@Sun.COM 		free(keystore->capath);
472*9781SMoriah.Waterland@Sun.COM 	if (keystore->passphrase != NULL)
473*9781SMoriah.Waterland@Sun.COM 		free(keystore->passphrase);
474*9781SMoriah.Waterland@Sun.COM 	if (keystore->clpath != NULL)
475*9781SMoriah.Waterland@Sun.COM 		free(keystore->clpath);
476*9781SMoriah.Waterland@Sun.COM 	if (keystore->keypath != NULL)
477*9781SMoriah.Waterland@Sun.COM 		free(keystore->keypath);
478*9781SMoriah.Waterland@Sun.COM 
479*9781SMoriah.Waterland@Sun.COM 	if (keystore->pkeys != NULL) {
480*9781SMoriah.Waterland@Sun.COM 		sk_EVP_PKEY_pop_free(keystore->pkeys,
481*9781SMoriah.Waterland@Sun.COM 		    sunw_evp_pkey_free);
482*9781SMoriah.Waterland@Sun.COM 	}
483*9781SMoriah.Waterland@Sun.COM 	if (keystore->clcerts != NULL)
484*9781SMoriah.Waterland@Sun.COM 		sk_X509_free(keystore->clcerts);
485*9781SMoriah.Waterland@Sun.COM 	if (keystore->cacerts != NULL)
486*9781SMoriah.Waterland@Sun.COM 		sk_X509_free(keystore->cacerts);
487*9781SMoriah.Waterland@Sun.COM 	free(keystore);
488*9781SMoriah.Waterland@Sun.COM }
489*9781SMoriah.Waterland@Sun.COM 
490*9781SMoriah.Waterland@Sun.COM /*
491*9781SMoriah.Waterland@Sun.COM  * close_keystore - Writes keystore to disk if needed, then
492*9781SMoriah.Waterland@Sun.COM  * unlocks and closes keystore.
493*9781SMoriah.Waterland@Sun.COM  *
494*9781SMoriah.Waterland@Sun.COM  * Arguments:
495*9781SMoriah.Waterland@Sun.COM  * err - Error object to append errors to
496*9781SMoriah.Waterland@Sun.COM  * keystore - Keystore which should be closed
497*9781SMoriah.Waterland@Sun.COM  * passwd - Password used to encrypt keystore
498*9781SMoriah.Waterland@Sun.COM  *
499*9781SMoriah.Waterland@Sun.COM  * Returns:
500*9781SMoriah.Waterland@Sun.COM  *   0 - Success - keystore is committed to disk, and unlocked
501*9781SMoriah.Waterland@Sun.COM  *   non-zero - Failure, errors added to err
502*9781SMoriah.Waterland@Sun.COM  */
503*9781SMoriah.Waterland@Sun.COM int
close_keystore(PKG_ERR * err,keystore_handle_t keystore_h,keystore_passphrase_cb cb)504*9781SMoriah.Waterland@Sun.COM close_keystore(PKG_ERR *err, keystore_handle_t keystore_h,
505*9781SMoriah.Waterland@Sun.COM     keystore_passphrase_cb cb)
506*9781SMoriah.Waterland@Sun.COM {
507*9781SMoriah.Waterland@Sun.COM 	int ret = 0;
508*9781SMoriah.Waterland@Sun.COM 	keystore_t *keystore = keystore_h;
509*9781SMoriah.Waterland@Sun.COM 
510*9781SMoriah.Waterland@Sun.COM 	if (keystore->dirty) {
511*9781SMoriah.Waterland@Sun.COM 		/* write out the keystore first */
512*9781SMoriah.Waterland@Sun.COM 		if (!write_keystore(err, keystore, cb)) {
513*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_WRITE,
514*9781SMoriah.Waterland@Sun.COM 			    gettext(ERR_KEYSTORE_WRITE),
515*9781SMoriah.Waterland@Sun.COM 			    keystore->path);
516*9781SMoriah.Waterland@Sun.COM 			ret = 1;
517*9781SMoriah.Waterland@Sun.COM 			goto cleanup;
518*9781SMoriah.Waterland@Sun.COM 		}
519*9781SMoriah.Waterland@Sun.COM 	}
520*9781SMoriah.Waterland@Sun.COM 
521*9781SMoriah.Waterland@Sun.COM 	if (!unlock_keystore(err, keystore)) {
522*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_UNLOCK, gettext(ERR_KEYSTORE_UNLOCK),
523*9781SMoriah.Waterland@Sun.COM 		    keystore->path);
524*9781SMoriah.Waterland@Sun.COM 		ret = 1;
525*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
526*9781SMoriah.Waterland@Sun.COM 	}
527*9781SMoriah.Waterland@Sun.COM 
528*9781SMoriah.Waterland@Sun.COM 	free_keystore(keystore);
529*9781SMoriah.Waterland@Sun.COM cleanup:
530*9781SMoriah.Waterland@Sun.COM 	return (ret);
531*9781SMoriah.Waterland@Sun.COM }
532*9781SMoriah.Waterland@Sun.COM 
533*9781SMoriah.Waterland@Sun.COM /*
534*9781SMoriah.Waterland@Sun.COM  * merge_ca_cert - Adds a trusted certificate (trust anchor) to a keystore.
535*9781SMoriah.Waterland@Sun.COM  * certificate checked for validity dates and non-duplicity.
536*9781SMoriah.Waterland@Sun.COM  *
537*9781SMoriah.Waterland@Sun.COM  * Arguments:
538*9781SMoriah.Waterland@Sun.COM  * err - Error object to add errors to
539*9781SMoriah.Waterland@Sun.COM  * cacert - Certificate which to merge into keystore
540*9781SMoriah.Waterland@Sun.COM  * keystore - The keystore into which the certificate is merged
541*9781SMoriah.Waterland@Sun.COM  *
542*9781SMoriah.Waterland@Sun.COM  * Returns:
543*9781SMoriah.Waterland@Sun.COM  *   0 - Success - Certificate passes validity, and
544*9781SMoriah.Waterland@Sun.COM  *		is merged into keystore
545*9781SMoriah.Waterland@Sun.COM  * non-zero - Failure, errors recorded in err
546*9781SMoriah.Waterland@Sun.COM  */
547*9781SMoriah.Waterland@Sun.COM int
merge_ca_cert(PKG_ERR * err,X509 * cacert,keystore_handle_t keystore_h)548*9781SMoriah.Waterland@Sun.COM merge_ca_cert(PKG_ERR *err, X509 *cacert, keystore_handle_t keystore_h)
549*9781SMoriah.Waterland@Sun.COM {
550*9781SMoriah.Waterland@Sun.COM 
551*9781SMoriah.Waterland@Sun.COM 	int		ret = 0;
552*9781SMoriah.Waterland@Sun.COM 	X509		*existing = NULL;
553*9781SMoriah.Waterland@Sun.COM 	char		*fname;
554*9781SMoriah.Waterland@Sun.COM 	keystore_t	*keystore = keystore_h;
555*9781SMoriah.Waterland@Sun.COM 
556*9781SMoriah.Waterland@Sun.COM 	/* check validity dates */
557*9781SMoriah.Waterland@Sun.COM 	if (check_cert(err, cacert) != 0) {
558*9781SMoriah.Waterland@Sun.COM 		ret = 1;
559*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
560*9781SMoriah.Waterland@Sun.COM 	}
561*9781SMoriah.Waterland@Sun.COM 
562*9781SMoriah.Waterland@Sun.COM 	/* create the certificate's friendlyName */
563*9781SMoriah.Waterland@Sun.COM 	fname = get_subject_display_name(cacert);
564*9781SMoriah.Waterland@Sun.COM 
565*9781SMoriah.Waterland@Sun.COM 	if (sunw_set_fname(fname, NULL, cacert) != 0) {
566*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM));
567*9781SMoriah.Waterland@Sun.COM 		ret = 1;
568*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
569*9781SMoriah.Waterland@Sun.COM 	}
570*9781SMoriah.Waterland@Sun.COM 
571*9781SMoriah.Waterland@Sun.COM 	/* merge certificate into the keystore */
572*9781SMoriah.Waterland@Sun.COM 	if (keystore->cacerts == NULL) {
573*9781SMoriah.Waterland@Sun.COM 		/* no existing truststore, so make a new one */
574*9781SMoriah.Waterland@Sun.COM 		if ((keystore->cacerts = sk_X509_new_null()) == NULL) {
575*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM));
576*9781SMoriah.Waterland@Sun.COM 			ret = 1;
577*9781SMoriah.Waterland@Sun.COM 			goto cleanup;
578*9781SMoriah.Waterland@Sun.COM 		}
579*9781SMoriah.Waterland@Sun.COM 	} else {
580*9781SMoriah.Waterland@Sun.COM 		/* existing truststore, make sure there's no duplicate */
581*9781SMoriah.Waterland@Sun.COM 		if (sunw_find_fname(fname, NULL, keystore->cacerts,
582*9781SMoriah.Waterland@Sun.COM 		    NULL, &existing) < 0) {
583*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_INTERNAL,
584*9781SMoriah.Waterland@Sun.COM 			    gettext(ERR_KEYSTORE_INTERNAL),
585*9781SMoriah.Waterland@Sun.COM 			    __FILE__, __LINE__);
586*9781SMoriah.Waterland@Sun.COM 			ERR_print_errors_fp(stderr);
587*9781SMoriah.Waterland@Sun.COM 			ret = 1;
588*9781SMoriah.Waterland@Sun.COM 			goto cleanup;
589*9781SMoriah.Waterland@Sun.COM 			/* could not search properly! */
590*9781SMoriah.Waterland@Sun.COM 		}
591*9781SMoriah.Waterland@Sun.COM 		if (existing != NULL) {
592*9781SMoriah.Waterland@Sun.COM 			/* whoops, found one already */
593*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_DUPLICATE,
594*9781SMoriah.Waterland@Sun.COM 			    gettext(ERR_KEYSTORE_DUPLICATECERT), fname);
595*9781SMoriah.Waterland@Sun.COM 			ret = 1;
596*9781SMoriah.Waterland@Sun.COM 			goto cleanup;
597*9781SMoriah.Waterland@Sun.COM 		}
598*9781SMoriah.Waterland@Sun.COM 	}
599*9781SMoriah.Waterland@Sun.COM 
600*9781SMoriah.Waterland@Sun.COM 	(void) sk_X509_push(keystore->cacerts, cacert);
601*9781SMoriah.Waterland@Sun.COM 	keystore->dirty = B_TRUE;
602*9781SMoriah.Waterland@Sun.COM cleanup:
603*9781SMoriah.Waterland@Sun.COM 	if (existing != NULL)
604*9781SMoriah.Waterland@Sun.COM 		X509_free(existing);
605*9781SMoriah.Waterland@Sun.COM 	return (ret);
606*9781SMoriah.Waterland@Sun.COM }
607*9781SMoriah.Waterland@Sun.COM 
608*9781SMoriah.Waterland@Sun.COM /*
609*9781SMoriah.Waterland@Sun.COM  * find_key_cert_pair - Searches a keystore for a matching
610*9781SMoriah.Waterland@Sun.COM  * public key certificate and private key, given an alias.
611*9781SMoriah.Waterland@Sun.COM  *
612*9781SMoriah.Waterland@Sun.COM  * Arguments:
613*9781SMoriah.Waterland@Sun.COM  * err - Error object to add errors to
614*9781SMoriah.Waterland@Sun.COM  * ks - Keystore to search
615*9781SMoriah.Waterland@Sun.COM  * alias - Name to used to match certificate's alias
616*9781SMoriah.Waterland@Sun.COM  * key - Resulting key is placed here
617*9781SMoriah.Waterland@Sun.COM  * cert - Resulting cert is placed here
618*9781SMoriah.Waterland@Sun.COM  *
619*9781SMoriah.Waterland@Sun.COM  * Returns:
620*9781SMoriah.Waterland@Sun.COM  *   0 - Success - Matching cert/key pair placed in key and cert.
621*9781SMoriah.Waterland@Sun.COM  * non-zero - Failure, errors recorded in err
622*9781SMoriah.Waterland@Sun.COM  */
623*9781SMoriah.Waterland@Sun.COM int
find_key_cert_pair(PKG_ERR * err,keystore_handle_t ks_h,char * alias,EVP_PKEY ** key,X509 ** cert)624*9781SMoriah.Waterland@Sun.COM find_key_cert_pair(PKG_ERR *err, keystore_handle_t ks_h, char *alias,
625*9781SMoriah.Waterland@Sun.COM     EVP_PKEY **key, X509 **cert)
626*9781SMoriah.Waterland@Sun.COM {
627*9781SMoriah.Waterland@Sun.COM 	X509		*tmpcert = NULL;
628*9781SMoriah.Waterland@Sun.COM 	EVP_PKEY	*tmpkey = NULL;
629*9781SMoriah.Waterland@Sun.COM 	int		ret = 0;
630*9781SMoriah.Waterland@Sun.COM 	int		items_found;
631*9781SMoriah.Waterland@Sun.COM 	keystore_t	*ks = ks_h;
632*9781SMoriah.Waterland@Sun.COM 
633*9781SMoriah.Waterland@Sun.COM 	if (key == NULL || cert == NULL) {
634*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_NOPUBKEY,
635*9781SMoriah.Waterland@Sun.COM 		    gettext(ERR_KEYSTORE_NOPUBCERTS), ks->path);
636*9781SMoriah.Waterland@Sun.COM 		ret = 1;
637*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
638*9781SMoriah.Waterland@Sun.COM 	}
639*9781SMoriah.Waterland@Sun.COM 
640*9781SMoriah.Waterland@Sun.COM 	if (ks->clcerts == NULL) {
641*9781SMoriah.Waterland@Sun.COM 		/* no public certs */
642*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_NOPUBKEY,
643*9781SMoriah.Waterland@Sun.COM 		    gettext(ERR_KEYSTORE_NOCERTS), ks->path);
644*9781SMoriah.Waterland@Sun.COM 		ret = 1;
645*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
646*9781SMoriah.Waterland@Sun.COM 	}
647*9781SMoriah.Waterland@Sun.COM 	if (ks->pkeys == NULL) {
648*9781SMoriah.Waterland@Sun.COM 		/* no private keys */
649*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_NOPRIVKEY,
650*9781SMoriah.Waterland@Sun.COM 		    gettext(ERR_KEYSTORE_NOKEYS), ks->path);
651*9781SMoriah.Waterland@Sun.COM 		ret = 1;
652*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
653*9781SMoriah.Waterland@Sun.COM 	}
654*9781SMoriah.Waterland@Sun.COM 
655*9781SMoriah.Waterland@Sun.COM 	/* try the easy case first */
656*9781SMoriah.Waterland@Sun.COM 	if ((sk_EVP_PKEY_num(ks->pkeys) == 1) &&
657*9781SMoriah.Waterland@Sun.COM 	    (sk_X509_num(ks->clcerts) == 1)) {
658*9781SMoriah.Waterland@Sun.COM 		tmpkey = sk_EVP_PKEY_value(ks->pkeys, 0);
659*9781SMoriah.Waterland@Sun.COM 		tmpcert = sk_X509_value(ks->clcerts, 0);
660*9781SMoriah.Waterland@Sun.COM 		if (sunw_check_keys(tmpcert, tmpkey)) {
661*9781SMoriah.Waterland@Sun.COM 			/*
662*9781SMoriah.Waterland@Sun.COM 			 * only one private key and public key cert, and they
663*9781SMoriah.Waterland@Sun.COM 			 * match, so use them
664*9781SMoriah.Waterland@Sun.COM 			 */
665*9781SMoriah.Waterland@Sun.COM 			*key = tmpkey;
666*9781SMoriah.Waterland@Sun.COM 			tmpkey = NULL;
667*9781SMoriah.Waterland@Sun.COM 			*cert = tmpcert;
668*9781SMoriah.Waterland@Sun.COM 			tmpcert = NULL;
669*9781SMoriah.Waterland@Sun.COM 			goto cleanup;
670*9781SMoriah.Waterland@Sun.COM 		}
671*9781SMoriah.Waterland@Sun.COM 	}
672*9781SMoriah.Waterland@Sun.COM 
673*9781SMoriah.Waterland@Sun.COM 	/* Attempt to find the right pair given the alias */
674*9781SMoriah.Waterland@Sun.COM 	items_found = sunw_find_fname(alias, ks->pkeys, ks->clcerts,
675*9781SMoriah.Waterland@Sun.COM 	    &tmpkey, &tmpcert);
676*9781SMoriah.Waterland@Sun.COM 
677*9781SMoriah.Waterland@Sun.COM 	if ((items_found < 0) ||
678*9781SMoriah.Waterland@Sun.COM 	    (items_found & (FOUND_PKEY | FOUND_CERT)) == 0) {
679*9781SMoriah.Waterland@Sun.COM 		/* no key/cert pair found. bail. */
680*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_BADALIAS,
681*9781SMoriah.Waterland@Sun.COM 		    gettext(ERR_KEYSTORE_NOMATCH), alias);
682*9781SMoriah.Waterland@Sun.COM 		ret = 1;
683*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
684*9781SMoriah.Waterland@Sun.COM 	}
685*9781SMoriah.Waterland@Sun.COM 
686*9781SMoriah.Waterland@Sun.COM 	/* success */
687*9781SMoriah.Waterland@Sun.COM 	*key = tmpkey;
688*9781SMoriah.Waterland@Sun.COM 	tmpkey = NULL;
689*9781SMoriah.Waterland@Sun.COM 	*cert = tmpcert;
690*9781SMoriah.Waterland@Sun.COM 	tmpcert = NULL;
691*9781SMoriah.Waterland@Sun.COM 
692*9781SMoriah.Waterland@Sun.COM cleanup:
693*9781SMoriah.Waterland@Sun.COM 
694*9781SMoriah.Waterland@Sun.COM 	if (tmpcert != NULL)
695*9781SMoriah.Waterland@Sun.COM 		(void) X509_free(tmpcert);
696*9781SMoriah.Waterland@Sun.COM 
697*9781SMoriah.Waterland@Sun.COM 	if (tmpkey != NULL)
698*9781SMoriah.Waterland@Sun.COM 		sunw_evp_pkey_free(tmpkey);
699*9781SMoriah.Waterland@Sun.COM 
700*9781SMoriah.Waterland@Sun.COM 	return (ret);
701*9781SMoriah.Waterland@Sun.COM }
702*9781SMoriah.Waterland@Sun.COM 
703*9781SMoriah.Waterland@Sun.COM /*
704*9781SMoriah.Waterland@Sun.COM  * find_ca_certs - Searches a keystore for trusted certificates
705*9781SMoriah.Waterland@Sun.COM  *
706*9781SMoriah.Waterland@Sun.COM  * Arguments:
707*9781SMoriah.Waterland@Sun.COM  * err - Error object to add errors to
708*9781SMoriah.Waterland@Sun.COM  * ks - Keystore to search
709*9781SMoriah.Waterland@Sun.COM  * cacerts - resulting set of trusted certs are placed here
710*9781SMoriah.Waterland@Sun.COM  *
711*9781SMoriah.Waterland@Sun.COM  * Returns:
712*9781SMoriah.Waterland@Sun.COM  *   0 - Success - trusted cert list returned in cacerts
713*9781SMoriah.Waterland@Sun.COM  * non-zero - Failure, errors recorded in err
714*9781SMoriah.Waterland@Sun.COM  */
715*9781SMoriah.Waterland@Sun.COM int
find_ca_certs(PKG_ERR * err,keystore_handle_t ks_h,STACK_OF (X509)** cacerts)716*9781SMoriah.Waterland@Sun.COM find_ca_certs(PKG_ERR *err, keystore_handle_t ks_h, STACK_OF(X509) **cacerts)
717*9781SMoriah.Waterland@Sun.COM {
718*9781SMoriah.Waterland@Sun.COM 
719*9781SMoriah.Waterland@Sun.COM 	keystore_t	*ks = ks_h;
720*9781SMoriah.Waterland@Sun.COM 
721*9781SMoriah.Waterland@Sun.COM 	/* easy */
722*9781SMoriah.Waterland@Sun.COM 	if (cacerts == NULL) {
723*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_INTERNAL,
724*9781SMoriah.Waterland@Sun.COM 		    gettext(ERR_KEYSTORE_INTERNAL), __FILE__, __LINE__);
725*9781SMoriah.Waterland@Sun.COM 		return (1);
726*9781SMoriah.Waterland@Sun.COM 	}
727*9781SMoriah.Waterland@Sun.COM 
728*9781SMoriah.Waterland@Sun.COM 	*cacerts = ks->cacerts;
729*9781SMoriah.Waterland@Sun.COM 	return (0);
730*9781SMoriah.Waterland@Sun.COM }
731*9781SMoriah.Waterland@Sun.COM 
732*9781SMoriah.Waterland@Sun.COM /*
733*9781SMoriah.Waterland@Sun.COM  * find_cl_certs - Searches a keystore for user certificates
734*9781SMoriah.Waterland@Sun.COM  *
735*9781SMoriah.Waterland@Sun.COM  * Arguments:
736*9781SMoriah.Waterland@Sun.COM  * err - Error object to add errors to
737*9781SMoriah.Waterland@Sun.COM  * ks - Keystore to search
738*9781SMoriah.Waterland@Sun.COM  * cacerts - resulting set of user certs are placed here
739*9781SMoriah.Waterland@Sun.COM  *
740*9781SMoriah.Waterland@Sun.COM  * No matching of any kind is performed.
741*9781SMoriah.Waterland@Sun.COM  * Returns:
742*9781SMoriah.Waterland@Sun.COM  *   0 - Success - trusted cert list returned in cacerts
743*9781SMoriah.Waterland@Sun.COM  * non-zero - Failure, errors recorded in err
744*9781SMoriah.Waterland@Sun.COM  */
745*9781SMoriah.Waterland@Sun.COM /* ARGSUSED */
746*9781SMoriah.Waterland@Sun.COM int
find_cl_certs(PKG_ERR * err,keystore_handle_t ks_h,STACK_OF (X509)** clcerts)747*9781SMoriah.Waterland@Sun.COM find_cl_certs(PKG_ERR *err, keystore_handle_t ks_h, STACK_OF(X509) **clcerts)
748*9781SMoriah.Waterland@Sun.COM {
749*9781SMoriah.Waterland@Sun.COM 	keystore_t	*ks = ks_h;
750*9781SMoriah.Waterland@Sun.COM 
751*9781SMoriah.Waterland@Sun.COM 	/* easy */
752*9781SMoriah.Waterland@Sun.COM 	*clcerts = ks->clcerts;
753*9781SMoriah.Waterland@Sun.COM 	return (0);
754*9781SMoriah.Waterland@Sun.COM }
755*9781SMoriah.Waterland@Sun.COM 
756*9781SMoriah.Waterland@Sun.COM 
757*9781SMoriah.Waterland@Sun.COM /*
758*9781SMoriah.Waterland@Sun.COM  * merge_cert_and_key - Adds a user certificate and matching
759*9781SMoriah.Waterland@Sun.COM  * private key to a keystore.
760*9781SMoriah.Waterland@Sun.COM  * certificate checked for validity dates and non-duplicity.
761*9781SMoriah.Waterland@Sun.COM  *
762*9781SMoriah.Waterland@Sun.COM  * Arguments:
763*9781SMoriah.Waterland@Sun.COM  * err - Error object to add errors to
764*9781SMoriah.Waterland@Sun.COM  * cert - Certificate which to merge into keystore
765*9781SMoriah.Waterland@Sun.COM  * key - matching private key to 'cert'
766*9781SMoriah.Waterland@Sun.COM  * alias - Name which to store the cert and key under
767*9781SMoriah.Waterland@Sun.COM  * keystore - The keystore into which the certificate is merged
768*9781SMoriah.Waterland@Sun.COM  *
769*9781SMoriah.Waterland@Sun.COM  * Returns:
770*9781SMoriah.Waterland@Sun.COM  *   0 - Success - Certificate passes validity, and
771*9781SMoriah.Waterland@Sun.COM  *		is merged into keystore, along with key
772*9781SMoriah.Waterland@Sun.COM  * non-zero - Failure, errors recorded in err
773*9781SMoriah.Waterland@Sun.COM  */
774*9781SMoriah.Waterland@Sun.COM int
merge_cert_and_key(PKG_ERR * err,X509 * cert,EVP_PKEY * key,char * alias,keystore_handle_t keystore_h)775*9781SMoriah.Waterland@Sun.COM merge_cert_and_key(PKG_ERR *err, X509 *cert, EVP_PKEY *key, char *alias,
776*9781SMoriah.Waterland@Sun.COM     keystore_handle_t keystore_h)
777*9781SMoriah.Waterland@Sun.COM {
778*9781SMoriah.Waterland@Sun.COM 	X509		*existingcert = NULL;
779*9781SMoriah.Waterland@Sun.COM 	EVP_PKEY	*existingkey = NULL;
780*9781SMoriah.Waterland@Sun.COM 	int		ret = 0;
781*9781SMoriah.Waterland@Sun.COM 	keystore_t	*keystore = keystore_h;
782*9781SMoriah.Waterland@Sun.COM 
783*9781SMoriah.Waterland@Sun.COM 	/* check validity dates */
784*9781SMoriah.Waterland@Sun.COM 	if (check_cert(err, cert) != 0) {
785*9781SMoriah.Waterland@Sun.COM 		ret = 1;
786*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
787*9781SMoriah.Waterland@Sun.COM 	}
788*9781SMoriah.Waterland@Sun.COM 
789*9781SMoriah.Waterland@Sun.COM 	/* set the friendlyName of the key and cert to the supplied alias */
790*9781SMoriah.Waterland@Sun.COM 	if (sunw_set_fname(alias, key, cert) != 0) {
791*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM));
792*9781SMoriah.Waterland@Sun.COM 		ret = 1;
793*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
794*9781SMoriah.Waterland@Sun.COM 	}
795*9781SMoriah.Waterland@Sun.COM 
796*9781SMoriah.Waterland@Sun.COM 	/* merge certificate and key into the keystore */
797*9781SMoriah.Waterland@Sun.COM 	if (keystore->clcerts == NULL) {
798*9781SMoriah.Waterland@Sun.COM 		/* no existing truststore, so make a new one */
799*9781SMoriah.Waterland@Sun.COM 		if ((keystore->clcerts = sk_X509_new_null()) == NULL) {
800*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM));
801*9781SMoriah.Waterland@Sun.COM 			ret = 1;
802*9781SMoriah.Waterland@Sun.COM 			goto cleanup;
803*9781SMoriah.Waterland@Sun.COM 		}
804*9781SMoriah.Waterland@Sun.COM 	} else {
805*9781SMoriah.Waterland@Sun.COM 		/* existing certstore, make sure there's no duplicate */
806*9781SMoriah.Waterland@Sun.COM 		if (sunw_find_fname(alias, NULL, keystore->clcerts,
807*9781SMoriah.Waterland@Sun.COM 		    NULL, &existingcert) < 0) {
808*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_INTERNAL,
809*9781SMoriah.Waterland@Sun.COM 			    gettext(ERR_KEYSTORE_INTERNAL),
810*9781SMoriah.Waterland@Sun.COM 			    __FILE__, __LINE__);
811*9781SMoriah.Waterland@Sun.COM 			ERR_print_errors_fp(stderr);
812*9781SMoriah.Waterland@Sun.COM 			ret = 1;
813*9781SMoriah.Waterland@Sun.COM 			goto cleanup;
814*9781SMoriah.Waterland@Sun.COM 			/* could not search properly! */
815*9781SMoriah.Waterland@Sun.COM 		}
816*9781SMoriah.Waterland@Sun.COM 		if (existingcert != NULL) {
817*9781SMoriah.Waterland@Sun.COM 			/* whoops, found one already */
818*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_DUPLICATE,
819*9781SMoriah.Waterland@Sun.COM 			    gettext(ERR_KEYSTORE_DUPLICATECERT), alias);
820*9781SMoriah.Waterland@Sun.COM 			ret = 1;
821*9781SMoriah.Waterland@Sun.COM 			goto cleanup;
822*9781SMoriah.Waterland@Sun.COM 		}
823*9781SMoriah.Waterland@Sun.COM 	}
824*9781SMoriah.Waterland@Sun.COM 
825*9781SMoriah.Waterland@Sun.COM 	if (keystore->pkeys == NULL) {
826*9781SMoriah.Waterland@Sun.COM 		/* no existing keystore, so make a new one */
827*9781SMoriah.Waterland@Sun.COM 		if ((keystore->pkeys = sk_EVP_PKEY_new_null()) == NULL) {
828*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM));
829*9781SMoriah.Waterland@Sun.COM 			ret = 1;
830*9781SMoriah.Waterland@Sun.COM 			goto cleanup;
831*9781SMoriah.Waterland@Sun.COM 		}
832*9781SMoriah.Waterland@Sun.COM 	} else {
833*9781SMoriah.Waterland@Sun.COM 		/* existing keystore, so make sure there's no duplicate entry */
834*9781SMoriah.Waterland@Sun.COM 		if (sunw_find_fname(alias, keystore->pkeys, NULL,
835*9781SMoriah.Waterland@Sun.COM 		    &existingkey, NULL) < 0) {
836*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_INTERNAL,
837*9781SMoriah.Waterland@Sun.COM 			    gettext(ERR_KEYSTORE_INTERNAL),
838*9781SMoriah.Waterland@Sun.COM 			    __FILE__, __LINE__);
839*9781SMoriah.Waterland@Sun.COM 			ERR_print_errors_fp(stderr);
840*9781SMoriah.Waterland@Sun.COM 			ret = 1;
841*9781SMoriah.Waterland@Sun.COM 			goto cleanup;
842*9781SMoriah.Waterland@Sun.COM 			/* could not search properly! */
843*9781SMoriah.Waterland@Sun.COM 		}
844*9781SMoriah.Waterland@Sun.COM 		if (existingkey != NULL) {
845*9781SMoriah.Waterland@Sun.COM 			/* whoops, found one already */
846*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_DUPLICATE,
847*9781SMoriah.Waterland@Sun.COM 			    gettext(ERR_KEYSTORE_DUPLICATEKEY), alias);
848*9781SMoriah.Waterland@Sun.COM 			ret = 1;
849*9781SMoriah.Waterland@Sun.COM 			goto cleanup;
850*9781SMoriah.Waterland@Sun.COM 		}
851*9781SMoriah.Waterland@Sun.COM 	}
852*9781SMoriah.Waterland@Sun.COM 
853*9781SMoriah.Waterland@Sun.COM 	(void) sk_X509_push(keystore->clcerts, cert);
854*9781SMoriah.Waterland@Sun.COM 	(void) sk_EVP_PKEY_push(keystore->pkeys, key);
855*9781SMoriah.Waterland@Sun.COM 	keystore->dirty = B_TRUE;
856*9781SMoriah.Waterland@Sun.COM cleanup:
857*9781SMoriah.Waterland@Sun.COM 	if (existingcert != NULL)
858*9781SMoriah.Waterland@Sun.COM 		(void) X509_free(existingcert);
859*9781SMoriah.Waterland@Sun.COM 	if (existingkey != NULL)
860*9781SMoriah.Waterland@Sun.COM 		(void) sunw_evp_pkey_free(existingkey);
861*9781SMoriah.Waterland@Sun.COM 	return (ret);
862*9781SMoriah.Waterland@Sun.COM }
863*9781SMoriah.Waterland@Sun.COM 
864*9781SMoriah.Waterland@Sun.COM /*
865*9781SMoriah.Waterland@Sun.COM  * delete_cert_and_keys - Deletes one or more certificates
866*9781SMoriah.Waterland@Sun.COM  *  and matching private keys from a keystore.
867*9781SMoriah.Waterland@Sun.COM  *
868*9781SMoriah.Waterland@Sun.COM  * Arguments:
869*9781SMoriah.Waterland@Sun.COM  * err - Error object to add errors to
870*9781SMoriah.Waterland@Sun.COM  * ks - The keystore from which certs and keys are deleted
871*9781SMoriah.Waterland@Sun.COM  * alias - Name which to search for certificates and keys
872*9781SMoriah.Waterland@Sun.COM  *	to delete
873*9781SMoriah.Waterland@Sun.COM  *
874*9781SMoriah.Waterland@Sun.COM  * Returns:
875*9781SMoriah.Waterland@Sun.COM  *   0 - Success - All trusted certs which match 'alias'
876*9781SMoriah.Waterland@Sun.COM  *		are deleted.  All user certificates
877*9781SMoriah.Waterland@Sun.COM  *		which match 'alias' are deleted, along
878*9781SMoriah.Waterland@Sun.COM  *		with the matching private key.
879*9781SMoriah.Waterland@Sun.COM  * non-zero - Failure, errors recorded in err
880*9781SMoriah.Waterland@Sun.COM  */
881*9781SMoriah.Waterland@Sun.COM int
delete_cert_and_keys(PKG_ERR * err,keystore_handle_t ks_h,char * alias)882*9781SMoriah.Waterland@Sun.COM delete_cert_and_keys(PKG_ERR *err, keystore_handle_t ks_h, char *alias)
883*9781SMoriah.Waterland@Sun.COM {
884*9781SMoriah.Waterland@Sun.COM 	X509		*existingcert;
885*9781SMoriah.Waterland@Sun.COM 	EVP_PKEY	*existingkey;
886*9781SMoriah.Waterland@Sun.COM 	int		i;
887*9781SMoriah.Waterland@Sun.COM 	char		*fname = NULL;
888*9781SMoriah.Waterland@Sun.COM 	boolean_t	found = B_FALSE;
889*9781SMoriah.Waterland@Sun.COM 	keystore_t	*ks = ks_h;
890*9781SMoriah.Waterland@Sun.COM 
891*9781SMoriah.Waterland@Sun.COM 	/* delete any and all client certs with the supplied name */
892*9781SMoriah.Waterland@Sun.COM 	if (ks->clcerts != NULL) {
893*9781SMoriah.Waterland@Sun.COM 		for (i = 0; i < sk_X509_num(ks->clcerts); i++) {
894*9781SMoriah.Waterland@Sun.COM 			existingcert = sk_X509_value(ks->clcerts, i);
895*9781SMoriah.Waterland@Sun.COM 			if (sunw_get_cert_fname(GETDO_COPY,
896*9781SMoriah.Waterland@Sun.COM 			    existingcert, &fname) >= 0) {
897*9781SMoriah.Waterland@Sun.COM 				if (streq(fname, alias)) {
898*9781SMoriah.Waterland@Sun.COM 					/* match, so nuke it */
899*9781SMoriah.Waterland@Sun.COM 					existingcert =
900*9781SMoriah.Waterland@Sun.COM 					    sk_X509_delete(ks->clcerts, i);
901*9781SMoriah.Waterland@Sun.COM 					X509_free(existingcert);
902*9781SMoriah.Waterland@Sun.COM 					existingcert = NULL;
903*9781SMoriah.Waterland@Sun.COM 					found = B_TRUE;
904*9781SMoriah.Waterland@Sun.COM 				}
905*9781SMoriah.Waterland@Sun.COM 				(void) OPENSSL_free(fname);
906*9781SMoriah.Waterland@Sun.COM 				fname = NULL;
907*9781SMoriah.Waterland@Sun.COM 			}
908*9781SMoriah.Waterland@Sun.COM 		}
909*9781SMoriah.Waterland@Sun.COM 		if (sk_X509_num(ks->clcerts) <= 0) {
910*9781SMoriah.Waterland@Sun.COM 			/* we deleted all the client certs */
911*9781SMoriah.Waterland@Sun.COM 			sk_X509_free(ks->clcerts);
912*9781SMoriah.Waterland@Sun.COM 			ks->clcerts = NULL;
913*9781SMoriah.Waterland@Sun.COM 		}
914*9781SMoriah.Waterland@Sun.COM 	}
915*9781SMoriah.Waterland@Sun.COM 
916*9781SMoriah.Waterland@Sun.COM 	/* and now the private keys */
917*9781SMoriah.Waterland@Sun.COM 	if (ks->pkeys != NULL) {
918*9781SMoriah.Waterland@Sun.COM 		for (i = 0; i < sk_EVP_PKEY_num(ks->pkeys); i++) {
919*9781SMoriah.Waterland@Sun.COM 			existingkey = sk_EVP_PKEY_value(ks->pkeys, i);
920*9781SMoriah.Waterland@Sun.COM 			if (sunw_get_pkey_fname(GETDO_COPY,
921*9781SMoriah.Waterland@Sun.COM 			    existingkey, &fname) >= 0) {
922*9781SMoriah.Waterland@Sun.COM 				if (streq(fname, alias)) {
923*9781SMoriah.Waterland@Sun.COM 					/* match, so nuke it */
924*9781SMoriah.Waterland@Sun.COM 					existingkey =
925*9781SMoriah.Waterland@Sun.COM 					    sk_EVP_PKEY_delete(ks->pkeys, i);
926*9781SMoriah.Waterland@Sun.COM 					sunw_evp_pkey_free(existingkey);
927*9781SMoriah.Waterland@Sun.COM 					existingkey = NULL;
928*9781SMoriah.Waterland@Sun.COM 					found = B_TRUE;
929*9781SMoriah.Waterland@Sun.COM 				}
930*9781SMoriah.Waterland@Sun.COM 				(void) OPENSSL_free(fname);
931*9781SMoriah.Waterland@Sun.COM 				fname = NULL;
932*9781SMoriah.Waterland@Sun.COM 			}
933*9781SMoriah.Waterland@Sun.COM 		}
934*9781SMoriah.Waterland@Sun.COM 		if (sk_EVP_PKEY_num(ks->pkeys) <= 0) {
935*9781SMoriah.Waterland@Sun.COM 			/* we deleted all the private keys */
936*9781SMoriah.Waterland@Sun.COM 			sk_EVP_PKEY_free(ks->pkeys);
937*9781SMoriah.Waterland@Sun.COM 			ks->pkeys = NULL;
938*9781SMoriah.Waterland@Sun.COM 		}
939*9781SMoriah.Waterland@Sun.COM 	}
940*9781SMoriah.Waterland@Sun.COM 
941*9781SMoriah.Waterland@Sun.COM 	/* finally, remove any trust anchors that match */
942*9781SMoriah.Waterland@Sun.COM 
943*9781SMoriah.Waterland@Sun.COM 	if (ks->cacerts != NULL) {
944*9781SMoriah.Waterland@Sun.COM 		for (i = 0; i < sk_X509_num(ks->cacerts); i++) {
945*9781SMoriah.Waterland@Sun.COM 			existingcert = sk_X509_value(ks->cacerts, i);
946*9781SMoriah.Waterland@Sun.COM 			if (sunw_get_cert_fname(GETDO_COPY,
947*9781SMoriah.Waterland@Sun.COM 			    existingcert, &fname) >= 0) {
948*9781SMoriah.Waterland@Sun.COM 				if (streq(fname, alias)) {
949*9781SMoriah.Waterland@Sun.COM 					/* match, so nuke it */
950*9781SMoriah.Waterland@Sun.COM 					existingcert =
951*9781SMoriah.Waterland@Sun.COM 					    sk_X509_delete(ks->cacerts, i);
952*9781SMoriah.Waterland@Sun.COM 					X509_free(existingcert);
953*9781SMoriah.Waterland@Sun.COM 					existingcert = NULL;
954*9781SMoriah.Waterland@Sun.COM 					found = B_TRUE;
955*9781SMoriah.Waterland@Sun.COM 				}
956*9781SMoriah.Waterland@Sun.COM 				(void) OPENSSL_free(fname);
957*9781SMoriah.Waterland@Sun.COM 				fname = NULL;
958*9781SMoriah.Waterland@Sun.COM 			}
959*9781SMoriah.Waterland@Sun.COM 		}
960*9781SMoriah.Waterland@Sun.COM 		if (sk_X509_num(ks->cacerts) <= 0) {
961*9781SMoriah.Waterland@Sun.COM 			/* we deleted all the CA certs */
962*9781SMoriah.Waterland@Sun.COM 			sk_X509_free(ks->cacerts);
963*9781SMoriah.Waterland@Sun.COM 			ks->cacerts = NULL;
964*9781SMoriah.Waterland@Sun.COM 		}
965*9781SMoriah.Waterland@Sun.COM 	}
966*9781SMoriah.Waterland@Sun.COM 
967*9781SMoriah.Waterland@Sun.COM 	if (found) {
968*9781SMoriah.Waterland@Sun.COM 		ks->dirty = B_TRUE;
969*9781SMoriah.Waterland@Sun.COM 		return (0);
970*9781SMoriah.Waterland@Sun.COM 	} else {
971*9781SMoriah.Waterland@Sun.COM 		/* no certs or keys deleted */
972*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_NOALIASMATCH,
973*9781SMoriah.Waterland@Sun.COM 		    gettext(ERR_KEYSTORE_NOCERTKEY),
974*9781SMoriah.Waterland@Sun.COM 		    alias, ks->path);
975*9781SMoriah.Waterland@Sun.COM 		return (1);
976*9781SMoriah.Waterland@Sun.COM 	}
977*9781SMoriah.Waterland@Sun.COM }
978*9781SMoriah.Waterland@Sun.COM 
979*9781SMoriah.Waterland@Sun.COM /*
980*9781SMoriah.Waterland@Sun.COM  * check_cert - Checks certificate validity.  This routine
981*9781SMoriah.Waterland@Sun.COM  * checks that the current time falls within the period
982*9781SMoriah.Waterland@Sun.COM  * of validity for the cert.
983*9781SMoriah.Waterland@Sun.COM  *
984*9781SMoriah.Waterland@Sun.COM  * Arguments:
985*9781SMoriah.Waterland@Sun.COM  * err - Error object to add errors to
986*9781SMoriah.Waterland@Sun.COM  * cert - The certificate to check
987*9781SMoriah.Waterland@Sun.COM  *
988*9781SMoriah.Waterland@Sun.COM  * Returns:
989*9781SMoriah.Waterland@Sun.COM  *   0 - Success - Certificate checks out
990*9781SMoriah.Waterland@Sun.COM  * non-zero - Failure, errors and reasons recorded in err
991*9781SMoriah.Waterland@Sun.COM  */
992*9781SMoriah.Waterland@Sun.COM int
check_cert(PKG_ERR * err,X509 * cert)993*9781SMoriah.Waterland@Sun.COM check_cert(PKG_ERR *err, X509 *cert)
994*9781SMoriah.Waterland@Sun.COM {
995*9781SMoriah.Waterland@Sun.COM 	char			currtimestr[ATTR_MAX];
996*9781SMoriah.Waterland@Sun.COM 	time_t			currtime;
997*9781SMoriah.Waterland@Sun.COM 	char			*r, *before_str, *after_str;
998*9781SMoriah.Waterland@Sun.COM 	/* get current time */
999*9781SMoriah.Waterland@Sun.COM 	if ((currtime = time(NULL)) == (time_t)-1) {
1000*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_TIME, gettext(ERR_CURR_TIME));
1001*9781SMoriah.Waterland@Sun.COM 		return (1);
1002*9781SMoriah.Waterland@Sun.COM 	}
1003*9781SMoriah.Waterland@Sun.COM 
1004*9781SMoriah.Waterland@Sun.COM 	(void) strlcpy(currtimestr, ctime(&currtime), ATTR_MAX);
1005*9781SMoriah.Waterland@Sun.COM 
1006*9781SMoriah.Waterland@Sun.COM 	/* trim whitespace from end of time string */
1007*9781SMoriah.Waterland@Sun.COM 	for (r = (currtimestr + strlen(currtimestr) - 1); isspace(*r); r--) {
1008*9781SMoriah.Waterland@Sun.COM 		*r = '\0';
1009*9781SMoriah.Waterland@Sun.COM 	}
1010*9781SMoriah.Waterland@Sun.COM 	/* check  validity of cert */
1011*9781SMoriah.Waterland@Sun.COM 	switch (sunw_check_cert_times(CHK_BOTH, cert)) {
1012*9781SMoriah.Waterland@Sun.COM 	case CHKERR_TIME_OK:
1013*9781SMoriah.Waterland@Sun.COM 		/* Current time meets requested checks */
1014*9781SMoriah.Waterland@Sun.COM 		break;
1015*9781SMoriah.Waterland@Sun.COM 	case CHKERR_TIME_BEFORE_BAD:
1016*9781SMoriah.Waterland@Sun.COM 		/* 'not before' field is invalid */
1017*9781SMoriah.Waterland@Sun.COM 	case CHKERR_TIME_AFTER_BAD:
1018*9781SMoriah.Waterland@Sun.COM 		/* 'not after' field is invalid */
1019*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_TIME, gettext(ERR_CERT_TIME_BAD));
1020*9781SMoriah.Waterland@Sun.COM 		return (1);
1021*9781SMoriah.Waterland@Sun.COM 	case CHKERR_TIME_IS_BEFORE:
1022*9781SMoriah.Waterland@Sun.COM 		/* Current time is before 'not before' */
1023*9781SMoriah.Waterland@Sun.COM 	case CHKERR_TIME_HAS_EXPIRED:
1024*9781SMoriah.Waterland@Sun.COM 		/*
1025*9781SMoriah.Waterland@Sun.COM 		 * Ignore expiration time since the trust cert used to
1026*9781SMoriah.Waterland@Sun.COM 		 * verify the certs used to sign Sun patches is already
1027*9781SMoriah.Waterland@Sun.COM 		 * expired. Once the patches get resigned with the new
1028*9781SMoriah.Waterland@Sun.COM 		 * cert we will check expiration against the time the
1029*9781SMoriah.Waterland@Sun.COM 		 * patch was signed and not the time it is installed.
1030*9781SMoriah.Waterland@Sun.COM 		 */
1031*9781SMoriah.Waterland@Sun.COM 		return (0);
1032*9781SMoriah.Waterland@Sun.COM 	default:
1033*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_INTERNAL,
1034*9781SMoriah.Waterland@Sun.COM 		    gettext(ERR_KEYSTORE_INTERNAL),
1035*9781SMoriah.Waterland@Sun.COM 		    __FILE__, __LINE__);
1036*9781SMoriah.Waterland@Sun.COM 		return (1);
1037*9781SMoriah.Waterland@Sun.COM 	}
1038*9781SMoriah.Waterland@Sun.COM 
1039*9781SMoriah.Waterland@Sun.COM 	/* all checks ok */
1040*9781SMoriah.Waterland@Sun.COM 	return (0);
1041*9781SMoriah.Waterland@Sun.COM }
1042*9781SMoriah.Waterland@Sun.COM 
1043*9781SMoriah.Waterland@Sun.COM /*
1044*9781SMoriah.Waterland@Sun.COM  * check_cert - Checks certificate validity.  This routine
1045*9781SMoriah.Waterland@Sun.COM  * checks everything that check_cert checks, and additionally
1046*9781SMoriah.Waterland@Sun.COM  * verifies that the private key and corresponding public
1047*9781SMoriah.Waterland@Sun.COM  * key are indeed a pair.
1048*9781SMoriah.Waterland@Sun.COM  *
1049*9781SMoriah.Waterland@Sun.COM  * Arguments:
1050*9781SMoriah.Waterland@Sun.COM  * err - Error object to add errors to
1051*9781SMoriah.Waterland@Sun.COM  * cert - The certificate to check
1052*9781SMoriah.Waterland@Sun.COM  * key - the key to check
1053*9781SMoriah.Waterland@Sun.COM  * Returns:
1054*9781SMoriah.Waterland@Sun.COM  *   0 - Success - Certificate checks out
1055*9781SMoriah.Waterland@Sun.COM  * non-zero - Failure, errors and reasons recorded in err
1056*9781SMoriah.Waterland@Sun.COM  */
1057*9781SMoriah.Waterland@Sun.COM int
check_cert_and_key(PKG_ERR * err,X509 * cert,EVP_PKEY * key)1058*9781SMoriah.Waterland@Sun.COM check_cert_and_key(PKG_ERR *err, X509 *cert, EVP_PKEY *key)
1059*9781SMoriah.Waterland@Sun.COM {
1060*9781SMoriah.Waterland@Sun.COM 
1061*9781SMoriah.Waterland@Sun.COM 	/* check validity dates */
1062*9781SMoriah.Waterland@Sun.COM 	if (check_cert(err, cert) != 0) {
1063*9781SMoriah.Waterland@Sun.COM 		return (1);
1064*9781SMoriah.Waterland@Sun.COM 	}
1065*9781SMoriah.Waterland@Sun.COM 
1066*9781SMoriah.Waterland@Sun.COM 	/* check key pair match */
1067*9781SMoriah.Waterland@Sun.COM 	if (sunw_check_keys(cert, key) == 0) {
1068*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_VERIFY, gettext(ERR_MISMATCHED_KEYS),
1069*9781SMoriah.Waterland@Sun.COM 		    get_subject_display_name(cert));
1070*9781SMoriah.Waterland@Sun.COM 		return (1);
1071*9781SMoriah.Waterland@Sun.COM 	}
1072*9781SMoriah.Waterland@Sun.COM 
1073*9781SMoriah.Waterland@Sun.COM 	/* all checks OK */
1074*9781SMoriah.Waterland@Sun.COM 	return (0);
1075*9781SMoriah.Waterland@Sun.COM }
1076*9781SMoriah.Waterland@Sun.COM 
1077*9781SMoriah.Waterland@Sun.COM /* ------------------ private functions ---------------------- */
1078*9781SMoriah.Waterland@Sun.COM 
1079*9781SMoriah.Waterland@Sun.COM /*
1080*9781SMoriah.Waterland@Sun.COM  * verify_keystore_integrity - Searches for the remnants
1081*9781SMoriah.Waterland@Sun.COM  * of a failed or aborted keystore modification, and
1082*9781SMoriah.Waterland@Sun.COM  * cleans up the files, retstores the keystore to a known
1083*9781SMoriah.Waterland@Sun.COM  * state.
1084*9781SMoriah.Waterland@Sun.COM  *
1085*9781SMoriah.Waterland@Sun.COM  * Arguments:
1086*9781SMoriah.Waterland@Sun.COM  * err - Error object to add errors to
1087*9781SMoriah.Waterland@Sun.COM  * keystore_file - Base directory or filename of keystore
1088*9781SMoriah.Waterland@Sun.COM  * app - Application making request
1089*9781SMoriah.Waterland@Sun.COM  *
1090*9781SMoriah.Waterland@Sun.COM  * Returns:
1091*9781SMoriah.Waterland@Sun.COM  *   0 - Success - Keystore is restored, or untouched in the
1092*9781SMoriah.Waterland@Sun.COM  *		case that cleanup was unnecessary
1093*9781SMoriah.Waterland@Sun.COM  * non-zero - Failure, errors and reasons recorded in err
1094*9781SMoriah.Waterland@Sun.COM  */
1095*9781SMoriah.Waterland@Sun.COM static boolean_t
verify_keystore_integrity(PKG_ERR * err,keystore_t * keystore)1096*9781SMoriah.Waterland@Sun.COM verify_keystore_integrity(PKG_ERR *err, keystore_t *keystore)
1097*9781SMoriah.Waterland@Sun.COM {
1098*9781SMoriah.Waterland@Sun.COM 	if (keystore->capath != NULL) {
1099*9781SMoriah.Waterland@Sun.COM 		if (!restore_keystore_file(err, keystore->capath)) {
1100*9781SMoriah.Waterland@Sun.COM 			return (B_FALSE);
1101*9781SMoriah.Waterland@Sun.COM 		}
1102*9781SMoriah.Waterland@Sun.COM 	}
1103*9781SMoriah.Waterland@Sun.COM 	if (keystore->clpath != NULL) {
1104*9781SMoriah.Waterland@Sun.COM 		if (!restore_keystore_file(err, keystore->clpath)) {
1105*9781SMoriah.Waterland@Sun.COM 			return (B_FALSE);
1106*9781SMoriah.Waterland@Sun.COM 		}
1107*9781SMoriah.Waterland@Sun.COM 	}
1108*9781SMoriah.Waterland@Sun.COM 	if (keystore->keypath != NULL) {
1109*9781SMoriah.Waterland@Sun.COM 		if (!restore_keystore_file(err, keystore->keypath)) {
1110*9781SMoriah.Waterland@Sun.COM 			return (B_FALSE);
1111*9781SMoriah.Waterland@Sun.COM 		}
1112*9781SMoriah.Waterland@Sun.COM 	}
1113*9781SMoriah.Waterland@Sun.COM 	return (B_TRUE);
1114*9781SMoriah.Waterland@Sun.COM }
1115*9781SMoriah.Waterland@Sun.COM 
1116*9781SMoriah.Waterland@Sun.COM /*
1117*9781SMoriah.Waterland@Sun.COM  * restore_keystore_file - restores a keystore file to
1118*9781SMoriah.Waterland@Sun.COM  * a known state.
1119*9781SMoriah.Waterland@Sun.COM  *
1120*9781SMoriah.Waterland@Sun.COM  * Keystore files can possibly be corrupted by a variety
1121*9781SMoriah.Waterland@Sun.COM  * of error conditions during reading/writing.  This
1122*9781SMoriah.Waterland@Sun.COM  * routine, along with write_keystore_file, tries to
1123*9781SMoriah.Waterland@Sun.COM  * maintain keystore integrity by writing the files
1124*9781SMoriah.Waterland@Sun.COM  * out in a particular order, minimizing the time period
1125*9781SMoriah.Waterland@Sun.COM  * that the keystore is in an indeterminate state.
1126*9781SMoriah.Waterland@Sun.COM  *
1127*9781SMoriah.Waterland@Sun.COM  * With the current implementation, there are some failures
1128*9781SMoriah.Waterland@Sun.COM  * that are wholly unrecoverable, such as disk corruption.
1129*9781SMoriah.Waterland@Sun.COM  * These routines attempt to minimize the risk, but not
1130*9781SMoriah.Waterland@Sun.COM  * eliminate it.  When better, atomic operations are available
1131*9781SMoriah.Waterland@Sun.COM  * (such as a trued atabase with commit, rollback, and
1132*9781SMoriah.Waterland@Sun.COM  * guaranteed atomicity), this implementation should use that.
1133*9781SMoriah.Waterland@Sun.COM  *
1134*9781SMoriah.Waterland@Sun.COM  * Arguments:
1135*9781SMoriah.Waterland@Sun.COM  * err - Error object to add errors to
1136*9781SMoriah.Waterland@Sun.COM  * keystore_file - keystore file path to restore.
1137*9781SMoriah.Waterland@Sun.COM  *
1138*9781SMoriah.Waterland@Sun.COM  * Returns:
1139*9781SMoriah.Waterland@Sun.COM  *   0 - Success - Keystore file is restored, or untouched in the
1140*9781SMoriah.Waterland@Sun.COM  *		case that cleanup was unnecessary
1141*9781SMoriah.Waterland@Sun.COM  * non-zero - Failure, errors and reasons recorded in err
1142*9781SMoriah.Waterland@Sun.COM  */
1143*9781SMoriah.Waterland@Sun.COM /* ARGSUSED */
1144*9781SMoriah.Waterland@Sun.COM static boolean_t
restore_keystore_file(PKG_ERR * err,char * keystore_file)1145*9781SMoriah.Waterland@Sun.COM restore_keystore_file(PKG_ERR *err, char *keystore_file)
1146*9781SMoriah.Waterland@Sun.COM {
1147*9781SMoriah.Waterland@Sun.COM 	char	newpath[MAXPATHLEN];
1148*9781SMoriah.Waterland@Sun.COM 	char	backuppath[MAXPATHLEN];
1149*9781SMoriah.Waterland@Sun.COM 	int	newfd;
1150*9781SMoriah.Waterland@Sun.COM 	struct stat buf;
1151*9781SMoriah.Waterland@Sun.COM 	int len;
1152*9781SMoriah.Waterland@Sun.COM 
1153*9781SMoriah.Waterland@Sun.COM 	if (((len = snprintf(newpath, MAXPATHLEN, "%s.new",
1154*9781SMoriah.Waterland@Sun.COM 	    keystore_file)) < 0) ||
1155*9781SMoriah.Waterland@Sun.COM 	    (len >= ATTR_MAX)) {
1156*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN), keystore_file);
1157*9781SMoriah.Waterland@Sun.COM 		return (B_FALSE);
1158*9781SMoriah.Waterland@Sun.COM 	}
1159*9781SMoriah.Waterland@Sun.COM 
1160*9781SMoriah.Waterland@Sun.COM 	if (((len = snprintf(backuppath, MAXPATHLEN, "%s.bak",
1161*9781SMoriah.Waterland@Sun.COM 	    keystore_file)) < 0) ||
1162*9781SMoriah.Waterland@Sun.COM 	    (len >= ATTR_MAX)) {
1163*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN), keystore_file);
1164*9781SMoriah.Waterland@Sun.COM 		return (B_FALSE);
1165*9781SMoriah.Waterland@Sun.COM 	}
1166*9781SMoriah.Waterland@Sun.COM 
1167*9781SMoriah.Waterland@Sun.COM 	if ((newfd = open(newpath, O_RDWR|O_NONBLOCK, 0)) != -1) {
1168*9781SMoriah.Waterland@Sun.COM 		if (fstat(newfd, &buf) != -1) {
1169*9781SMoriah.Waterland@Sun.COM 			if (S_ISREG(buf.st_mode)) {
1170*9781SMoriah.Waterland@Sun.COM 				/*
1171*9781SMoriah.Waterland@Sun.COM 				 * restore the file, waiting on it
1172*9781SMoriah.Waterland@Sun.COM 				 * to be free for locking, or for
1173*9781SMoriah.Waterland@Sun.COM 				 * it to disappear
1174*9781SMoriah.Waterland@Sun.COM 				 */
1175*9781SMoriah.Waterland@Sun.COM 				if (!wait_restore(newfd, keystore_file,
1176*9781SMoriah.Waterland@Sun.COM 				    newpath, backuppath)) {
1177*9781SMoriah.Waterland@Sun.COM 					pkgerr_add(err, PKGERR_WRITE,
1178*9781SMoriah.Waterland@Sun.COM 					    gettext(ERR_WRITE),
1179*9781SMoriah.Waterland@Sun.COM 					    newpath, strerror(errno));
1180*9781SMoriah.Waterland@Sun.COM 					(void) close(newfd);
1181*9781SMoriah.Waterland@Sun.COM 					return (B_FALSE);
1182*9781SMoriah.Waterland@Sun.COM 				} else {
1183*9781SMoriah.Waterland@Sun.COM 					return (B_TRUE);
1184*9781SMoriah.Waterland@Sun.COM 				}
1185*9781SMoriah.Waterland@Sun.COM 			} else {
1186*9781SMoriah.Waterland@Sun.COM 				/* "new" file is not a regular file */
1187*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_WRITE,
1188*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_NOT_REG), newpath);
1189*9781SMoriah.Waterland@Sun.COM 				(void) close(newfd);
1190*9781SMoriah.Waterland@Sun.COM 				return (B_FALSE);
1191*9781SMoriah.Waterland@Sun.COM 			}
1192*9781SMoriah.Waterland@Sun.COM 		} else {
1193*9781SMoriah.Waterland@Sun.COM 			/* couldn't stat "new" file */
1194*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_WRITE,
1195*9781SMoriah.Waterland@Sun.COM 			    gettext(ERR_WRITE), newpath,
1196*9781SMoriah.Waterland@Sun.COM 			    strerror(errno));
1197*9781SMoriah.Waterland@Sun.COM 			(void) close(newfd);
1198*9781SMoriah.Waterland@Sun.COM 			return (B_FALSE);
1199*9781SMoriah.Waterland@Sun.COM 		}
1200*9781SMoriah.Waterland@Sun.COM 	} else {
1201*9781SMoriah.Waterland@Sun.COM 		/* "new" file doesn't exist */
1202*9781SMoriah.Waterland@Sun.COM 		return (B_TRUE);
1203*9781SMoriah.Waterland@Sun.COM 	}
1204*9781SMoriah.Waterland@Sun.COM }
1205*9781SMoriah.Waterland@Sun.COM 
1206*9781SMoriah.Waterland@Sun.COM static boolean_t
wait_restore(int newfd,char * keystore_file,char * origpath,char * backuppath)1207*9781SMoriah.Waterland@Sun.COM wait_restore(int newfd, char *keystore_file,
1208*9781SMoriah.Waterland@Sun.COM     char *origpath, char *backuppath)
1209*9781SMoriah.Waterland@Sun.COM {
1210*9781SMoriah.Waterland@Sun.COM 	struct stat buf;
1211*9781SMoriah.Waterland@Sun.COM 	FILE *newstream;
1212*9781SMoriah.Waterland@Sun.COM 	PKCS12 *p12;
1213*9781SMoriah.Waterland@Sun.COM 
1214*9781SMoriah.Waterland@Sun.COM 	(void) alarm(LOCK_TIMEOUT);
1215*9781SMoriah.Waterland@Sun.COM 	if (file_lock(newfd, F_WRLCK, 1) == -1) {
1216*9781SMoriah.Waterland@Sun.COM 		/* could not lock file */
1217*9781SMoriah.Waterland@Sun.COM 		(void) alarm(0);
1218*9781SMoriah.Waterland@Sun.COM 		return (B_FALSE);
1219*9781SMoriah.Waterland@Sun.COM 	}
1220*9781SMoriah.Waterland@Sun.COM 	(void) alarm(0);
1221*9781SMoriah.Waterland@Sun.COM 
1222*9781SMoriah.Waterland@Sun.COM 	if (fstat(newfd, &buf) != -1) {
1223*9781SMoriah.Waterland@Sun.COM 		if (S_ISREG(buf.st_mode)) {
1224*9781SMoriah.Waterland@Sun.COM 			/*
1225*9781SMoriah.Waterland@Sun.COM 			 * The new file still
1226*9781SMoriah.Waterland@Sun.COM 			 * exists, with no
1227*9781SMoriah.Waterland@Sun.COM 			 * owner.  It must be
1228*9781SMoriah.Waterland@Sun.COM 			 * the result of an
1229*9781SMoriah.Waterland@Sun.COM 			 * aborted update.
1230*9781SMoriah.Waterland@Sun.COM 			 */
1231*9781SMoriah.Waterland@Sun.COM 			newstream = fdopen(newfd, "r");
1232*9781SMoriah.Waterland@Sun.COM 			if ((p12 =
1233*9781SMoriah.Waterland@Sun.COM 			    d2i_PKCS12_fp(newstream,
1234*9781SMoriah.Waterland@Sun.COM 				NULL)) != NULL) {
1235*9781SMoriah.Waterland@Sun.COM 				/*
1236*9781SMoriah.Waterland@Sun.COM 				 * The file
1237*9781SMoriah.Waterland@Sun.COM 				 * appears
1238*9781SMoriah.Waterland@Sun.COM 				 * complete.
1239*9781SMoriah.Waterland@Sun.COM 				 * Replace the
1240*9781SMoriah.Waterland@Sun.COM 				 * exsisting
1241*9781SMoriah.Waterland@Sun.COM 				 * keystore
1242*9781SMoriah.Waterland@Sun.COM 				 * file with
1243*9781SMoriah.Waterland@Sun.COM 				 * this one
1244*9781SMoriah.Waterland@Sun.COM 				 */
1245*9781SMoriah.Waterland@Sun.COM 				(void) rename(keystore_file, backuppath);
1246*9781SMoriah.Waterland@Sun.COM 				(void) rename(origpath, keystore_file);
1247*9781SMoriah.Waterland@Sun.COM 				PKCS12_free(p12);
1248*9781SMoriah.Waterland@Sun.COM 			} else {
1249*9781SMoriah.Waterland@Sun.COM 				/* The file is not complete.  Remove it */
1250*9781SMoriah.Waterland@Sun.COM 				(void) remove(origpath);
1251*9781SMoriah.Waterland@Sun.COM 			}
1252*9781SMoriah.Waterland@Sun.COM 			/* remove backup file */
1253*9781SMoriah.Waterland@Sun.COM 			(void) remove(backuppath);
1254*9781SMoriah.Waterland@Sun.COM 			(void) fclose(newstream);
1255*9781SMoriah.Waterland@Sun.COM 			(void) close(newfd);
1256*9781SMoriah.Waterland@Sun.COM 			return (B_TRUE);
1257*9781SMoriah.Waterland@Sun.COM 		} else {
1258*9781SMoriah.Waterland@Sun.COM 			/*
1259*9781SMoriah.Waterland@Sun.COM 			 * new file exists, but is not a
1260*9781SMoriah.Waterland@Sun.COM 			 * regular file
1261*9781SMoriah.Waterland@Sun.COM 			 */
1262*9781SMoriah.Waterland@Sun.COM 			(void) close(newfd);
1263*9781SMoriah.Waterland@Sun.COM 			return (B_FALSE);
1264*9781SMoriah.Waterland@Sun.COM 		}
1265*9781SMoriah.Waterland@Sun.COM 	} else {
1266*9781SMoriah.Waterland@Sun.COM 		/*
1267*9781SMoriah.Waterland@Sun.COM 		 * could not stat file.  Unless
1268*9781SMoriah.Waterland@Sun.COM 		 * the reason was that the file
1269*9781SMoriah.Waterland@Sun.COM 		 * is now gone, this is an error
1270*9781SMoriah.Waterland@Sun.COM 		 */
1271*9781SMoriah.Waterland@Sun.COM 		if (errno != ENOENT) {
1272*9781SMoriah.Waterland@Sun.COM 			(void) close(newfd);
1273*9781SMoriah.Waterland@Sun.COM 			return (B_FALSE);
1274*9781SMoriah.Waterland@Sun.COM 		}
1275*9781SMoriah.Waterland@Sun.COM 		/*
1276*9781SMoriah.Waterland@Sun.COM 		 * otherwise, file is gone.  The process
1277*9781SMoriah.Waterland@Sun.COM 		 * that held the lock must have
1278*9781SMoriah.Waterland@Sun.COM 		 * successfully cleaned up and
1279*9781SMoriah.Waterland@Sun.COM 		 * exited with a valid keystore
1280*9781SMoriah.Waterland@Sun.COM 		 * state
1281*9781SMoriah.Waterland@Sun.COM 		 */
1282*9781SMoriah.Waterland@Sun.COM 		(void) close(newfd);
1283*9781SMoriah.Waterland@Sun.COM 		return (B_TRUE);
1284*9781SMoriah.Waterland@Sun.COM 	}
1285*9781SMoriah.Waterland@Sun.COM }
1286*9781SMoriah.Waterland@Sun.COM 
1287*9781SMoriah.Waterland@Sun.COM /*
1288*9781SMoriah.Waterland@Sun.COM  * resolve_paths - figure out if we are dealing with a single-file
1289*9781SMoriah.Waterland@Sun.COM  * or multi-file keystore
1290*9781SMoriah.Waterland@Sun.COM  *
1291*9781SMoriah.Waterland@Sun.COM  * The flags tell resolve_paths how to behave:
1292*9781SMoriah.Waterland@Sun.COM  *
1293*9781SMoriah.Waterland@Sun.COM  * KEYSTORE_PATH_SOFT
1294*9781SMoriah.Waterland@Sun.COM  * If the keystore file does not exist at <base>/<app> then
1295*9781SMoriah.Waterland@Sun.COM  * use <base> as the path to the keystore.  This can be used,
1296*9781SMoriah.Waterland@Sun.COM  * for example, to access an app-specific keystore iff it
1297*9781SMoriah.Waterland@Sun.COM  * exists, otherwise revert back to an app-generic keystore.
1298*9781SMoriah.Waterland@Sun.COM  *
1299*9781SMoriah.Waterland@Sun.COM  * KEYSTORE_PATH_HARD
1300*9781SMoriah.Waterland@Sun.COM  * Always use the keystore located at <keystore_path>/<app>.
1301*9781SMoriah.Waterland@Sun.COM  * In read/write mode, if the files do not exist, then
1302*9781SMoriah.Waterland@Sun.COM  * they will be created.  This is used to avoid falling
1303*9781SMoriah.Waterland@Sun.COM  * back to an app-generic keystore path when the app-specific
1304*9781SMoriah.Waterland@Sun.COM  * one does not exist.
1305*9781SMoriah.Waterland@Sun.COM  *
1306*9781SMoriah.Waterland@Sun.COM  * Arguments:
1307*9781SMoriah.Waterland@Sun.COM  * err - Error object to add errors to
1308*9781SMoriah.Waterland@Sun.COM  * keystore_file - base keystore file path to lock
1309*9781SMoriah.Waterland@Sun.COM  * app - Application making requests
1310*9781SMoriah.Waterland@Sun.COM  * flags - Control flags (see above description)
1311*9781SMoriah.Waterland@Sun.COM  * keystore - object which is being locked
1312*9781SMoriah.Waterland@Sun.COM  *
1313*9781SMoriah.Waterland@Sun.COM  * Returns:
1314*9781SMoriah.Waterland@Sun.COM  *   B_TRUE - Success - Keystore file is locked, paths to
1315*9781SMoriah.Waterland@Sun.COM  *		appropriate files placed in keystore.
1316*9781SMoriah.Waterland@Sun.COM  *   B_FALSE - Failure, errors and reasons recorded in err
1317*9781SMoriah.Waterland@Sun.COM  */
1318*9781SMoriah.Waterland@Sun.COM static boolean_t
resolve_paths(PKG_ERR * err,char * keystore_file,char * app,long flags,keystore_t * keystore)1319*9781SMoriah.Waterland@Sun.COM resolve_paths(PKG_ERR *err, char *keystore_file, char *app,
1320*9781SMoriah.Waterland@Sun.COM     long flags, keystore_t *keystore)
1321*9781SMoriah.Waterland@Sun.COM {
1322*9781SMoriah.Waterland@Sun.COM 	char			storepath[PATH_MAX];
1323*9781SMoriah.Waterland@Sun.COM 	struct stat		buf;
1324*9781SMoriah.Waterland@Sun.COM 	boolean_t		multi = B_FALSE;
1325*9781SMoriah.Waterland@Sun.COM 	int			fd1, fd2, len;
1326*9781SMoriah.Waterland@Sun.COM 
1327*9781SMoriah.Waterland@Sun.COM 	/*
1328*9781SMoriah.Waterland@Sun.COM 	 * figure out whether we are dealing with a single-file keystore
1329*9781SMoriah.Waterland@Sun.COM 	 * or a multi-file keystore
1330*9781SMoriah.Waterland@Sun.COM 	 */
1331*9781SMoriah.Waterland@Sun.COM 	if (app != NULL) {
1332*9781SMoriah.Waterland@Sun.COM 		if (((len = snprintf(storepath, PATH_MAX, "%s/%s",
1333*9781SMoriah.Waterland@Sun.COM 		    keystore_file, app)) < 0) ||
1334*9781SMoriah.Waterland@Sun.COM 		    (len >= ATTR_MAX)) {
1335*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN),
1336*9781SMoriah.Waterland@Sun.COM 			    keystore_file);
1337*9781SMoriah.Waterland@Sun.COM 			return (B_FALSE);
1338*9781SMoriah.Waterland@Sun.COM 		}
1339*9781SMoriah.Waterland@Sun.COM 
1340*9781SMoriah.Waterland@Sun.COM 		if (((fd1 = open(storepath, O_NONBLOCK|O_RDONLY)) == -1) ||
1341*9781SMoriah.Waterland@Sun.COM 		    (fstat(fd1, &buf) == -1) ||
1342*9781SMoriah.Waterland@Sun.COM 		    !S_ISDIR(buf.st_mode)) {
1343*9781SMoriah.Waterland@Sun.COM 			/*
1344*9781SMoriah.Waterland@Sun.COM 			 * app-specific does not exist
1345*9781SMoriah.Waterland@Sun.COM 			 * fallback to app-generic, if flags say we can
1346*9781SMoriah.Waterland@Sun.COM 			 */
1347*9781SMoriah.Waterland@Sun.COM 			if ((flags & KEYSTORE_PATH_MASK) ==
1348*9781SMoriah.Waterland@Sun.COM 			    KEYSTORE_PATH_SOFT) {
1349*9781SMoriah.Waterland@Sun.COM 
1350*9781SMoriah.Waterland@Sun.COM 				if (((fd2 = open(keystore_file,
1351*9781SMoriah.Waterland@Sun.COM 				    O_NONBLOCK|O_RDONLY)) != -1) &&
1352*9781SMoriah.Waterland@Sun.COM 				    (fstat(fd2, &buf) != -1)) {
1353*9781SMoriah.Waterland@Sun.COM 					if (S_ISDIR(buf.st_mode)) {
1354*9781SMoriah.Waterland@Sun.COM 						/*
1355*9781SMoriah.Waterland@Sun.COM 						 * app-generic dir
1356*9781SMoriah.Waterland@Sun.COM 						 * exists, so use it
1357*9781SMoriah.Waterland@Sun.COM 						 * as a multi-file
1358*9781SMoriah.Waterland@Sun.COM 						 * keystore
1359*9781SMoriah.Waterland@Sun.COM 						 */
1360*9781SMoriah.Waterland@Sun.COM 						multi = B_TRUE;
1361*9781SMoriah.Waterland@Sun.COM 						app = NULL;
1362*9781SMoriah.Waterland@Sun.COM 					} else if (S_ISREG(buf.st_mode)) {
1363*9781SMoriah.Waterland@Sun.COM 						/*
1364*9781SMoriah.Waterland@Sun.COM 						 * app-generic file exists, so
1365*9781SMoriah.Waterland@Sun.COM 						 * use it as a single file ks
1366*9781SMoriah.Waterland@Sun.COM 						 */
1367*9781SMoriah.Waterland@Sun.COM 						multi = B_FALSE;
1368*9781SMoriah.Waterland@Sun.COM 						app = NULL;
1369*9781SMoriah.Waterland@Sun.COM 					}
1370*9781SMoriah.Waterland@Sun.COM 				}
1371*9781SMoriah.Waterland@Sun.COM 			}
1372*9781SMoriah.Waterland@Sun.COM 		}
1373*9781SMoriah.Waterland@Sun.COM 		if (fd1 != -1)
1374*9781SMoriah.Waterland@Sun.COM 			(void) close(fd1);
1375*9781SMoriah.Waterland@Sun.COM 		if (fd2 != -1)
1376*9781SMoriah.Waterland@Sun.COM 			(void) close(fd2);
1377*9781SMoriah.Waterland@Sun.COM 	} else {
1378*9781SMoriah.Waterland@Sun.COM 		if (((fd1 = open(keystore_file,
1379*9781SMoriah.Waterland@Sun.COM 		    O_NONBLOCK|O_RDONLY)) != -1) &&
1380*9781SMoriah.Waterland@Sun.COM 		    (fstat(fd1, &buf) != -1) &&
1381*9781SMoriah.Waterland@Sun.COM 		    S_ISDIR(buf.st_mode)) {
1382*9781SMoriah.Waterland@Sun.COM 			/*
1383*9781SMoriah.Waterland@Sun.COM 			 * app-generic dir exists, so use
1384*9781SMoriah.Waterland@Sun.COM 			 * it as a multi-file keystore
1385*9781SMoriah.Waterland@Sun.COM 			 */
1386*9781SMoriah.Waterland@Sun.COM 			multi = B_TRUE;
1387*9781SMoriah.Waterland@Sun.COM 		}
1388*9781SMoriah.Waterland@Sun.COM 		if (fd1 != -1)
1389*9781SMoriah.Waterland@Sun.COM 			(void) close(fd1);
1390*9781SMoriah.Waterland@Sun.COM 	}
1391*9781SMoriah.Waterland@Sun.COM 
1392*9781SMoriah.Waterland@Sun.COM 	if (app != NULL) {
1393*9781SMoriah.Waterland@Sun.COM 		/* app-specific keystore */
1394*9781SMoriah.Waterland@Sun.COM 		(void) snprintf(storepath, PATH_MAX, "%s/%s/%s",
1395*9781SMoriah.Waterland@Sun.COM 		    keystore_file, app, TRUSTSTORE);
1396*9781SMoriah.Waterland@Sun.COM 		keystore->capath = xstrdup(storepath);
1397*9781SMoriah.Waterland@Sun.COM 		(void) snprintf(storepath, PATH_MAX, "%s/%s/%s",
1398*9781SMoriah.Waterland@Sun.COM 		    keystore_file, app, CERTSTORE);
1399*9781SMoriah.Waterland@Sun.COM 		keystore->clpath = xstrdup(storepath);
1400*9781SMoriah.Waterland@Sun.COM 		(void) snprintf(storepath, PATH_MAX, "%s/%s/%s",
1401*9781SMoriah.Waterland@Sun.COM 		    keystore_file, app, KEYSTORE);
1402*9781SMoriah.Waterland@Sun.COM 		keystore->keypath = xstrdup(storepath);
1403*9781SMoriah.Waterland@Sun.COM 	} else {
1404*9781SMoriah.Waterland@Sun.COM 		/* app-generic keystore */
1405*9781SMoriah.Waterland@Sun.COM 		if (!multi) {
1406*9781SMoriah.Waterland@Sun.COM 			/* single-file app-generic keystore */
1407*9781SMoriah.Waterland@Sun.COM 			keystore->capath = xstrdup(keystore_file);
1408*9781SMoriah.Waterland@Sun.COM 			keystore->keypath = NULL;
1409*9781SMoriah.Waterland@Sun.COM 			keystore->clpath = NULL;
1410*9781SMoriah.Waterland@Sun.COM 		} else {
1411*9781SMoriah.Waterland@Sun.COM 			/* multi-file app-generic keystore */
1412*9781SMoriah.Waterland@Sun.COM 			(void) snprintf(storepath, PATH_MAX, "%s/%s",
1413*9781SMoriah.Waterland@Sun.COM 			    keystore_file, TRUSTSTORE);
1414*9781SMoriah.Waterland@Sun.COM 			keystore->capath = xstrdup(storepath);
1415*9781SMoriah.Waterland@Sun.COM 			(void) snprintf(storepath, PATH_MAX, "%s/%s",
1416*9781SMoriah.Waterland@Sun.COM 			    keystore_file, CERTSTORE);
1417*9781SMoriah.Waterland@Sun.COM 			keystore->clpath = xstrdup(storepath);
1418*9781SMoriah.Waterland@Sun.COM 			(void) snprintf(storepath, PATH_MAX, "%s/%s",
1419*9781SMoriah.Waterland@Sun.COM 			    keystore_file, KEYSTORE);
1420*9781SMoriah.Waterland@Sun.COM 			keystore->keypath = xstrdup(storepath);
1421*9781SMoriah.Waterland@Sun.COM 		}
1422*9781SMoriah.Waterland@Sun.COM 	}
1423*9781SMoriah.Waterland@Sun.COM 
1424*9781SMoriah.Waterland@Sun.COM 	return (B_TRUE);
1425*9781SMoriah.Waterland@Sun.COM }
1426*9781SMoriah.Waterland@Sun.COM 
1427*9781SMoriah.Waterland@Sun.COM /*
1428*9781SMoriah.Waterland@Sun.COM  * lock_keystore - Locks a keystore for shared (read-only)
1429*9781SMoriah.Waterland@Sun.COM  * or exclusive (read-write) access.
1430*9781SMoriah.Waterland@Sun.COM  *
1431*9781SMoriah.Waterland@Sun.COM  * The flags tell lock_keystore how to behave:
1432*9781SMoriah.Waterland@Sun.COM  *
1433*9781SMoriah.Waterland@Sun.COM  * KEYSTORE_ACCESS_READONLY
1434*9781SMoriah.Waterland@Sun.COM  * opens keystore read-only.  Attempts to modify results in an error
1435*9781SMoriah.Waterland@Sun.COM  *
1436*9781SMoriah.Waterland@Sun.COM  * KEYSTORE_ACCESS_READWRITE
1437*9781SMoriah.Waterland@Sun.COM  * opens keystore read-write
1438*9781SMoriah.Waterland@Sun.COM  *
1439*9781SMoriah.Waterland@Sun.COM  * KEYSTORE_PATH_SOFT
1440*9781SMoriah.Waterland@Sun.COM  * If the keystore file does not exist at <base>/<app> then
1441*9781SMoriah.Waterland@Sun.COM  * use <base> as the path to the keystore.  This can be used,
1442*9781SMoriah.Waterland@Sun.COM  * for example, to access an app-specific keystore iff it
1443*9781SMoriah.Waterland@Sun.COM  * exists, otherwise revert back to an app-generic keystore.
1444*9781SMoriah.Waterland@Sun.COM  *
1445*9781SMoriah.Waterland@Sun.COM  * KEYSTORE_PATH_HARD
1446*9781SMoriah.Waterland@Sun.COM  * Always use the keystore located at <keystore_path>/<app>.
1447*9781SMoriah.Waterland@Sun.COM  * In read/write mode, if the files do not exist, then
1448*9781SMoriah.Waterland@Sun.COM  * they will be created.  This is used to avoid falling
1449*9781SMoriah.Waterland@Sun.COM  * back to an app-generic keystore path when the app-specific
1450*9781SMoriah.Waterland@Sun.COM  * one does not exist.
1451*9781SMoriah.Waterland@Sun.COM  *
1452*9781SMoriah.Waterland@Sun.COM  * Arguments:
1453*9781SMoriah.Waterland@Sun.COM  * err - Error object to add errors to
1454*9781SMoriah.Waterland@Sun.COM  * flags - Control flags (see above description)
1455*9781SMoriah.Waterland@Sun.COM  * keystore - object which is being locked
1456*9781SMoriah.Waterland@Sun.COM  *
1457*9781SMoriah.Waterland@Sun.COM  * Returns:
1458*9781SMoriah.Waterland@Sun.COM  *   0 - Success - Keystore file is locked, paths to
1459*9781SMoriah.Waterland@Sun.COM  *		appropriate files placed in keystore.
1460*9781SMoriah.Waterland@Sun.COM  * non-zero - Failure, errors and reasons recorded in err
1461*9781SMoriah.Waterland@Sun.COM  */
1462*9781SMoriah.Waterland@Sun.COM static boolean_t
lock_keystore(PKG_ERR * err,long flags,keystore_t * keystore)1463*9781SMoriah.Waterland@Sun.COM lock_keystore(PKG_ERR *err, long flags, keystore_t *keystore)
1464*9781SMoriah.Waterland@Sun.COM {
1465*9781SMoriah.Waterland@Sun.COM 	boolean_t		ret = B_TRUE;
1466*9781SMoriah.Waterland@Sun.COM 	struct stat		buf;
1467*9781SMoriah.Waterland@Sun.COM 
1468*9781SMoriah.Waterland@Sun.COM 	switch (flags & KEYSTORE_ACCESS_MASK) {
1469*9781SMoriah.Waterland@Sun.COM 	case KEYSTORE_ACCESS_READONLY:
1470*9781SMoriah.Waterland@Sun.COM 		if ((keystore->cafd =
1471*9781SMoriah.Waterland@Sun.COM 		    open(keystore->capath, O_NONBLOCK|O_RDONLY)) == -1) {
1472*9781SMoriah.Waterland@Sun.COM 			if (errno == ENOENT) {
1473*9781SMoriah.Waterland@Sun.COM 				/*
1474*9781SMoriah.Waterland@Sun.COM 				 * no keystore.  try to create an
1475*9781SMoriah.Waterland@Sun.COM 				 * empty one so we can lock on it and
1476*9781SMoriah.Waterland@Sun.COM 				 * prevent others from gaining
1477*9781SMoriah.Waterland@Sun.COM 				 * exclusive access.  It will be
1478*9781SMoriah.Waterland@Sun.COM 				 * deleted when the keystore is closed.
1479*9781SMoriah.Waterland@Sun.COM 				 */
1480*9781SMoriah.Waterland@Sun.COM 				if ((keystore->cafd =
1481*9781SMoriah.Waterland@Sun.COM 				    open(keystore->capath,
1482*9781SMoriah.Waterland@Sun.COM 					O_NONBLOCK|O_RDWR|O_CREAT|O_EXCL,
1483*9781SMoriah.Waterland@Sun.COM 					S_IRUSR|S_IWUSR)) == -1) {
1484*9781SMoriah.Waterland@Sun.COM 					pkgerr_add(err, PKGERR_READ,
1485*9781SMoriah.Waterland@Sun.COM 					    gettext(ERR_NO_KEYSTORE),
1486*9781SMoriah.Waterland@Sun.COM 					    keystore->capath);
1487*9781SMoriah.Waterland@Sun.COM 					ret = B_FALSE;
1488*9781SMoriah.Waterland@Sun.COM 					goto cleanup;
1489*9781SMoriah.Waterland@Sun.COM 				}
1490*9781SMoriah.Waterland@Sun.COM 			} else {
1491*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_READ,
1492*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_KEYSTORE_OPEN),
1493*9781SMoriah.Waterland@Sun.COM 				    keystore->capath, strerror(errno));
1494*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
1495*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
1496*9781SMoriah.Waterland@Sun.COM 			}
1497*9781SMoriah.Waterland@Sun.COM 		}
1498*9781SMoriah.Waterland@Sun.COM 		if (fstat(keystore->cafd, &buf) != -1) {
1499*9781SMoriah.Waterland@Sun.COM 			if (S_ISREG(buf.st_mode)) {
1500*9781SMoriah.Waterland@Sun.COM 				if (file_lock(keystore->cafd, F_RDLCK,
1501*9781SMoriah.Waterland@Sun.COM 				    0) == -1) {
1502*9781SMoriah.Waterland@Sun.COM 					pkgerr_add(err, PKGERR_LOCKED,
1503*9781SMoriah.Waterland@Sun.COM 					    gettext(ERR_KEYSTORE_LOCKED_READ),
1504*9781SMoriah.Waterland@Sun.COM 					    keystore->capath);
1505*9781SMoriah.Waterland@Sun.COM 					ret = B_FALSE;
1506*9781SMoriah.Waterland@Sun.COM 					goto cleanup;
1507*9781SMoriah.Waterland@Sun.COM 				}
1508*9781SMoriah.Waterland@Sun.COM 			} else {
1509*9781SMoriah.Waterland@Sun.COM 				/* ca file not a regular file! */
1510*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_READ,
1511*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_NOT_REG),
1512*9781SMoriah.Waterland@Sun.COM 				    keystore->capath);
1513*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
1514*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
1515*9781SMoriah.Waterland@Sun.COM 			}
1516*9781SMoriah.Waterland@Sun.COM 		} else {
1517*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_READ,
1518*9781SMoriah.Waterland@Sun.COM 			    gettext(ERR_KEYSTORE_OPEN),
1519*9781SMoriah.Waterland@Sun.COM 			    keystore->capath, strerror(errno));
1520*9781SMoriah.Waterland@Sun.COM 			ret = B_FALSE;
1521*9781SMoriah.Waterland@Sun.COM 			goto cleanup;
1522*9781SMoriah.Waterland@Sun.COM 		}
1523*9781SMoriah.Waterland@Sun.COM 		break;
1524*9781SMoriah.Waterland@Sun.COM 	case KEYSTORE_ACCESS_READWRITE:
1525*9781SMoriah.Waterland@Sun.COM 
1526*9781SMoriah.Waterland@Sun.COM 		if ((keystore->cafd = open(keystore->capath,
1527*9781SMoriah.Waterland@Sun.COM 		    O_RDWR|O_NONBLOCK)) == -1) {
1528*9781SMoriah.Waterland@Sun.COM 			/* does not exist.  try to create an empty one */
1529*9781SMoriah.Waterland@Sun.COM 			if (errno == ENOENT) {
1530*9781SMoriah.Waterland@Sun.COM 				if ((keystore->cafd =
1531*9781SMoriah.Waterland@Sun.COM 				    open(keystore->capath,
1532*9781SMoriah.Waterland@Sun.COM 					O_NONBLOCK|O_RDWR|O_CREAT|O_EXCL,
1533*9781SMoriah.Waterland@Sun.COM 					S_IRUSR|S_IWUSR)) == -1) {
1534*9781SMoriah.Waterland@Sun.COM 					pkgerr_add(err, PKGERR_READ,
1535*9781SMoriah.Waterland@Sun.COM 					    gettext(ERR_KEYSTORE_WRITE),
1536*9781SMoriah.Waterland@Sun.COM 					    keystore->capath);
1537*9781SMoriah.Waterland@Sun.COM 					ret = B_FALSE;
1538*9781SMoriah.Waterland@Sun.COM 					goto cleanup;
1539*9781SMoriah.Waterland@Sun.COM 				}
1540*9781SMoriah.Waterland@Sun.COM 			} else {
1541*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_READ,
1542*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_KEYSTORE_OPEN),
1543*9781SMoriah.Waterland@Sun.COM 				    keystore->capath, strerror(errno));
1544*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
1545*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
1546*9781SMoriah.Waterland@Sun.COM 			}
1547*9781SMoriah.Waterland@Sun.COM 		}
1548*9781SMoriah.Waterland@Sun.COM 		if (fstat(keystore->cafd, &buf) != -1) {
1549*9781SMoriah.Waterland@Sun.COM 			if (S_ISREG(buf.st_mode)) {
1550*9781SMoriah.Waterland@Sun.COM 				if (file_lock(keystore->cafd, F_WRLCK,
1551*9781SMoriah.Waterland@Sun.COM 				    0) == -1) {
1552*9781SMoriah.Waterland@Sun.COM 					pkgerr_add(err, PKGERR_LOCKED,
1553*9781SMoriah.Waterland@Sun.COM 					    gettext(ERR_KEYSTORE_LOCKED),
1554*9781SMoriah.Waterland@Sun.COM 					    keystore->capath);
1555*9781SMoriah.Waterland@Sun.COM 					ret = B_FALSE;
1556*9781SMoriah.Waterland@Sun.COM 					goto cleanup;
1557*9781SMoriah.Waterland@Sun.COM 				}
1558*9781SMoriah.Waterland@Sun.COM 			} else {
1559*9781SMoriah.Waterland@Sun.COM 				/* ca file not a regular file! */
1560*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_READ,
1561*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_NOT_REG),
1562*9781SMoriah.Waterland@Sun.COM 				    keystore->capath);
1563*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
1564*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
1565*9781SMoriah.Waterland@Sun.COM 			}
1566*9781SMoriah.Waterland@Sun.COM 		} else {
1567*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_READ,
1568*9781SMoriah.Waterland@Sun.COM 			    gettext(ERR_KEYSTORE_OPEN),
1569*9781SMoriah.Waterland@Sun.COM 			    keystore->capath, strerror(errno));
1570*9781SMoriah.Waterland@Sun.COM 			ret = B_FALSE;
1571*9781SMoriah.Waterland@Sun.COM 			goto cleanup;
1572*9781SMoriah.Waterland@Sun.COM 		}
1573*9781SMoriah.Waterland@Sun.COM 
1574*9781SMoriah.Waterland@Sun.COM 		break;
1575*9781SMoriah.Waterland@Sun.COM 	default:
1576*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_INTERNAL,
1577*9781SMoriah.Waterland@Sun.COM 		    gettext(ERR_KEYSTORE_INTERNAL),
1578*9781SMoriah.Waterland@Sun.COM 		    __FILE__, __LINE__);
1579*9781SMoriah.Waterland@Sun.COM 		ret = B_FALSE;
1580*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
1581*9781SMoriah.Waterland@Sun.COM 	}
1582*9781SMoriah.Waterland@Sun.COM 
1583*9781SMoriah.Waterland@Sun.COM cleanup:
1584*9781SMoriah.Waterland@Sun.COM 	if (!ret) {
1585*9781SMoriah.Waterland@Sun.COM 		if (keystore->cafd > 0) {
1586*9781SMoriah.Waterland@Sun.COM 			(void) file_unlock(keystore->cafd);
1587*9781SMoriah.Waterland@Sun.COM 			(void) close(keystore->cafd);
1588*9781SMoriah.Waterland@Sun.COM 			keystore->cafd = -1;
1589*9781SMoriah.Waterland@Sun.COM 		}
1590*9781SMoriah.Waterland@Sun.COM 
1591*9781SMoriah.Waterland@Sun.COM 		if (keystore->capath != NULL)
1592*9781SMoriah.Waterland@Sun.COM 			free(keystore->capath);
1593*9781SMoriah.Waterland@Sun.COM 		if (keystore->clpath != NULL)
1594*9781SMoriah.Waterland@Sun.COM 			free(keystore->clpath);
1595*9781SMoriah.Waterland@Sun.COM 		if (keystore->keypath != NULL)
1596*9781SMoriah.Waterland@Sun.COM 			free(keystore->keypath);
1597*9781SMoriah.Waterland@Sun.COM 		keystore->capath = NULL;
1598*9781SMoriah.Waterland@Sun.COM 		keystore->clpath = NULL;
1599*9781SMoriah.Waterland@Sun.COM 		keystore->keypath = NULL;
1600*9781SMoriah.Waterland@Sun.COM 	}
1601*9781SMoriah.Waterland@Sun.COM 
1602*9781SMoriah.Waterland@Sun.COM 	return (ret);
1603*9781SMoriah.Waterland@Sun.COM }
1604*9781SMoriah.Waterland@Sun.COM 
1605*9781SMoriah.Waterland@Sun.COM /*
1606*9781SMoriah.Waterland@Sun.COM  * unlock_keystore - Unocks a keystore
1607*9781SMoriah.Waterland@Sun.COM  *
1608*9781SMoriah.Waterland@Sun.COM  * Arguments:
1609*9781SMoriah.Waterland@Sun.COM  * err - Error object to add errors to
1610*9781SMoriah.Waterland@Sun.COM  * keystore - keystore object to unlock
1611*9781SMoriah.Waterland@Sun.COM  * Returns:
1612*9781SMoriah.Waterland@Sun.COM  *   0 - Success - Keystore files are unlocked, files are closed,
1613*9781SMoriah.Waterland@Sun.COM  * non-zero - Failure, errors and reasons recorded in err
1614*9781SMoriah.Waterland@Sun.COM  */
1615*9781SMoriah.Waterland@Sun.COM /* ARGSUSED */
1616*9781SMoriah.Waterland@Sun.COM static boolean_t
unlock_keystore(PKG_ERR * err,keystore_t * keystore)1617*9781SMoriah.Waterland@Sun.COM unlock_keystore(PKG_ERR *err, keystore_t *keystore)
1618*9781SMoriah.Waterland@Sun.COM {
1619*9781SMoriah.Waterland@Sun.COM 
1620*9781SMoriah.Waterland@Sun.COM 	/*
1621*9781SMoriah.Waterland@Sun.COM 	 * Release lock on the CA file.
1622*9781SMoriah.Waterland@Sun.COM 	 * Delete file if it is empty
1623*9781SMoriah.Waterland@Sun.COM 	 */
1624*9781SMoriah.Waterland@Sun.COM 	if (file_empty(keystore->capath)) {
1625*9781SMoriah.Waterland@Sun.COM 		(void) remove(keystore->capath);
1626*9781SMoriah.Waterland@Sun.COM 	}
1627*9781SMoriah.Waterland@Sun.COM 
1628*9781SMoriah.Waterland@Sun.COM 	(void) file_unlock(keystore->cafd);
1629*9781SMoriah.Waterland@Sun.COM 	(void) close(keystore->cafd);
1630*9781SMoriah.Waterland@Sun.COM 	return (B_TRUE);
1631*9781SMoriah.Waterland@Sun.COM }
1632*9781SMoriah.Waterland@Sun.COM 
1633*9781SMoriah.Waterland@Sun.COM /*
1634*9781SMoriah.Waterland@Sun.COM  * read_keystore - Reads keystore files of disk, parses
1635*9781SMoriah.Waterland@Sun.COM  * into internal structures.
1636*9781SMoriah.Waterland@Sun.COM  *
1637*9781SMoriah.Waterland@Sun.COM  * Arguments:
1638*9781SMoriah.Waterland@Sun.COM  * err - Error object to add errors to
1639*9781SMoriah.Waterland@Sun.COM  * keystore - keystore object to read into
1640*9781SMoriah.Waterland@Sun.COM  * cb - callback to get password, if required
1641*9781SMoriah.Waterland@Sun.COM  * Returns:
1642*9781SMoriah.Waterland@Sun.COM  *   0 - Success - Keystore files are read, and placed
1643*9781SMoriah.Waterland@Sun.COM  * into keystore structure.
1644*9781SMoriah.Waterland@Sun.COM  * non-zero - Failure, errors and reasons recorded in err
1645*9781SMoriah.Waterland@Sun.COM  */
1646*9781SMoriah.Waterland@Sun.COM static boolean_t
read_keystore(PKG_ERR * err,keystore_t * keystore,keystore_passphrase_cb cb)1647*9781SMoriah.Waterland@Sun.COM read_keystore(PKG_ERR *err, keystore_t *keystore, keystore_passphrase_cb cb)
1648*9781SMoriah.Waterland@Sun.COM {
1649*9781SMoriah.Waterland@Sun.COM 	boolean_t	ret = B_TRUE;
1650*9781SMoriah.Waterland@Sun.COM 	PKCS12		*p12 = NULL;
1651*9781SMoriah.Waterland@Sun.COM 	boolean_t	ca_empty;
1652*9781SMoriah.Waterland@Sun.COM 	boolean_t	have_passwd = B_FALSE;
1653*9781SMoriah.Waterland@Sun.COM 	boolean_t	cl_empty = B_TRUE;
1654*9781SMoriah.Waterland@Sun.COM 	boolean_t	key_empty = B_TRUE;
1655*9781SMoriah.Waterland@Sun.COM 
1656*9781SMoriah.Waterland@Sun.COM 	ca_empty = file_empty(keystore->capath);
1657*9781SMoriah.Waterland@Sun.COM 
1658*9781SMoriah.Waterland@Sun.COM 	if (keystore->clpath != NULL)
1659*9781SMoriah.Waterland@Sun.COM 		cl_empty = file_empty(keystore->clpath);
1660*9781SMoriah.Waterland@Sun.COM 	if (keystore->keypath != NULL)
1661*9781SMoriah.Waterland@Sun.COM 		key_empty = file_empty(keystore->keypath);
1662*9781SMoriah.Waterland@Sun.COM 
1663*9781SMoriah.Waterland@Sun.COM 	if (ca_empty && cl_empty && key_empty) {
1664*9781SMoriah.Waterland@Sun.COM 	    keystore->new = B_TRUE;
1665*9781SMoriah.Waterland@Sun.COM 	}
1666*9781SMoriah.Waterland@Sun.COM 
1667*9781SMoriah.Waterland@Sun.COM 	if (!ca_empty) {
1668*9781SMoriah.Waterland@Sun.COM 		/* first read the ca file */
1669*9781SMoriah.Waterland@Sun.COM 		if ((p12 = read_keystore_file(err,
1670*9781SMoriah.Waterland@Sun.COM 		    keystore->capath)) == NULL) {
1671*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_CORRUPT,
1672*9781SMoriah.Waterland@Sun.COM 			    gettext(ERR_KEYSTORE_CORRUPT), keystore->capath);
1673*9781SMoriah.Waterland@Sun.COM 			ret = B_FALSE;
1674*9781SMoriah.Waterland@Sun.COM 			goto cleanup;
1675*9781SMoriah.Waterland@Sun.COM 		}
1676*9781SMoriah.Waterland@Sun.COM 
1677*9781SMoriah.Waterland@Sun.COM 		/* Get password, using callback if necessary */
1678*9781SMoriah.Waterland@Sun.COM 		if (!have_passwd) {
1679*9781SMoriah.Waterland@Sun.COM 			if (!get_keystore_passwd(err, p12, cb, keystore)) {
1680*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
1681*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
1682*9781SMoriah.Waterland@Sun.COM 			}
1683*9781SMoriah.Waterland@Sun.COM 			have_passwd = B_TRUE;
1684*9781SMoriah.Waterland@Sun.COM 		}
1685*9781SMoriah.Waterland@Sun.COM 
1686*9781SMoriah.Waterland@Sun.COM 		/* decrypt and parse keystore file */
1687*9781SMoriah.Waterland@Sun.COM 		if (sunw_PKCS12_contents(p12, keystore->passphrase,
1688*9781SMoriah.Waterland@Sun.COM 		    &keystore->pkeys, &keystore->cacerts) < 0) {
1689*9781SMoriah.Waterland@Sun.COM 			/* could not parse the contents */
1690*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_CORRUPT,
1691*9781SMoriah.Waterland@Sun.COM 			    gettext(ERR_KEYSTORE_CORRUPT), keystore->capath);
1692*9781SMoriah.Waterland@Sun.COM 			ret = B_FALSE;
1693*9781SMoriah.Waterland@Sun.COM 			goto cleanup;
1694*9781SMoriah.Waterland@Sun.COM 		}
1695*9781SMoriah.Waterland@Sun.COM 
1696*9781SMoriah.Waterland@Sun.COM 		PKCS12_free(p12);
1697*9781SMoriah.Waterland@Sun.COM 		p12 = NULL;
1698*9781SMoriah.Waterland@Sun.COM 	} else {
1699*9781SMoriah.Waterland@Sun.COM 
1700*9781SMoriah.Waterland@Sun.COM 		/*
1701*9781SMoriah.Waterland@Sun.COM 		 * truststore is empty, so we don't have any trusted
1702*9781SMoriah.Waterland@Sun.COM 		 * certs
1703*9781SMoriah.Waterland@Sun.COM 		 */
1704*9781SMoriah.Waterland@Sun.COM 		keystore->cacerts = NULL;
1705*9781SMoriah.Waterland@Sun.COM 	}
1706*9781SMoriah.Waterland@Sun.COM 
1707*9781SMoriah.Waterland@Sun.COM 	/*
1708*9781SMoriah.Waterland@Sun.COM 	 * if there is no cl file or key file, use the cl's and key's found
1709*9781SMoriah.Waterland@Sun.COM 	 * in the ca file
1710*9781SMoriah.Waterland@Sun.COM 	 */
1711*9781SMoriah.Waterland@Sun.COM 	if (keystore->clpath == NULL && !ca_empty) {
1712*9781SMoriah.Waterland@Sun.COM 		if (sunw_split_certs(keystore->pkeys, keystore->cacerts,
1713*9781SMoriah.Waterland@Sun.COM 		    &keystore->clcerts, NULL) < 0) {
1714*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_CORRUPT,
1715*9781SMoriah.Waterland@Sun.COM 			    gettext(ERR_KEYSTORE_CORRUPT), keystore->capath);
1716*9781SMoriah.Waterland@Sun.COM 			ret = B_FALSE;
1717*9781SMoriah.Waterland@Sun.COM 			goto cleanup;
1718*9781SMoriah.Waterland@Sun.COM 		}
1719*9781SMoriah.Waterland@Sun.COM 	} else {
1720*9781SMoriah.Waterland@Sun.COM 		/*
1721*9781SMoriah.Waterland@Sun.COM 		 * files are in separate files.  read keys out of the keystore
1722*9781SMoriah.Waterland@Sun.COM 		 * certs out of the certstore, if they are not empty
1723*9781SMoriah.Waterland@Sun.COM 		 */
1724*9781SMoriah.Waterland@Sun.COM 		if (!cl_empty) {
1725*9781SMoriah.Waterland@Sun.COM 			if ((p12 = read_keystore_file(err,
1726*9781SMoriah.Waterland@Sun.COM 			    keystore->clpath)) == NULL) {
1727*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_CORRUPT,
1728*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_KEYSTORE_CORRUPT),
1729*9781SMoriah.Waterland@Sun.COM 				    keystore->clpath);
1730*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
1731*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
1732*9781SMoriah.Waterland@Sun.COM 			}
1733*9781SMoriah.Waterland@Sun.COM 
1734*9781SMoriah.Waterland@Sun.COM 			/* Get password, using callback if necessary */
1735*9781SMoriah.Waterland@Sun.COM 			if (!have_passwd) {
1736*9781SMoriah.Waterland@Sun.COM 				if (!get_keystore_passwd(err, p12, cb,
1737*9781SMoriah.Waterland@Sun.COM 				    keystore)) {
1738*9781SMoriah.Waterland@Sun.COM 					ret = B_FALSE;
1739*9781SMoriah.Waterland@Sun.COM 					goto cleanup;
1740*9781SMoriah.Waterland@Sun.COM 				}
1741*9781SMoriah.Waterland@Sun.COM 				have_passwd = B_TRUE;
1742*9781SMoriah.Waterland@Sun.COM 			}
1743*9781SMoriah.Waterland@Sun.COM 
1744*9781SMoriah.Waterland@Sun.COM 			if (check_password(p12,
1745*9781SMoriah.Waterland@Sun.COM 			    keystore->passphrase) == B_FALSE) {
1746*9781SMoriah.Waterland@Sun.COM 				/*
1747*9781SMoriah.Waterland@Sun.COM 				 * password in client cert file
1748*9781SMoriah.Waterland@Sun.COM 				 * is different than
1749*9781SMoriah.Waterland@Sun.COM 				 * the one in the other files!
1750*9781SMoriah.Waterland@Sun.COM 				 */
1751*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_BADPASS,
1752*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_MISMATCHPASS),
1753*9781SMoriah.Waterland@Sun.COM 				    keystore->clpath,
1754*9781SMoriah.Waterland@Sun.COM 				    keystore->capath, keystore->path);
1755*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
1756*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
1757*9781SMoriah.Waterland@Sun.COM 			}
1758*9781SMoriah.Waterland@Sun.COM 
1759*9781SMoriah.Waterland@Sun.COM 			if (sunw_PKCS12_contents(p12, keystore->passphrase,
1760*9781SMoriah.Waterland@Sun.COM 			    NULL, &keystore->clcerts) < 0) {
1761*9781SMoriah.Waterland@Sun.COM 				/* could not parse the contents */
1762*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_CORRUPT,
1763*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_KEYSTORE_CORRUPT),
1764*9781SMoriah.Waterland@Sun.COM 				    keystore->clpath);
1765*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
1766*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
1767*9781SMoriah.Waterland@Sun.COM 			}
1768*9781SMoriah.Waterland@Sun.COM 
1769*9781SMoriah.Waterland@Sun.COM 			PKCS12_free(p12);
1770*9781SMoriah.Waterland@Sun.COM 			p12 = NULL;
1771*9781SMoriah.Waterland@Sun.COM 		} else {
1772*9781SMoriah.Waterland@Sun.COM 			keystore->clcerts = NULL;
1773*9781SMoriah.Waterland@Sun.COM 		}
1774*9781SMoriah.Waterland@Sun.COM 
1775*9781SMoriah.Waterland@Sun.COM 		if (!key_empty) {
1776*9781SMoriah.Waterland@Sun.COM 			if ((p12 = read_keystore_file(err,
1777*9781SMoriah.Waterland@Sun.COM 			    keystore->keypath)) == NULL) {
1778*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_CORRUPT,
1779*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_KEYSTORE_CORRUPT),
1780*9781SMoriah.Waterland@Sun.COM 				    keystore->keypath);
1781*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
1782*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
1783*9781SMoriah.Waterland@Sun.COM 			}
1784*9781SMoriah.Waterland@Sun.COM 
1785*9781SMoriah.Waterland@Sun.COM 			/* Get password, using callback if necessary */
1786*9781SMoriah.Waterland@Sun.COM 			if (!have_passwd) {
1787*9781SMoriah.Waterland@Sun.COM 				if (!get_keystore_passwd(err, p12, cb,
1788*9781SMoriah.Waterland@Sun.COM 				    keystore)) {
1789*9781SMoriah.Waterland@Sun.COM 					ret = B_FALSE;
1790*9781SMoriah.Waterland@Sun.COM 					goto cleanup;
1791*9781SMoriah.Waterland@Sun.COM 				}
1792*9781SMoriah.Waterland@Sun.COM 				have_passwd = B_TRUE;
1793*9781SMoriah.Waterland@Sun.COM 			}
1794*9781SMoriah.Waterland@Sun.COM 
1795*9781SMoriah.Waterland@Sun.COM 			if (check_password(p12,
1796*9781SMoriah.Waterland@Sun.COM 			    keystore->passphrase) == B_FALSE) {
1797*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_BADPASS,
1798*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_MISMATCHPASS),
1799*9781SMoriah.Waterland@Sun.COM 				    keystore->keypath,
1800*9781SMoriah.Waterland@Sun.COM 				    keystore->capath, keystore->path);
1801*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
1802*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
1803*9781SMoriah.Waterland@Sun.COM 			}
1804*9781SMoriah.Waterland@Sun.COM 
1805*9781SMoriah.Waterland@Sun.COM 			if (sunw_PKCS12_contents(p12, keystore->passphrase,
1806*9781SMoriah.Waterland@Sun.COM 			    &keystore->pkeys, NULL) < 0) {
1807*9781SMoriah.Waterland@Sun.COM 				/* could not parse the contents */
1808*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_CORRUPT,
1809*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_KEYSTORE_CORRUPT),
1810*9781SMoriah.Waterland@Sun.COM 				    keystore->keypath);
1811*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
1812*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
1813*9781SMoriah.Waterland@Sun.COM 			}
1814*9781SMoriah.Waterland@Sun.COM 
1815*9781SMoriah.Waterland@Sun.COM 			PKCS12_free(p12);
1816*9781SMoriah.Waterland@Sun.COM 			p12 = NULL;
1817*9781SMoriah.Waterland@Sun.COM 		} else {
1818*9781SMoriah.Waterland@Sun.COM 			keystore->pkeys = NULL;
1819*9781SMoriah.Waterland@Sun.COM 		}
1820*9781SMoriah.Waterland@Sun.COM 	}
1821*9781SMoriah.Waterland@Sun.COM 
1822*9781SMoriah.Waterland@Sun.COM cleanup:
1823*9781SMoriah.Waterland@Sun.COM 	if (p12 != NULL)
1824*9781SMoriah.Waterland@Sun.COM 		PKCS12_free(p12);
1825*9781SMoriah.Waterland@Sun.COM 	return (ret);
1826*9781SMoriah.Waterland@Sun.COM }
1827*9781SMoriah.Waterland@Sun.COM 
1828*9781SMoriah.Waterland@Sun.COM /*
1829*9781SMoriah.Waterland@Sun.COM  * get_keystore_password - retrieves pasword used to
1830*9781SMoriah.Waterland@Sun.COM  * decrypt PKCS12 structure.
1831*9781SMoriah.Waterland@Sun.COM  *
1832*9781SMoriah.Waterland@Sun.COM  * Arguments:
1833*9781SMoriah.Waterland@Sun.COM  * err - Error object to add errors to
1834*9781SMoriah.Waterland@Sun.COM  * p12 - PKCS12 structure which returned password should
1835*9781SMoriah.Waterland@Sun.COM  * decrypt
1836*9781SMoriah.Waterland@Sun.COM  * cb - callback to collect password.
1837*9781SMoriah.Waterland@Sun.COM  * keystore - The keystore in which the PKCS12 structure
1838*9781SMoriah.Waterland@Sun.COM  * will eventually populate.
1839*9781SMoriah.Waterland@Sun.COM  * Returns:
1840*9781SMoriah.Waterland@Sun.COM  *   B_TRUE - success.
1841*9781SMoriah.Waterland@Sun.COM  *     keystore password is set in keystore->passphrase.
1842*9781SMoriah.Waterland@Sun.COM  *   B_FALSE - failure, errors logged
1843*9781SMoriah.Waterland@Sun.COM  */
1844*9781SMoriah.Waterland@Sun.COM static boolean_t
get_keystore_passwd(PKG_ERR * err,PKCS12 * p12,keystore_passphrase_cb cb,keystore_t * keystore)1845*9781SMoriah.Waterland@Sun.COM get_keystore_passwd(PKG_ERR *err, PKCS12 *p12, keystore_passphrase_cb cb,
1846*9781SMoriah.Waterland@Sun.COM     keystore_t *keystore)
1847*9781SMoriah.Waterland@Sun.COM {
1848*9781SMoriah.Waterland@Sun.COM 	char				*passwd;
1849*9781SMoriah.Waterland@Sun.COM 	char				passbuf[KEYSTORE_PASS_MAX + 1];
1850*9781SMoriah.Waterland@Sun.COM 	keystore_passphrase_data	data;
1851*9781SMoriah.Waterland@Sun.COM 
1852*9781SMoriah.Waterland@Sun.COM 	/* see if no password is the right password */
1853*9781SMoriah.Waterland@Sun.COM 	if (check_password(p12, "") == B_TRUE) {
1854*9781SMoriah.Waterland@Sun.COM 		passwd = "";
1855*9781SMoriah.Waterland@Sun.COM 	} else if (check_password(p12, NULL) == B_TRUE) {
1856*9781SMoriah.Waterland@Sun.COM 		passwd = NULL;
1857*9781SMoriah.Waterland@Sun.COM 	} else {
1858*9781SMoriah.Waterland@Sun.COM 		/* oops, it's encrypted.  get password */
1859*9781SMoriah.Waterland@Sun.COM 		data.err = err;
1860*9781SMoriah.Waterland@Sun.COM 		if (cb(passbuf, KEYSTORE_PASS_MAX, 0,
1861*9781SMoriah.Waterland@Sun.COM 		    &data) == -1) {
1862*9781SMoriah.Waterland@Sun.COM 			/* could not get password */
1863*9781SMoriah.Waterland@Sun.COM 			return (B_FALSE);
1864*9781SMoriah.Waterland@Sun.COM 		}
1865*9781SMoriah.Waterland@Sun.COM 
1866*9781SMoriah.Waterland@Sun.COM 		if (check_password(p12, passbuf) == B_FALSE) {
1867*9781SMoriah.Waterland@Sun.COM 				/* wrong password */
1868*9781SMoriah.Waterland@Sun.COM 			pkgerr_add(err, PKGERR_BADPASS,
1869*9781SMoriah.Waterland@Sun.COM 			    gettext(ERR_BADPASS));
1870*9781SMoriah.Waterland@Sun.COM 			return (B_FALSE);
1871*9781SMoriah.Waterland@Sun.COM 		}
1872*9781SMoriah.Waterland@Sun.COM 
1873*9781SMoriah.Waterland@Sun.COM 		/*
1874*9781SMoriah.Waterland@Sun.COM 		 * make copy of password buffer, since it
1875*9781SMoriah.Waterland@Sun.COM 		 * goes away upon return
1876*9781SMoriah.Waterland@Sun.COM 		 */
1877*9781SMoriah.Waterland@Sun.COM 		passwd = xstrdup(passbuf);
1878*9781SMoriah.Waterland@Sun.COM 	}
1879*9781SMoriah.Waterland@Sun.COM 	keystore->passphrase = passwd;
1880*9781SMoriah.Waterland@Sun.COM 	return (B_TRUE);
1881*9781SMoriah.Waterland@Sun.COM }
1882*9781SMoriah.Waterland@Sun.COM 
1883*9781SMoriah.Waterland@Sun.COM /*
1884*9781SMoriah.Waterland@Sun.COM  * write_keystore - Writes keystore files to disk
1885*9781SMoriah.Waterland@Sun.COM  *
1886*9781SMoriah.Waterland@Sun.COM  * Arguments:
1887*9781SMoriah.Waterland@Sun.COM  * err - Error object to add errors to
1888*9781SMoriah.Waterland@Sun.COM  * keystore - keystore object to write from
1889*9781SMoriah.Waterland@Sun.COM  * passwd - password used to encrypt keystore
1890*9781SMoriah.Waterland@Sun.COM  * Returns:
1891*9781SMoriah.Waterland@Sun.COM  *   0 - Success - Keystore contents are written out to
1892*9781SMoriah.Waterland@Sun.COM  *   the same locations as read from
1893*9781SMoriah.Waterland@Sun.COM  * non-zero - Failure, errors and reasons recorded in err
1894*9781SMoriah.Waterland@Sun.COM  */
1895*9781SMoriah.Waterland@Sun.COM static boolean_t
write_keystore(PKG_ERR * err,keystore_t * keystore,keystore_passphrase_cb cb)1896*9781SMoriah.Waterland@Sun.COM write_keystore(PKG_ERR *err, keystore_t *keystore,
1897*9781SMoriah.Waterland@Sun.COM     keystore_passphrase_cb cb)
1898*9781SMoriah.Waterland@Sun.COM {
1899*9781SMoriah.Waterland@Sun.COM 	PKCS12	*p12 = NULL;
1900*9781SMoriah.Waterland@Sun.COM 	boolean_t ret = B_TRUE;
1901*9781SMoriah.Waterland@Sun.COM 	keystore_passphrase_data data;
1902*9781SMoriah.Waterland@Sun.COM 	char		passbuf[KEYSTORE_PASS_MAX + 1];
1903*9781SMoriah.Waterland@Sun.COM 
1904*9781SMoriah.Waterland@Sun.COM 	if (keystore->capath != NULL && keystore->clpath == NULL &&
1905*9781SMoriah.Waterland@Sun.COM 	    keystore->keypath == NULL) {
1906*9781SMoriah.Waterland@Sun.COM 
1907*9781SMoriah.Waterland@Sun.COM 		/*
1908*9781SMoriah.Waterland@Sun.COM 		 * keystore is a file.
1909*9781SMoriah.Waterland@Sun.COM 		 * just write out a single file
1910*9781SMoriah.Waterland@Sun.COM 		 */
1911*9781SMoriah.Waterland@Sun.COM 		if ((keystore->pkeys == NULL) &&
1912*9781SMoriah.Waterland@Sun.COM 		    (keystore->clcerts == NULL) &&
1913*9781SMoriah.Waterland@Sun.COM 		    (keystore->cacerts == NULL)) {
1914*9781SMoriah.Waterland@Sun.COM 			if (!clear_keystore_file(err, keystore->capath)) {
1915*9781SMoriah.Waterland@Sun.COM 				/*
1916*9781SMoriah.Waterland@Sun.COM 				 * no keys or certs to write out, so
1917*9781SMoriah.Waterland@Sun.COM 				 * blank the ca file.  we do not
1918*9781SMoriah.Waterland@Sun.COM 				 * delete it since it is used as a
1919*9781SMoriah.Waterland@Sun.COM 				 * lock by lock_keystore() in
1920*9781SMoriah.Waterland@Sun.COM 				 * subsequent invocations
1921*9781SMoriah.Waterland@Sun.COM 				 */
1922*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_WRITE,
1923*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_KEYSTORE_WRITE),
1924*9781SMoriah.Waterland@Sun.COM 				    keystore->capath);
1925*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
1926*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
1927*9781SMoriah.Waterland@Sun.COM 			}
1928*9781SMoriah.Waterland@Sun.COM 		} else {
1929*9781SMoriah.Waterland@Sun.COM 			/*
1930*9781SMoriah.Waterland@Sun.COM 			 * if the keystore is being created for the first time,
1931*9781SMoriah.Waterland@Sun.COM 			 * prompt for a passphrase for encryption
1932*9781SMoriah.Waterland@Sun.COM 			 */
1933*9781SMoriah.Waterland@Sun.COM 			if (keystore->new) {
1934*9781SMoriah.Waterland@Sun.COM 				data.err = err;
1935*9781SMoriah.Waterland@Sun.COM 				if (cb(passbuf, KEYSTORE_PASS_MAX,
1936*9781SMoriah.Waterland@Sun.COM 				    1, &data) == -1) {
1937*9781SMoriah.Waterland@Sun.COM 					ret = B_FALSE;
1938*9781SMoriah.Waterland@Sun.COM 					goto cleanup;
1939*9781SMoriah.Waterland@Sun.COM 				}
1940*9781SMoriah.Waterland@Sun.COM 			} else {
1941*9781SMoriah.Waterland@Sun.COM 				/*
1942*9781SMoriah.Waterland@Sun.COM 				 * use the one used when the keystore
1943*9781SMoriah.Waterland@Sun.COM 				 * was read
1944*9781SMoriah.Waterland@Sun.COM 				 */
1945*9781SMoriah.Waterland@Sun.COM 				strlcpy(passbuf, keystore->passphrase,
1946*9781SMoriah.Waterland@Sun.COM 				    KEYSTORE_PASS_MAX);
1947*9781SMoriah.Waterland@Sun.COM 			}
1948*9781SMoriah.Waterland@Sun.COM 
1949*9781SMoriah.Waterland@Sun.COM 			p12 = sunw_PKCS12_create(passbuf, keystore->pkeys,
1950*9781SMoriah.Waterland@Sun.COM 			    keystore->clcerts, keystore->cacerts);
1951*9781SMoriah.Waterland@Sun.COM 
1952*9781SMoriah.Waterland@Sun.COM 			if (p12 == NULL) {
1953*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_WRITE,
1954*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_KEYSTORE_FORM),
1955*9781SMoriah.Waterland@Sun.COM 				    keystore->capath);
1956*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
1957*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
1958*9781SMoriah.Waterland@Sun.COM 			}
1959*9781SMoriah.Waterland@Sun.COM 
1960*9781SMoriah.Waterland@Sun.COM 			if (!write_keystore_file(err, keystore->capath, p12)) {
1961*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_WRITE,
1962*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_KEYSTORE_WRITE),
1963*9781SMoriah.Waterland@Sun.COM 				    keystore->capath);
1964*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
1965*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
1966*9781SMoriah.Waterland@Sun.COM 			}
1967*9781SMoriah.Waterland@Sun.COM 		}
1968*9781SMoriah.Waterland@Sun.COM 
1969*9781SMoriah.Waterland@Sun.COM 	} else {
1970*9781SMoriah.Waterland@Sun.COM 		/* files are seprate. Do one at a time */
1971*9781SMoriah.Waterland@Sun.COM 
1972*9781SMoriah.Waterland@Sun.COM 		/*
1973*9781SMoriah.Waterland@Sun.COM 		 * if the keystore is being created for the first time,
1974*9781SMoriah.Waterland@Sun.COM 		 * prompt for a passphrase for encryption
1975*9781SMoriah.Waterland@Sun.COM 		 */
1976*9781SMoriah.Waterland@Sun.COM 		if (keystore->new && ((keystore->pkeys != NULL) ||
1977*9781SMoriah.Waterland@Sun.COM 		    (keystore->clcerts != NULL) ||
1978*9781SMoriah.Waterland@Sun.COM 		    (keystore->cacerts != NULL))) {
1979*9781SMoriah.Waterland@Sun.COM 			data.err = err;
1980*9781SMoriah.Waterland@Sun.COM 			if (cb(passbuf, KEYSTORE_PASS_MAX,
1981*9781SMoriah.Waterland@Sun.COM 			    1, &data) == -1) {
1982*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
1983*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
1984*9781SMoriah.Waterland@Sun.COM 			}
1985*9781SMoriah.Waterland@Sun.COM 		} else {
1986*9781SMoriah.Waterland@Sun.COM 			/* use the one used when the keystore was read */
1987*9781SMoriah.Waterland@Sun.COM 			strlcpy(passbuf, keystore->passphrase,
1988*9781SMoriah.Waterland@Sun.COM 			    KEYSTORE_PASS_MAX);
1989*9781SMoriah.Waterland@Sun.COM 		}
1990*9781SMoriah.Waterland@Sun.COM 
1991*9781SMoriah.Waterland@Sun.COM 		/* do private keys first */
1992*9781SMoriah.Waterland@Sun.COM 		if (keystore->pkeys != NULL) {
1993*9781SMoriah.Waterland@Sun.COM 			p12 = sunw_PKCS12_create(passbuf, keystore->pkeys,
1994*9781SMoriah.Waterland@Sun.COM 			    NULL, NULL);
1995*9781SMoriah.Waterland@Sun.COM 
1996*9781SMoriah.Waterland@Sun.COM 			if (p12 == NULL) {
1997*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_WRITE,
1998*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_KEYSTORE_FORM),
1999*9781SMoriah.Waterland@Sun.COM 				    keystore->keypath);
2000*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
2001*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
2002*9781SMoriah.Waterland@Sun.COM 			}
2003*9781SMoriah.Waterland@Sun.COM 
2004*9781SMoriah.Waterland@Sun.COM 			if (!write_keystore_file(err, keystore->keypath,
2005*9781SMoriah.Waterland@Sun.COM 			    p12)) {
2006*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_WRITE,
2007*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_KEYSTORE_WRITE),
2008*9781SMoriah.Waterland@Sun.COM 				    keystore->keypath);
2009*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
2010*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
2011*9781SMoriah.Waterland@Sun.COM 			}
2012*9781SMoriah.Waterland@Sun.COM 
2013*9781SMoriah.Waterland@Sun.COM 			PKCS12_free(p12);
2014*9781SMoriah.Waterland@Sun.COM 		} else {
2015*9781SMoriah.Waterland@Sun.COM 			if ((remove(keystore->keypath) != 0) &&
2016*9781SMoriah.Waterland@Sun.COM 			    (errno != ENOENT)) {
2017*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_WRITE,
2018*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_KEYSTORE_REMOVE),
2019*9781SMoriah.Waterland@Sun.COM 				    keystore->keypath);
2020*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
2021*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
2022*9781SMoriah.Waterland@Sun.COM 			}
2023*9781SMoriah.Waterland@Sun.COM 		}
2024*9781SMoriah.Waterland@Sun.COM 
2025*9781SMoriah.Waterland@Sun.COM 		/* do user certs next */
2026*9781SMoriah.Waterland@Sun.COM 		if (keystore->clcerts != NULL) {
2027*9781SMoriah.Waterland@Sun.COM 			p12 = sunw_PKCS12_create(passbuf, NULL,
2028*9781SMoriah.Waterland@Sun.COM 			    keystore->clcerts, NULL);
2029*9781SMoriah.Waterland@Sun.COM 
2030*9781SMoriah.Waterland@Sun.COM 			if (p12 == NULL) {
2031*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_WRITE,
2032*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_KEYSTORE_FORM),
2033*9781SMoriah.Waterland@Sun.COM 				    keystore->clpath);
2034*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
2035*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
2036*9781SMoriah.Waterland@Sun.COM 			}
2037*9781SMoriah.Waterland@Sun.COM 
2038*9781SMoriah.Waterland@Sun.COM 			if (!write_keystore_file(err, keystore->clpath, p12)) {
2039*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_WRITE,
2040*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_KEYSTORE_WRITE),
2041*9781SMoriah.Waterland@Sun.COM 				    keystore->clpath);
2042*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
2043*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
2044*9781SMoriah.Waterland@Sun.COM 			}
2045*9781SMoriah.Waterland@Sun.COM 
2046*9781SMoriah.Waterland@Sun.COM 			PKCS12_free(p12);
2047*9781SMoriah.Waterland@Sun.COM 		} else {
2048*9781SMoriah.Waterland@Sun.COM 			if ((remove(keystore->clpath) != 0) &&
2049*9781SMoriah.Waterland@Sun.COM 			    (errno != ENOENT)) {
2050*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_WRITE,
2051*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_KEYSTORE_REMOVE),
2052*9781SMoriah.Waterland@Sun.COM 				    keystore->clpath);
2053*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
2054*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
2055*9781SMoriah.Waterland@Sun.COM 			}
2056*9781SMoriah.Waterland@Sun.COM 		}
2057*9781SMoriah.Waterland@Sun.COM 
2058*9781SMoriah.Waterland@Sun.COM 
2059*9781SMoriah.Waterland@Sun.COM 		/* finally do CA cert file */
2060*9781SMoriah.Waterland@Sun.COM 		if (keystore->cacerts != NULL) {
2061*9781SMoriah.Waterland@Sun.COM 			p12 = sunw_PKCS12_create(passbuf, NULL,
2062*9781SMoriah.Waterland@Sun.COM 			    NULL, keystore->cacerts);
2063*9781SMoriah.Waterland@Sun.COM 
2064*9781SMoriah.Waterland@Sun.COM 			if (p12 == NULL) {
2065*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_WRITE,
2066*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_KEYSTORE_FORM),
2067*9781SMoriah.Waterland@Sun.COM 				    keystore->capath);
2068*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
2069*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
2070*9781SMoriah.Waterland@Sun.COM 			}
2071*9781SMoriah.Waterland@Sun.COM 
2072*9781SMoriah.Waterland@Sun.COM 			if (!write_keystore_file(err, keystore->capath, p12)) {
2073*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_WRITE,
2074*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_KEYSTORE_WRITE),
2075*9781SMoriah.Waterland@Sun.COM 				    keystore->capath);
2076*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
2077*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
2078*9781SMoriah.Waterland@Sun.COM 			}
2079*9781SMoriah.Waterland@Sun.COM 
2080*9781SMoriah.Waterland@Sun.COM 			PKCS12_free(p12);
2081*9781SMoriah.Waterland@Sun.COM 			p12 = NULL;
2082*9781SMoriah.Waterland@Sun.COM 		} else {
2083*9781SMoriah.Waterland@Sun.COM 			/*
2084*9781SMoriah.Waterland@Sun.COM 			 * nothing to write out, so truncate the file
2085*9781SMoriah.Waterland@Sun.COM 			 * (it will be deleted during close_keystore)
2086*9781SMoriah.Waterland@Sun.COM 			 */
2087*9781SMoriah.Waterland@Sun.COM 			if (!clear_keystore_file(err, keystore->capath)) {
2088*9781SMoriah.Waterland@Sun.COM 				pkgerr_add(err, PKGERR_WRITE,
2089*9781SMoriah.Waterland@Sun.COM 				    gettext(ERR_KEYSTORE_WRITE),
2090*9781SMoriah.Waterland@Sun.COM 				    keystore->capath);
2091*9781SMoriah.Waterland@Sun.COM 				ret = B_FALSE;
2092*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
2093*9781SMoriah.Waterland@Sun.COM 			}
2094*9781SMoriah.Waterland@Sun.COM 		}
2095*9781SMoriah.Waterland@Sun.COM 	}
2096*9781SMoriah.Waterland@Sun.COM 
2097*9781SMoriah.Waterland@Sun.COM cleanup:
2098*9781SMoriah.Waterland@Sun.COM 	if (p12 != NULL)
2099*9781SMoriah.Waterland@Sun.COM 		PKCS12_free(p12);
2100*9781SMoriah.Waterland@Sun.COM 
2101*9781SMoriah.Waterland@Sun.COM 	return (ret);
2102*9781SMoriah.Waterland@Sun.COM }
2103*9781SMoriah.Waterland@Sun.COM 
2104*9781SMoriah.Waterland@Sun.COM /*
2105*9781SMoriah.Waterland@Sun.COM  * clear_keystore_file - Clears (zeros out) a keystore file.
2106*9781SMoriah.Waterland@Sun.COM  *
2107*9781SMoriah.Waterland@Sun.COM  * Arguments:
2108*9781SMoriah.Waterland@Sun.COM  * err - Error object to add errors to
2109*9781SMoriah.Waterland@Sun.COM  * dest - Path of keystore file to zero out.
2110*9781SMoriah.Waterland@Sun.COM  * Returns:
2111*9781SMoriah.Waterland@Sun.COM  *   0 - Success - Keystore file is truncated to zero length
2112*9781SMoriah.Waterland@Sun.COM  * non-zero - Failure, errors and reasons recorded in err
2113*9781SMoriah.Waterland@Sun.COM  */
2114*9781SMoriah.Waterland@Sun.COM static boolean_t
clear_keystore_file(PKG_ERR * err,char * dest)2115*9781SMoriah.Waterland@Sun.COM clear_keystore_file(PKG_ERR *err, char *dest)
2116*9781SMoriah.Waterland@Sun.COM {
2117*9781SMoriah.Waterland@Sun.COM 	int fd;
2118*9781SMoriah.Waterland@Sun.COM 	struct stat buf;
2119*9781SMoriah.Waterland@Sun.COM 
2120*9781SMoriah.Waterland@Sun.COM 	fd = open(dest, O_RDWR|O_NONBLOCK);
2121*9781SMoriah.Waterland@Sun.COM 	if (fd == -1) {
2122*9781SMoriah.Waterland@Sun.COM 		/* can't open for writing */
2123*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_WRITE, gettext(MSG_OPEN),
2124*9781SMoriah.Waterland@Sun.COM 		    errno);
2125*9781SMoriah.Waterland@Sun.COM 		return (B_FALSE);
2126*9781SMoriah.Waterland@Sun.COM 	}
2127*9781SMoriah.Waterland@Sun.COM 
2128*9781SMoriah.Waterland@Sun.COM 	if ((fstat(fd, &buf) == -1) || !S_ISREG(buf.st_mode)) {
2129*9781SMoriah.Waterland@Sun.COM 		/* not a regular file */
2130*9781SMoriah.Waterland@Sun.COM 		(void) close(fd);
2131*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_WRITE, gettext(ERR_NOT_REG),
2132*9781SMoriah.Waterland@Sun.COM 		    dest);
2133*9781SMoriah.Waterland@Sun.COM 		return (B_FALSE);
2134*9781SMoriah.Waterland@Sun.COM 	}
2135*9781SMoriah.Waterland@Sun.COM 
2136*9781SMoriah.Waterland@Sun.COM 	if (ftruncate(fd, 0) == -1) {
2137*9781SMoriah.Waterland@Sun.COM 		(void) close(fd);
2138*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_WRITE, gettext(ERR_WRITE),
2139*9781SMoriah.Waterland@Sun.COM 		    dest, strerror(errno));
2140*9781SMoriah.Waterland@Sun.COM 		return (B_FALSE);
2141*9781SMoriah.Waterland@Sun.COM 	}
2142*9781SMoriah.Waterland@Sun.COM 
2143*9781SMoriah.Waterland@Sun.COM 	(void) close(fd);
2144*9781SMoriah.Waterland@Sun.COM 	return (B_TRUE);
2145*9781SMoriah.Waterland@Sun.COM }
2146*9781SMoriah.Waterland@Sun.COM 
2147*9781SMoriah.Waterland@Sun.COM /*
2148*9781SMoriah.Waterland@Sun.COM  * write_keystore_file - Writes keystore file to disk.
2149*9781SMoriah.Waterland@Sun.COM  *
2150*9781SMoriah.Waterland@Sun.COM  * Keystore files can possibly be corrupted by a variety
2151*9781SMoriah.Waterland@Sun.COM  * of error conditions during reading/writing.  This
2152*9781SMoriah.Waterland@Sun.COM  * routine, along with restore_keystore_file, tries to
2153*9781SMoriah.Waterland@Sun.COM  * maintain keystore integity by writing the files
2154*9781SMoriah.Waterland@Sun.COM  * out in a particular order, minimizing the time period
2155*9781SMoriah.Waterland@Sun.COM  * that the keystore is in an indeterminate state.
2156*9781SMoriah.Waterland@Sun.COM  *
2157*9781SMoriah.Waterland@Sun.COM  * With the current implementation, there are some failures
2158*9781SMoriah.Waterland@Sun.COM  * that are wholly unrecoverable, such as disk corruption.
2159*9781SMoriah.Waterland@Sun.COM  * These routines attempt to minimize the risk, but not
2160*9781SMoriah.Waterland@Sun.COM  * eliminate it.  When better, atomic operations are available
2161*9781SMoriah.Waterland@Sun.COM  * (such as a true database with commit, rollback, and
2162*9781SMoriah.Waterland@Sun.COM  * guaranteed atomicity), this implementation should use that.
2163*9781SMoriah.Waterland@Sun.COM  *
2164*9781SMoriah.Waterland@Sun.COM  *
2165*9781SMoriah.Waterland@Sun.COM  * Arguments:
2166*9781SMoriah.Waterland@Sun.COM  * err - Error object to add errors to
2167*9781SMoriah.Waterland@Sun.COM  * dest - Destination filename
2168*9781SMoriah.Waterland@Sun.COM  * contents - Contents to write to the file
2169*9781SMoriah.Waterland@Sun.COM  * Returns:
2170*9781SMoriah.Waterland@Sun.COM  *   0 - Success - Keystore contents are written out to
2171*9781SMoriah.Waterland@Sun.COM  *   the destination.
2172*9781SMoriah.Waterland@Sun.COM  * non-zero - Failure, errors and reasons recorded in err
2173*9781SMoriah.Waterland@Sun.COM  */
2174*9781SMoriah.Waterland@Sun.COM static boolean_t
write_keystore_file(PKG_ERR * err,char * dest,PKCS12 * contents)2175*9781SMoriah.Waterland@Sun.COM write_keystore_file(PKG_ERR *err, char *dest, PKCS12 *contents)
2176*9781SMoriah.Waterland@Sun.COM {
2177*9781SMoriah.Waterland@Sun.COM 	FILE	*newfile = NULL;
2178*9781SMoriah.Waterland@Sun.COM 	boolean_t	ret = B_TRUE;
2179*9781SMoriah.Waterland@Sun.COM 	char	newpath[MAXPATHLEN];
2180*9781SMoriah.Waterland@Sun.COM 	char	backuppath[MAXPATHLEN];
2181*9781SMoriah.Waterland@Sun.COM 	struct stat buf;
2182*9781SMoriah.Waterland@Sun.COM 	int fd;
2183*9781SMoriah.Waterland@Sun.COM 
2184*9781SMoriah.Waterland@Sun.COM 	(void) snprintf(newpath, MAXPATHLEN, "%s.new", dest);
2185*9781SMoriah.Waterland@Sun.COM 	(void) snprintf(backuppath, MAXPATHLEN, "%s.bak", dest);
2186*9781SMoriah.Waterland@Sun.COM 
2187*9781SMoriah.Waterland@Sun.COM 	if ((fd = open(newpath, O_CREAT|O_EXCL|O_WRONLY|O_NONBLOCK,
2188*9781SMoriah.Waterland@Sun.COM 	    S_IRUSR|S_IWUSR)) == -1) {
2189*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN),
2190*9781SMoriah.Waterland@Sun.COM 		    newpath, strerror(errno));
2191*9781SMoriah.Waterland@Sun.COM 		ret = B_FALSE;
2192*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
2193*9781SMoriah.Waterland@Sun.COM 	}
2194*9781SMoriah.Waterland@Sun.COM 
2195*9781SMoriah.Waterland@Sun.COM 	if (fstat(fd, &buf) == -1) {
2196*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN),
2197*9781SMoriah.Waterland@Sun.COM 		    newpath, strerror(errno));
2198*9781SMoriah.Waterland@Sun.COM 		ret = B_FALSE;
2199*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
2200*9781SMoriah.Waterland@Sun.COM 	}
2201*9781SMoriah.Waterland@Sun.COM 
2202*9781SMoriah.Waterland@Sun.COM 	if (!S_ISREG(buf.st_mode)) {
2203*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_READ, gettext(ERR_NOT_REG),
2204*9781SMoriah.Waterland@Sun.COM 		    newpath);
2205*9781SMoriah.Waterland@Sun.COM 		ret = B_FALSE;
2206*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
2207*9781SMoriah.Waterland@Sun.COM 	}
2208*9781SMoriah.Waterland@Sun.COM 
2209*9781SMoriah.Waterland@Sun.COM 	if ((newfile = fdopen(fd, "w")) == NULL) {
2210*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN),
2211*9781SMoriah.Waterland@Sun.COM 		    newpath, strerror(errno));
2212*9781SMoriah.Waterland@Sun.COM 		ret = B_FALSE;
2213*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
2214*9781SMoriah.Waterland@Sun.COM 	}
2215*9781SMoriah.Waterland@Sun.COM 
2216*9781SMoriah.Waterland@Sun.COM 	if (i2d_PKCS12_fp(newfile, contents) == 0) {
2217*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_WRITE, gettext(ERR_KEYSTORE_WRITE),
2218*9781SMoriah.Waterland@Sun.COM 		    newpath);
2219*9781SMoriah.Waterland@Sun.COM 		ret = B_FALSE;
2220*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
2221*9781SMoriah.Waterland@Sun.COM 	}
2222*9781SMoriah.Waterland@Sun.COM 
2223*9781SMoriah.Waterland@Sun.COM 	/* flush, then close */
2224*9781SMoriah.Waterland@Sun.COM 	(void) fflush(newfile);
2225*9781SMoriah.Waterland@Sun.COM 	(void) fclose(newfile);
2226*9781SMoriah.Waterland@Sun.COM 	newfile = NULL;
2227*9781SMoriah.Waterland@Sun.COM 
2228*9781SMoriah.Waterland@Sun.COM 	/* now back up the original file */
2229*9781SMoriah.Waterland@Sun.COM 	(void) rename(dest, backuppath);
2230*9781SMoriah.Waterland@Sun.COM 
2231*9781SMoriah.Waterland@Sun.COM 	/* put new one in its place */
2232*9781SMoriah.Waterland@Sun.COM 	(void) rename(newpath, dest);
2233*9781SMoriah.Waterland@Sun.COM 
2234*9781SMoriah.Waterland@Sun.COM 	/* remove backup */
2235*9781SMoriah.Waterland@Sun.COM 	(void) remove(backuppath);
2236*9781SMoriah.Waterland@Sun.COM 
2237*9781SMoriah.Waterland@Sun.COM cleanup:
2238*9781SMoriah.Waterland@Sun.COM 	if (newfile != NULL)
2239*9781SMoriah.Waterland@Sun.COM 		(void) fclose(newfile);
2240*9781SMoriah.Waterland@Sun.COM 	if (fd != -1)
2241*9781SMoriah.Waterland@Sun.COM 		(void) close(fd);
2242*9781SMoriah.Waterland@Sun.COM 
2243*9781SMoriah.Waterland@Sun.COM 	return (ret);
2244*9781SMoriah.Waterland@Sun.COM }
2245*9781SMoriah.Waterland@Sun.COM 
2246*9781SMoriah.Waterland@Sun.COM /*
2247*9781SMoriah.Waterland@Sun.COM  * read_keystore_file - Reads single keystore file
2248*9781SMoriah.Waterland@Sun.COM  * off disk in PKCS12 format.
2249*9781SMoriah.Waterland@Sun.COM  *
2250*9781SMoriah.Waterland@Sun.COM  * Arguments:
2251*9781SMoriah.Waterland@Sun.COM  * err - Error object to add errors to
2252*9781SMoriah.Waterland@Sun.COM  * file - File path to read
2253*9781SMoriah.Waterland@Sun.COM  * Returns:
2254*9781SMoriah.Waterland@Sun.COM  *   PKCS12 contents of file, or NULL if an error occurred.
2255*9781SMoriah.Waterland@Sun.COM  *   errors recorded in 'err'.
2256*9781SMoriah.Waterland@Sun.COM  */
2257*9781SMoriah.Waterland@Sun.COM static PKCS12
read_keystore_file(PKG_ERR * err,char * file)2258*9781SMoriah.Waterland@Sun.COM *read_keystore_file(PKG_ERR *err, char *file)
2259*9781SMoriah.Waterland@Sun.COM {
2260*9781SMoriah.Waterland@Sun.COM 	int fd;
2261*9781SMoriah.Waterland@Sun.COM 	struct stat buf;
2262*9781SMoriah.Waterland@Sun.COM 	FILE *newfile;
2263*9781SMoriah.Waterland@Sun.COM 	PKCS12 *p12 = NULL;
2264*9781SMoriah.Waterland@Sun.COM 
2265*9781SMoriah.Waterland@Sun.COM 	if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) {
2266*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN),
2267*9781SMoriah.Waterland@Sun.COM 		    file, strerror(errno));
2268*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
2269*9781SMoriah.Waterland@Sun.COM 	}
2270*9781SMoriah.Waterland@Sun.COM 
2271*9781SMoriah.Waterland@Sun.COM 	if (fstat(fd, &buf) == -1) {
2272*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN),
2273*9781SMoriah.Waterland@Sun.COM 		    file, strerror(errno));
2274*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
2275*9781SMoriah.Waterland@Sun.COM 	}
2276*9781SMoriah.Waterland@Sun.COM 
2277*9781SMoriah.Waterland@Sun.COM 	if (!S_ISREG(buf.st_mode)) {
2278*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_READ, gettext(ERR_NOT_REG),
2279*9781SMoriah.Waterland@Sun.COM 		    file);
2280*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
2281*9781SMoriah.Waterland@Sun.COM 	}
2282*9781SMoriah.Waterland@Sun.COM 
2283*9781SMoriah.Waterland@Sun.COM 	if ((newfile = fdopen(fd, "r")) == NULL) {
2284*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN),
2285*9781SMoriah.Waterland@Sun.COM 		    file, strerror(errno));
2286*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
2287*9781SMoriah.Waterland@Sun.COM 	}
2288*9781SMoriah.Waterland@Sun.COM 
2289*9781SMoriah.Waterland@Sun.COM 	if ((p12 = d2i_PKCS12_fp(newfile, NULL)) == NULL) {
2290*9781SMoriah.Waterland@Sun.COM 		pkgerr_add(err, PKGERR_CORRUPT,
2291*9781SMoriah.Waterland@Sun.COM 		    gettext(ERR_KEYSTORE_CORRUPT), file);
2292*9781SMoriah.Waterland@Sun.COM 		goto cleanup;
2293*9781SMoriah.Waterland@Sun.COM 	}
2294*9781SMoriah.Waterland@Sun.COM 
2295*9781SMoriah.Waterland@Sun.COM cleanup:
2296*9781SMoriah.Waterland@Sun.COM 	if (newfile != NULL)
2297*9781SMoriah.Waterland@Sun.COM 		(void) fclose(newfile);
2298*9781SMoriah.Waterland@Sun.COM 	if (fd != -1)
2299*9781SMoriah.Waterland@Sun.COM 		(void) close(fd);
2300*9781SMoriah.Waterland@Sun.COM 
2301*9781SMoriah.Waterland@Sun.COM 	return (p12);
2302*9781SMoriah.Waterland@Sun.COM }
2303*9781SMoriah.Waterland@Sun.COM 
2304*9781SMoriah.Waterland@Sun.COM 
2305*9781SMoriah.Waterland@Sun.COM /*
2306*9781SMoriah.Waterland@Sun.COM  * Locks the specified file.
2307*9781SMoriah.Waterland@Sun.COM  */
2308*9781SMoriah.Waterland@Sun.COM static int
file_lock(int fd,int type,int wait)2309*9781SMoriah.Waterland@Sun.COM file_lock(int fd, int type, int wait)
2310*9781SMoriah.Waterland@Sun.COM {
2311*9781SMoriah.Waterland@Sun.COM 	struct flock lock;
2312*9781SMoriah.Waterland@Sun.COM 
2313*9781SMoriah.Waterland@Sun.COM 	lock.l_type = type;
2314*9781SMoriah.Waterland@Sun.COM 	lock.l_start = 0;
2315*9781SMoriah.Waterland@Sun.COM 	lock.l_whence = SEEK_SET;
2316*9781SMoriah.Waterland@Sun.COM 	lock.l_len = 0;
2317*9781SMoriah.Waterland@Sun.COM 
2318*9781SMoriah.Waterland@Sun.COM 	if (!wait) {
2319*9781SMoriah.Waterland@Sun.COM 		if (file_lock_test(fd, type)) {
2320*9781SMoriah.Waterland@Sun.COM 			/*
2321*9781SMoriah.Waterland@Sun.COM 			 * The caller would have to wait to get the
2322*9781SMoriah.Waterland@Sun.COM 			 * lock on this file.
2323*9781SMoriah.Waterland@Sun.COM 			 */
2324*9781SMoriah.Waterland@Sun.COM 			return (-1);
2325*9781SMoriah.Waterland@Sun.COM 		}
2326*9781SMoriah.Waterland@Sun.COM 	}
2327*9781SMoriah.Waterland@Sun.COM 
2328*9781SMoriah.Waterland@Sun.COM 	return (fcntl(fd, F_SETLKW, &lock));
2329*9781SMoriah.Waterland@Sun.COM }
2330*9781SMoriah.Waterland@Sun.COM 
2331*9781SMoriah.Waterland@Sun.COM /*
2332*9781SMoriah.Waterland@Sun.COM  * Returns FALSE if the file is not locked; TRUE
2333*9781SMoriah.Waterland@Sun.COM  * otherwise.
2334*9781SMoriah.Waterland@Sun.COM  */
2335*9781SMoriah.Waterland@Sun.COM static boolean_t
file_lock_test(int fd,int type)2336*9781SMoriah.Waterland@Sun.COM file_lock_test(int fd, int type)
2337*9781SMoriah.Waterland@Sun.COM {
2338*9781SMoriah.Waterland@Sun.COM 	struct flock lock;
2339*9781SMoriah.Waterland@Sun.COM 
2340*9781SMoriah.Waterland@Sun.COM 	lock.l_type = type;
2341*9781SMoriah.Waterland@Sun.COM 	lock.l_start = 0;
2342*9781SMoriah.Waterland@Sun.COM 	lock.l_whence = SEEK_SET;
2343*9781SMoriah.Waterland@Sun.COM 	lock.l_len = 0;
2344*9781SMoriah.Waterland@Sun.COM 
2345*9781SMoriah.Waterland@Sun.COM 	if (fcntl(fd, F_GETLK, &lock) != -1) {
2346*9781SMoriah.Waterland@Sun.COM 		if (lock.l_type != F_UNLCK) {
2347*9781SMoriah.Waterland@Sun.COM 			/*
2348*9781SMoriah.Waterland@Sun.COM 			 * The caller would have to wait to get the
2349*9781SMoriah.Waterland@Sun.COM 			 * lock on this file.
2350*9781SMoriah.Waterland@Sun.COM 			 */
2351*9781SMoriah.Waterland@Sun.COM 			return (B_TRUE);
2352*9781SMoriah.Waterland@Sun.COM 		}
2353*9781SMoriah.Waterland@Sun.COM 	}
2354*9781SMoriah.Waterland@Sun.COM 
2355*9781SMoriah.Waterland@Sun.COM 	/*
2356*9781SMoriah.Waterland@Sun.COM 	 * The file is not locked.
2357*9781SMoriah.Waterland@Sun.COM 	 */
2358*9781SMoriah.Waterland@Sun.COM 	return (B_FALSE);
2359*9781SMoriah.Waterland@Sun.COM }
2360*9781SMoriah.Waterland@Sun.COM 
2361*9781SMoriah.Waterland@Sun.COM /*
2362*9781SMoriah.Waterland@Sun.COM  * Unlocks the specified file.
2363*9781SMoriah.Waterland@Sun.COM  */
2364*9781SMoriah.Waterland@Sun.COM static int
file_unlock(int fd)2365*9781SMoriah.Waterland@Sun.COM file_unlock(int fd)
2366*9781SMoriah.Waterland@Sun.COM {
2367*9781SMoriah.Waterland@Sun.COM 	struct flock lock;
2368*9781SMoriah.Waterland@Sun.COM 
2369*9781SMoriah.Waterland@Sun.COM 	lock.l_type = F_UNLCK;
2370*9781SMoriah.Waterland@Sun.COM 	lock.l_start = 0;
2371*9781SMoriah.Waterland@Sun.COM 	lock.l_whence = SEEK_SET;
2372*9781SMoriah.Waterland@Sun.COM 	lock.l_len = 0;
2373*9781SMoriah.Waterland@Sun.COM 
2374*9781SMoriah.Waterland@Sun.COM 	return (fcntl(fd, F_SETLK, &lock));
2375*9781SMoriah.Waterland@Sun.COM }
2376*9781SMoriah.Waterland@Sun.COM 
2377*9781SMoriah.Waterland@Sun.COM /*
2378*9781SMoriah.Waterland@Sun.COM  * Determines if file has a length of 0 or not
2379*9781SMoriah.Waterland@Sun.COM  */
2380*9781SMoriah.Waterland@Sun.COM static boolean_t
file_empty(char * path)2381*9781SMoriah.Waterland@Sun.COM file_empty(char *path)
2382*9781SMoriah.Waterland@Sun.COM {
2383*9781SMoriah.Waterland@Sun.COM 	struct stat	buf;
2384*9781SMoriah.Waterland@Sun.COM 
2385*9781SMoriah.Waterland@Sun.COM 	/* file is empty if size = 0 or it doesn't exist */
2386*9781SMoriah.Waterland@Sun.COM 	if (lstat(path, &buf) == 0) {
2387*9781SMoriah.Waterland@Sun.COM 		if (buf.st_size == 0) {
2388*9781SMoriah.Waterland@Sun.COM 			return (B_TRUE);
2389*9781SMoriah.Waterland@Sun.COM 		}
2390*9781SMoriah.Waterland@Sun.COM 	} else {
2391*9781SMoriah.Waterland@Sun.COM 		if (errno == ENOENT) {
2392*9781SMoriah.Waterland@Sun.COM 			return (B_TRUE);
2393*9781SMoriah.Waterland@Sun.COM 		}
2394*9781SMoriah.Waterland@Sun.COM 	}
2395*9781SMoriah.Waterland@Sun.COM 
2396*9781SMoriah.Waterland@Sun.COM 	return (B_FALSE);
2397*9781SMoriah.Waterland@Sun.COM }
2398*9781SMoriah.Waterland@Sun.COM 
2399*9781SMoriah.Waterland@Sun.COM /*
2400*9781SMoriah.Waterland@Sun.COM  * Name:		get_time_string
2401*9781SMoriah.Waterland@Sun.COM  * Description:	Generates a human-readable string from an ASN1_TIME
2402*9781SMoriah.Waterland@Sun.COM  *
2403*9781SMoriah.Waterland@Sun.COM  * Arguments:	intime - The time to convert
2404*9781SMoriah.Waterland@Sun.COM  *
2405*9781SMoriah.Waterland@Sun.COM  * Returns :	A pointer to a static string representing the passed-in time.
2406*9781SMoriah.Waterland@Sun.COM  */
2407*9781SMoriah.Waterland@Sun.COM static char
get_time_string(ASN1_TIME * intime)2408*9781SMoriah.Waterland@Sun.COM *get_time_string(ASN1_TIME *intime)
2409*9781SMoriah.Waterland@Sun.COM {
2410*9781SMoriah.Waterland@Sun.COM 
2411*9781SMoriah.Waterland@Sun.COM 	static char	time[ATTR_MAX];
2412*9781SMoriah.Waterland@Sun.COM 	BIO		*mem;
2413*9781SMoriah.Waterland@Sun.COM 	char	*p;
2414*9781SMoriah.Waterland@Sun.COM 
2415*9781SMoriah.Waterland@Sun.COM 	if (intime == NULL) {
2416*9781SMoriah.Waterland@Sun.COM 		return (NULL);
2417*9781SMoriah.Waterland@Sun.COM 	}
2418*9781SMoriah.Waterland@Sun.COM 	if ((mem = BIO_new(BIO_s_mem())) == NULL) {
2419*9781SMoriah.Waterland@Sun.COM 		return (NULL);
2420*9781SMoriah.Waterland@Sun.COM 	}
2421*9781SMoriah.Waterland@Sun.COM 
2422*9781SMoriah.Waterland@Sun.COM 	if (ASN1_TIME_print(mem, intime) == 0) {
2423*9781SMoriah.Waterland@Sun.COM 		(void) BIO_free(mem);
2424*9781SMoriah.Waterland@Sun.COM 		return (NULL);
2425*9781SMoriah.Waterland@Sun.COM 	}
2426*9781SMoriah.Waterland@Sun.COM 
2427*9781SMoriah.Waterland@Sun.COM 	if (BIO_gets(mem, time, ATTR_MAX) <= 0) {
2428*9781SMoriah.Waterland@Sun.COM 		(void) BIO_free(mem);
2429*9781SMoriah.Waterland@Sun.COM 		return (NULL);
2430*9781SMoriah.Waterland@Sun.COM 	}
2431*9781SMoriah.Waterland@Sun.COM 
2432*9781SMoriah.Waterland@Sun.COM 	(void) BIO_free(mem);
2433*9781SMoriah.Waterland@Sun.COM 
2434*9781SMoriah.Waterland@Sun.COM 	/* trim the end of the string */
2435*9781SMoriah.Waterland@Sun.COM 	for (p = time + strlen(time) - 1; isspace(*p); p--) {
2436*9781SMoriah.Waterland@Sun.COM 		*p = '\0';
2437*9781SMoriah.Waterland@Sun.COM 	}
2438*9781SMoriah.Waterland@Sun.COM 
2439*9781SMoriah.Waterland@Sun.COM 	return (time);
2440*9781SMoriah.Waterland@Sun.COM }
2441*9781SMoriah.Waterland@Sun.COM 
2442*9781SMoriah.Waterland@Sun.COM /*
2443*9781SMoriah.Waterland@Sun.COM  * check_password - do various password checks to see if the current password
2444*9781SMoriah.Waterland@Sun.COM  *                  will work or we need to prompt for a new one.
2445*9781SMoriah.Waterland@Sun.COM  *
2446*9781SMoriah.Waterland@Sun.COM  * Arguments:
2447*9781SMoriah.Waterland@Sun.COM  *   pass   - password to check
2448*9781SMoriah.Waterland@Sun.COM  *
2449*9781SMoriah.Waterland@Sun.COM  * Returns:
2450*9781SMoriah.Waterland@Sun.COM  *   B_TRUE  - Password is OK.
2451*9781SMoriah.Waterland@Sun.COM  *   B_FALSE - Password not valid.
2452*9781SMoriah.Waterland@Sun.COM  */
2453*9781SMoriah.Waterland@Sun.COM static boolean_t
check_password(PKCS12 * p12,char * pass)2454*9781SMoriah.Waterland@Sun.COM check_password(PKCS12 *p12, char *pass)
2455*9781SMoriah.Waterland@Sun.COM {
2456*9781SMoriah.Waterland@Sun.COM 	boolean_t ret = B_TRUE;
2457*9781SMoriah.Waterland@Sun.COM 
2458*9781SMoriah.Waterland@Sun.COM 	/*
2459*9781SMoriah.Waterland@Sun.COM 	 * If password is zero length or NULL then try verifying both cases
2460*9781SMoriah.Waterland@Sun.COM 	 * to determine which password is correct. The reason for this is that
2461*9781SMoriah.Waterland@Sun.COM 	 * under PKCS#12 password based encryption no password and a zero
2462*9781SMoriah.Waterland@Sun.COM 	 * length password are two different things...
2463*9781SMoriah.Waterland@Sun.COM 	 */
2464*9781SMoriah.Waterland@Sun.COM 
2465*9781SMoriah.Waterland@Sun.COM 	/* Check the mac */
2466*9781SMoriah.Waterland@Sun.COM 	if (pass == NULL || *pass == '\0') {
2467*9781SMoriah.Waterland@Sun.COM 		if (PKCS12_verify_mac(p12, NULL, 0) == 0 &&
2468*9781SMoriah.Waterland@Sun.COM 		    PKCS12_verify_mac(p12, "", 0) == 0)
2469*9781SMoriah.Waterland@Sun.COM 			ret = B_FALSE;
2470*9781SMoriah.Waterland@Sun.COM 	} else if (PKCS12_verify_mac(p12, pass, -1) == 0) {
2471*9781SMoriah.Waterland@Sun.COM 		ret = B_FALSE;
2472*9781SMoriah.Waterland@Sun.COM 	}
2473*9781SMoriah.Waterland@Sun.COM 	return (ret);
2474*9781SMoriah.Waterland@Sun.COM }
2475