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