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