1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27
28 #include <stdio.h>
29 #include <limits.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <pkglocs.h>
34 #include <locale.h>
35 #include <libintl.h>
36 #include <signal.h>
37 #include <sys/stat.h>
38 #include <sys/statvfs.h>
39 #include <sys/types.h>
40 #include <fcntl.h>
41 #include <libintl.h>
42 #include <dirent.h>
43 #include <openssl/err.h>
44 #include <openssl/pkcs7.h>
45 #include <openssl/pkcs12.h>
46 #include <openssl/x509.h>
47 #include <openssl/pem.h>
48 #include <openssl/x509v3.h>
49
50 #include <pkglib.h>
51 #include <p12lib.h>
52 #include <install.h>
53 #include <libadm.h>
54 #include <libinst.h>
55 #include "pkgadm.h"
56 #include "pkgadm_msgs.h"
57
58
59 /*
60 * Function: load_cert_and_key
61 * Description: Loads a public key certificate and associated private key
62 * from a stream.
63 * Parameters: err - Where to write errors to for underlying library calls
64 * incert - File to read certs and keys from
65 * format - The format of the file
66 * passarg - How to collect password if needed to decrypt file
67 * key - Location to store resulting key if found
68 * cert - Location to store resulting cert if found.
69 *
70 * Returns: f one or more certificates are found in the file,
71 * and one or more keys are found, then the first
72 * certificate is used, and the keys are searched for a
73 * match. If no key matches the cert, then only the cert
74 * is returned. If no certs are found, but one or more
75 * keys are found, then the first key is returned.
76 */
77 int
load_cert_and_key(PKG_ERR * err,FILE * incert,keystore_encoding_format_t format,char * passarg,EVP_PKEY ** key,X509 ** cert)78 load_cert_and_key(PKG_ERR *err, FILE *incert,
79 keystore_encoding_format_t format, char *passarg, EVP_PKEY **key,
80 X509 **cert)
81 {
82 X509 *tmpcert = NULL;
83 EVP_PKEY *tmpkey = NULL;
84 STACK_OF(EVP_PKEY) *keys = NULL;
85 STACK_OF(X509) *certs = NULL;
86 int i, ret = 0;
87 keystore_passphrase_data data;
88 unsigned long crypto_err;
89
90 if (key) *key = NULL;
91 if (cert) *cert = NULL;
92
93 switch (format) {
94 case KEYSTORE_FORMAT_DER:
95 /* first try to load a DER cert, which cannot contain a key */
96 if ((tmpcert = d2i_X509_fp(incert, NULL)) == NULL) {
97 log_msg(LOG_MSG_ERR, MSG_PARSE);
98 ret = 1;
99 }
100 break;
101 case KEYSTORE_FORMAT_PEM:
102 default:
103 data.err = err;
104 set_passphrase_passarg(passarg);
105 set_passphrase_prompt(gettext("Enter PEM passphrase:"));
106 if (sunw_PEM_contents(incert, pkg_passphrase_cb,
107 &data, &keys, &certs) < 0) {
108 /* print out openssl-generated PEM errors */
109 while ((crypto_err = ERR_get_error()) != 0) {
110 log_msg(LOG_MSG_ERR,
111 ERR_reason_error_string(crypto_err));
112 }
113 ret = 1;
114 goto cleanup;
115 }
116
117 /* take the first cert in the file, if any */
118 if (cert && (certs != NULL)) {
119 if (sk_X509_num(certs) != 1) {
120 log_msg(LOG_MSG_ERR, MSG_MULTIPLE_CERTS);
121 ret = 1;
122 goto cleanup;
123 } else {
124 tmpcert = sk_X509_value(certs, 0);
125 }
126 }
127
128 if (key && (keys != NULL)) {
129 if (tmpcert != NULL) {
130 /*
131 * if we found a cert and some keys,
132 * only return the key that
133 * matches the cert
134 */
135 for (i = 0; i < sk_EVP_PKEY_num(keys); i++) {
136 if (X509_check_private_key(tmpcert,
137 sk_EVP_PKEY_value(keys, i))) {
138 tmpkey =
139 sk_EVP_PKEY_value(keys, i);
140 break;
141 }
142 }
143 } else {
144 if (sk_EVP_PKEY_num(keys) > 0) {
145 tmpkey = sk_EVP_PKEY_value(keys, 0);
146 }
147 }
148 }
149 break;
150 }
151
152 /* set results */
153 if (key && tmpkey) {
154 *key = tmpkey;
155 tmpkey = NULL;
156 }
157
158 if (cert && tmpcert) {
159 *cert = tmpcert;
160 tmpcert = NULL;
161 }
162
163 cleanup:
164 if (tmpcert != NULL) {
165 X509_free(tmpcert);
166 }
167 if (tmpkey != NULL) {
168 sunw_evp_pkey_free(tmpkey);
169 }
170 return (ret);
171 }
172
173 /*
174 * Function: load_all_certs
175 * Description: Loads alll certificates from a stream.
176 * Parameters: err - Where to write errors to for underlying library calls
177 * incert - File to read certs and keys from
178 * format - The format of the file
179 * passarg - How to collect password if needed to decrypt file
180 * certs - Location to store resulting cert if found.
181 *
182 * Returns: 0 - success, all certs placed in ''certs'
183 * non-zero failure, errors in 'err'
184 */
185 int
load_all_certs(PKG_ERR * err,FILE * incert,keystore_encoding_format_t format,char * passarg,STACK_OF (X509)** certs)186 load_all_certs(PKG_ERR *err, FILE *incert,
187 keystore_encoding_format_t format, char *passarg, STACK_OF(X509) **certs)
188 {
189 X509 *tmpcert = NULL;
190 STACK_OF(X509) *tmpcerts = NULL;
191 int ret = 0;
192 keystore_passphrase_data data;
193 unsigned long crypto_err;
194 if (certs) *certs = NULL;
195
196 switch (format) {
197 case KEYSTORE_FORMAT_DER:
198 /* first try to load a DER cert, which cannot contain a key */
199 if ((tmpcert = d2i_X509_fp(incert, NULL)) == NULL) {
200 log_msg(LOG_MSG_ERR, MSG_PARSE);
201 ret = 1;
202 goto cleanup;
203 }
204
205 if ((tmpcerts = sk_X509_new_null()) == NULL) {
206 log_msg(LOG_MSG_ERR, MSG_MEM);
207 ret = 1;
208 goto cleanup;
209 }
210 sk_X509_push(tmpcerts, tmpcert);
211 break;
212 case KEYSTORE_FORMAT_PEM:
213 default:
214 data.err = err;
215 set_passphrase_prompt(MSG_PEM_PASSPROMPT);
216 set_passphrase_passarg(passarg);
217 if (sunw_PEM_contents(incert, pkg_passphrase_cb,
218 &data, NULL, &tmpcerts) < 0) {
219 /* print out openssl-generated PEM errors */
220 while ((crypto_err = ERR_get_error()) != 0) {
221 log_msg(LOG_MSG_ERR,
222 ERR_reason_error_string(crypto_err));
223 }
224 }
225 break;
226 }
227
228 /* set results */
229 if (certs && tmpcerts) {
230 *certs = tmpcerts;
231 tmpcerts = NULL;
232 }
233
234 cleanup:
235 if (tmpcerts != NULL) {
236 sk_X509_free(tmpcerts);
237 }
238 return (ret);
239 }
240