xref: /onnv-gate/usr/src/cmd/svr4pkg/pkgadm/certs.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 2009 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 #include <stdio.h>
29*9781SMoriah.Waterland@Sun.COM #include <limits.h>
30*9781SMoriah.Waterland@Sun.COM #include <stdlib.h>
31*9781SMoriah.Waterland@Sun.COM #include <unistd.h>
32*9781SMoriah.Waterland@Sun.COM #include <string.h>
33*9781SMoriah.Waterland@Sun.COM #include <pkglocs.h>
34*9781SMoriah.Waterland@Sun.COM #include <locale.h>
35*9781SMoriah.Waterland@Sun.COM #include <libintl.h>
36*9781SMoriah.Waterland@Sun.COM #include <signal.h>
37*9781SMoriah.Waterland@Sun.COM #include <sys/stat.h>
38*9781SMoriah.Waterland@Sun.COM #include <sys/statvfs.h>
39*9781SMoriah.Waterland@Sun.COM #include <sys/types.h>
40*9781SMoriah.Waterland@Sun.COM #include <fcntl.h>
41*9781SMoriah.Waterland@Sun.COM #include <libintl.h>
42*9781SMoriah.Waterland@Sun.COM #include <dirent.h>
43*9781SMoriah.Waterland@Sun.COM #include <openssl/err.h>
44*9781SMoriah.Waterland@Sun.COM #include <openssl/pkcs7.h>
45*9781SMoriah.Waterland@Sun.COM #include <openssl/pkcs12.h>
46*9781SMoriah.Waterland@Sun.COM #include <openssl/x509.h>
47*9781SMoriah.Waterland@Sun.COM #include <openssl/pem.h>
48*9781SMoriah.Waterland@Sun.COM #include <openssl/x509v3.h>
49*9781SMoriah.Waterland@Sun.COM 
50*9781SMoriah.Waterland@Sun.COM #include <pkglib.h>
51*9781SMoriah.Waterland@Sun.COM #include <p12lib.h>
52*9781SMoriah.Waterland@Sun.COM #include <install.h>
53*9781SMoriah.Waterland@Sun.COM #include <libadm.h>
54*9781SMoriah.Waterland@Sun.COM #include <libinst.h>
55*9781SMoriah.Waterland@Sun.COM #include "pkgadm.h"
56*9781SMoriah.Waterland@Sun.COM #include "pkgadm_msgs.h"
57*9781SMoriah.Waterland@Sun.COM 
58*9781SMoriah.Waterland@Sun.COM 
59*9781SMoriah.Waterland@Sun.COM /*
60*9781SMoriah.Waterland@Sun.COM  * Function:	load_cert_and_key
61*9781SMoriah.Waterland@Sun.COM  * Description:	Loads a public key certificate and associated private key
62*9781SMoriah.Waterland@Sun.COM  *		from a stream.
63*9781SMoriah.Waterland@Sun.COM  * Parameters:	err	- Where to write errors to for underlying library calls
64*9781SMoriah.Waterland@Sun.COM  *		incert - File to read certs and keys from
65*9781SMoriah.Waterland@Sun.COM  *		format - The format of the file
66*9781SMoriah.Waterland@Sun.COM  *		passarg - How to collect password if needed to decrypt file
67*9781SMoriah.Waterland@Sun.COM  *		key - Location to store resulting key if found
68*9781SMoriah.Waterland@Sun.COM  *		cert - Location to store resulting cert if found.
69*9781SMoriah.Waterland@Sun.COM  *
70*9781SMoriah.Waterland@Sun.COM  * Returns:	f one or more certificates are found in the file,
71*9781SMoriah.Waterland@Sun.COM  *		and one or more keys are found, then the first
72*9781SMoriah.Waterland@Sun.COM  *		certificate is used, and the keys are searched for a
73*9781SMoriah.Waterland@Sun.COM  *		match.  If no key matches the cert, then only the cert
74*9781SMoriah.Waterland@Sun.COM  *		is returned.  If no certs are found, but one or more
75*9781SMoriah.Waterland@Sun.COM  *		keys are found, then the first key is returned.
76*9781SMoriah.Waterland@Sun.COM  */
77*9781SMoriah.Waterland@Sun.COM int
load_cert_and_key(PKG_ERR * err,FILE * incert,keystore_encoding_format_t format,char * passarg,EVP_PKEY ** key,X509 ** cert)78*9781SMoriah.Waterland@Sun.COM load_cert_and_key(PKG_ERR *err, FILE *incert,
79*9781SMoriah.Waterland@Sun.COM     keystore_encoding_format_t format, char *passarg, EVP_PKEY **key,
80*9781SMoriah.Waterland@Sun.COM     X509 **cert)
81*9781SMoriah.Waterland@Sun.COM {
82*9781SMoriah.Waterland@Sun.COM 	X509 *tmpcert = NULL;
83*9781SMoriah.Waterland@Sun.COM 	EVP_PKEY *tmpkey = NULL;
84*9781SMoriah.Waterland@Sun.COM 	STACK_OF(EVP_PKEY)	*keys = NULL;
85*9781SMoriah.Waterland@Sun.COM 	STACK_OF(X509)		*certs = NULL;
86*9781SMoriah.Waterland@Sun.COM 	int i, ret = 0;
87*9781SMoriah.Waterland@Sun.COM 	keystore_passphrase_data	data;
88*9781SMoriah.Waterland@Sun.COM 	unsigned long crypto_err;
89*9781SMoriah.Waterland@Sun.COM 
90*9781SMoriah.Waterland@Sun.COM 	if (key) *key = NULL;
91*9781SMoriah.Waterland@Sun.COM 	if (cert) *cert = NULL;
92*9781SMoriah.Waterland@Sun.COM 
93*9781SMoriah.Waterland@Sun.COM 	switch (format) {
94*9781SMoriah.Waterland@Sun.COM 	case KEYSTORE_FORMAT_DER:
95*9781SMoriah.Waterland@Sun.COM 		/* first try to load a DER cert, which cannot contain a key */
96*9781SMoriah.Waterland@Sun.COM 		if ((tmpcert = d2i_X509_fp(incert, NULL)) == NULL) {
97*9781SMoriah.Waterland@Sun.COM 			log_msg(LOG_MSG_ERR, MSG_PARSE);
98*9781SMoriah.Waterland@Sun.COM 			ret = 1;
99*9781SMoriah.Waterland@Sun.COM 		}
100*9781SMoriah.Waterland@Sun.COM 		break;
101*9781SMoriah.Waterland@Sun.COM 	case KEYSTORE_FORMAT_PEM:
102*9781SMoriah.Waterland@Sun.COM 	default:
103*9781SMoriah.Waterland@Sun.COM 		data.err = err;
104*9781SMoriah.Waterland@Sun.COM 		set_passphrase_passarg(passarg);
105*9781SMoriah.Waterland@Sun.COM 		set_passphrase_prompt(gettext("Enter PEM passphrase:"));
106*9781SMoriah.Waterland@Sun.COM 		if (sunw_PEM_contents(incert, pkg_passphrase_cb,
107*9781SMoriah.Waterland@Sun.COM 		    &data, &keys, &certs) < 0) {
108*9781SMoriah.Waterland@Sun.COM 			/* print out openssl-generated PEM errors */
109*9781SMoriah.Waterland@Sun.COM 			while ((crypto_err = ERR_get_error()) != 0) {
110*9781SMoriah.Waterland@Sun.COM 				log_msg(LOG_MSG_ERR,
111*9781SMoriah.Waterland@Sun.COM 				    ERR_reason_error_string(crypto_err));
112*9781SMoriah.Waterland@Sun.COM 			}
113*9781SMoriah.Waterland@Sun.COM 			ret = 1;
114*9781SMoriah.Waterland@Sun.COM 			goto cleanup;
115*9781SMoriah.Waterland@Sun.COM 		}
116*9781SMoriah.Waterland@Sun.COM 
117*9781SMoriah.Waterland@Sun.COM 		/* take the first cert in the file, if any */
118*9781SMoriah.Waterland@Sun.COM 		if (cert && (certs != NULL)) {
119*9781SMoriah.Waterland@Sun.COM 			if (sk_X509_num(certs) != 1) {
120*9781SMoriah.Waterland@Sun.COM 				log_msg(LOG_MSG_ERR, MSG_MULTIPLE_CERTS);
121*9781SMoriah.Waterland@Sun.COM 				ret = 1;
122*9781SMoriah.Waterland@Sun.COM 				goto cleanup;
123*9781SMoriah.Waterland@Sun.COM 			} else {
124*9781SMoriah.Waterland@Sun.COM 				tmpcert = sk_X509_value(certs, 0);
125*9781SMoriah.Waterland@Sun.COM 			}
126*9781SMoriah.Waterland@Sun.COM 		}
127*9781SMoriah.Waterland@Sun.COM 
128*9781SMoriah.Waterland@Sun.COM 		if (key && (keys != NULL)) {
129*9781SMoriah.Waterland@Sun.COM 			if (tmpcert != NULL) {
130*9781SMoriah.Waterland@Sun.COM 				/*
131*9781SMoriah.Waterland@Sun.COM 				 * if we found a cert and some keys,
132*9781SMoriah.Waterland@Sun.COM 				 * only return the key that
133*9781SMoriah.Waterland@Sun.COM 				 * matches the cert
134*9781SMoriah.Waterland@Sun.COM 				 */
135*9781SMoriah.Waterland@Sun.COM 				for (i = 0; i < sk_EVP_PKEY_num(keys); i++) {
136*9781SMoriah.Waterland@Sun.COM 					if (X509_check_private_key(tmpcert,
137*9781SMoriah.Waterland@Sun.COM 					    sk_EVP_PKEY_value(keys, i))) {
138*9781SMoriah.Waterland@Sun.COM 						tmpkey =
139*9781SMoriah.Waterland@Sun.COM 						    sk_EVP_PKEY_value(keys, i);
140*9781SMoriah.Waterland@Sun.COM 						break;
141*9781SMoriah.Waterland@Sun.COM 					}
142*9781SMoriah.Waterland@Sun.COM 				}
143*9781SMoriah.Waterland@Sun.COM 			} else {
144*9781SMoriah.Waterland@Sun.COM 				if (sk_EVP_PKEY_num(keys) > 0) {
145*9781SMoriah.Waterland@Sun.COM 					tmpkey = sk_EVP_PKEY_value(keys, 0);
146*9781SMoriah.Waterland@Sun.COM 				}
147*9781SMoriah.Waterland@Sun.COM 			}
148*9781SMoriah.Waterland@Sun.COM 		}
149*9781SMoriah.Waterland@Sun.COM 		break;
150*9781SMoriah.Waterland@Sun.COM 	}
151*9781SMoriah.Waterland@Sun.COM 
152*9781SMoriah.Waterland@Sun.COM 	/* set results */
153*9781SMoriah.Waterland@Sun.COM 	if (key && tmpkey) {
154*9781SMoriah.Waterland@Sun.COM 		*key = tmpkey;
155*9781SMoriah.Waterland@Sun.COM 		tmpkey = NULL;
156*9781SMoriah.Waterland@Sun.COM 	}
157*9781SMoriah.Waterland@Sun.COM 
158*9781SMoriah.Waterland@Sun.COM 	if (cert && tmpcert) {
159*9781SMoriah.Waterland@Sun.COM 		*cert = tmpcert;
160*9781SMoriah.Waterland@Sun.COM 		tmpcert = NULL;
161*9781SMoriah.Waterland@Sun.COM 	}
162*9781SMoriah.Waterland@Sun.COM 
163*9781SMoriah.Waterland@Sun.COM cleanup:
164*9781SMoriah.Waterland@Sun.COM 	if (tmpcert != NULL) {
165*9781SMoriah.Waterland@Sun.COM 		X509_free(tmpcert);
166*9781SMoriah.Waterland@Sun.COM 	}
167*9781SMoriah.Waterland@Sun.COM 	if (tmpkey != NULL) {
168*9781SMoriah.Waterland@Sun.COM 		sunw_evp_pkey_free(tmpkey);
169*9781SMoriah.Waterland@Sun.COM 	}
170*9781SMoriah.Waterland@Sun.COM 	return (ret);
171*9781SMoriah.Waterland@Sun.COM }
172*9781SMoriah.Waterland@Sun.COM 
173*9781SMoriah.Waterland@Sun.COM /*
174*9781SMoriah.Waterland@Sun.COM  * Function:	load_all_certs
175*9781SMoriah.Waterland@Sun.COM  * Description:	Loads alll certificates from a stream.
176*9781SMoriah.Waterland@Sun.COM  * Parameters:	err	- Where to write errors to for underlying library calls
177*9781SMoriah.Waterland@Sun.COM  *		incert - File to read certs and keys from
178*9781SMoriah.Waterland@Sun.COM  *		format - The format of the file
179*9781SMoriah.Waterland@Sun.COM  *		passarg - How to collect password if needed to decrypt file
180*9781SMoriah.Waterland@Sun.COM  *		certs - Location to store resulting cert if found.
181*9781SMoriah.Waterland@Sun.COM  *
182*9781SMoriah.Waterland@Sun.COM  * Returns:	0 - success, all certs placed in ''certs'
183*9781SMoriah.Waterland@Sun.COM  *		non-zero failure, errors in 'err'
184*9781SMoriah.Waterland@Sun.COM  */
185*9781SMoriah.Waterland@Sun.COM int
load_all_certs(PKG_ERR * err,FILE * incert,keystore_encoding_format_t format,char * passarg,STACK_OF (X509)** certs)186*9781SMoriah.Waterland@Sun.COM load_all_certs(PKG_ERR *err, FILE *incert,
187*9781SMoriah.Waterland@Sun.COM     keystore_encoding_format_t format, char *passarg, STACK_OF(X509) **certs)
188*9781SMoriah.Waterland@Sun.COM {
189*9781SMoriah.Waterland@Sun.COM 	X509 *tmpcert = NULL;
190*9781SMoriah.Waterland@Sun.COM 	STACK_OF(X509) *tmpcerts = NULL;
191*9781SMoriah.Waterland@Sun.COM 	int ret = 0;
192*9781SMoriah.Waterland@Sun.COM 	keystore_passphrase_data	data;
193*9781SMoriah.Waterland@Sun.COM 	unsigned long crypto_err;
194*9781SMoriah.Waterland@Sun.COM 	if (certs) *certs = NULL;
195*9781SMoriah.Waterland@Sun.COM 
196*9781SMoriah.Waterland@Sun.COM 	switch (format) {
197*9781SMoriah.Waterland@Sun.COM 	case KEYSTORE_FORMAT_DER:
198*9781SMoriah.Waterland@Sun.COM 		/* first try to load a DER cert, which cannot contain a key */
199*9781SMoriah.Waterland@Sun.COM 		if ((tmpcert = d2i_X509_fp(incert, NULL)) == NULL) {
200*9781SMoriah.Waterland@Sun.COM 		    log_msg(LOG_MSG_ERR, MSG_PARSE);
201*9781SMoriah.Waterland@Sun.COM 			ret = 1;
202*9781SMoriah.Waterland@Sun.COM 			goto cleanup;
203*9781SMoriah.Waterland@Sun.COM 		}
204*9781SMoriah.Waterland@Sun.COM 
205*9781SMoriah.Waterland@Sun.COM 		if ((tmpcerts = sk_X509_new_null()) == NULL) {
206*9781SMoriah.Waterland@Sun.COM 			log_msg(LOG_MSG_ERR, MSG_MEM);
207*9781SMoriah.Waterland@Sun.COM 			ret = 1;
208*9781SMoriah.Waterland@Sun.COM 			goto cleanup;
209*9781SMoriah.Waterland@Sun.COM 		}
210*9781SMoriah.Waterland@Sun.COM 		sk_X509_push(tmpcerts, tmpcert);
211*9781SMoriah.Waterland@Sun.COM 		break;
212*9781SMoriah.Waterland@Sun.COM 	case KEYSTORE_FORMAT_PEM:
213*9781SMoriah.Waterland@Sun.COM 	default:
214*9781SMoriah.Waterland@Sun.COM 		data.err = err;
215*9781SMoriah.Waterland@Sun.COM 		set_passphrase_prompt(MSG_PEM_PASSPROMPT);
216*9781SMoriah.Waterland@Sun.COM 		set_passphrase_passarg(passarg);
217*9781SMoriah.Waterland@Sun.COM 		if (sunw_PEM_contents(incert, pkg_passphrase_cb,
218*9781SMoriah.Waterland@Sun.COM 		    &data, NULL, &tmpcerts) < 0) {
219*9781SMoriah.Waterland@Sun.COM 			/* print out openssl-generated PEM errors */
220*9781SMoriah.Waterland@Sun.COM 			while ((crypto_err = ERR_get_error()) != 0) {
221*9781SMoriah.Waterland@Sun.COM 				log_msg(LOG_MSG_ERR,
222*9781SMoriah.Waterland@Sun.COM 				    ERR_reason_error_string(crypto_err));
223*9781SMoriah.Waterland@Sun.COM 			}
224*9781SMoriah.Waterland@Sun.COM 		}
225*9781SMoriah.Waterland@Sun.COM 		break;
226*9781SMoriah.Waterland@Sun.COM 	}
227*9781SMoriah.Waterland@Sun.COM 
228*9781SMoriah.Waterland@Sun.COM 	/* set results */
229*9781SMoriah.Waterland@Sun.COM 	if (certs && tmpcerts) {
230*9781SMoriah.Waterland@Sun.COM 		*certs = tmpcerts;
231*9781SMoriah.Waterland@Sun.COM 		tmpcerts = NULL;
232*9781SMoriah.Waterland@Sun.COM 	}
233*9781SMoriah.Waterland@Sun.COM 
234*9781SMoriah.Waterland@Sun.COM cleanup:
235*9781SMoriah.Waterland@Sun.COM 	if (tmpcerts != NULL) {
236*9781SMoriah.Waterland@Sun.COM 		sk_X509_free(tmpcerts);
237*9781SMoriah.Waterland@Sun.COM 	}
238*9781SMoriah.Waterland@Sun.COM 	return (ret);
239*9781SMoriah.Waterland@Sun.COM }
240