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