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 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 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