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 <stdarg.h> 30*5c51f124SMoriah Waterland #include <stdlib.h> 31*5c51f124SMoriah Waterland #include <string.h> 32*5c51f124SMoriah Waterland #include <sys/types.h> 33*5c51f124SMoriah Waterland #include <unistd.h> 34*5c51f124SMoriah Waterland #include <signal.h> 35*5c51f124SMoriah Waterland #include <locale.h> 36*5c51f124SMoriah Waterland #include <sys/param.h> 37*5c51f124SMoriah Waterland #include <openssl/bio.h> 38*5c51f124SMoriah Waterland #include <openssl/x509v3.h> 39*5c51f124SMoriah Waterland #include <openssl/ui.h> 40*5c51f124SMoriah Waterland 41*5c51f124SMoriah Waterland #include <pkglib.h> 42*5c51f124SMoriah Waterland #include <libinst.h> 43*5c51f124SMoriah Waterland #include <pkgerr.h> 44*5c51f124SMoriah Waterland #include <keystore.h> 45*5c51f124SMoriah Waterland #include "pkgadm.h" 46*5c51f124SMoriah Waterland #include "pkgadm_msgs.h" 47*5c51f124SMoriah Waterland 48*5c51f124SMoriah Waterland typedef enum { 49*5c51f124SMoriah Waterland VerifyFailed, 50*5c51f124SMoriah Waterland Accept, 51*5c51f124SMoriah Waterland Reject 52*5c51f124SMoriah Waterland } VerifyStatus; 53*5c51f124SMoriah Waterland 54*5c51f124SMoriah Waterland static VerifyStatus verify_trust(X509 *); 55*5c51f124SMoriah Waterland static boolean_t is_ca_cert(X509 *); 56*5c51f124SMoriah Waterland 57*5c51f124SMoriah Waterland /* 58*5c51f124SMoriah Waterland * Name: addcert 59*5c51f124SMoriah Waterland * Desc: Imports a user certificate into the keystore, along with a 60*5c51f124SMoriah Waterland * private key. 61*5c51f124SMoriah Waterland * Returns: 0 on success, non-zero otherwise. 62*5c51f124SMoriah Waterland */ 63*5c51f124SMoriah Waterland int 64*5c51f124SMoriah Waterland addcert(int argc, char **argv) 65*5c51f124SMoriah Waterland { 66*5c51f124SMoriah Waterland int i; 67*5c51f124SMoriah Waterland char keystore_file[MAXPATHLEN] = ""; 68*5c51f124SMoriah Waterland char *keystore_base = NULL; 69*5c51f124SMoriah Waterland char *homedir; 70*5c51f124SMoriah Waterland char *passarg = NULL; 71*5c51f124SMoriah Waterland char *import_passarg = NULL; 72*5c51f124SMoriah Waterland char *altroot = NULL; 73*5c51f124SMoriah Waterland char *prog = NULL; 74*5c51f124SMoriah Waterland char *alias = NULL; 75*5c51f124SMoriah Waterland char *infile = NULL; 76*5c51f124SMoriah Waterland char *inkeyfile = NULL; 77*5c51f124SMoriah Waterland keystore_encoding_format_t informat = NULL; 78*5c51f124SMoriah Waterland char *informat_str = NULL; 79*5c51f124SMoriah Waterland int ret = 1; 80*5c51f124SMoriah Waterland boolean_t trusted = B_FALSE; 81*5c51f124SMoriah Waterland boolean_t implicit_trust = B_FALSE; 82*5c51f124SMoriah Waterland 83*5c51f124SMoriah Waterland FILE *certfile = NULL; 84*5c51f124SMoriah Waterland FILE *keyfile = NULL; 85*5c51f124SMoriah Waterland X509 *cert = NULL; 86*5c51f124SMoriah Waterland STACK_OF(X509) *trustcerts = NULL; 87*5c51f124SMoriah Waterland EVP_PKEY *key = NULL; 88*5c51f124SMoriah Waterland PKG_ERR *err = NULL; 89*5c51f124SMoriah Waterland keystore_handle_t keystore = NULL; 90*5c51f124SMoriah Waterland 91*5c51f124SMoriah Waterland while ((i = getopt(argc, argv, ":a:k:e:f:n:P:p:R:ty")) != EOF) { 92*5c51f124SMoriah Waterland switch (i) { 93*5c51f124SMoriah Waterland case 'a': 94*5c51f124SMoriah Waterland prog = optarg; 95*5c51f124SMoriah Waterland break; 96*5c51f124SMoriah Waterland case 'k': 97*5c51f124SMoriah Waterland keystore_base = optarg; 98*5c51f124SMoriah Waterland break; 99*5c51f124SMoriah Waterland case 'e': 100*5c51f124SMoriah Waterland inkeyfile = optarg; 101*5c51f124SMoriah Waterland break; 102*5c51f124SMoriah Waterland case 'f': 103*5c51f124SMoriah Waterland informat_str = optarg; 104*5c51f124SMoriah Waterland break; 105*5c51f124SMoriah Waterland case 'n': 106*5c51f124SMoriah Waterland alias = optarg; 107*5c51f124SMoriah Waterland break; 108*5c51f124SMoriah Waterland case 'P': 109*5c51f124SMoriah Waterland passarg = optarg; 110*5c51f124SMoriah Waterland break; 111*5c51f124SMoriah Waterland case 'p': 112*5c51f124SMoriah Waterland import_passarg = optarg; 113*5c51f124SMoriah Waterland break; 114*5c51f124SMoriah Waterland case 'R': 115*5c51f124SMoriah Waterland altroot = optarg; 116*5c51f124SMoriah Waterland break; 117*5c51f124SMoriah Waterland case 't': 118*5c51f124SMoriah Waterland trusted = B_TRUE; 119*5c51f124SMoriah Waterland break; 120*5c51f124SMoriah Waterland case 'y': 121*5c51f124SMoriah Waterland implicit_trust = B_TRUE; 122*5c51f124SMoriah Waterland break; 123*5c51f124SMoriah Waterland case ':': 124*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_MISSING_OPERAND, optopt); 125*5c51f124SMoriah Waterland /* LINTED fallthrough intentional */ 126*5c51f124SMoriah Waterland case '?': 127*5c51f124SMoriah Waterland default: 128*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_USAGE); 129*5c51f124SMoriah Waterland goto cleanup; 130*5c51f124SMoriah Waterland } 131*5c51f124SMoriah Waterland } 132*5c51f124SMoriah Waterland 133*5c51f124SMoriah Waterland if (!trusted && alias == NULL) { 134*5c51f124SMoriah Waterland /* for untrusted (user) certs, we require a name */ 135*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_USER_NAME); 136*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_USAGE); 137*5c51f124SMoriah Waterland goto cleanup; 138*5c51f124SMoriah Waterland } else if (trusted && alias != NULL) { 139*5c51f124SMoriah Waterland /* for trusted certs, we cannot have a name */ 140*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_TRUSTED_NAME); 141*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_USAGE); 142*5c51f124SMoriah Waterland goto cleanup; 143*5c51f124SMoriah Waterland } 144*5c51f124SMoriah Waterland 145*5c51f124SMoriah Waterland if (trusted && inkeyfile != NULL) { 146*5c51f124SMoriah Waterland /* for trusted certs, we cannot have a private key */ 147*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_TRUSTED_KEY); 148*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_USAGE); 149*5c51f124SMoriah Waterland goto cleanup; 150*5c51f124SMoriah Waterland } 151*5c51f124SMoriah Waterland 152*5c51f124SMoriah Waterland /* last argument should be the path to the certificate */ 153*5c51f124SMoriah Waterland if ((argc-optind) > 1) { 154*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_USAGE); 155*5c51f124SMoriah Waterland goto cleanup; 156*5c51f124SMoriah Waterland } else if ((argc-optind) < 1) { 157*5c51f124SMoriah Waterland infile = "stdin"; 158*5c51f124SMoriah Waterland certfile = stdin; 159*5c51f124SMoriah Waterland log_msg(LOG_MSG_DEBUG, "Loading stdin certificate"); 160*5c51f124SMoriah Waterland } else { 161*5c51f124SMoriah Waterland infile = argv[optind]; 162*5c51f124SMoriah Waterland log_msg(LOG_MSG_DEBUG, "Loading <%s> certificate", 163*5c51f124SMoriah Waterland argv[optind]); 164*5c51f124SMoriah Waterland if ((certfile = fopen(infile, "r")) == NULL) { 165*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_OPEN, infile); 166*5c51f124SMoriah Waterland goto cleanup; 167*5c51f124SMoriah Waterland } 168*5c51f124SMoriah Waterland } 169*5c51f124SMoriah Waterland 170*5c51f124SMoriah Waterland /* 171*5c51f124SMoriah Waterland * if specific key file supplied, open it, otherwise open 172*5c51f124SMoriah Waterland * default (stdin) 173*5c51f124SMoriah Waterland */ 174*5c51f124SMoriah Waterland if (inkeyfile != NULL) { 175*5c51f124SMoriah Waterland if ((keyfile = fopen(inkeyfile, "r")) == NULL) { 176*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_OPEN, inkeyfile); 177*5c51f124SMoriah Waterland goto cleanup; 178*5c51f124SMoriah Waterland } 179*5c51f124SMoriah Waterland } else { 180*5c51f124SMoriah Waterland inkeyfile = "stdin"; 181*5c51f124SMoriah Waterland keyfile = stdin; 182*5c51f124SMoriah Waterland } 183*5c51f124SMoriah Waterland 184*5c51f124SMoriah Waterland /* set up proper keystore */ 185*5c51f124SMoriah Waterland if (altroot != NULL) { 186*5c51f124SMoriah Waterland if (strlcpy(keystore_file, altroot, MAXPATHLEN) >= MAXPATHLEN) { 187*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_TOO_LONG, altroot); 188*5c51f124SMoriah Waterland goto cleanup; 189*5c51f124SMoriah Waterland } 190*5c51f124SMoriah Waterland 191*5c51f124SMoriah Waterland if (strlcat(keystore_file, "/", MAXPATHLEN) >= MAXPATHLEN) { 192*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_TOO_LONG, altroot); 193*5c51f124SMoriah Waterland goto cleanup; 194*5c51f124SMoriah Waterland } 195*5c51f124SMoriah Waterland } 196*5c51f124SMoriah Waterland 197*5c51f124SMoriah Waterland if (keystore_base == NULL) { 198*5c51f124SMoriah Waterland if (geteuid() == 0 || altroot != NULL) { 199*5c51f124SMoriah Waterland /* 200*5c51f124SMoriah Waterland * If we have an alternate 201*5c51f124SMoriah Waterland * root, then we have no choice but to use 202*5c51f124SMoriah Waterland * root's keystore on that alternate root, 203*5c51f124SMoriah Waterland * since there is no way to resolve a 204*5c51f124SMoriah Waterland * user's home dir given an alternate root 205*5c51f124SMoriah Waterland */ 206*5c51f124SMoriah Waterland if (strlcat(keystore_file, PKGSEC, 207*5c51f124SMoriah Waterland MAXPATHLEN) >= MAXPATHLEN) { 208*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_TOO_LONG, 209*5c51f124SMoriah Waterland keystore_file); 210*5c51f124SMoriah Waterland goto cleanup; 211*5c51f124SMoriah Waterland } 212*5c51f124SMoriah Waterland } else { 213*5c51f124SMoriah Waterland if ((homedir = getenv("HOME")) == NULL) { 214*5c51f124SMoriah Waterland /* 215*5c51f124SMoriah Waterland * not superuser, but no home dir, so 216*5c51f124SMoriah Waterland * use superuser's keystore 217*5c51f124SMoriah Waterland */ 218*5c51f124SMoriah Waterland if (strlcat(keystore_file, PKGSEC, 219*5c51f124SMoriah Waterland MAXPATHLEN) >= MAXPATHLEN) { 220*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_TOO_LONG, 221*5c51f124SMoriah Waterland keystore_file); 222*5c51f124SMoriah Waterland goto cleanup; 223*5c51f124SMoriah Waterland } 224*5c51f124SMoriah Waterland } else { 225*5c51f124SMoriah Waterland if (strlcat(keystore_file, homedir, 226*5c51f124SMoriah Waterland MAXPATHLEN) >= MAXPATHLEN) { 227*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_TOO_LONG, 228*5c51f124SMoriah Waterland homedir); 229*5c51f124SMoriah Waterland goto cleanup; 230*5c51f124SMoriah Waterland } 231*5c51f124SMoriah Waterland if (strlcat(keystore_file, "/.pkg/security", 232*5c51f124SMoriah Waterland MAXPATHLEN) >= MAXPATHLEN) { 233*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_TOO_LONG, 234*5c51f124SMoriah Waterland keystore_file); 235*5c51f124SMoriah Waterland goto cleanup; 236*5c51f124SMoriah Waterland } 237*5c51f124SMoriah Waterland } 238*5c51f124SMoriah Waterland } 239*5c51f124SMoriah Waterland } else { 240*5c51f124SMoriah Waterland if (strlcat(keystore_file, keystore_base, 241*5c51f124SMoriah Waterland MAXPATHLEN) >= MAXPATHLEN) { 242*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_TOO_LONG, 243*5c51f124SMoriah Waterland keystore_base); 244*5c51f124SMoriah Waterland goto cleanup; 245*5c51f124SMoriah Waterland } 246*5c51f124SMoriah Waterland } 247*5c51f124SMoriah Waterland 248*5c51f124SMoriah Waterland /* figure out input format */ 249*5c51f124SMoriah Waterland if (informat_str == NULL) { 250*5c51f124SMoriah Waterland informat = KEYSTORE_FORMAT_PEM; 251*5c51f124SMoriah Waterland } else { 252*5c51f124SMoriah Waterland if (ci_streq(informat_str, "pem")) { 253*5c51f124SMoriah Waterland informat = KEYSTORE_FORMAT_PEM; 254*5c51f124SMoriah Waterland } else if (ci_streq(informat_str, "der")) { 255*5c51f124SMoriah Waterland informat = KEYSTORE_FORMAT_DER; 256*5c51f124SMoriah Waterland } else { 257*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_BAD_FORMAT, informat_str); 258*5c51f124SMoriah Waterland goto cleanup; 259*5c51f124SMoriah Waterland } 260*5c51f124SMoriah Waterland } 261*5c51f124SMoriah Waterland 262*5c51f124SMoriah Waterland err = pkgerr_new(); 263*5c51f124SMoriah Waterland 264*5c51f124SMoriah Waterland if (trusted) { 265*5c51f124SMoriah Waterland /* load all possible certs */ 266*5c51f124SMoriah Waterland if (load_all_certs(err, certfile, informat, import_passarg, 267*5c51f124SMoriah Waterland &trustcerts) != 0) { 268*5c51f124SMoriah Waterland log_pkgerr(LOG_MSG_ERR, err); 269*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_NO_ADDCERT, infile); 270*5c51f124SMoriah Waterland goto cleanup; 271*5c51f124SMoriah Waterland } 272*5c51f124SMoriah Waterland 273*5c51f124SMoriah Waterland /* we must have gotten at least one cert, if not, fail */ 274*5c51f124SMoriah Waterland if (sk_X509_num(trustcerts) < 1) { 275*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_NO_CERTS, infile); 276*5c51f124SMoriah Waterland goto cleanup; 277*5c51f124SMoriah Waterland } 278*5c51f124SMoriah Waterland } else { 279*5c51f124SMoriah Waterland /* first, try to load user certificate and key */ 280*5c51f124SMoriah Waterland if (load_cert_and_key(err, certfile, informat, import_passarg, 281*5c51f124SMoriah Waterland &key, &cert) != 0) { 282*5c51f124SMoriah Waterland log_pkgerr(LOG_MSG_ERR, err); 283*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_NO_ADDCERT, infile); 284*5c51f124SMoriah Waterland goto cleanup; 285*5c51f124SMoriah Waterland } 286*5c51f124SMoriah Waterland 287*5c51f124SMoriah Waterland /* we must have gotten a cert, if not, fail */ 288*5c51f124SMoriah Waterland if (cert == NULL) { 289*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_NO_CERTS, infile); 290*5c51f124SMoriah Waterland goto cleanup; 291*5c51f124SMoriah Waterland } 292*5c51f124SMoriah Waterland 293*5c51f124SMoriah Waterland if (key == NULL) { 294*5c51f124SMoriah Waterland /* 295*5c51f124SMoriah Waterland * if we are importing a user cert, and did not get 296*5c51f124SMoriah Waterland * a key, try to load it from the key file 297*5c51f124SMoriah Waterland */ 298*5c51f124SMoriah Waterland if (keyfile == NULL) { 299*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_NEED_KEY, infile); 300*5c51f124SMoriah Waterland goto cleanup; 301*5c51f124SMoriah Waterland } else { 302*5c51f124SMoriah Waterland log_msg(LOG_MSG_DEBUG, 303*5c51f124SMoriah Waterland "Loading private key <%s>", inkeyfile); 304*5c51f124SMoriah Waterland if (load_cert_and_key(err, keyfile, informat, 305*5c51f124SMoriah Waterland import_passarg, 306*5c51f124SMoriah Waterland &key, NULL) != 0) { 307*5c51f124SMoriah Waterland log_pkgerr(LOG_MSG_ERR, err); 308*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, 309*5c51f124SMoriah Waterland MSG_NO_ADDKEY, inkeyfile); 310*5c51f124SMoriah Waterland goto cleanup; 311*5c51f124SMoriah Waterland } 312*5c51f124SMoriah Waterland 313*5c51f124SMoriah Waterland if (key == NULL) { 314*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_NO_PRIVKEY, 315*5c51f124SMoriah Waterland inkeyfile); 316*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, 317*5c51f124SMoriah Waterland MSG_NO_ADDKEY, inkeyfile); 318*5c51f124SMoriah Waterland goto cleanup; 319*5c51f124SMoriah Waterland } 320*5c51f124SMoriah Waterland } 321*5c51f124SMoriah Waterland } 322*5c51f124SMoriah Waterland } 323*5c51f124SMoriah Waterland 324*5c51f124SMoriah Waterland if (trusted) { 325*5c51f124SMoriah Waterland /* check validity date of all certificates */ 326*5c51f124SMoriah Waterland for (i = 0; i < sk_X509_num(trustcerts); i++) { 327*5c51f124SMoriah Waterland /* LINTED pointer cast may result in improper algnmnt */ 328*5c51f124SMoriah Waterland cert = sk_X509_value(trustcerts, i); 329*5c51f124SMoriah Waterland if (check_cert(err, cert) != 0) { 330*5c51f124SMoriah Waterland log_pkgerr(LOG_MSG_ERR, err); 331*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_NO_ADDCERT, 332*5c51f124SMoriah Waterland infile); 333*5c51f124SMoriah Waterland goto cleanup; 334*5c51f124SMoriah Waterland } 335*5c51f124SMoriah Waterland } 336*5c51f124SMoriah Waterland } else { 337*5c51f124SMoriah Waterland /* check validity date of user certificate */ 338*5c51f124SMoriah Waterland if (check_cert_and_key(err, cert, key) != 0) { 339*5c51f124SMoriah Waterland log_pkgerr(LOG_MSG_ERR, err); 340*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_NO_ADDCERT, infile); 341*5c51f124SMoriah Waterland goto cleanup; 342*5c51f124SMoriah Waterland } 343*5c51f124SMoriah Waterland } 344*5c51f124SMoriah Waterland 345*5c51f124SMoriah Waterland if (trusted && !implicit_trust) { 346*5c51f124SMoriah Waterland /* 347*5c51f124SMoriah Waterland * if importing more than one cert, must use implicit trust, 348*5c51f124SMoriah Waterland * because we can't ask the user to individually trust 349*5c51f124SMoriah Waterland * each one, since there may be many 350*5c51f124SMoriah Waterland */ 351*5c51f124SMoriah Waterland if (sk_X509_num(trustcerts) != 1) { 352*5c51f124SMoriah Waterland log_pkgerr(LOG_MSG_ERR, err); 353*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_MULTIPLE_TRUST, infile, "-y"); 354*5c51f124SMoriah Waterland goto cleanup; 355*5c51f124SMoriah Waterland } else { 356*5c51f124SMoriah Waterland /* LINTED pointer cast may result in improper algnmnt */ 357*5c51f124SMoriah Waterland cert = sk_X509_value(trustcerts, 0); 358*5c51f124SMoriah Waterland } 359*5c51f124SMoriah Waterland 360*5c51f124SMoriah Waterland /* ask the user */ 361*5c51f124SMoriah Waterland switch (verify_trust(cert)) { 362*5c51f124SMoriah Waterland case Accept: 363*5c51f124SMoriah Waterland /* user accepted */ 364*5c51f124SMoriah Waterland break; 365*5c51f124SMoriah Waterland case Reject: 366*5c51f124SMoriah Waterland /* user aborted operation */ 367*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_ADDCERT_ABORT); 368*5c51f124SMoriah Waterland goto cleanup; 369*5c51f124SMoriah Waterland case VerifyFailed: 370*5c51f124SMoriah Waterland default: 371*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_NO_ADDCERT, infile); 372*5c51f124SMoriah Waterland goto cleanup; 373*5c51f124SMoriah Waterland } 374*5c51f124SMoriah Waterland } 375*5c51f124SMoriah Waterland 376*5c51f124SMoriah Waterland /* now load the key store */ 377*5c51f124SMoriah Waterland log_msg(LOG_MSG_DEBUG, "Loading keystore <%s>", keystore_file); 378*5c51f124SMoriah Waterland 379*5c51f124SMoriah Waterland set_passphrase_prompt(MSG_KEYSTORE_PASSPROMPT); 380*5c51f124SMoriah Waterland set_passphrase_passarg(passarg); 381*5c51f124SMoriah Waterland if (open_keystore(err, keystore_file, prog, pkg_passphrase_cb, 382*5c51f124SMoriah Waterland KEYSTORE_ACCESS_READWRITE | KEYSTORE_PATH_HARD, &keystore) != 0) { 383*5c51f124SMoriah Waterland log_pkgerr(LOG_MSG_ERR, err); 384*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_NO_ADDCERT, infile); 385*5c51f124SMoriah Waterland goto cleanup; 386*5c51f124SMoriah Waterland } 387*5c51f124SMoriah Waterland 388*5c51f124SMoriah Waterland /* now merge the new cert into the keystore */ 389*5c51f124SMoriah Waterland log_msg(LOG_MSG_DEBUG, "Merging certificate <%s>", 390*5c51f124SMoriah Waterland get_subject_display_name(cert)); 391*5c51f124SMoriah Waterland if (trusted) { 392*5c51f124SMoriah Waterland /* merge all trusted certs found */ 393*5c51f124SMoriah Waterland for (i = 0; i < sk_X509_num(trustcerts); i++) { 394*5c51f124SMoriah Waterland /* LINTED pointer cast may result in improper algnmnt */ 395*5c51f124SMoriah Waterland cert = sk_X509_value(trustcerts, i); 396*5c51f124SMoriah Waterland if (merge_ca_cert(err, cert, keystore) != 0) { 397*5c51f124SMoriah Waterland log_pkgerr(LOG_MSG_ERR, err); 398*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, 399*5c51f124SMoriah Waterland MSG_NO_ADDCERT, infile); 400*5c51f124SMoriah Waterland goto cleanup; 401*5c51f124SMoriah Waterland 402*5c51f124SMoriah Waterland } else { 403*5c51f124SMoriah Waterland log_msg(LOG_MSG_INFO, MSG_TRUSTING, 404*5c51f124SMoriah Waterland get_subject_display_name(cert)); 405*5c51f124SMoriah Waterland } 406*5c51f124SMoriah Waterland } 407*5c51f124SMoriah Waterland } else { 408*5c51f124SMoriah Waterland /* merge user cert */ 409*5c51f124SMoriah Waterland if (merge_cert_and_key(err, cert, key, alias, keystore) != 0) { 410*5c51f124SMoriah Waterland log_pkgerr(LOG_MSG_ERR, err); 411*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_NO_ADDCERT, infile); 412*5c51f124SMoriah Waterland goto cleanup; 413*5c51f124SMoriah Waterland } 414*5c51f124SMoriah Waterland } 415*5c51f124SMoriah Waterland 416*5c51f124SMoriah Waterland /* now write it back out */ 417*5c51f124SMoriah Waterland log_msg(LOG_MSG_DEBUG, "Closing keystore"); 418*5c51f124SMoriah Waterland set_passphrase_prompt(MSG_KEYSTORE_PASSOUTPROMPT); 419*5c51f124SMoriah Waterland set_passphrase_passarg(passarg); 420*5c51f124SMoriah Waterland if (close_keystore(err, keystore, pkg_passphrase_cb) != 0) { 421*5c51f124SMoriah Waterland log_pkgerr(LOG_MSG_ERR, err); 422*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_NO_ADDCERT, infile); 423*5c51f124SMoriah Waterland goto cleanup; 424*5c51f124SMoriah Waterland } 425*5c51f124SMoriah Waterland 426*5c51f124SMoriah Waterland if (trusted) { 427*5c51f124SMoriah Waterland log_msg(LOG_MSG_INFO, MSG_TRUSTED, infile); 428*5c51f124SMoriah Waterland } else { 429*5c51f124SMoriah Waterland log_msg(LOG_MSG_INFO, MSG_ADDED, infile, alias); 430*5c51f124SMoriah Waterland } 431*5c51f124SMoriah Waterland 432*5c51f124SMoriah Waterland ret = 0; 433*5c51f124SMoriah Waterland 434*5c51f124SMoriah Waterland /* fallthrough intentional */ 435*5c51f124SMoriah Waterland cleanup: 436*5c51f124SMoriah Waterland if (err != NULL) 437*5c51f124SMoriah Waterland pkgerr_free(err); 438*5c51f124SMoriah Waterland 439*5c51f124SMoriah Waterland if (certfile != NULL) 440*5c51f124SMoriah Waterland (void) fclose(certfile); 441*5c51f124SMoriah Waterland 442*5c51f124SMoriah Waterland if (keyfile != NULL) 443*5c51f124SMoriah Waterland (void) fclose(keyfile); 444*5c51f124SMoriah Waterland 445*5c51f124SMoriah Waterland return (ret); 446*5c51f124SMoriah Waterland } 447*5c51f124SMoriah Waterland 448*5c51f124SMoriah Waterland /* Asks user to verify certificate data before proceeding */ 449*5c51f124SMoriah Waterland static VerifyStatus verify_trust(X509 *cert) 450*5c51f124SMoriah Waterland { 451*5c51f124SMoriah Waterland char vfy_trust = 'y'; 452*5c51f124SMoriah Waterland VerifyStatus ret = Accept; 453*5c51f124SMoriah Waterland PKG_ERR *err; 454*5c51f124SMoriah Waterland UI *ui = NULL; 455*5c51f124SMoriah Waterland 456*5c51f124SMoriah Waterland err = pkgerr_new(); 457*5c51f124SMoriah Waterland /* print cert data */ 458*5c51f124SMoriah Waterland if (print_cert(err, cert, KEYSTORE_FORMAT_TEXT, 459*5c51f124SMoriah Waterland get_subject_display_name(cert), B_TRUE, stdout) != 0) { 460*5c51f124SMoriah Waterland log_pkgerr(LOG_MSG_ERR, err); 461*5c51f124SMoriah Waterland ret = VerifyFailed; 462*5c51f124SMoriah Waterland goto cleanup; 463*5c51f124SMoriah Waterland } 464*5c51f124SMoriah Waterland 465*5c51f124SMoriah Waterland if ((ui = UI_new()) == NULL) { 466*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_MEM); 467*5c51f124SMoriah Waterland ret = VerifyFailed; 468*5c51f124SMoriah Waterland goto cleanup; 469*5c51f124SMoriah Waterland } 470*5c51f124SMoriah Waterland 471*5c51f124SMoriah Waterland /* 472*5c51f124SMoriah Waterland * The prompt is internationalized, but the valid 473*5c51f124SMoriah Waterland * response values are fixed, to avoid any complex 474*5c51f124SMoriah Waterland * multibyte processing that results in bugs 475*5c51f124SMoriah Waterland */ 476*5c51f124SMoriah Waterland if (UI_add_input_boolean(ui, MSG_VERIFY_TRUST, 477*5c51f124SMoriah Waterland "", 478*5c51f124SMoriah Waterland "yY", "nN", 479*5c51f124SMoriah Waterland UI_INPUT_FLAG_ECHO, &vfy_trust) <= 0) { 480*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_MEM); 481*5c51f124SMoriah Waterland ret = VerifyFailed; 482*5c51f124SMoriah Waterland goto cleanup; 483*5c51f124SMoriah Waterland } 484*5c51f124SMoriah Waterland 485*5c51f124SMoriah Waterland if (UI_process(ui) != 0) { 486*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_MEM); 487*5c51f124SMoriah Waterland ret = VerifyFailed; 488*5c51f124SMoriah Waterland goto cleanup; 489*5c51f124SMoriah Waterland } 490*5c51f124SMoriah Waterland 491*5c51f124SMoriah Waterland if (vfy_trust != 'y') { 492*5c51f124SMoriah Waterland ret = Reject; 493*5c51f124SMoriah Waterland goto cleanup; 494*5c51f124SMoriah Waterland } 495*5c51f124SMoriah Waterland 496*5c51f124SMoriah Waterland /* 497*5c51f124SMoriah Waterland * if the cert does not appear to be a CA cert 498*5c51f124SMoriah Waterland * r is not self-signed, verify that as well 499*5c51f124SMoriah Waterland */ 500*5c51f124SMoriah Waterland if (!is_ca_cert(cert)) { 501*5c51f124SMoriah Waterland UI_free(ui); 502*5c51f124SMoriah Waterland if ((ui = UI_new()) == NULL) { 503*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_MEM); 504*5c51f124SMoriah Waterland ret = VerifyFailed; 505*5c51f124SMoriah Waterland goto cleanup; 506*5c51f124SMoriah Waterland } 507*5c51f124SMoriah Waterland 508*5c51f124SMoriah Waterland if (UI_add_input_boolean(ui, 509*5c51f124SMoriah Waterland MSG_VERIFY_NOT_CA, 510*5c51f124SMoriah Waterland "", 511*5c51f124SMoriah Waterland "yY", "nN", 512*5c51f124SMoriah Waterland UI_INPUT_FLAG_ECHO, &vfy_trust) <= 0) { 513*5c51f124SMoriah Waterland ret = VerifyFailed; 514*5c51f124SMoriah Waterland goto cleanup; 515*5c51f124SMoriah Waterland } 516*5c51f124SMoriah Waterland 517*5c51f124SMoriah Waterland if (UI_process(ui) != 0) { 518*5c51f124SMoriah Waterland log_msg(LOG_MSG_ERR, MSG_MEM); 519*5c51f124SMoriah Waterland ret = VerifyFailed; 520*5c51f124SMoriah Waterland goto cleanup; 521*5c51f124SMoriah Waterland } 522*5c51f124SMoriah Waterland 523*5c51f124SMoriah Waterland if (vfy_trust != 'y') { 524*5c51f124SMoriah Waterland ret = Reject; 525*5c51f124SMoriah Waterland goto cleanup; 526*5c51f124SMoriah Waterland } 527*5c51f124SMoriah Waterland } 528*5c51f124SMoriah Waterland 529*5c51f124SMoriah Waterland cleanup: 530*5c51f124SMoriah Waterland if (ui != NULL) 531*5c51f124SMoriah Waterland UI_free(ui); 532*5c51f124SMoriah Waterland 533*5c51f124SMoriah Waterland if (err != NULL) 534*5c51f124SMoriah Waterland pkgerr_free(err); 535*5c51f124SMoriah Waterland 536*5c51f124SMoriah Waterland return (ret); 537*5c51f124SMoriah Waterland } 538*5c51f124SMoriah Waterland /* 539*5c51f124SMoriah Waterland * Name: is_ca_cert 540*5c51f124SMoriah Waterland * Desc: Determines if a given certificate has the attributes 541*5c51f124SMoriah Waterland * of a CA certificate 542*5c51f124SMoriah Waterland * Returns: B_TRUE if certificate has attributes of a CA cert 543*5c51f124SMoriah Waterland * B_FALSE otherwise 544*5c51f124SMoriah Waterland */ 545*5c51f124SMoriah Waterland static boolean_t 546*5c51f124SMoriah Waterland is_ca_cert(X509 *x) 547*5c51f124SMoriah Waterland { 548*5c51f124SMoriah Waterland 549*5c51f124SMoriah Waterland /* 550*5c51f124SMoriah Waterland * X509_check_purpose causes the extensions that we 551*5c51f124SMoriah Waterland * care about to be decoded and stored in the X509 552*5c51f124SMoriah Waterland * structure, so we must call it first 553*5c51f124SMoriah Waterland * before checking for CA extensions in the X509 554*5c51f124SMoriah Waterland * structure 555*5c51f124SMoriah Waterland */ 556*5c51f124SMoriah Waterland (void) X509_check_purpose(x, X509_PURPOSE_ANY, 0); 557*5c51f124SMoriah Waterland 558*5c51f124SMoriah Waterland /* keyUsage if present should allow cert signing */ 559*5c51f124SMoriah Waterland if ((x->ex_flags & EXFLAG_KUSAGE) && 560*5c51f124SMoriah Waterland !(x->ex_kusage & KU_KEY_CERT_SIGN)) { 561*5c51f124SMoriah Waterland return (B_FALSE); 562*5c51f124SMoriah Waterland } 563*5c51f124SMoriah Waterland 564*5c51f124SMoriah Waterland /* If basicConstraints says not a CA then say so */ 565*5c51f124SMoriah Waterland if (x->ex_flags & EXFLAG_BCONS) { 566*5c51f124SMoriah Waterland if (!(x->ex_flags & EXFLAG_CA)) { 567*5c51f124SMoriah Waterland return (B_FALSE); 568*5c51f124SMoriah Waterland } 569*5c51f124SMoriah Waterland } 570*5c51f124SMoriah Waterland 571*5c51f124SMoriah Waterland /* no explicit not-a-CA flags set, so assume that it is */ 572*5c51f124SMoriah Waterland return (B_TRUE); 573*5c51f124SMoriah Waterland } 574