15c51f124SMoriah Waterland /* 25c51f124SMoriah Waterland * CDDL HEADER START 35c51f124SMoriah Waterland * 45c51f124SMoriah Waterland * The contents of this file are subject to the terms of the 55c51f124SMoriah Waterland * Common Development and Distribution License (the "License"). 65c51f124SMoriah Waterland * You may not use this file except in compliance with the License. 75c51f124SMoriah Waterland * 85c51f124SMoriah Waterland * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95c51f124SMoriah Waterland * or http://www.opensolaris.org/os/licensing. 105c51f124SMoriah Waterland * See the License for the specific language governing permissions 115c51f124SMoriah Waterland * and limitations under the License. 125c51f124SMoriah Waterland * 135c51f124SMoriah Waterland * When distributing Covered Code, include this CDDL HEADER in each 145c51f124SMoriah Waterland * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155c51f124SMoriah Waterland * If applicable, add the following below this CDDL HEADER, with the 165c51f124SMoriah Waterland * fields enclosed by brackets "[]" replaced with your own identifying 175c51f124SMoriah Waterland * information: Portions Copyright [yyyy] [name of copyright owner] 185c51f124SMoriah Waterland * 195c51f124SMoriah Waterland * CDDL HEADER END 205c51f124SMoriah Waterland */ 215c51f124SMoriah Waterland 225c51f124SMoriah Waterland /* 235c51f124SMoriah Waterland * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 245c51f124SMoriah Waterland * Use is subject to license terms. 255c51f124SMoriah Waterland */ 265c51f124SMoriah Waterland 275c51f124SMoriah Waterland /* 285c51f124SMoriah Waterland * Module: keystore.c 295c51f124SMoriah Waterland * Description: This module contains the structure definitions for processing 305c51f124SMoriah Waterland * package keystore files. 315c51f124SMoriah Waterland */ 325c51f124SMoriah Waterland 335c51f124SMoriah Waterland #include <errno.h> 345c51f124SMoriah Waterland #include <fcntl.h> 355c51f124SMoriah Waterland #include <unistd.h> 365c51f124SMoriah Waterland #include <strings.h> 375c51f124SMoriah Waterland #include <libintl.h> 385c51f124SMoriah Waterland #include <time.h> 395c51f124SMoriah Waterland #include <ctype.h> 405c51f124SMoriah Waterland #include <sys/types.h> 415c51f124SMoriah Waterland #include <sys/stat.h> 425c51f124SMoriah Waterland #include <openssl/evp.h> 435c51f124SMoriah Waterland #include <openssl/x509.h> 445c51f124SMoriah Waterland #include <openssl/pkcs12.h> 455c51f124SMoriah Waterland #include <openssl/asn1.h> 465c51f124SMoriah Waterland #include <openssl/pem.h> 475c51f124SMoriah Waterland #include <openssl/err.h> 485c51f124SMoriah Waterland #include <openssl/safestack.h> 495c51f124SMoriah Waterland #include <openssl/stack.h> 505c51f124SMoriah Waterland #include "p12lib.h" 515c51f124SMoriah Waterland #include "pkgerr.h" 525c51f124SMoriah Waterland #include "keystore.h" 535c51f124SMoriah Waterland #include "pkglib.h" 545c51f124SMoriah Waterland #include "pkglibmsgs.h" 555c51f124SMoriah Waterland 565c51f124SMoriah Waterland typedef struct keystore_t { 575c51f124SMoriah Waterland boolean_t dirty; 585c51f124SMoriah Waterland boolean_t new; 595c51f124SMoriah Waterland char *path; 605c51f124SMoriah Waterland char *passphrase; 615c51f124SMoriah Waterland /* truststore handles */ 625c51f124SMoriah Waterland int cafd; 635c51f124SMoriah Waterland STACK_OF(X509) *cacerts; 645c51f124SMoriah Waterland char *capath; 655c51f124SMoriah Waterland 665c51f124SMoriah Waterland /* user certificate handles */ 675c51f124SMoriah Waterland STACK_OF(X509) *clcerts; 685c51f124SMoriah Waterland char *clpath; 695c51f124SMoriah Waterland 705c51f124SMoriah Waterland /* private key handles */ 715c51f124SMoriah Waterland STACK_OF(EVP_PKEY) *pkeys; 725c51f124SMoriah Waterland char *keypath; 735c51f124SMoriah Waterland } keystore_t; 745c51f124SMoriah Waterland 755c51f124SMoriah Waterland /* local routines */ 765c51f124SMoriah Waterland static keystore_t *new_keystore(void); 775c51f124SMoriah Waterland static void free_keystore(keystore_t *); 785c51f124SMoriah Waterland static boolean_t verify_keystore_integrity(PKG_ERR *, keystore_t *); 795c51f124SMoriah Waterland static boolean_t check_password(PKCS12 *, char *); 805c51f124SMoriah Waterland static boolean_t resolve_paths(PKG_ERR *, char *, char *, 815c51f124SMoriah Waterland long, keystore_t *); 825c51f124SMoriah Waterland static boolean_t lock_keystore(PKG_ERR *, long, keystore_t *); 835c51f124SMoriah Waterland 845c51f124SMoriah Waterland static boolean_t unlock_keystore(PKG_ERR *, keystore_t *); 855c51f124SMoriah Waterland static boolean_t read_keystore(PKG_ERR *, keystore_t *, 865c51f124SMoriah Waterland keystore_passphrase_cb); 875c51f124SMoriah Waterland static boolean_t write_keystore(PKG_ERR *, keystore_t *, 885c51f124SMoriah Waterland keystore_passphrase_cb); 895c51f124SMoriah Waterland static boolean_t write_keystore_file(PKG_ERR *, char *, PKCS12 *); 905c51f124SMoriah Waterland static boolean_t clear_keystore_file(PKG_ERR *, char *); 915c51f124SMoriah Waterland static PKCS12 *read_keystore_file(PKG_ERR *, char *); 925c51f124SMoriah Waterland static char *get_time_string(ASN1_TIME *); 935c51f124SMoriah Waterland 945c51f124SMoriah Waterland /* locking routines */ 955c51f124SMoriah Waterland static boolean_t restore_keystore_file(PKG_ERR *, char *); 965c51f124SMoriah Waterland static int file_lock(int, int, int); 975c51f124SMoriah Waterland static int file_unlock(int); 985c51f124SMoriah Waterland static boolean_t file_lock_test(int, int); 995c51f124SMoriah Waterland static boolean_t file_empty(char *); 1005c51f124SMoriah Waterland static boolean_t get_keystore_passwd(PKG_ERR *err, PKCS12 *p12, 1015c51f124SMoriah Waterland keystore_passphrase_cb cb, keystore_t *keystore); 1025c51f124SMoriah Waterland static boolean_t wait_restore(int, char *, char *, char *); 1035c51f124SMoriah Waterland 1045c51f124SMoriah Waterland #define KEYSTORE_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) 1055c51f124SMoriah Waterland 1065c51f124SMoriah Waterland /* wait on other keystore access for 1 minute before giving up */ 1075c51f124SMoriah Waterland #define LOCK_TIMEOUT 60 1085c51f124SMoriah Waterland 1095c51f124SMoriah Waterland /* 1105c51f124SMoriah Waterland * print_certs - prints certificates out of a keystore, to a file. 1115c51f124SMoriah Waterland * 1125c51f124SMoriah Waterland * Arguments: 1135c51f124SMoriah Waterland * err - Error object to append errors to 1145c51f124SMoriah Waterland * keystore - Keystore on which to operate 1155c51f124SMoriah Waterland * alias - Name of certificate to print, NULL means print all 1165c51f124SMoriah Waterland * format - Format in which to print certificates 1175c51f124SMoriah Waterland * outfile - Where to print certificates 1185c51f124SMoriah Waterland * 1195c51f124SMoriah Waterland * Returns: 1205c51f124SMoriah Waterland * 0 - Success 1215c51f124SMoriah Waterland * non-zero - Failure, errors added to err 1225c51f124SMoriah Waterland */ 1235c51f124SMoriah Waterland int 1245c51f124SMoriah Waterland print_certs(PKG_ERR *err, keystore_handle_t keystore_h, char *alias, 1255c51f124SMoriah Waterland keystore_encoding_format_t format, FILE *outfile) 1265c51f124SMoriah Waterland { 1275c51f124SMoriah Waterland int i; 1285c51f124SMoriah Waterland X509 *cert; 1295c51f124SMoriah Waterland char *fname = NULL; 1305c51f124SMoriah Waterland boolean_t found = B_FALSE; 1315c51f124SMoriah Waterland keystore_t *keystore = keystore_h; 1325c51f124SMoriah Waterland 1335c51f124SMoriah Waterland if (keystore->clcerts != NULL) { 1345c51f124SMoriah Waterland /* print out each client cert */ 1355c51f124SMoriah Waterland for (i = 0; i < sk_X509_num(keystore->clcerts); i++) { 1365c51f124SMoriah Waterland cert = sk_X509_value(keystore->clcerts, i); 1375c51f124SMoriah Waterland (void) sunw_get_cert_fname(GETDO_COPY, cert, 1385c51f124SMoriah Waterland &fname); 1395c51f124SMoriah Waterland 1405c51f124SMoriah Waterland if (fname == NULL) { 1415c51f124SMoriah Waterland /* no name recorded, keystore is corrupt */ 1425c51f124SMoriah Waterland pkgerr_add(err, PKGERR_CORRUPT, 1435c51f124SMoriah Waterland gettext(ERR_KEYSTORE_NO_ALIAS), 1445c51f124SMoriah Waterland get_subject_display_name(cert)); 1455c51f124SMoriah Waterland return (1); 1465c51f124SMoriah Waterland } 1475c51f124SMoriah Waterland 1485c51f124SMoriah Waterland if ((alias != NULL) && (!streq(alias, fname))) { 1495c51f124SMoriah Waterland /* name does not match, skip it */ 1505c51f124SMoriah Waterland (void) OPENSSL_free(fname); 1515c51f124SMoriah Waterland fname = NULL; 1525c51f124SMoriah Waterland continue; 1535c51f124SMoriah Waterland } else { 1545c51f124SMoriah Waterland found = B_TRUE; 1555c51f124SMoriah Waterland (void) print_cert(err, cert, format, 1565c51f124SMoriah Waterland fname, B_FALSE, outfile); 1575c51f124SMoriah Waterland (void) OPENSSL_free(fname); 1585c51f124SMoriah Waterland fname = NULL; 1595c51f124SMoriah Waterland } 1605c51f124SMoriah Waterland } 1615c51f124SMoriah Waterland } 1625c51f124SMoriah Waterland 1635c51f124SMoriah Waterland if (fname != NULL) { 1645c51f124SMoriah Waterland (void) OPENSSL_free(fname); 1655c51f124SMoriah Waterland fname = NULL; 1665c51f124SMoriah Waterland } 1675c51f124SMoriah Waterland 1685c51f124SMoriah Waterland if (keystore->cacerts != NULL) { 1695c51f124SMoriah Waterland /* print out each trusted cert */ 1705c51f124SMoriah Waterland for (i = 0; i < sk_X509_num(keystore->cacerts); i++) { 1715c51f124SMoriah Waterland cert = sk_X509_value(keystore->cacerts, i); 1725c51f124SMoriah Waterland (void) sunw_get_cert_fname(GETDO_COPY, 1735c51f124SMoriah Waterland cert, &fname); 1745c51f124SMoriah Waterland 1755c51f124SMoriah Waterland if (fname == NULL) { 1765c51f124SMoriah Waterland /* no name recorded, keystore is corrupt */ 1775c51f124SMoriah Waterland pkgerr_add(err, PKGERR_CORRUPT, 1785c51f124SMoriah Waterland gettext(ERR_KEYSTORE_NO_ALIAS), 1795c51f124SMoriah Waterland get_subject_display_name(cert)); 1805c51f124SMoriah Waterland return (1); 1815c51f124SMoriah Waterland } 1825c51f124SMoriah Waterland 1835c51f124SMoriah Waterland if ((alias != NULL) && (!streq(alias, fname))) { 1845c51f124SMoriah Waterland /* name does not match, skip it */ 1855c51f124SMoriah Waterland (void) OPENSSL_free(fname); 1865c51f124SMoriah Waterland fname = NULL; 1875c51f124SMoriah Waterland continue; 1885c51f124SMoriah Waterland } else { 1895c51f124SMoriah Waterland found = B_TRUE; 1905c51f124SMoriah Waterland (void) print_cert(err, cert, format, 1915c51f124SMoriah Waterland fname, B_TRUE, outfile); 1925c51f124SMoriah Waterland (void) OPENSSL_free(fname); 1935c51f124SMoriah Waterland fname = NULL; 1945c51f124SMoriah Waterland } 1955c51f124SMoriah Waterland } 1965c51f124SMoriah Waterland } 1975c51f124SMoriah Waterland 1985c51f124SMoriah Waterland if (fname != NULL) { 1995c51f124SMoriah Waterland (void) OPENSSL_free(fname); 2005c51f124SMoriah Waterland fname = NULL; 2015c51f124SMoriah Waterland } 2025c51f124SMoriah Waterland 2035c51f124SMoriah Waterland if (found) { 2045c51f124SMoriah Waterland return (0); 2055c51f124SMoriah Waterland } else { 2065c51f124SMoriah Waterland /* no certs printed */ 2075c51f124SMoriah Waterland if (alias != NULL) { 2085c51f124SMoriah Waterland pkgerr_add(err, PKGERR_NOALIASMATCH, 2095c51f124SMoriah Waterland gettext(ERR_KEYSTORE_NOCERT), 2105c51f124SMoriah Waterland alias, keystore->path); 2115c51f124SMoriah Waterland } else { 2125c51f124SMoriah Waterland pkgerr_add(err, PKGERR_NOPUBKEY, 2135c51f124SMoriah Waterland gettext(ERR_KEYSTORE_NOPUBCERTS), 2145c51f124SMoriah Waterland keystore->path); 2155c51f124SMoriah Waterland pkgerr_add(err, PKGERR_NOCACERT, 2165c51f124SMoriah Waterland gettext(ERR_KEYSTORE_NOCACERTS), 2175c51f124SMoriah Waterland keystore->path); 2185c51f124SMoriah Waterland } 2195c51f124SMoriah Waterland return (1); 2205c51f124SMoriah Waterland } 2215c51f124SMoriah Waterland } 2225c51f124SMoriah Waterland 2235c51f124SMoriah Waterland /* 2245c51f124SMoriah Waterland * print_cert - prints a single certificate, to a file 2255c51f124SMoriah Waterland * 2265c51f124SMoriah Waterland * Arguments: 2275c51f124SMoriah Waterland * err - Error object to append errors to 2285c51f124SMoriah Waterland * x - The certificate to print 2295c51f124SMoriah Waterland * alias - Name of certificate to print 2305c51f124SMoriah Waterland * format - Format in which to print certificate 2315c51f124SMoriah Waterland * outfile - Where to print certificate 2325c51f124SMoriah Waterland * 2335c51f124SMoriah Waterland * Returns: 2345c51f124SMoriah Waterland * 0 - Success 2355c51f124SMoriah Waterland * non-zero - Failure, errors added to err 2365c51f124SMoriah Waterland */ 2375c51f124SMoriah Waterland int print_cert(PKG_ERR *err, X509 *x, 2385c51f124SMoriah Waterland keystore_encoding_format_t format, char *alias, boolean_t is_trusted, 2395c51f124SMoriah Waterland FILE *outfile) 2405c51f124SMoriah Waterland { 2415c51f124SMoriah Waterland 2425c51f124SMoriah Waterland char *vdb_str; 2435c51f124SMoriah Waterland char *vda_str; 2445c51f124SMoriah Waterland char vd_str[ATTR_MAX]; 2455c51f124SMoriah Waterland int ret = 0; 2465c51f124SMoriah Waterland char *cn_str, *icn_str, *typ_str; 2475c51f124SMoriah Waterland char *tmp; 2485c51f124SMoriah Waterland char *md5_fp; 2495c51f124SMoriah Waterland char *sha1_fp; 2505c51f124SMoriah Waterland int len; 2515c51f124SMoriah Waterland 2525c51f124SMoriah Waterland /* need to localize the word "Fingerprint", hence these pointers */ 2535c51f124SMoriah Waterland char md5_label[ATTR_MAX]; 2545c51f124SMoriah Waterland char sha1_label[ATTR_MAX]; 2555c51f124SMoriah Waterland 2565c51f124SMoriah Waterland if (is_trusted) { 2575c51f124SMoriah Waterland typ_str = gettext(MSG_KEYSTORE_TRUSTED); 2585c51f124SMoriah Waterland } else { 2595c51f124SMoriah Waterland typ_str = gettext(MSG_KEYSTORE_UNTRUSTED); 2605c51f124SMoriah Waterland } 2615c51f124SMoriah Waterland 2625c51f124SMoriah Waterland if ((cn_str = get_subject_display_name(x)) == NULL) { 2635c51f124SMoriah Waterland cn_str = gettext(MSG_KEYSTORE_UNKNOWN); 2645c51f124SMoriah Waterland } 2655c51f124SMoriah Waterland 2665c51f124SMoriah Waterland if ((icn_str = get_issuer_display_name(x)) == NULL) { 2675c51f124SMoriah Waterland icn_str = gettext(MSG_KEYSTORE_UNKNOWN); 2685c51f124SMoriah Waterland } 2695c51f124SMoriah Waterland 2705c51f124SMoriah Waterland vdb_str = xstrdup(get_time_string(X509_get_notBefore(x))); 2715c51f124SMoriah Waterland vda_str = xstrdup(get_time_string(X509_get_notAfter(x))); 2725c51f124SMoriah Waterland if (((len = snprintf(vd_str, ATTR_MAX, "<%s> - <%s>", 2735c51f124SMoriah Waterland vdb_str, vda_str)) < 0) || (len >= ATTR_MAX)) { 2745c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN), vdb_str); 2755c51f124SMoriah Waterland ret = 1; 2765c51f124SMoriah Waterland goto cleanup; 2775c51f124SMoriah Waterland } 2785c51f124SMoriah Waterland 2795c51f124SMoriah Waterland if ((tmp = get_fingerprint(x, EVP_md5())) == NULL) { 2805c51f124SMoriah Waterland md5_fp = gettext(MSG_KEYSTORE_UNKNOWN); 2815c51f124SMoriah Waterland } else { 2825c51f124SMoriah Waterland /* 2835c51f124SMoriah Waterland * make a copy, otherwise the next call to get_fingerprint 2845c51f124SMoriah Waterland * will overwrite this one 2855c51f124SMoriah Waterland */ 2865c51f124SMoriah Waterland md5_fp = xstrdup(tmp); 2875c51f124SMoriah Waterland } 2885c51f124SMoriah Waterland 2895c51f124SMoriah Waterland if ((tmp = get_fingerprint(x, EVP_sha1())) == NULL) { 2905c51f124SMoriah Waterland sha1_fp = gettext(MSG_KEYSTORE_UNKNOWN); 2915c51f124SMoriah Waterland } else { 2925c51f124SMoriah Waterland sha1_fp = xstrdup(tmp); 2935c51f124SMoriah Waterland } 2945c51f124SMoriah Waterland 2955c51f124SMoriah Waterland (void) snprintf(md5_label, ATTR_MAX, "%s %s", 2965c51f124SMoriah Waterland OBJ_nid2sn(EVP_MD_type(EVP_md5())), 2975c51f124SMoriah Waterland /* i18n: 14 characters max */ 2985c51f124SMoriah Waterland gettext(MSG_KEYSTORE_FP)); 2995c51f124SMoriah Waterland 3005c51f124SMoriah Waterland (void) snprintf(sha1_label, ATTR_MAX, "%s %s", 3015c51f124SMoriah Waterland OBJ_nid2sn(EVP_MD_type(EVP_sha1())), 3025c51f124SMoriah Waterland /* i18n: 14 characters max */ 3035c51f124SMoriah Waterland gettext(MSG_KEYSTORE_FP)); 3045c51f124SMoriah Waterland 3055c51f124SMoriah Waterland switch (format) { 3065c51f124SMoriah Waterland case KEYSTORE_FORMAT_PEM: 3075c51f124SMoriah Waterland (void) PEM_write_X509(outfile, x); 3085c51f124SMoriah Waterland break; 3095c51f124SMoriah Waterland case KEYSTORE_FORMAT_DER: 3105c51f124SMoriah Waterland (void) i2d_X509_fp(outfile, x); 3115c51f124SMoriah Waterland break; 3125c51f124SMoriah Waterland case KEYSTORE_FORMAT_TEXT: 3135c51f124SMoriah Waterland (void) fprintf(outfile, "%18s: %s\n", 3145c51f124SMoriah Waterland /* i18n: 18 characters max */ 3155c51f124SMoriah Waterland gettext(MSG_KEYSTORE_AL), alias); 3165c51f124SMoriah Waterland (void) fprintf(outfile, "%18s: %s\n", 3175c51f124SMoriah Waterland /* i18n: 18 characters max */ 3185c51f124SMoriah Waterland gettext(MSG_KEYSTORE_CN), cn_str); 3195c51f124SMoriah Waterland (void) fprintf(outfile, "%18s: %s\n", 3205c51f124SMoriah Waterland /* i18n: 18 characters max */ 3215c51f124SMoriah Waterland gettext(MSG_KEYSTORE_TY), typ_str); 3225c51f124SMoriah Waterland (void) fprintf(outfile, "%18s: %s\n", 3235c51f124SMoriah Waterland /* i18n: 18 characters max */ 3245c51f124SMoriah Waterland gettext(MSG_KEYSTORE_IN), icn_str); 3255c51f124SMoriah Waterland (void) fprintf(outfile, "%18s: %s\n", 3265c51f124SMoriah Waterland /* i18n: 18 characters max */ 3275c51f124SMoriah Waterland gettext(MSG_KEYSTORE_VD), vd_str); 3285c51f124SMoriah Waterland (void) fprintf(outfile, "%18s: %s\n", md5_label, md5_fp); 3295c51f124SMoriah Waterland (void) fprintf(outfile, "%18s: %s\n", sha1_label, sha1_fp); 3305c51f124SMoriah Waterland (void) fprintf(outfile, "\n"); 3315c51f124SMoriah Waterland break; 3325c51f124SMoriah Waterland default: 3335c51f124SMoriah Waterland pkgerr_add(err, PKGERR_INTERNAL, 3345c51f124SMoriah Waterland gettext(ERR_KEYSTORE_INTERNAL), 3355c51f124SMoriah Waterland __FILE__, __LINE__); 3365c51f124SMoriah Waterland ret = 1; 3375c51f124SMoriah Waterland goto cleanup; 3385c51f124SMoriah Waterland } 3395c51f124SMoriah Waterland 3405c51f124SMoriah Waterland cleanup: 3415c51f124SMoriah Waterland if (md5_fp != NULL) 3425c51f124SMoriah Waterland free(md5_fp); 3435c51f124SMoriah Waterland if (sha1_fp != NULL) 3445c51f124SMoriah Waterland free(sha1_fp); 3455c51f124SMoriah Waterland if (vda_str != NULL) 3465c51f124SMoriah Waterland free(vda_str); 3475c51f124SMoriah Waterland if (vdb_str != NULL) 3485c51f124SMoriah Waterland free(vdb_str); 3495c51f124SMoriah Waterland return (ret); 3505c51f124SMoriah Waterland } 3515c51f124SMoriah Waterland 3525c51f124SMoriah Waterland /* 3535c51f124SMoriah Waterland * open_keystore - Initialize new keystore object for 3545c51f124SMoriah Waterland * impending access. 3555c51f124SMoriah Waterland * 3565c51f124SMoriah Waterland * Arguments: 3575c51f124SMoriah Waterland * err - Error object to append errors to 3585c51f124SMoriah Waterland * keystore_file - Base filename or directory of keystore 3595c51f124SMoriah Waterland * app - Application making request 3605c51f124SMoriah Waterland * passwd - Password used to decrypt keystore 3615c51f124SMoriah Waterland * flags - Control flags used to control access mode and behavior 3625c51f124SMoriah Waterland * result - Resulting keystore object stored here on success 3635c51f124SMoriah Waterland * 3645c51f124SMoriah Waterland * Returns: 3655c51f124SMoriah Waterland * 0 - Success - result contains a pointer to the opened keystore 3665c51f124SMoriah Waterland * non-zero - Failure, errors added to err 3675c51f124SMoriah Waterland */ 3685c51f124SMoriah Waterland int 3695c51f124SMoriah Waterland open_keystore(PKG_ERR *err, char *keystore_file, char *app, 3705c51f124SMoriah Waterland keystore_passphrase_cb cb, long flags, keystore_handle_t *result) 3715c51f124SMoriah Waterland { 3725c51f124SMoriah Waterland int ret = 0; 3735c51f124SMoriah Waterland keystore_t *tmpstore; 3745c51f124SMoriah Waterland 3755c51f124SMoriah Waterland tmpstore = new_keystore(); 3765c51f124SMoriah Waterland 3775c51f124SMoriah Waterland tmpstore->dirty = B_FALSE; 3785c51f124SMoriah Waterland tmpstore->new = B_FALSE; 3795c51f124SMoriah Waterland tmpstore->path = xstrdup(keystore_file); 3805c51f124SMoriah Waterland 3815c51f124SMoriah Waterland if (!resolve_paths(err, keystore_file, app, flags, tmpstore)) { 3825c51f124SMoriah Waterland /* unable to determine keystore paths */ 3835c51f124SMoriah Waterland pkgerr_add(err, PKGERR_CORRUPT, gettext(ERR_KEYSTORE_REPAIR), 3845c51f124SMoriah Waterland keystore_file); 3855c51f124SMoriah Waterland ret = 1; 3865c51f124SMoriah Waterland goto cleanup; 3875c51f124SMoriah Waterland } 3885c51f124SMoriah Waterland 3895c51f124SMoriah Waterland if (!verify_keystore_integrity(err, tmpstore)) { 3905c51f124SMoriah Waterland /* unable to repair keystore */ 3915c51f124SMoriah Waterland pkgerr_add(err, PKGERR_CORRUPT, gettext(ERR_KEYSTORE_REPAIR), 3925c51f124SMoriah Waterland keystore_file); 3935c51f124SMoriah Waterland ret = 1; 3945c51f124SMoriah Waterland goto cleanup; 3955c51f124SMoriah Waterland } 3965c51f124SMoriah Waterland 3975c51f124SMoriah Waterland if (!lock_keystore(err, flags, tmpstore)) { 3985c51f124SMoriah Waterland pkgerr_add(err, PKGERR_LOCKED, gettext(ERR_KEYSTORE_LOCKED), 3995c51f124SMoriah Waterland keystore_file); 4005c51f124SMoriah Waterland ret = 1; 4015c51f124SMoriah Waterland goto cleanup; 4025c51f124SMoriah Waterland } 4035c51f124SMoriah Waterland 4045c51f124SMoriah Waterland /* now that we have locked the keystore, go ahead and read it */ 4055c51f124SMoriah Waterland if (!read_keystore(err, tmpstore, cb)) { 4065c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, gettext(ERR_PARSE), 4075c51f124SMoriah Waterland keystore_file); 4085c51f124SMoriah Waterland ret = 1; 4095c51f124SMoriah Waterland goto cleanup; 4105c51f124SMoriah Waterland } 4115c51f124SMoriah Waterland 4125c51f124SMoriah Waterland *result = tmpstore; 4135c51f124SMoriah Waterland tmpstore = NULL; 4145c51f124SMoriah Waterland 4155c51f124SMoriah Waterland cleanup: 4165c51f124SMoriah Waterland if (tmpstore != NULL) 4175c51f124SMoriah Waterland free_keystore(tmpstore); 4185c51f124SMoriah Waterland return (ret); 4195c51f124SMoriah Waterland } 4205c51f124SMoriah Waterland 4215c51f124SMoriah Waterland /* 4225c51f124SMoriah Waterland * new_keystore - Allocates and initializes a Keystore object 4235c51f124SMoriah Waterland * 4245c51f124SMoriah Waterland * Arguments: 4255c51f124SMoriah Waterland * NONE 4265c51f124SMoriah Waterland * 4275c51f124SMoriah Waterland * Returns: 4285c51f124SMoriah Waterland * NULL - out of memory 4295c51f124SMoriah Waterland * otherwise, returns a pointer to the newly allocated object, 4305c51f124SMoriah Waterland * which should be freed with free_keystore() when no longer 4315c51f124SMoriah Waterland * needed. 4325c51f124SMoriah Waterland */ 4335c51f124SMoriah Waterland static keystore_t 4345c51f124SMoriah Waterland *new_keystore(void) 4355c51f124SMoriah Waterland { 4365c51f124SMoriah Waterland keystore_t *tmpstore; 4375c51f124SMoriah Waterland 4385c51f124SMoriah Waterland if ((tmpstore = (keystore_t *)malloc(sizeof (keystore_t))) == NULL) { 4395c51f124SMoriah Waterland return (NULL); 4405c51f124SMoriah Waterland } 4415c51f124SMoriah Waterland tmpstore->dirty = B_FALSE; 4425c51f124SMoriah Waterland tmpstore->new = B_FALSE; 4435c51f124SMoriah Waterland tmpstore->path = NULL; 4445c51f124SMoriah Waterland tmpstore->passphrase = NULL; 4455c51f124SMoriah Waterland tmpstore->cafd = -1; 4465c51f124SMoriah Waterland tmpstore->cacerts = NULL; 4475c51f124SMoriah Waterland tmpstore->capath = NULL; 4485c51f124SMoriah Waterland tmpstore->clcerts = NULL; 4495c51f124SMoriah Waterland tmpstore->clpath = NULL; 4505c51f124SMoriah Waterland tmpstore->pkeys = NULL; 4515c51f124SMoriah Waterland tmpstore->keypath = NULL; 4525c51f124SMoriah Waterland 4535c51f124SMoriah Waterland return (tmpstore); 4545c51f124SMoriah Waterland } 4555c51f124SMoriah Waterland 4565c51f124SMoriah Waterland /* 4575c51f124SMoriah Waterland * free_keystore - Deallocates a Keystore object 4585c51f124SMoriah Waterland * 4595c51f124SMoriah Waterland * Arguments: 4605c51f124SMoriah Waterland * keystore - The keystore to deallocate 4615c51f124SMoriah Waterland * 4625c51f124SMoriah Waterland * Returns: 4635c51f124SMoriah Waterland * NONE 4645c51f124SMoriah Waterland */ 4655c51f124SMoriah Waterland static void 4665c51f124SMoriah Waterland free_keystore(keystore_t *keystore) 4675c51f124SMoriah Waterland { 4685c51f124SMoriah Waterland if (keystore->path != NULL) 4695c51f124SMoriah Waterland free(keystore->path); 4705c51f124SMoriah Waterland if (keystore->capath != NULL) 4715c51f124SMoriah Waterland free(keystore->capath); 4725c51f124SMoriah Waterland if (keystore->passphrase != NULL) 4735c51f124SMoriah Waterland free(keystore->passphrase); 4745c51f124SMoriah Waterland if (keystore->clpath != NULL) 4755c51f124SMoriah Waterland free(keystore->clpath); 4765c51f124SMoriah Waterland if (keystore->keypath != NULL) 4775c51f124SMoriah Waterland free(keystore->keypath); 4785c51f124SMoriah Waterland 4795c51f124SMoriah Waterland if (keystore->pkeys != NULL) { 4805c51f124SMoriah Waterland sk_EVP_PKEY_pop_free(keystore->pkeys, 4815c51f124SMoriah Waterland sunw_evp_pkey_free); 4825c51f124SMoriah Waterland } 4835c51f124SMoriah Waterland if (keystore->clcerts != NULL) 4845c51f124SMoriah Waterland sk_X509_free(keystore->clcerts); 4855c51f124SMoriah Waterland if (keystore->cacerts != NULL) 4865c51f124SMoriah Waterland sk_X509_free(keystore->cacerts); 4875c51f124SMoriah Waterland free(keystore); 4885c51f124SMoriah Waterland } 4895c51f124SMoriah Waterland 4905c51f124SMoriah Waterland /* 4915c51f124SMoriah Waterland * close_keystore - Writes keystore to disk if needed, then 4925c51f124SMoriah Waterland * unlocks and closes keystore. 4935c51f124SMoriah Waterland * 4945c51f124SMoriah Waterland * Arguments: 4955c51f124SMoriah Waterland * err - Error object to append errors to 4965c51f124SMoriah Waterland * keystore - Keystore which should be closed 4975c51f124SMoriah Waterland * passwd - Password used to encrypt keystore 4985c51f124SMoriah Waterland * 4995c51f124SMoriah Waterland * Returns: 5005c51f124SMoriah Waterland * 0 - Success - keystore is committed to disk, and unlocked 5015c51f124SMoriah Waterland * non-zero - Failure, errors added to err 5025c51f124SMoriah Waterland */ 5035c51f124SMoriah Waterland int 5045c51f124SMoriah Waterland close_keystore(PKG_ERR *err, keystore_handle_t keystore_h, 5055c51f124SMoriah Waterland keystore_passphrase_cb cb) 5065c51f124SMoriah Waterland { 5075c51f124SMoriah Waterland int ret = 0; 5085c51f124SMoriah Waterland keystore_t *keystore = keystore_h; 5095c51f124SMoriah Waterland 5105c51f124SMoriah Waterland if (keystore->dirty) { 5115c51f124SMoriah Waterland /* write out the keystore first */ 5125c51f124SMoriah Waterland if (!write_keystore(err, keystore, cb)) { 5135c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WRITE, 5145c51f124SMoriah Waterland gettext(ERR_KEYSTORE_WRITE), 5155c51f124SMoriah Waterland keystore->path); 5165c51f124SMoriah Waterland ret = 1; 5175c51f124SMoriah Waterland goto cleanup; 5185c51f124SMoriah Waterland } 5195c51f124SMoriah Waterland } 5205c51f124SMoriah Waterland 5215c51f124SMoriah Waterland if (!unlock_keystore(err, keystore)) { 5225c51f124SMoriah Waterland pkgerr_add(err, PKGERR_UNLOCK, gettext(ERR_KEYSTORE_UNLOCK), 5235c51f124SMoriah Waterland keystore->path); 5245c51f124SMoriah Waterland ret = 1; 5255c51f124SMoriah Waterland goto cleanup; 5265c51f124SMoriah Waterland } 5275c51f124SMoriah Waterland 5285c51f124SMoriah Waterland free_keystore(keystore); 5295c51f124SMoriah Waterland cleanup: 5305c51f124SMoriah Waterland return (ret); 5315c51f124SMoriah Waterland } 5325c51f124SMoriah Waterland 5335c51f124SMoriah Waterland /* 5345c51f124SMoriah Waterland * merge_ca_cert - Adds a trusted certificate (trust anchor) to a keystore. 5355c51f124SMoriah Waterland * certificate checked for validity dates and non-duplicity. 5365c51f124SMoriah Waterland * 5375c51f124SMoriah Waterland * Arguments: 5385c51f124SMoriah Waterland * err - Error object to add errors to 5395c51f124SMoriah Waterland * cacert - Certificate which to merge into keystore 5405c51f124SMoriah Waterland * keystore - The keystore into which the certificate is merged 5415c51f124SMoriah Waterland * 5425c51f124SMoriah Waterland * Returns: 5435c51f124SMoriah Waterland * 0 - Success - Certificate passes validity, and 5445c51f124SMoriah Waterland * is merged into keystore 5455c51f124SMoriah Waterland * non-zero - Failure, errors recorded in err 5465c51f124SMoriah Waterland */ 5475c51f124SMoriah Waterland int 5485c51f124SMoriah Waterland merge_ca_cert(PKG_ERR *err, X509 *cacert, keystore_handle_t keystore_h) 5495c51f124SMoriah Waterland { 5505c51f124SMoriah Waterland 5515c51f124SMoriah Waterland int ret = 0; 5525c51f124SMoriah Waterland X509 *existing = NULL; 5535c51f124SMoriah Waterland char *fname; 5545c51f124SMoriah Waterland keystore_t *keystore = keystore_h; 5555c51f124SMoriah Waterland 5565c51f124SMoriah Waterland /* check validity dates */ 5575c51f124SMoriah Waterland if (check_cert(err, cacert) != 0) { 5585c51f124SMoriah Waterland ret = 1; 5595c51f124SMoriah Waterland goto cleanup; 5605c51f124SMoriah Waterland } 5615c51f124SMoriah Waterland 5625c51f124SMoriah Waterland /* create the certificate's friendlyName */ 5635c51f124SMoriah Waterland fname = get_subject_display_name(cacert); 5645c51f124SMoriah Waterland 5655c51f124SMoriah Waterland if (sunw_set_fname(fname, NULL, cacert) != 0) { 5665c51f124SMoriah Waterland pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM)); 5675c51f124SMoriah Waterland ret = 1; 5685c51f124SMoriah Waterland goto cleanup; 5695c51f124SMoriah Waterland } 5705c51f124SMoriah Waterland 5715c51f124SMoriah Waterland /* merge certificate into the keystore */ 5725c51f124SMoriah Waterland if (keystore->cacerts == NULL) { 5735c51f124SMoriah Waterland /* no existing truststore, so make a new one */ 5745c51f124SMoriah Waterland if ((keystore->cacerts = sk_X509_new_null()) == NULL) { 5755c51f124SMoriah Waterland pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM)); 5765c51f124SMoriah Waterland ret = 1; 5775c51f124SMoriah Waterland goto cleanup; 5785c51f124SMoriah Waterland } 5795c51f124SMoriah Waterland } else { 5805c51f124SMoriah Waterland /* existing truststore, make sure there's no duplicate */ 5815c51f124SMoriah Waterland if (sunw_find_fname(fname, NULL, keystore->cacerts, 5825c51f124SMoriah Waterland NULL, &existing) < 0) { 5835c51f124SMoriah Waterland pkgerr_add(err, PKGERR_INTERNAL, 5845c51f124SMoriah Waterland gettext(ERR_KEYSTORE_INTERNAL), 5855c51f124SMoriah Waterland __FILE__, __LINE__); 5865c51f124SMoriah Waterland ERR_print_errors_fp(stderr); 5875c51f124SMoriah Waterland ret = 1; 5885c51f124SMoriah Waterland goto cleanup; 5895c51f124SMoriah Waterland /* could not search properly! */ 5905c51f124SMoriah Waterland } 5915c51f124SMoriah Waterland if (existing != NULL) { 5925c51f124SMoriah Waterland /* whoops, found one already */ 5935c51f124SMoriah Waterland pkgerr_add(err, PKGERR_DUPLICATE, 5945c51f124SMoriah Waterland gettext(ERR_KEYSTORE_DUPLICATECERT), fname); 5955c51f124SMoriah Waterland ret = 1; 5965c51f124SMoriah Waterland goto cleanup; 5975c51f124SMoriah Waterland } 5985c51f124SMoriah Waterland } 5995c51f124SMoriah Waterland 6005c51f124SMoriah Waterland (void) sk_X509_push(keystore->cacerts, cacert); 6015c51f124SMoriah Waterland keystore->dirty = B_TRUE; 6025c51f124SMoriah Waterland cleanup: 6035c51f124SMoriah Waterland if (existing != NULL) 6045c51f124SMoriah Waterland X509_free(existing); 6055c51f124SMoriah Waterland return (ret); 6065c51f124SMoriah Waterland } 6075c51f124SMoriah Waterland 6085c51f124SMoriah Waterland /* 6095c51f124SMoriah Waterland * find_key_cert_pair - Searches a keystore for a matching 6105c51f124SMoriah Waterland * public key certificate and private key, given an alias. 6115c51f124SMoriah Waterland * 6125c51f124SMoriah Waterland * Arguments: 6135c51f124SMoriah Waterland * err - Error object to add errors to 6145c51f124SMoriah Waterland * ks - Keystore to search 6155c51f124SMoriah Waterland * alias - Name to used to match certificate's alias 6165c51f124SMoriah Waterland * key - Resulting key is placed here 6175c51f124SMoriah Waterland * cert - Resulting cert is placed here 6185c51f124SMoriah Waterland * 6195c51f124SMoriah Waterland * Returns: 6205c51f124SMoriah Waterland * 0 - Success - Matching cert/key pair placed in key and cert. 6215c51f124SMoriah Waterland * non-zero - Failure, errors recorded in err 6225c51f124SMoriah Waterland */ 6235c51f124SMoriah Waterland int 6245c51f124SMoriah Waterland find_key_cert_pair(PKG_ERR *err, keystore_handle_t ks_h, char *alias, 6255c51f124SMoriah Waterland EVP_PKEY **key, X509 **cert) 6265c51f124SMoriah Waterland { 6275c51f124SMoriah Waterland X509 *tmpcert = NULL; 6285c51f124SMoriah Waterland EVP_PKEY *tmpkey = NULL; 6295c51f124SMoriah Waterland int ret = 0; 6305c51f124SMoriah Waterland int items_found; 6315c51f124SMoriah Waterland keystore_t *ks = ks_h; 6325c51f124SMoriah Waterland 6335c51f124SMoriah Waterland if (key == NULL || cert == NULL) { 6345c51f124SMoriah Waterland pkgerr_add(err, PKGERR_NOPUBKEY, 6355c51f124SMoriah Waterland gettext(ERR_KEYSTORE_NOPUBCERTS), ks->path); 6365c51f124SMoriah Waterland ret = 1; 6375c51f124SMoriah Waterland goto cleanup; 6385c51f124SMoriah Waterland } 6395c51f124SMoriah Waterland 6405c51f124SMoriah Waterland if (ks->clcerts == NULL) { 6415c51f124SMoriah Waterland /* no public certs */ 6425c51f124SMoriah Waterland pkgerr_add(err, PKGERR_NOPUBKEY, 6435c51f124SMoriah Waterland gettext(ERR_KEYSTORE_NOCERTS), ks->path); 6445c51f124SMoriah Waterland ret = 1; 6455c51f124SMoriah Waterland goto cleanup; 6465c51f124SMoriah Waterland } 6475c51f124SMoriah Waterland if (ks->pkeys == NULL) { 6485c51f124SMoriah Waterland /* no private keys */ 6495c51f124SMoriah Waterland pkgerr_add(err, PKGERR_NOPRIVKEY, 6505c51f124SMoriah Waterland gettext(ERR_KEYSTORE_NOKEYS), ks->path); 6515c51f124SMoriah Waterland ret = 1; 6525c51f124SMoriah Waterland goto cleanup; 6535c51f124SMoriah Waterland } 6545c51f124SMoriah Waterland 6555c51f124SMoriah Waterland /* try the easy case first */ 6565c51f124SMoriah Waterland if ((sk_EVP_PKEY_num(ks->pkeys) == 1) && 6575c51f124SMoriah Waterland (sk_X509_num(ks->clcerts) == 1)) { 6585c51f124SMoriah Waterland tmpkey = sk_EVP_PKEY_value(ks->pkeys, 0); 6595c51f124SMoriah Waterland tmpcert = sk_X509_value(ks->clcerts, 0); 6605c51f124SMoriah Waterland if (sunw_check_keys(tmpcert, tmpkey)) { 6615c51f124SMoriah Waterland /* 6625c51f124SMoriah Waterland * only one private key and public key cert, and they 6635c51f124SMoriah Waterland * match, so use them 6645c51f124SMoriah Waterland */ 6655c51f124SMoriah Waterland *key = tmpkey; 6665c51f124SMoriah Waterland tmpkey = NULL; 6675c51f124SMoriah Waterland *cert = tmpcert; 6685c51f124SMoriah Waterland tmpcert = NULL; 6695c51f124SMoriah Waterland goto cleanup; 6705c51f124SMoriah Waterland } 6715c51f124SMoriah Waterland } 6725c51f124SMoriah Waterland 6735c51f124SMoriah Waterland /* Attempt to find the right pair given the alias */ 6745c51f124SMoriah Waterland items_found = sunw_find_fname(alias, ks->pkeys, ks->clcerts, 6755c51f124SMoriah Waterland &tmpkey, &tmpcert); 6765c51f124SMoriah Waterland 6775c51f124SMoriah Waterland if ((items_found < 0) || 6785c51f124SMoriah Waterland (items_found & (FOUND_PKEY | FOUND_CERT)) == 0) { 6795c51f124SMoriah Waterland /* no key/cert pair found. bail. */ 6805c51f124SMoriah Waterland pkgerr_add(err, PKGERR_BADALIAS, 6815c51f124SMoriah Waterland gettext(ERR_KEYSTORE_NOMATCH), alias); 6825c51f124SMoriah Waterland ret = 1; 6835c51f124SMoriah Waterland goto cleanup; 6845c51f124SMoriah Waterland } 6855c51f124SMoriah Waterland 6865c51f124SMoriah Waterland /* success */ 6875c51f124SMoriah Waterland *key = tmpkey; 6885c51f124SMoriah Waterland tmpkey = NULL; 6895c51f124SMoriah Waterland *cert = tmpcert; 6905c51f124SMoriah Waterland tmpcert = NULL; 6915c51f124SMoriah Waterland 6925c51f124SMoriah Waterland cleanup: 6935c51f124SMoriah Waterland 6945c51f124SMoriah Waterland if (tmpcert != NULL) 6955c51f124SMoriah Waterland (void) X509_free(tmpcert); 6965c51f124SMoriah Waterland 6975c51f124SMoriah Waterland if (tmpkey != NULL) 6985c51f124SMoriah Waterland sunw_evp_pkey_free(tmpkey); 6995c51f124SMoriah Waterland 7005c51f124SMoriah Waterland return (ret); 7015c51f124SMoriah Waterland } 7025c51f124SMoriah Waterland 7035c51f124SMoriah Waterland /* 7045c51f124SMoriah Waterland * find_ca_certs - Searches a keystore for trusted certificates 7055c51f124SMoriah Waterland * 7065c51f124SMoriah Waterland * Arguments: 7075c51f124SMoriah Waterland * err - Error object to add errors to 7085c51f124SMoriah Waterland * ks - Keystore to search 7095c51f124SMoriah Waterland * cacerts - resulting set of trusted certs are placed here 7105c51f124SMoriah Waterland * 7115c51f124SMoriah Waterland * Returns: 7125c51f124SMoriah Waterland * 0 - Success - trusted cert list returned in cacerts 7135c51f124SMoriah Waterland * non-zero - Failure, errors recorded in err 7145c51f124SMoriah Waterland */ 7155c51f124SMoriah Waterland int 7165c51f124SMoriah Waterland find_ca_certs(PKG_ERR *err, keystore_handle_t ks_h, STACK_OF(X509) **cacerts) 7175c51f124SMoriah Waterland { 7185c51f124SMoriah Waterland 7195c51f124SMoriah Waterland keystore_t *ks = ks_h; 7205c51f124SMoriah Waterland 7215c51f124SMoriah Waterland /* easy */ 7225c51f124SMoriah Waterland if (cacerts == NULL) { 7235c51f124SMoriah Waterland pkgerr_add(err, PKGERR_INTERNAL, 7245c51f124SMoriah Waterland gettext(ERR_KEYSTORE_INTERNAL), __FILE__, __LINE__); 7255c51f124SMoriah Waterland return (1); 7265c51f124SMoriah Waterland } 7275c51f124SMoriah Waterland 7285c51f124SMoriah Waterland *cacerts = ks->cacerts; 7295c51f124SMoriah Waterland return (0); 7305c51f124SMoriah Waterland } 7315c51f124SMoriah Waterland 7325c51f124SMoriah Waterland /* 7335c51f124SMoriah Waterland * find_cl_certs - Searches a keystore for user certificates 7345c51f124SMoriah Waterland * 7355c51f124SMoriah Waterland * Arguments: 7365c51f124SMoriah Waterland * err - Error object to add errors to 7375c51f124SMoriah Waterland * ks - Keystore to search 7385c51f124SMoriah Waterland * cacerts - resulting set of user certs are placed here 7395c51f124SMoriah Waterland * 7405c51f124SMoriah Waterland * No matching of any kind is performed. 7415c51f124SMoriah Waterland * Returns: 7425c51f124SMoriah Waterland * 0 - Success - trusted cert list returned in cacerts 7435c51f124SMoriah Waterland * non-zero - Failure, errors recorded in err 7445c51f124SMoriah Waterland */ 7455c51f124SMoriah Waterland /* ARGSUSED */ 7465c51f124SMoriah Waterland int 7475c51f124SMoriah Waterland find_cl_certs(PKG_ERR *err, keystore_handle_t ks_h, STACK_OF(X509) **clcerts) 7485c51f124SMoriah Waterland { 7495c51f124SMoriah Waterland keystore_t *ks = ks_h; 7505c51f124SMoriah Waterland 7515c51f124SMoriah Waterland /* easy */ 7525c51f124SMoriah Waterland *clcerts = ks->clcerts; 7535c51f124SMoriah Waterland return (0); 7545c51f124SMoriah Waterland } 7555c51f124SMoriah Waterland 7565c51f124SMoriah Waterland 7575c51f124SMoriah Waterland /* 7585c51f124SMoriah Waterland * merge_cert_and_key - Adds a user certificate and matching 7595c51f124SMoriah Waterland * private key to a keystore. 7605c51f124SMoriah Waterland * certificate checked for validity dates and non-duplicity. 7615c51f124SMoriah Waterland * 7625c51f124SMoriah Waterland * Arguments: 7635c51f124SMoriah Waterland * err - Error object to add errors to 7645c51f124SMoriah Waterland * cert - Certificate which to merge into keystore 7655c51f124SMoriah Waterland * key - matching private key to 'cert' 7665c51f124SMoriah Waterland * alias - Name which to store the cert and key under 7675c51f124SMoriah Waterland * keystore - The keystore into which the certificate is merged 7685c51f124SMoriah Waterland * 7695c51f124SMoriah Waterland * Returns: 7705c51f124SMoriah Waterland * 0 - Success - Certificate passes validity, and 7715c51f124SMoriah Waterland * is merged into keystore, along with key 7725c51f124SMoriah Waterland * non-zero - Failure, errors recorded in err 7735c51f124SMoriah Waterland */ 7745c51f124SMoriah Waterland int 7755c51f124SMoriah Waterland merge_cert_and_key(PKG_ERR *err, X509 *cert, EVP_PKEY *key, char *alias, 7765c51f124SMoriah Waterland keystore_handle_t keystore_h) 7775c51f124SMoriah Waterland { 7785c51f124SMoriah Waterland X509 *existingcert = NULL; 7795c51f124SMoriah Waterland EVP_PKEY *existingkey = NULL; 7805c51f124SMoriah Waterland int ret = 0; 7815c51f124SMoriah Waterland keystore_t *keystore = keystore_h; 7825c51f124SMoriah Waterland 7835c51f124SMoriah Waterland /* check validity dates */ 7845c51f124SMoriah Waterland if (check_cert(err, cert) != 0) { 7855c51f124SMoriah Waterland ret = 1; 7865c51f124SMoriah Waterland goto cleanup; 7875c51f124SMoriah Waterland } 7885c51f124SMoriah Waterland 7895c51f124SMoriah Waterland /* set the friendlyName of the key and cert to the supplied alias */ 7905c51f124SMoriah Waterland if (sunw_set_fname(alias, key, cert) != 0) { 7915c51f124SMoriah Waterland pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM)); 7925c51f124SMoriah Waterland ret = 1; 7935c51f124SMoriah Waterland goto cleanup; 7945c51f124SMoriah Waterland } 7955c51f124SMoriah Waterland 7965c51f124SMoriah Waterland /* merge certificate and key into the keystore */ 7975c51f124SMoriah Waterland if (keystore->clcerts == NULL) { 7985c51f124SMoriah Waterland /* no existing truststore, so make a new one */ 7995c51f124SMoriah Waterland if ((keystore->clcerts = sk_X509_new_null()) == NULL) { 8005c51f124SMoriah Waterland pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM)); 8015c51f124SMoriah Waterland ret = 1; 8025c51f124SMoriah Waterland goto cleanup; 8035c51f124SMoriah Waterland } 8045c51f124SMoriah Waterland } else { 8055c51f124SMoriah Waterland /* existing certstore, make sure there's no duplicate */ 8065c51f124SMoriah Waterland if (sunw_find_fname(alias, NULL, keystore->clcerts, 8075c51f124SMoriah Waterland NULL, &existingcert) < 0) { 8085c51f124SMoriah Waterland pkgerr_add(err, PKGERR_INTERNAL, 8095c51f124SMoriah Waterland gettext(ERR_KEYSTORE_INTERNAL), 8105c51f124SMoriah Waterland __FILE__, __LINE__); 8115c51f124SMoriah Waterland ERR_print_errors_fp(stderr); 8125c51f124SMoriah Waterland ret = 1; 8135c51f124SMoriah Waterland goto cleanup; 8145c51f124SMoriah Waterland /* could not search properly! */ 8155c51f124SMoriah Waterland } 8165c51f124SMoriah Waterland if (existingcert != NULL) { 8175c51f124SMoriah Waterland /* whoops, found one already */ 8185c51f124SMoriah Waterland pkgerr_add(err, PKGERR_DUPLICATE, 8195c51f124SMoriah Waterland gettext(ERR_KEYSTORE_DUPLICATECERT), alias); 8205c51f124SMoriah Waterland ret = 1; 8215c51f124SMoriah Waterland goto cleanup; 8225c51f124SMoriah Waterland } 8235c51f124SMoriah Waterland } 8245c51f124SMoriah Waterland 8255c51f124SMoriah Waterland if (keystore->pkeys == NULL) { 8265c51f124SMoriah Waterland /* no existing keystore, so make a new one */ 8275c51f124SMoriah Waterland if ((keystore->pkeys = sk_EVP_PKEY_new_null()) == NULL) { 8285c51f124SMoriah Waterland pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM)); 8295c51f124SMoriah Waterland ret = 1; 8305c51f124SMoriah Waterland goto cleanup; 8315c51f124SMoriah Waterland } 8325c51f124SMoriah Waterland } else { 8335c51f124SMoriah Waterland /* existing keystore, so make sure there's no duplicate entry */ 8345c51f124SMoriah Waterland if (sunw_find_fname(alias, keystore->pkeys, NULL, 8355c51f124SMoriah Waterland &existingkey, NULL) < 0) { 8365c51f124SMoriah Waterland pkgerr_add(err, PKGERR_INTERNAL, 8375c51f124SMoriah Waterland gettext(ERR_KEYSTORE_INTERNAL), 8385c51f124SMoriah Waterland __FILE__, __LINE__); 8395c51f124SMoriah Waterland ERR_print_errors_fp(stderr); 8405c51f124SMoriah Waterland ret = 1; 8415c51f124SMoriah Waterland goto cleanup; 8425c51f124SMoriah Waterland /* could not search properly! */ 8435c51f124SMoriah Waterland } 8445c51f124SMoriah Waterland if (existingkey != NULL) { 8455c51f124SMoriah Waterland /* whoops, found one already */ 8465c51f124SMoriah Waterland pkgerr_add(err, PKGERR_DUPLICATE, 8475c51f124SMoriah Waterland gettext(ERR_KEYSTORE_DUPLICATEKEY), alias); 8485c51f124SMoriah Waterland ret = 1; 8495c51f124SMoriah Waterland goto cleanup; 8505c51f124SMoriah Waterland } 8515c51f124SMoriah Waterland } 8525c51f124SMoriah Waterland 8535c51f124SMoriah Waterland (void) sk_X509_push(keystore->clcerts, cert); 8545c51f124SMoriah Waterland (void) sk_EVP_PKEY_push(keystore->pkeys, key); 8555c51f124SMoriah Waterland keystore->dirty = B_TRUE; 8565c51f124SMoriah Waterland cleanup: 8575c51f124SMoriah Waterland if (existingcert != NULL) 8585c51f124SMoriah Waterland (void) X509_free(existingcert); 8595c51f124SMoriah Waterland if (existingkey != NULL) 8605c51f124SMoriah Waterland (void) sunw_evp_pkey_free(existingkey); 8615c51f124SMoriah Waterland return (ret); 8625c51f124SMoriah Waterland } 8635c51f124SMoriah Waterland 8645c51f124SMoriah Waterland /* 8655c51f124SMoriah Waterland * delete_cert_and_keys - Deletes one or more certificates 8665c51f124SMoriah Waterland * and matching private keys from a keystore. 8675c51f124SMoriah Waterland * 8685c51f124SMoriah Waterland * Arguments: 8695c51f124SMoriah Waterland * err - Error object to add errors to 8705c51f124SMoriah Waterland * ks - The keystore from which certs and keys are deleted 8715c51f124SMoriah Waterland * alias - Name which to search for certificates and keys 8725c51f124SMoriah Waterland * to delete 8735c51f124SMoriah Waterland * 8745c51f124SMoriah Waterland * Returns: 8755c51f124SMoriah Waterland * 0 - Success - All trusted certs which match 'alias' 8765c51f124SMoriah Waterland * are deleted. All user certificates 8775c51f124SMoriah Waterland * which match 'alias' are deleted, along 8785c51f124SMoriah Waterland * with the matching private key. 8795c51f124SMoriah Waterland * non-zero - Failure, errors recorded in err 8805c51f124SMoriah Waterland */ 8815c51f124SMoriah Waterland int 8825c51f124SMoriah Waterland delete_cert_and_keys(PKG_ERR *err, keystore_handle_t ks_h, char *alias) 8835c51f124SMoriah Waterland { 8845c51f124SMoriah Waterland X509 *existingcert; 8855c51f124SMoriah Waterland EVP_PKEY *existingkey; 8865c51f124SMoriah Waterland int i; 8875c51f124SMoriah Waterland char *fname = NULL; 8885c51f124SMoriah Waterland boolean_t found = B_FALSE; 8895c51f124SMoriah Waterland keystore_t *ks = ks_h; 8905c51f124SMoriah Waterland 8915c51f124SMoriah Waterland /* delete any and all client certs with the supplied name */ 8925c51f124SMoriah Waterland if (ks->clcerts != NULL) { 8935c51f124SMoriah Waterland for (i = 0; i < sk_X509_num(ks->clcerts); i++) { 8945c51f124SMoriah Waterland existingcert = sk_X509_value(ks->clcerts, i); 8955c51f124SMoriah Waterland if (sunw_get_cert_fname(GETDO_COPY, 8965c51f124SMoriah Waterland existingcert, &fname) >= 0) { 8975c51f124SMoriah Waterland if (streq(fname, alias)) { 8985c51f124SMoriah Waterland /* match, so nuke it */ 8995c51f124SMoriah Waterland existingcert = 9005c51f124SMoriah Waterland sk_X509_delete(ks->clcerts, i); 9015c51f124SMoriah Waterland X509_free(existingcert); 9025c51f124SMoriah Waterland existingcert = NULL; 9035c51f124SMoriah Waterland found = B_TRUE; 9045c51f124SMoriah Waterland } 9055c51f124SMoriah Waterland (void) OPENSSL_free(fname); 9065c51f124SMoriah Waterland fname = NULL; 9075c51f124SMoriah Waterland } 9085c51f124SMoriah Waterland } 9095c51f124SMoriah Waterland if (sk_X509_num(ks->clcerts) <= 0) { 9105c51f124SMoriah Waterland /* we deleted all the client certs */ 9115c51f124SMoriah Waterland sk_X509_free(ks->clcerts); 9125c51f124SMoriah Waterland ks->clcerts = NULL; 9135c51f124SMoriah Waterland } 9145c51f124SMoriah Waterland } 9155c51f124SMoriah Waterland 9165c51f124SMoriah Waterland /* and now the private keys */ 9175c51f124SMoriah Waterland if (ks->pkeys != NULL) { 9185c51f124SMoriah Waterland for (i = 0; i < sk_EVP_PKEY_num(ks->pkeys); i++) { 9195c51f124SMoriah Waterland existingkey = sk_EVP_PKEY_value(ks->pkeys, i); 9205c51f124SMoriah Waterland if (sunw_get_pkey_fname(GETDO_COPY, 9215c51f124SMoriah Waterland existingkey, &fname) >= 0) { 9225c51f124SMoriah Waterland if (streq(fname, alias)) { 9235c51f124SMoriah Waterland /* match, so nuke it */ 9245c51f124SMoriah Waterland existingkey = 9255c51f124SMoriah Waterland sk_EVP_PKEY_delete(ks->pkeys, i); 9265c51f124SMoriah Waterland sunw_evp_pkey_free(existingkey); 9275c51f124SMoriah Waterland existingkey = NULL; 9285c51f124SMoriah Waterland found = B_TRUE; 9295c51f124SMoriah Waterland } 9305c51f124SMoriah Waterland (void) OPENSSL_free(fname); 9315c51f124SMoriah Waterland fname = NULL; 9325c51f124SMoriah Waterland } 9335c51f124SMoriah Waterland } 9345c51f124SMoriah Waterland if (sk_EVP_PKEY_num(ks->pkeys) <= 0) { 9355c51f124SMoriah Waterland /* we deleted all the private keys */ 9365c51f124SMoriah Waterland sk_EVP_PKEY_free(ks->pkeys); 9375c51f124SMoriah Waterland ks->pkeys = NULL; 9385c51f124SMoriah Waterland } 9395c51f124SMoriah Waterland } 9405c51f124SMoriah Waterland 9415c51f124SMoriah Waterland /* finally, remove any trust anchors that match */ 9425c51f124SMoriah Waterland 9435c51f124SMoriah Waterland if (ks->cacerts != NULL) { 9445c51f124SMoriah Waterland for (i = 0; i < sk_X509_num(ks->cacerts); i++) { 9455c51f124SMoriah Waterland existingcert = sk_X509_value(ks->cacerts, i); 9465c51f124SMoriah Waterland if (sunw_get_cert_fname(GETDO_COPY, 9475c51f124SMoriah Waterland existingcert, &fname) >= 0) { 9485c51f124SMoriah Waterland if (streq(fname, alias)) { 9495c51f124SMoriah Waterland /* match, so nuke it */ 9505c51f124SMoriah Waterland existingcert = 9515c51f124SMoriah Waterland sk_X509_delete(ks->cacerts, i); 9525c51f124SMoriah Waterland X509_free(existingcert); 9535c51f124SMoriah Waterland existingcert = NULL; 9545c51f124SMoriah Waterland found = B_TRUE; 9555c51f124SMoriah Waterland } 9565c51f124SMoriah Waterland (void) OPENSSL_free(fname); 9575c51f124SMoriah Waterland fname = NULL; 9585c51f124SMoriah Waterland } 9595c51f124SMoriah Waterland } 9605c51f124SMoriah Waterland if (sk_X509_num(ks->cacerts) <= 0) { 9615c51f124SMoriah Waterland /* we deleted all the CA certs */ 9625c51f124SMoriah Waterland sk_X509_free(ks->cacerts); 9635c51f124SMoriah Waterland ks->cacerts = NULL; 9645c51f124SMoriah Waterland } 9655c51f124SMoriah Waterland } 9665c51f124SMoriah Waterland 9675c51f124SMoriah Waterland if (found) { 9685c51f124SMoriah Waterland ks->dirty = B_TRUE; 9695c51f124SMoriah Waterland return (0); 9705c51f124SMoriah Waterland } else { 9715c51f124SMoriah Waterland /* no certs or keys deleted */ 9725c51f124SMoriah Waterland pkgerr_add(err, PKGERR_NOALIASMATCH, 9735c51f124SMoriah Waterland gettext(ERR_KEYSTORE_NOCERTKEY), 9745c51f124SMoriah Waterland alias, ks->path); 9755c51f124SMoriah Waterland return (1); 9765c51f124SMoriah Waterland } 9775c51f124SMoriah Waterland } 9785c51f124SMoriah Waterland 9795c51f124SMoriah Waterland /* 9805c51f124SMoriah Waterland * check_cert - Checks certificate validity. This routine 9815c51f124SMoriah Waterland * checks that the current time falls within the period 9825c51f124SMoriah Waterland * of validity for the cert. 9835c51f124SMoriah Waterland * 9845c51f124SMoriah Waterland * Arguments: 9855c51f124SMoriah Waterland * err - Error object to add errors to 9865c51f124SMoriah Waterland * cert - The certificate to check 9875c51f124SMoriah Waterland * 9885c51f124SMoriah Waterland * Returns: 9895c51f124SMoriah Waterland * 0 - Success - Certificate checks out 9905c51f124SMoriah Waterland * non-zero - Failure, errors and reasons recorded in err 9915c51f124SMoriah Waterland */ 9925c51f124SMoriah Waterland int 9935c51f124SMoriah Waterland check_cert(PKG_ERR *err, X509 *cert) 9945c51f124SMoriah Waterland { 9955c51f124SMoriah Waterland char currtimestr[ATTR_MAX]; 9965c51f124SMoriah Waterland time_t currtime; 997*4656d474SGarrett D'Amore char *r; 9985c51f124SMoriah Waterland /* get current time */ 9995c51f124SMoriah Waterland if ((currtime = time(NULL)) == (time_t)-1) { 10005c51f124SMoriah Waterland pkgerr_add(err, PKGERR_TIME, gettext(ERR_CURR_TIME)); 10015c51f124SMoriah Waterland return (1); 10025c51f124SMoriah Waterland } 10035c51f124SMoriah Waterland 10045c51f124SMoriah Waterland (void) strlcpy(currtimestr, ctime(&currtime), ATTR_MAX); 10055c51f124SMoriah Waterland 10065c51f124SMoriah Waterland /* trim whitespace from end of time string */ 10075c51f124SMoriah Waterland for (r = (currtimestr + strlen(currtimestr) - 1); isspace(*r); r--) { 10085c51f124SMoriah Waterland *r = '\0'; 10095c51f124SMoriah Waterland } 10105c51f124SMoriah Waterland /* check validity of cert */ 10115c51f124SMoriah Waterland switch (sunw_check_cert_times(CHK_BOTH, cert)) { 10125c51f124SMoriah Waterland case CHKERR_TIME_OK: 10135c51f124SMoriah Waterland /* Current time meets requested checks */ 10145c51f124SMoriah Waterland break; 10155c51f124SMoriah Waterland case CHKERR_TIME_BEFORE_BAD: 10165c51f124SMoriah Waterland /* 'not before' field is invalid */ 10175c51f124SMoriah Waterland case CHKERR_TIME_AFTER_BAD: 10185c51f124SMoriah Waterland /* 'not after' field is invalid */ 10195c51f124SMoriah Waterland pkgerr_add(err, PKGERR_TIME, gettext(ERR_CERT_TIME_BAD)); 10205c51f124SMoriah Waterland return (1); 10215c51f124SMoriah Waterland case CHKERR_TIME_IS_BEFORE: 10225c51f124SMoriah Waterland /* Current time is before 'not before' */ 10235c51f124SMoriah Waterland case CHKERR_TIME_HAS_EXPIRED: 10245c51f124SMoriah Waterland /* 10255c51f124SMoriah Waterland * Ignore expiration time since the trust cert used to 10265c51f124SMoriah Waterland * verify the certs used to sign Sun patches is already 10275c51f124SMoriah Waterland * expired. Once the patches get resigned with the new 10285c51f124SMoriah Waterland * cert we will check expiration against the time the 10295c51f124SMoriah Waterland * patch was signed and not the time it is installed. 10305c51f124SMoriah Waterland */ 10315c51f124SMoriah Waterland return (0); 10325c51f124SMoriah Waterland default: 10335c51f124SMoriah Waterland pkgerr_add(err, PKGERR_INTERNAL, 10345c51f124SMoriah Waterland gettext(ERR_KEYSTORE_INTERNAL), 10355c51f124SMoriah Waterland __FILE__, __LINE__); 10365c51f124SMoriah Waterland return (1); 10375c51f124SMoriah Waterland } 10385c51f124SMoriah Waterland 10395c51f124SMoriah Waterland /* all checks ok */ 10405c51f124SMoriah Waterland return (0); 10415c51f124SMoriah Waterland } 10425c51f124SMoriah Waterland 10435c51f124SMoriah Waterland /* 10445c51f124SMoriah Waterland * check_cert - Checks certificate validity. This routine 10455c51f124SMoriah Waterland * checks everything that check_cert checks, and additionally 10465c51f124SMoriah Waterland * verifies that the private key and corresponding public 10475c51f124SMoriah Waterland * key are indeed a pair. 10485c51f124SMoriah Waterland * 10495c51f124SMoriah Waterland * Arguments: 10505c51f124SMoriah Waterland * err - Error object to add errors to 10515c51f124SMoriah Waterland * cert - The certificate to check 10525c51f124SMoriah Waterland * key - the key to check 10535c51f124SMoriah Waterland * Returns: 10545c51f124SMoriah Waterland * 0 - Success - Certificate checks out 10555c51f124SMoriah Waterland * non-zero - Failure, errors and reasons recorded in err 10565c51f124SMoriah Waterland */ 10575c51f124SMoriah Waterland int 10585c51f124SMoriah Waterland check_cert_and_key(PKG_ERR *err, X509 *cert, EVP_PKEY *key) 10595c51f124SMoriah Waterland { 10605c51f124SMoriah Waterland 10615c51f124SMoriah Waterland /* check validity dates */ 10625c51f124SMoriah Waterland if (check_cert(err, cert) != 0) { 10635c51f124SMoriah Waterland return (1); 10645c51f124SMoriah Waterland } 10655c51f124SMoriah Waterland 10665c51f124SMoriah Waterland /* check key pair match */ 10675c51f124SMoriah Waterland if (sunw_check_keys(cert, key) == 0) { 10685c51f124SMoriah Waterland pkgerr_add(err, PKGERR_VERIFY, gettext(ERR_MISMATCHED_KEYS), 10695c51f124SMoriah Waterland get_subject_display_name(cert)); 10705c51f124SMoriah Waterland return (1); 10715c51f124SMoriah Waterland } 10725c51f124SMoriah Waterland 10735c51f124SMoriah Waterland /* all checks OK */ 10745c51f124SMoriah Waterland return (0); 10755c51f124SMoriah Waterland } 10765c51f124SMoriah Waterland 10775c51f124SMoriah Waterland /* ------------------ private functions ---------------------- */ 10785c51f124SMoriah Waterland 10795c51f124SMoriah Waterland /* 10805c51f124SMoriah Waterland * verify_keystore_integrity - Searches for the remnants 10815c51f124SMoriah Waterland * of a failed or aborted keystore modification, and 10825c51f124SMoriah Waterland * cleans up the files, retstores the keystore to a known 10835c51f124SMoriah Waterland * state. 10845c51f124SMoriah Waterland * 10855c51f124SMoriah Waterland * Arguments: 10865c51f124SMoriah Waterland * err - Error object to add errors to 10875c51f124SMoriah Waterland * keystore_file - Base directory or filename of keystore 10885c51f124SMoriah Waterland * app - Application making request 10895c51f124SMoriah Waterland * 10905c51f124SMoriah Waterland * Returns: 10915c51f124SMoriah Waterland * 0 - Success - Keystore is restored, or untouched in the 10925c51f124SMoriah Waterland * case that cleanup was unnecessary 10935c51f124SMoriah Waterland * non-zero - Failure, errors and reasons recorded in err 10945c51f124SMoriah Waterland */ 10955c51f124SMoriah Waterland static boolean_t 10965c51f124SMoriah Waterland verify_keystore_integrity(PKG_ERR *err, keystore_t *keystore) 10975c51f124SMoriah Waterland { 10985c51f124SMoriah Waterland if (keystore->capath != NULL) { 10995c51f124SMoriah Waterland if (!restore_keystore_file(err, keystore->capath)) { 11005c51f124SMoriah Waterland return (B_FALSE); 11015c51f124SMoriah Waterland } 11025c51f124SMoriah Waterland } 11035c51f124SMoriah Waterland if (keystore->clpath != NULL) { 11045c51f124SMoriah Waterland if (!restore_keystore_file(err, keystore->clpath)) { 11055c51f124SMoriah Waterland return (B_FALSE); 11065c51f124SMoriah Waterland } 11075c51f124SMoriah Waterland } 11085c51f124SMoriah Waterland if (keystore->keypath != NULL) { 11095c51f124SMoriah Waterland if (!restore_keystore_file(err, keystore->keypath)) { 11105c51f124SMoriah Waterland return (B_FALSE); 11115c51f124SMoriah Waterland } 11125c51f124SMoriah Waterland } 11135c51f124SMoriah Waterland return (B_TRUE); 11145c51f124SMoriah Waterland } 11155c51f124SMoriah Waterland 11165c51f124SMoriah Waterland /* 11175c51f124SMoriah Waterland * restore_keystore_file - restores a keystore file to 11185c51f124SMoriah Waterland * a known state. 11195c51f124SMoriah Waterland * 11205c51f124SMoriah Waterland * Keystore files can possibly be corrupted by a variety 11215c51f124SMoriah Waterland * of error conditions during reading/writing. This 11225c51f124SMoriah Waterland * routine, along with write_keystore_file, tries to 11235c51f124SMoriah Waterland * maintain keystore integrity by writing the files 11245c51f124SMoriah Waterland * out in a particular order, minimizing the time period 11255c51f124SMoriah Waterland * that the keystore is in an indeterminate state. 11265c51f124SMoriah Waterland * 11275c51f124SMoriah Waterland * With the current implementation, there are some failures 11285c51f124SMoriah Waterland * that are wholly unrecoverable, such as disk corruption. 11295c51f124SMoriah Waterland * These routines attempt to minimize the risk, but not 11305c51f124SMoriah Waterland * eliminate it. When better, atomic operations are available 11315c51f124SMoriah Waterland * (such as a trued atabase with commit, rollback, and 11325c51f124SMoriah Waterland * guaranteed atomicity), this implementation should use that. 11335c51f124SMoriah Waterland * 11345c51f124SMoriah Waterland * Arguments: 11355c51f124SMoriah Waterland * err - Error object to add errors to 11365c51f124SMoriah Waterland * keystore_file - keystore file path to restore. 11375c51f124SMoriah Waterland * 11385c51f124SMoriah Waterland * Returns: 11395c51f124SMoriah Waterland * 0 - Success - Keystore file is restored, or untouched in the 11405c51f124SMoriah Waterland * case that cleanup was unnecessary 11415c51f124SMoriah Waterland * non-zero - Failure, errors and reasons recorded in err 11425c51f124SMoriah Waterland */ 11435c51f124SMoriah Waterland /* ARGSUSED */ 11445c51f124SMoriah Waterland static boolean_t 11455c51f124SMoriah Waterland restore_keystore_file(PKG_ERR *err, char *keystore_file) 11465c51f124SMoriah Waterland { 11475c51f124SMoriah Waterland char newpath[MAXPATHLEN]; 11485c51f124SMoriah Waterland char backuppath[MAXPATHLEN]; 11495c51f124SMoriah Waterland int newfd; 11505c51f124SMoriah Waterland struct stat buf; 11515c51f124SMoriah Waterland int len; 11525c51f124SMoriah Waterland 11535c51f124SMoriah Waterland if (((len = snprintf(newpath, MAXPATHLEN, "%s.new", 11545c51f124SMoriah Waterland keystore_file)) < 0) || 11555c51f124SMoriah Waterland (len >= ATTR_MAX)) { 11565c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN), keystore_file); 11575c51f124SMoriah Waterland return (B_FALSE); 11585c51f124SMoriah Waterland } 11595c51f124SMoriah Waterland 11605c51f124SMoriah Waterland if (((len = snprintf(backuppath, MAXPATHLEN, "%s.bak", 11615c51f124SMoriah Waterland keystore_file)) < 0) || 11625c51f124SMoriah Waterland (len >= ATTR_MAX)) { 11635c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN), keystore_file); 11645c51f124SMoriah Waterland return (B_FALSE); 11655c51f124SMoriah Waterland } 11665c51f124SMoriah Waterland 11675c51f124SMoriah Waterland if ((newfd = open(newpath, O_RDWR|O_NONBLOCK, 0)) != -1) { 11685c51f124SMoriah Waterland if (fstat(newfd, &buf) != -1) { 11695c51f124SMoriah Waterland if (S_ISREG(buf.st_mode)) { 11705c51f124SMoriah Waterland /* 11715c51f124SMoriah Waterland * restore the file, waiting on it 11725c51f124SMoriah Waterland * to be free for locking, or for 11735c51f124SMoriah Waterland * it to disappear 11745c51f124SMoriah Waterland */ 11755c51f124SMoriah Waterland if (!wait_restore(newfd, keystore_file, 11765c51f124SMoriah Waterland newpath, backuppath)) { 11775c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WRITE, 11785c51f124SMoriah Waterland gettext(ERR_WRITE), 11795c51f124SMoriah Waterland newpath, strerror(errno)); 11805c51f124SMoriah Waterland (void) close(newfd); 11815c51f124SMoriah Waterland return (B_FALSE); 11825c51f124SMoriah Waterland } else { 11835c51f124SMoriah Waterland return (B_TRUE); 11845c51f124SMoriah Waterland } 11855c51f124SMoriah Waterland } else { 11865c51f124SMoriah Waterland /* "new" file is not a regular file */ 11875c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WRITE, 11885c51f124SMoriah Waterland gettext(ERR_NOT_REG), newpath); 11895c51f124SMoriah Waterland (void) close(newfd); 11905c51f124SMoriah Waterland return (B_FALSE); 11915c51f124SMoriah Waterland } 11925c51f124SMoriah Waterland } else { 11935c51f124SMoriah Waterland /* couldn't stat "new" file */ 11945c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WRITE, 11955c51f124SMoriah Waterland gettext(ERR_WRITE), newpath, 11965c51f124SMoriah Waterland strerror(errno)); 11975c51f124SMoriah Waterland (void) close(newfd); 11985c51f124SMoriah Waterland return (B_FALSE); 11995c51f124SMoriah Waterland } 12005c51f124SMoriah Waterland } else { 12015c51f124SMoriah Waterland /* "new" file doesn't exist */ 12025c51f124SMoriah Waterland return (B_TRUE); 12035c51f124SMoriah Waterland } 12045c51f124SMoriah Waterland } 12055c51f124SMoriah Waterland 12065c51f124SMoriah Waterland static boolean_t 12075c51f124SMoriah Waterland wait_restore(int newfd, char *keystore_file, 12085c51f124SMoriah Waterland char *origpath, char *backuppath) 12095c51f124SMoriah Waterland { 12105c51f124SMoriah Waterland struct stat buf; 12115c51f124SMoriah Waterland FILE *newstream; 12125c51f124SMoriah Waterland PKCS12 *p12; 12135c51f124SMoriah Waterland 12145c51f124SMoriah Waterland (void) alarm(LOCK_TIMEOUT); 12155c51f124SMoriah Waterland if (file_lock(newfd, F_WRLCK, 1) == -1) { 12165c51f124SMoriah Waterland /* could not lock file */ 12175c51f124SMoriah Waterland (void) alarm(0); 12185c51f124SMoriah Waterland return (B_FALSE); 12195c51f124SMoriah Waterland } 12205c51f124SMoriah Waterland (void) alarm(0); 12215c51f124SMoriah Waterland 12225c51f124SMoriah Waterland if (fstat(newfd, &buf) != -1) { 12235c51f124SMoriah Waterland if (S_ISREG(buf.st_mode)) { 12245c51f124SMoriah Waterland /* 12255c51f124SMoriah Waterland * The new file still 12265c51f124SMoriah Waterland * exists, with no 12275c51f124SMoriah Waterland * owner. It must be 12285c51f124SMoriah Waterland * the result of an 12295c51f124SMoriah Waterland * aborted update. 12305c51f124SMoriah Waterland */ 12315c51f124SMoriah Waterland newstream = fdopen(newfd, "r"); 12325c51f124SMoriah Waterland if ((p12 = 12335c51f124SMoriah Waterland d2i_PKCS12_fp(newstream, 12345c51f124SMoriah Waterland NULL)) != NULL) { 12355c51f124SMoriah Waterland /* 12365c51f124SMoriah Waterland * The file 12375c51f124SMoriah Waterland * appears 12385c51f124SMoriah Waterland * complete. 12395c51f124SMoriah Waterland * Replace the 12405c51f124SMoriah Waterland * exsisting 12415c51f124SMoriah Waterland * keystore 12425c51f124SMoriah Waterland * file with 12435c51f124SMoriah Waterland * this one 12445c51f124SMoriah Waterland */ 12455c51f124SMoriah Waterland (void) rename(keystore_file, backuppath); 12465c51f124SMoriah Waterland (void) rename(origpath, keystore_file); 12475c51f124SMoriah Waterland PKCS12_free(p12); 12485c51f124SMoriah Waterland } else { 12495c51f124SMoriah Waterland /* The file is not complete. Remove it */ 12505c51f124SMoriah Waterland (void) remove(origpath); 12515c51f124SMoriah Waterland } 12525c51f124SMoriah Waterland /* remove backup file */ 12535c51f124SMoriah Waterland (void) remove(backuppath); 12545c51f124SMoriah Waterland (void) fclose(newstream); 12555c51f124SMoriah Waterland (void) close(newfd); 12565c51f124SMoriah Waterland return (B_TRUE); 12575c51f124SMoriah Waterland } else { 12585c51f124SMoriah Waterland /* 12595c51f124SMoriah Waterland * new file exists, but is not a 12605c51f124SMoriah Waterland * regular file 12615c51f124SMoriah Waterland */ 12625c51f124SMoriah Waterland (void) close(newfd); 12635c51f124SMoriah Waterland return (B_FALSE); 12645c51f124SMoriah Waterland } 12655c51f124SMoriah Waterland } else { 12665c51f124SMoriah Waterland /* 12675c51f124SMoriah Waterland * could not stat file. Unless 12685c51f124SMoriah Waterland * the reason was that the file 12695c51f124SMoriah Waterland * is now gone, this is an error 12705c51f124SMoriah Waterland */ 12715c51f124SMoriah Waterland if (errno != ENOENT) { 12725c51f124SMoriah Waterland (void) close(newfd); 12735c51f124SMoriah Waterland return (B_FALSE); 12745c51f124SMoriah Waterland } 12755c51f124SMoriah Waterland /* 12765c51f124SMoriah Waterland * otherwise, file is gone. The process 12775c51f124SMoriah Waterland * that held the lock must have 12785c51f124SMoriah Waterland * successfully cleaned up and 12795c51f124SMoriah Waterland * exited with a valid keystore 12805c51f124SMoriah Waterland * state 12815c51f124SMoriah Waterland */ 12825c51f124SMoriah Waterland (void) close(newfd); 12835c51f124SMoriah Waterland return (B_TRUE); 12845c51f124SMoriah Waterland } 12855c51f124SMoriah Waterland } 12865c51f124SMoriah Waterland 12875c51f124SMoriah Waterland /* 12885c51f124SMoriah Waterland * resolve_paths - figure out if we are dealing with a single-file 12895c51f124SMoriah Waterland * or multi-file keystore 12905c51f124SMoriah Waterland * 12915c51f124SMoriah Waterland * The flags tell resolve_paths how to behave: 12925c51f124SMoriah Waterland * 12935c51f124SMoriah Waterland * KEYSTORE_PATH_SOFT 12945c51f124SMoriah Waterland * If the keystore file does not exist at <base>/<app> then 12955c51f124SMoriah Waterland * use <base> as the path to the keystore. This can be used, 12965c51f124SMoriah Waterland * for example, to access an app-specific keystore iff it 12975c51f124SMoriah Waterland * exists, otherwise revert back to an app-generic keystore. 12985c51f124SMoriah Waterland * 12995c51f124SMoriah Waterland * KEYSTORE_PATH_HARD 13005c51f124SMoriah Waterland * Always use the keystore located at <keystore_path>/<app>. 13015c51f124SMoriah Waterland * In read/write mode, if the files do not exist, then 13025c51f124SMoriah Waterland * they will be created. This is used to avoid falling 13035c51f124SMoriah Waterland * back to an app-generic keystore path when the app-specific 13045c51f124SMoriah Waterland * one does not exist. 13055c51f124SMoriah Waterland * 13065c51f124SMoriah Waterland * Arguments: 13075c51f124SMoriah Waterland * err - Error object to add errors to 13085c51f124SMoriah Waterland * keystore_file - base keystore file path to lock 13095c51f124SMoriah Waterland * app - Application making requests 13105c51f124SMoriah Waterland * flags - Control flags (see above description) 13115c51f124SMoriah Waterland * keystore - object which is being locked 13125c51f124SMoriah Waterland * 13135c51f124SMoriah Waterland * Returns: 13145c51f124SMoriah Waterland * B_TRUE - Success - Keystore file is locked, paths to 13155c51f124SMoriah Waterland * appropriate files placed in keystore. 13165c51f124SMoriah Waterland * B_FALSE - Failure, errors and reasons recorded in err 13175c51f124SMoriah Waterland */ 13185c51f124SMoriah Waterland static boolean_t 13195c51f124SMoriah Waterland resolve_paths(PKG_ERR *err, char *keystore_file, char *app, 13205c51f124SMoriah Waterland long flags, keystore_t *keystore) 13215c51f124SMoriah Waterland { 13225c51f124SMoriah Waterland char storepath[PATH_MAX]; 13235c51f124SMoriah Waterland struct stat buf; 13245c51f124SMoriah Waterland boolean_t multi = B_FALSE; 13255c51f124SMoriah Waterland int fd1, fd2, len; 13265c51f124SMoriah Waterland 13275c51f124SMoriah Waterland /* 13285c51f124SMoriah Waterland * figure out whether we are dealing with a single-file keystore 13295c51f124SMoriah Waterland * or a multi-file keystore 13305c51f124SMoriah Waterland */ 13315c51f124SMoriah Waterland if (app != NULL) { 13325c51f124SMoriah Waterland if (((len = snprintf(storepath, PATH_MAX, "%s/%s", 13335c51f124SMoriah Waterland keystore_file, app)) < 0) || 13345c51f124SMoriah Waterland (len >= ATTR_MAX)) { 13355c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WEB, gettext(ERR_LEN), 13365c51f124SMoriah Waterland keystore_file); 13375c51f124SMoriah Waterland return (B_FALSE); 13385c51f124SMoriah Waterland } 13395c51f124SMoriah Waterland 13405c51f124SMoriah Waterland if (((fd1 = open(storepath, O_NONBLOCK|O_RDONLY)) == -1) || 13415c51f124SMoriah Waterland (fstat(fd1, &buf) == -1) || 13425c51f124SMoriah Waterland !S_ISDIR(buf.st_mode)) { 13435c51f124SMoriah Waterland /* 13445c51f124SMoriah Waterland * app-specific does not exist 13455c51f124SMoriah Waterland * fallback to app-generic, if flags say we can 13465c51f124SMoriah Waterland */ 13475c51f124SMoriah Waterland if ((flags & KEYSTORE_PATH_MASK) == 13485c51f124SMoriah Waterland KEYSTORE_PATH_SOFT) { 13495c51f124SMoriah Waterland 13505c51f124SMoriah Waterland if (((fd2 = open(keystore_file, 13515c51f124SMoriah Waterland O_NONBLOCK|O_RDONLY)) != -1) && 13525c51f124SMoriah Waterland (fstat(fd2, &buf) != -1)) { 13535c51f124SMoriah Waterland if (S_ISDIR(buf.st_mode)) { 13545c51f124SMoriah Waterland /* 13555c51f124SMoriah Waterland * app-generic dir 13565c51f124SMoriah Waterland * exists, so use it 13575c51f124SMoriah Waterland * as a multi-file 13585c51f124SMoriah Waterland * keystore 13595c51f124SMoriah Waterland */ 13605c51f124SMoriah Waterland multi = B_TRUE; 13615c51f124SMoriah Waterland app = NULL; 13625c51f124SMoriah Waterland } else if (S_ISREG(buf.st_mode)) { 13635c51f124SMoriah Waterland /* 13645c51f124SMoriah Waterland * app-generic file exists, so 13655c51f124SMoriah Waterland * use it as a single file ks 13665c51f124SMoriah Waterland */ 13675c51f124SMoriah Waterland multi = B_FALSE; 13685c51f124SMoriah Waterland app = NULL; 13695c51f124SMoriah Waterland } 13705c51f124SMoriah Waterland } 13715c51f124SMoriah Waterland } 13725c51f124SMoriah Waterland } 13735c51f124SMoriah Waterland if (fd1 != -1) 13745c51f124SMoriah Waterland (void) close(fd1); 13755c51f124SMoriah Waterland if (fd2 != -1) 13765c51f124SMoriah Waterland (void) close(fd2); 13775c51f124SMoriah Waterland } else { 13785c51f124SMoriah Waterland if (((fd1 = open(keystore_file, 13795c51f124SMoriah Waterland O_NONBLOCK|O_RDONLY)) != -1) && 13805c51f124SMoriah Waterland (fstat(fd1, &buf) != -1) && 13815c51f124SMoriah Waterland S_ISDIR(buf.st_mode)) { 13825c51f124SMoriah Waterland /* 13835c51f124SMoriah Waterland * app-generic dir exists, so use 13845c51f124SMoriah Waterland * it as a multi-file keystore 13855c51f124SMoriah Waterland */ 13865c51f124SMoriah Waterland multi = B_TRUE; 13875c51f124SMoriah Waterland } 13885c51f124SMoriah Waterland if (fd1 != -1) 13895c51f124SMoriah Waterland (void) close(fd1); 13905c51f124SMoriah Waterland } 13915c51f124SMoriah Waterland 13925c51f124SMoriah Waterland if (app != NULL) { 13935c51f124SMoriah Waterland /* app-specific keystore */ 13945c51f124SMoriah Waterland (void) snprintf(storepath, PATH_MAX, "%s/%s/%s", 13955c51f124SMoriah Waterland keystore_file, app, TRUSTSTORE); 13965c51f124SMoriah Waterland keystore->capath = xstrdup(storepath); 13975c51f124SMoriah Waterland (void) snprintf(storepath, PATH_MAX, "%s/%s/%s", 13985c51f124SMoriah Waterland keystore_file, app, CERTSTORE); 13995c51f124SMoriah Waterland keystore->clpath = xstrdup(storepath); 14005c51f124SMoriah Waterland (void) snprintf(storepath, PATH_MAX, "%s/%s/%s", 14015c51f124SMoriah Waterland keystore_file, app, KEYSTORE); 14025c51f124SMoriah Waterland keystore->keypath = xstrdup(storepath); 14035c51f124SMoriah Waterland } else { 14045c51f124SMoriah Waterland /* app-generic keystore */ 14055c51f124SMoriah Waterland if (!multi) { 14065c51f124SMoriah Waterland /* single-file app-generic keystore */ 14075c51f124SMoriah Waterland keystore->capath = xstrdup(keystore_file); 14085c51f124SMoriah Waterland keystore->keypath = NULL; 14095c51f124SMoriah Waterland keystore->clpath = NULL; 14105c51f124SMoriah Waterland } else { 14115c51f124SMoriah Waterland /* multi-file app-generic keystore */ 14125c51f124SMoriah Waterland (void) snprintf(storepath, PATH_MAX, "%s/%s", 14135c51f124SMoriah Waterland keystore_file, TRUSTSTORE); 14145c51f124SMoriah Waterland keystore->capath = xstrdup(storepath); 14155c51f124SMoriah Waterland (void) snprintf(storepath, PATH_MAX, "%s/%s", 14165c51f124SMoriah Waterland keystore_file, CERTSTORE); 14175c51f124SMoriah Waterland keystore->clpath = xstrdup(storepath); 14185c51f124SMoriah Waterland (void) snprintf(storepath, PATH_MAX, "%s/%s", 14195c51f124SMoriah Waterland keystore_file, KEYSTORE); 14205c51f124SMoriah Waterland keystore->keypath = xstrdup(storepath); 14215c51f124SMoriah Waterland } 14225c51f124SMoriah Waterland } 14235c51f124SMoriah Waterland 14245c51f124SMoriah Waterland return (B_TRUE); 14255c51f124SMoriah Waterland } 14265c51f124SMoriah Waterland 14275c51f124SMoriah Waterland /* 14285c51f124SMoriah Waterland * lock_keystore - Locks a keystore for shared (read-only) 14295c51f124SMoriah Waterland * or exclusive (read-write) access. 14305c51f124SMoriah Waterland * 14315c51f124SMoriah Waterland * The flags tell lock_keystore how to behave: 14325c51f124SMoriah Waterland * 14335c51f124SMoriah Waterland * KEYSTORE_ACCESS_READONLY 14345c51f124SMoriah Waterland * opens keystore read-only. Attempts to modify results in an error 14355c51f124SMoriah Waterland * 14365c51f124SMoriah Waterland * KEYSTORE_ACCESS_READWRITE 14375c51f124SMoriah Waterland * opens keystore read-write 14385c51f124SMoriah Waterland * 14395c51f124SMoriah Waterland * KEYSTORE_PATH_SOFT 14405c51f124SMoriah Waterland * If the keystore file does not exist at <base>/<app> then 14415c51f124SMoriah Waterland * use <base> as the path to the keystore. This can be used, 14425c51f124SMoriah Waterland * for example, to access an app-specific keystore iff it 14435c51f124SMoriah Waterland * exists, otherwise revert back to an app-generic keystore. 14445c51f124SMoriah Waterland * 14455c51f124SMoriah Waterland * KEYSTORE_PATH_HARD 14465c51f124SMoriah Waterland * Always use the keystore located at <keystore_path>/<app>. 14475c51f124SMoriah Waterland * In read/write mode, if the files do not exist, then 14485c51f124SMoriah Waterland * they will be created. This is used to avoid falling 14495c51f124SMoriah Waterland * back to an app-generic keystore path when the app-specific 14505c51f124SMoriah Waterland * one does not exist. 14515c51f124SMoriah Waterland * 14525c51f124SMoriah Waterland * Arguments: 14535c51f124SMoriah Waterland * err - Error object to add errors to 14545c51f124SMoriah Waterland * flags - Control flags (see above description) 14555c51f124SMoriah Waterland * keystore - object which is being locked 14565c51f124SMoriah Waterland * 14575c51f124SMoriah Waterland * Returns: 14585c51f124SMoriah Waterland * 0 - Success - Keystore file is locked, paths to 14595c51f124SMoriah Waterland * appropriate files placed in keystore. 14605c51f124SMoriah Waterland * non-zero - Failure, errors and reasons recorded in err 14615c51f124SMoriah Waterland */ 14625c51f124SMoriah Waterland static boolean_t 14635c51f124SMoriah Waterland lock_keystore(PKG_ERR *err, long flags, keystore_t *keystore) 14645c51f124SMoriah Waterland { 14655c51f124SMoriah Waterland boolean_t ret = B_TRUE; 14665c51f124SMoriah Waterland struct stat buf; 14675c51f124SMoriah Waterland 14685c51f124SMoriah Waterland switch (flags & KEYSTORE_ACCESS_MASK) { 14695c51f124SMoriah Waterland case KEYSTORE_ACCESS_READONLY: 14705c51f124SMoriah Waterland if ((keystore->cafd = 14715c51f124SMoriah Waterland open(keystore->capath, O_NONBLOCK|O_RDONLY)) == -1) { 14725c51f124SMoriah Waterland if (errno == ENOENT) { 14735c51f124SMoriah Waterland /* 14745c51f124SMoriah Waterland * no keystore. try to create an 14755c51f124SMoriah Waterland * empty one so we can lock on it and 14765c51f124SMoriah Waterland * prevent others from gaining 14775c51f124SMoriah Waterland * exclusive access. It will be 14785c51f124SMoriah Waterland * deleted when the keystore is closed. 14795c51f124SMoriah Waterland */ 14805c51f124SMoriah Waterland if ((keystore->cafd = 14815c51f124SMoriah Waterland open(keystore->capath, 14825c51f124SMoriah Waterland O_NONBLOCK|O_RDWR|O_CREAT|O_EXCL, 14835c51f124SMoriah Waterland S_IRUSR|S_IWUSR)) == -1) { 14845c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, 14855c51f124SMoriah Waterland gettext(ERR_NO_KEYSTORE), 14865c51f124SMoriah Waterland keystore->capath); 14875c51f124SMoriah Waterland ret = B_FALSE; 14885c51f124SMoriah Waterland goto cleanup; 14895c51f124SMoriah Waterland } 14905c51f124SMoriah Waterland } else { 14915c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, 14925c51f124SMoriah Waterland gettext(ERR_KEYSTORE_OPEN), 14935c51f124SMoriah Waterland keystore->capath, strerror(errno)); 14945c51f124SMoriah Waterland ret = B_FALSE; 14955c51f124SMoriah Waterland goto cleanup; 14965c51f124SMoriah Waterland } 14975c51f124SMoriah Waterland } 14985c51f124SMoriah Waterland if (fstat(keystore->cafd, &buf) != -1) { 14995c51f124SMoriah Waterland if (S_ISREG(buf.st_mode)) { 15005c51f124SMoriah Waterland if (file_lock(keystore->cafd, F_RDLCK, 15015c51f124SMoriah Waterland 0) == -1) { 15025c51f124SMoriah Waterland pkgerr_add(err, PKGERR_LOCKED, 15035c51f124SMoriah Waterland gettext(ERR_KEYSTORE_LOCKED_READ), 15045c51f124SMoriah Waterland keystore->capath); 15055c51f124SMoriah Waterland ret = B_FALSE; 15065c51f124SMoriah Waterland goto cleanup; 15075c51f124SMoriah Waterland } 15085c51f124SMoriah Waterland } else { 15095c51f124SMoriah Waterland /* ca file not a regular file! */ 15105c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, 15115c51f124SMoriah Waterland gettext(ERR_NOT_REG), 15125c51f124SMoriah Waterland keystore->capath); 15135c51f124SMoriah Waterland ret = B_FALSE; 15145c51f124SMoriah Waterland goto cleanup; 15155c51f124SMoriah Waterland } 15165c51f124SMoriah Waterland } else { 15175c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, 15185c51f124SMoriah Waterland gettext(ERR_KEYSTORE_OPEN), 15195c51f124SMoriah Waterland keystore->capath, strerror(errno)); 15205c51f124SMoriah Waterland ret = B_FALSE; 15215c51f124SMoriah Waterland goto cleanup; 15225c51f124SMoriah Waterland } 15235c51f124SMoriah Waterland break; 15245c51f124SMoriah Waterland case KEYSTORE_ACCESS_READWRITE: 15255c51f124SMoriah Waterland 15265c51f124SMoriah Waterland if ((keystore->cafd = open(keystore->capath, 15275c51f124SMoriah Waterland O_RDWR|O_NONBLOCK)) == -1) { 15285c51f124SMoriah Waterland /* does not exist. try to create an empty one */ 15295c51f124SMoriah Waterland if (errno == ENOENT) { 15305c51f124SMoriah Waterland if ((keystore->cafd = 15315c51f124SMoriah Waterland open(keystore->capath, 15325c51f124SMoriah Waterland O_NONBLOCK|O_RDWR|O_CREAT|O_EXCL, 15335c51f124SMoriah Waterland S_IRUSR|S_IWUSR)) == -1) { 15345c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, 15355c51f124SMoriah Waterland gettext(ERR_KEYSTORE_WRITE), 15365c51f124SMoriah Waterland keystore->capath); 15375c51f124SMoriah Waterland ret = B_FALSE; 15385c51f124SMoriah Waterland goto cleanup; 15395c51f124SMoriah Waterland } 15405c51f124SMoriah Waterland } else { 15415c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, 15425c51f124SMoriah Waterland gettext(ERR_KEYSTORE_OPEN), 15435c51f124SMoriah Waterland keystore->capath, strerror(errno)); 15445c51f124SMoriah Waterland ret = B_FALSE; 15455c51f124SMoriah Waterland goto cleanup; 15465c51f124SMoriah Waterland } 15475c51f124SMoriah Waterland } 15485c51f124SMoriah Waterland if (fstat(keystore->cafd, &buf) != -1) { 15495c51f124SMoriah Waterland if (S_ISREG(buf.st_mode)) { 15505c51f124SMoriah Waterland if (file_lock(keystore->cafd, F_WRLCK, 15515c51f124SMoriah Waterland 0) == -1) { 15525c51f124SMoriah Waterland pkgerr_add(err, PKGERR_LOCKED, 15535c51f124SMoriah Waterland gettext(ERR_KEYSTORE_LOCKED), 15545c51f124SMoriah Waterland keystore->capath); 15555c51f124SMoriah Waterland ret = B_FALSE; 15565c51f124SMoriah Waterland goto cleanup; 15575c51f124SMoriah Waterland } 15585c51f124SMoriah Waterland } else { 15595c51f124SMoriah Waterland /* ca file not a regular file! */ 15605c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, 15615c51f124SMoriah Waterland gettext(ERR_NOT_REG), 15625c51f124SMoriah Waterland keystore->capath); 15635c51f124SMoriah Waterland ret = B_FALSE; 15645c51f124SMoriah Waterland goto cleanup; 15655c51f124SMoriah Waterland } 15665c51f124SMoriah Waterland } else { 15675c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, 15685c51f124SMoriah Waterland gettext(ERR_KEYSTORE_OPEN), 15695c51f124SMoriah Waterland keystore->capath, strerror(errno)); 15705c51f124SMoriah Waterland ret = B_FALSE; 15715c51f124SMoriah Waterland goto cleanup; 15725c51f124SMoriah Waterland } 15735c51f124SMoriah Waterland 15745c51f124SMoriah Waterland break; 15755c51f124SMoriah Waterland default: 15765c51f124SMoriah Waterland pkgerr_add(err, PKGERR_INTERNAL, 15775c51f124SMoriah Waterland gettext(ERR_KEYSTORE_INTERNAL), 15785c51f124SMoriah Waterland __FILE__, __LINE__); 15795c51f124SMoriah Waterland ret = B_FALSE; 15805c51f124SMoriah Waterland goto cleanup; 15815c51f124SMoriah Waterland } 15825c51f124SMoriah Waterland 15835c51f124SMoriah Waterland cleanup: 15845c51f124SMoriah Waterland if (!ret) { 15855c51f124SMoriah Waterland if (keystore->cafd > 0) { 15865c51f124SMoriah Waterland (void) file_unlock(keystore->cafd); 15875c51f124SMoriah Waterland (void) close(keystore->cafd); 15885c51f124SMoriah Waterland keystore->cafd = -1; 15895c51f124SMoriah Waterland } 15905c51f124SMoriah Waterland 15915c51f124SMoriah Waterland if (keystore->capath != NULL) 15925c51f124SMoriah Waterland free(keystore->capath); 15935c51f124SMoriah Waterland if (keystore->clpath != NULL) 15945c51f124SMoriah Waterland free(keystore->clpath); 15955c51f124SMoriah Waterland if (keystore->keypath != NULL) 15965c51f124SMoriah Waterland free(keystore->keypath); 15975c51f124SMoriah Waterland keystore->capath = NULL; 15985c51f124SMoriah Waterland keystore->clpath = NULL; 15995c51f124SMoriah Waterland keystore->keypath = NULL; 16005c51f124SMoriah Waterland } 16015c51f124SMoriah Waterland 16025c51f124SMoriah Waterland return (ret); 16035c51f124SMoriah Waterland } 16045c51f124SMoriah Waterland 16055c51f124SMoriah Waterland /* 16065c51f124SMoriah Waterland * unlock_keystore - Unocks a keystore 16075c51f124SMoriah Waterland * 16085c51f124SMoriah Waterland * Arguments: 16095c51f124SMoriah Waterland * err - Error object to add errors to 16105c51f124SMoriah Waterland * keystore - keystore object to unlock 16115c51f124SMoriah Waterland * Returns: 16125c51f124SMoriah Waterland * 0 - Success - Keystore files are unlocked, files are closed, 16135c51f124SMoriah Waterland * non-zero - Failure, errors and reasons recorded in err 16145c51f124SMoriah Waterland */ 16155c51f124SMoriah Waterland /* ARGSUSED */ 16165c51f124SMoriah Waterland static boolean_t 16175c51f124SMoriah Waterland unlock_keystore(PKG_ERR *err, keystore_t *keystore) 16185c51f124SMoriah Waterland { 16195c51f124SMoriah Waterland 16205c51f124SMoriah Waterland /* 16215c51f124SMoriah Waterland * Release lock on the CA file. 16225c51f124SMoriah Waterland * Delete file if it is empty 16235c51f124SMoriah Waterland */ 16245c51f124SMoriah Waterland if (file_empty(keystore->capath)) { 16255c51f124SMoriah Waterland (void) remove(keystore->capath); 16265c51f124SMoriah Waterland } 16275c51f124SMoriah Waterland 16285c51f124SMoriah Waterland (void) file_unlock(keystore->cafd); 16295c51f124SMoriah Waterland (void) close(keystore->cafd); 16305c51f124SMoriah Waterland return (B_TRUE); 16315c51f124SMoriah Waterland } 16325c51f124SMoriah Waterland 16335c51f124SMoriah Waterland /* 16345c51f124SMoriah Waterland * read_keystore - Reads keystore files of disk, parses 16355c51f124SMoriah Waterland * into internal structures. 16365c51f124SMoriah Waterland * 16375c51f124SMoriah Waterland * Arguments: 16385c51f124SMoriah Waterland * err - Error object to add errors to 16395c51f124SMoriah Waterland * keystore - keystore object to read into 16405c51f124SMoriah Waterland * cb - callback to get password, if required 16415c51f124SMoriah Waterland * Returns: 16425c51f124SMoriah Waterland * 0 - Success - Keystore files are read, and placed 16435c51f124SMoriah Waterland * into keystore structure. 16445c51f124SMoriah Waterland * non-zero - Failure, errors and reasons recorded in err 16455c51f124SMoriah Waterland */ 16465c51f124SMoriah Waterland static boolean_t 16475c51f124SMoriah Waterland read_keystore(PKG_ERR *err, keystore_t *keystore, keystore_passphrase_cb cb) 16485c51f124SMoriah Waterland { 16495c51f124SMoriah Waterland boolean_t ret = B_TRUE; 16505c51f124SMoriah Waterland PKCS12 *p12 = NULL; 16515c51f124SMoriah Waterland boolean_t ca_empty; 16525c51f124SMoriah Waterland boolean_t have_passwd = B_FALSE; 16535c51f124SMoriah Waterland boolean_t cl_empty = B_TRUE; 16545c51f124SMoriah Waterland boolean_t key_empty = B_TRUE; 16555c51f124SMoriah Waterland 16565c51f124SMoriah Waterland ca_empty = file_empty(keystore->capath); 16575c51f124SMoriah Waterland 16585c51f124SMoriah Waterland if (keystore->clpath != NULL) 16595c51f124SMoriah Waterland cl_empty = file_empty(keystore->clpath); 16605c51f124SMoriah Waterland if (keystore->keypath != NULL) 16615c51f124SMoriah Waterland key_empty = file_empty(keystore->keypath); 16625c51f124SMoriah Waterland 16635c51f124SMoriah Waterland if (ca_empty && cl_empty && key_empty) { 16645c51f124SMoriah Waterland keystore->new = B_TRUE; 16655c51f124SMoriah Waterland } 16665c51f124SMoriah Waterland 16675c51f124SMoriah Waterland if (!ca_empty) { 16685c51f124SMoriah Waterland /* first read the ca file */ 16695c51f124SMoriah Waterland if ((p12 = read_keystore_file(err, 16705c51f124SMoriah Waterland keystore->capath)) == NULL) { 16715c51f124SMoriah Waterland pkgerr_add(err, PKGERR_CORRUPT, 16725c51f124SMoriah Waterland gettext(ERR_KEYSTORE_CORRUPT), keystore->capath); 16735c51f124SMoriah Waterland ret = B_FALSE; 16745c51f124SMoriah Waterland goto cleanup; 16755c51f124SMoriah Waterland } 16765c51f124SMoriah Waterland 16775c51f124SMoriah Waterland /* Get password, using callback if necessary */ 16785c51f124SMoriah Waterland if (!have_passwd) { 16795c51f124SMoriah Waterland if (!get_keystore_passwd(err, p12, cb, keystore)) { 16805c51f124SMoriah Waterland ret = B_FALSE; 16815c51f124SMoriah Waterland goto cleanup; 16825c51f124SMoriah Waterland } 16835c51f124SMoriah Waterland have_passwd = B_TRUE; 16845c51f124SMoriah Waterland } 16855c51f124SMoriah Waterland 16865c51f124SMoriah Waterland /* decrypt and parse keystore file */ 16875c51f124SMoriah Waterland if (sunw_PKCS12_contents(p12, keystore->passphrase, 16885c51f124SMoriah Waterland &keystore->pkeys, &keystore->cacerts) < 0) { 16895c51f124SMoriah Waterland /* could not parse the contents */ 16905c51f124SMoriah Waterland pkgerr_add(err, PKGERR_CORRUPT, 16915c51f124SMoriah Waterland gettext(ERR_KEYSTORE_CORRUPT), keystore->capath); 16925c51f124SMoriah Waterland ret = B_FALSE; 16935c51f124SMoriah Waterland goto cleanup; 16945c51f124SMoriah Waterland } 16955c51f124SMoriah Waterland 16965c51f124SMoriah Waterland PKCS12_free(p12); 16975c51f124SMoriah Waterland p12 = NULL; 16985c51f124SMoriah Waterland } else { 16995c51f124SMoriah Waterland 17005c51f124SMoriah Waterland /* 17015c51f124SMoriah Waterland * truststore is empty, so we don't have any trusted 17025c51f124SMoriah Waterland * certs 17035c51f124SMoriah Waterland */ 17045c51f124SMoriah Waterland keystore->cacerts = NULL; 17055c51f124SMoriah Waterland } 17065c51f124SMoriah Waterland 17075c51f124SMoriah Waterland /* 17085c51f124SMoriah Waterland * if there is no cl file or key file, use the cl's and key's found 17095c51f124SMoriah Waterland * in the ca file 17105c51f124SMoriah Waterland */ 17115c51f124SMoriah Waterland if (keystore->clpath == NULL && !ca_empty) { 17125c51f124SMoriah Waterland if (sunw_split_certs(keystore->pkeys, keystore->cacerts, 17135c51f124SMoriah Waterland &keystore->clcerts, NULL) < 0) { 17145c51f124SMoriah Waterland pkgerr_add(err, PKGERR_CORRUPT, 17155c51f124SMoriah Waterland gettext(ERR_KEYSTORE_CORRUPT), keystore->capath); 17165c51f124SMoriah Waterland ret = B_FALSE; 17175c51f124SMoriah Waterland goto cleanup; 17185c51f124SMoriah Waterland } 17195c51f124SMoriah Waterland } else { 17205c51f124SMoriah Waterland /* 17215c51f124SMoriah Waterland * files are in separate files. read keys out of the keystore 17225c51f124SMoriah Waterland * certs out of the certstore, if they are not empty 17235c51f124SMoriah Waterland */ 17245c51f124SMoriah Waterland if (!cl_empty) { 17255c51f124SMoriah Waterland if ((p12 = read_keystore_file(err, 17265c51f124SMoriah Waterland keystore->clpath)) == NULL) { 17275c51f124SMoriah Waterland pkgerr_add(err, PKGERR_CORRUPT, 17285c51f124SMoriah Waterland gettext(ERR_KEYSTORE_CORRUPT), 17295c51f124SMoriah Waterland keystore->clpath); 17305c51f124SMoriah Waterland ret = B_FALSE; 17315c51f124SMoriah Waterland goto cleanup; 17325c51f124SMoriah Waterland } 17335c51f124SMoriah Waterland 17345c51f124SMoriah Waterland /* Get password, using callback if necessary */ 17355c51f124SMoriah Waterland if (!have_passwd) { 17365c51f124SMoriah Waterland if (!get_keystore_passwd(err, p12, cb, 17375c51f124SMoriah Waterland keystore)) { 17385c51f124SMoriah Waterland ret = B_FALSE; 17395c51f124SMoriah Waterland goto cleanup; 17405c51f124SMoriah Waterland } 17415c51f124SMoriah Waterland have_passwd = B_TRUE; 17425c51f124SMoriah Waterland } 17435c51f124SMoriah Waterland 17445c51f124SMoriah Waterland if (check_password(p12, 17455c51f124SMoriah Waterland keystore->passphrase) == B_FALSE) { 17465c51f124SMoriah Waterland /* 17475c51f124SMoriah Waterland * password in client cert file 17485c51f124SMoriah Waterland * is different than 17495c51f124SMoriah Waterland * the one in the other files! 17505c51f124SMoriah Waterland */ 17515c51f124SMoriah Waterland pkgerr_add(err, PKGERR_BADPASS, 17525c51f124SMoriah Waterland gettext(ERR_MISMATCHPASS), 17535c51f124SMoriah Waterland keystore->clpath, 17545c51f124SMoriah Waterland keystore->capath, keystore->path); 17555c51f124SMoriah Waterland ret = B_FALSE; 17565c51f124SMoriah Waterland goto cleanup; 17575c51f124SMoriah Waterland } 17585c51f124SMoriah Waterland 17595c51f124SMoriah Waterland if (sunw_PKCS12_contents(p12, keystore->passphrase, 17605c51f124SMoriah Waterland NULL, &keystore->clcerts) < 0) { 17615c51f124SMoriah Waterland /* could not parse the contents */ 17625c51f124SMoriah Waterland pkgerr_add(err, PKGERR_CORRUPT, 17635c51f124SMoriah Waterland gettext(ERR_KEYSTORE_CORRUPT), 17645c51f124SMoriah Waterland keystore->clpath); 17655c51f124SMoriah Waterland ret = B_FALSE; 17665c51f124SMoriah Waterland goto cleanup; 17675c51f124SMoriah Waterland } 17685c51f124SMoriah Waterland 17695c51f124SMoriah Waterland PKCS12_free(p12); 17705c51f124SMoriah Waterland p12 = NULL; 17715c51f124SMoriah Waterland } else { 17725c51f124SMoriah Waterland keystore->clcerts = NULL; 17735c51f124SMoriah Waterland } 17745c51f124SMoriah Waterland 17755c51f124SMoriah Waterland if (!key_empty) { 17765c51f124SMoriah Waterland if ((p12 = read_keystore_file(err, 17775c51f124SMoriah Waterland keystore->keypath)) == NULL) { 17785c51f124SMoriah Waterland pkgerr_add(err, PKGERR_CORRUPT, 17795c51f124SMoriah Waterland gettext(ERR_KEYSTORE_CORRUPT), 17805c51f124SMoriah Waterland keystore->keypath); 17815c51f124SMoriah Waterland ret = B_FALSE; 17825c51f124SMoriah Waterland goto cleanup; 17835c51f124SMoriah Waterland } 17845c51f124SMoriah Waterland 17855c51f124SMoriah Waterland /* Get password, using callback if necessary */ 17865c51f124SMoriah Waterland if (!have_passwd) { 17875c51f124SMoriah Waterland if (!get_keystore_passwd(err, p12, cb, 17885c51f124SMoriah Waterland keystore)) { 17895c51f124SMoriah Waterland ret = B_FALSE; 17905c51f124SMoriah Waterland goto cleanup; 17915c51f124SMoriah Waterland } 17925c51f124SMoriah Waterland have_passwd = B_TRUE; 17935c51f124SMoriah Waterland } 17945c51f124SMoriah Waterland 17955c51f124SMoriah Waterland if (check_password(p12, 17965c51f124SMoriah Waterland keystore->passphrase) == B_FALSE) { 17975c51f124SMoriah Waterland pkgerr_add(err, PKGERR_BADPASS, 17985c51f124SMoriah Waterland gettext(ERR_MISMATCHPASS), 17995c51f124SMoriah Waterland keystore->keypath, 18005c51f124SMoriah Waterland keystore->capath, keystore->path); 18015c51f124SMoriah Waterland ret = B_FALSE; 18025c51f124SMoriah Waterland goto cleanup; 18035c51f124SMoriah Waterland } 18045c51f124SMoriah Waterland 18055c51f124SMoriah Waterland if (sunw_PKCS12_contents(p12, keystore->passphrase, 18065c51f124SMoriah Waterland &keystore->pkeys, NULL) < 0) { 18075c51f124SMoriah Waterland /* could not parse the contents */ 18085c51f124SMoriah Waterland pkgerr_add(err, PKGERR_CORRUPT, 18095c51f124SMoriah Waterland gettext(ERR_KEYSTORE_CORRUPT), 18105c51f124SMoriah Waterland keystore->keypath); 18115c51f124SMoriah Waterland ret = B_FALSE; 18125c51f124SMoriah Waterland goto cleanup; 18135c51f124SMoriah Waterland } 18145c51f124SMoriah Waterland 18155c51f124SMoriah Waterland PKCS12_free(p12); 18165c51f124SMoriah Waterland p12 = NULL; 18175c51f124SMoriah Waterland } else { 18185c51f124SMoriah Waterland keystore->pkeys = NULL; 18195c51f124SMoriah Waterland } 18205c51f124SMoriah Waterland } 18215c51f124SMoriah Waterland 18225c51f124SMoriah Waterland cleanup: 18235c51f124SMoriah Waterland if (p12 != NULL) 18245c51f124SMoriah Waterland PKCS12_free(p12); 18255c51f124SMoriah Waterland return (ret); 18265c51f124SMoriah Waterland } 18275c51f124SMoriah Waterland 18285c51f124SMoriah Waterland /* 18295c51f124SMoriah Waterland * get_keystore_password - retrieves pasword used to 18305c51f124SMoriah Waterland * decrypt PKCS12 structure. 18315c51f124SMoriah Waterland * 18325c51f124SMoriah Waterland * Arguments: 18335c51f124SMoriah Waterland * err - Error object to add errors to 18345c51f124SMoriah Waterland * p12 - PKCS12 structure which returned password should 18355c51f124SMoriah Waterland * decrypt 18365c51f124SMoriah Waterland * cb - callback to collect password. 18375c51f124SMoriah Waterland * keystore - The keystore in which the PKCS12 structure 18385c51f124SMoriah Waterland * will eventually populate. 18395c51f124SMoriah Waterland * Returns: 18405c51f124SMoriah Waterland * B_TRUE - success. 18415c51f124SMoriah Waterland * keystore password is set in keystore->passphrase. 18425c51f124SMoriah Waterland * B_FALSE - failure, errors logged 18435c51f124SMoriah Waterland */ 18445c51f124SMoriah Waterland static boolean_t 18455c51f124SMoriah Waterland get_keystore_passwd(PKG_ERR *err, PKCS12 *p12, keystore_passphrase_cb cb, 18465c51f124SMoriah Waterland keystore_t *keystore) 18475c51f124SMoriah Waterland { 18485c51f124SMoriah Waterland char *passwd; 18495c51f124SMoriah Waterland char passbuf[KEYSTORE_PASS_MAX + 1]; 18505c51f124SMoriah Waterland keystore_passphrase_data data; 18515c51f124SMoriah Waterland 18525c51f124SMoriah Waterland /* see if no password is the right password */ 18535c51f124SMoriah Waterland if (check_password(p12, "") == B_TRUE) { 18545c51f124SMoriah Waterland passwd = ""; 18555c51f124SMoriah Waterland } else if (check_password(p12, NULL) == B_TRUE) { 18565c51f124SMoriah Waterland passwd = NULL; 18575c51f124SMoriah Waterland } else { 18585c51f124SMoriah Waterland /* oops, it's encrypted. get password */ 18595c51f124SMoriah Waterland data.err = err; 18605c51f124SMoriah Waterland if (cb(passbuf, KEYSTORE_PASS_MAX, 0, 18615c51f124SMoriah Waterland &data) == -1) { 18625c51f124SMoriah Waterland /* could not get password */ 18635c51f124SMoriah Waterland return (B_FALSE); 18645c51f124SMoriah Waterland } 18655c51f124SMoriah Waterland 18665c51f124SMoriah Waterland if (check_password(p12, passbuf) == B_FALSE) { 18675c51f124SMoriah Waterland /* wrong password */ 18685c51f124SMoriah Waterland pkgerr_add(err, PKGERR_BADPASS, 18695c51f124SMoriah Waterland gettext(ERR_BADPASS)); 18705c51f124SMoriah Waterland return (B_FALSE); 18715c51f124SMoriah Waterland } 18725c51f124SMoriah Waterland 18735c51f124SMoriah Waterland /* 18745c51f124SMoriah Waterland * make copy of password buffer, since it 18755c51f124SMoriah Waterland * goes away upon return 18765c51f124SMoriah Waterland */ 18775c51f124SMoriah Waterland passwd = xstrdup(passbuf); 18785c51f124SMoriah Waterland } 18795c51f124SMoriah Waterland keystore->passphrase = passwd; 18805c51f124SMoriah Waterland return (B_TRUE); 18815c51f124SMoriah Waterland } 18825c51f124SMoriah Waterland 18835c51f124SMoriah Waterland /* 18845c51f124SMoriah Waterland * write_keystore - Writes keystore files to disk 18855c51f124SMoriah Waterland * 18865c51f124SMoriah Waterland * Arguments: 18875c51f124SMoriah Waterland * err - Error object to add errors to 18885c51f124SMoriah Waterland * keystore - keystore object to write from 18895c51f124SMoriah Waterland * passwd - password used to encrypt keystore 18905c51f124SMoriah Waterland * Returns: 18915c51f124SMoriah Waterland * 0 - Success - Keystore contents are written out to 18925c51f124SMoriah Waterland * the same locations as read from 18935c51f124SMoriah Waterland * non-zero - Failure, errors and reasons recorded in err 18945c51f124SMoriah Waterland */ 18955c51f124SMoriah Waterland static boolean_t 18965c51f124SMoriah Waterland write_keystore(PKG_ERR *err, keystore_t *keystore, 18975c51f124SMoriah Waterland keystore_passphrase_cb cb) 18985c51f124SMoriah Waterland { 18995c51f124SMoriah Waterland PKCS12 *p12 = NULL; 19005c51f124SMoriah Waterland boolean_t ret = B_TRUE; 19015c51f124SMoriah Waterland keystore_passphrase_data data; 19025c51f124SMoriah Waterland char passbuf[KEYSTORE_PASS_MAX + 1]; 19035c51f124SMoriah Waterland 19045c51f124SMoriah Waterland if (keystore->capath != NULL && keystore->clpath == NULL && 19055c51f124SMoriah Waterland keystore->keypath == NULL) { 19065c51f124SMoriah Waterland 19075c51f124SMoriah Waterland /* 19085c51f124SMoriah Waterland * keystore is a file. 19095c51f124SMoriah Waterland * just write out a single file 19105c51f124SMoriah Waterland */ 19115c51f124SMoriah Waterland if ((keystore->pkeys == NULL) && 19125c51f124SMoriah Waterland (keystore->clcerts == NULL) && 19135c51f124SMoriah Waterland (keystore->cacerts == NULL)) { 19145c51f124SMoriah Waterland if (!clear_keystore_file(err, keystore->capath)) { 19155c51f124SMoriah Waterland /* 19165c51f124SMoriah Waterland * no keys or certs to write out, so 19175c51f124SMoriah Waterland * blank the ca file. we do not 19185c51f124SMoriah Waterland * delete it since it is used as a 19195c51f124SMoriah Waterland * lock by lock_keystore() in 19205c51f124SMoriah Waterland * subsequent invocations 19215c51f124SMoriah Waterland */ 19225c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WRITE, 19235c51f124SMoriah Waterland gettext(ERR_KEYSTORE_WRITE), 19245c51f124SMoriah Waterland keystore->capath); 19255c51f124SMoriah Waterland ret = B_FALSE; 19265c51f124SMoriah Waterland goto cleanup; 19275c51f124SMoriah Waterland } 19285c51f124SMoriah Waterland } else { 19295c51f124SMoriah Waterland /* 19305c51f124SMoriah Waterland * if the keystore is being created for the first time, 19315c51f124SMoriah Waterland * prompt for a passphrase for encryption 19325c51f124SMoriah Waterland */ 19335c51f124SMoriah Waterland if (keystore->new) { 19345c51f124SMoriah Waterland data.err = err; 19355c51f124SMoriah Waterland if (cb(passbuf, KEYSTORE_PASS_MAX, 19365c51f124SMoriah Waterland 1, &data) == -1) { 19375c51f124SMoriah Waterland ret = B_FALSE; 19385c51f124SMoriah Waterland goto cleanup; 19395c51f124SMoriah Waterland } 19405c51f124SMoriah Waterland } else { 19415c51f124SMoriah Waterland /* 19425c51f124SMoriah Waterland * use the one used when the keystore 19435c51f124SMoriah Waterland * was read 19445c51f124SMoriah Waterland */ 1945*4656d474SGarrett D'Amore (void) strlcpy(passbuf, keystore->passphrase, 19465c51f124SMoriah Waterland KEYSTORE_PASS_MAX); 19475c51f124SMoriah Waterland } 19485c51f124SMoriah Waterland 19495c51f124SMoriah Waterland p12 = sunw_PKCS12_create(passbuf, keystore->pkeys, 19505c51f124SMoriah Waterland keystore->clcerts, keystore->cacerts); 19515c51f124SMoriah Waterland 19525c51f124SMoriah Waterland if (p12 == NULL) { 19535c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WRITE, 19545c51f124SMoriah Waterland gettext(ERR_KEYSTORE_FORM), 19555c51f124SMoriah Waterland keystore->capath); 19565c51f124SMoriah Waterland ret = B_FALSE; 19575c51f124SMoriah Waterland goto cleanup; 19585c51f124SMoriah Waterland } 19595c51f124SMoriah Waterland 19605c51f124SMoriah Waterland if (!write_keystore_file(err, keystore->capath, p12)) { 19615c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WRITE, 19625c51f124SMoriah Waterland gettext(ERR_KEYSTORE_WRITE), 19635c51f124SMoriah Waterland keystore->capath); 19645c51f124SMoriah Waterland ret = B_FALSE; 19655c51f124SMoriah Waterland goto cleanup; 19665c51f124SMoriah Waterland } 19675c51f124SMoriah Waterland } 19685c51f124SMoriah Waterland 19695c51f124SMoriah Waterland } else { 19705c51f124SMoriah Waterland /* files are seprate. Do one at a time */ 19715c51f124SMoriah Waterland 19725c51f124SMoriah Waterland /* 19735c51f124SMoriah Waterland * if the keystore is being created for the first time, 19745c51f124SMoriah Waterland * prompt for a passphrase for encryption 19755c51f124SMoriah Waterland */ 19765c51f124SMoriah Waterland if (keystore->new && ((keystore->pkeys != NULL) || 19775c51f124SMoriah Waterland (keystore->clcerts != NULL) || 19785c51f124SMoriah Waterland (keystore->cacerts != NULL))) { 19795c51f124SMoriah Waterland data.err = err; 19805c51f124SMoriah Waterland if (cb(passbuf, KEYSTORE_PASS_MAX, 19815c51f124SMoriah Waterland 1, &data) == -1) { 19825c51f124SMoriah Waterland ret = B_FALSE; 19835c51f124SMoriah Waterland goto cleanup; 19845c51f124SMoriah Waterland } 19855c51f124SMoriah Waterland } else { 19865c51f124SMoriah Waterland /* use the one used when the keystore was read */ 1987*4656d474SGarrett D'Amore (void) strlcpy(passbuf, keystore->passphrase, 19885c51f124SMoriah Waterland KEYSTORE_PASS_MAX); 19895c51f124SMoriah Waterland } 19905c51f124SMoriah Waterland 19915c51f124SMoriah Waterland /* do private keys first */ 19925c51f124SMoriah Waterland if (keystore->pkeys != NULL) { 19935c51f124SMoriah Waterland p12 = sunw_PKCS12_create(passbuf, keystore->pkeys, 19945c51f124SMoriah Waterland NULL, NULL); 19955c51f124SMoriah Waterland 19965c51f124SMoriah Waterland if (p12 == NULL) { 19975c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WRITE, 19985c51f124SMoriah Waterland gettext(ERR_KEYSTORE_FORM), 19995c51f124SMoriah Waterland keystore->keypath); 20005c51f124SMoriah Waterland ret = B_FALSE; 20015c51f124SMoriah Waterland goto cleanup; 20025c51f124SMoriah Waterland } 20035c51f124SMoriah Waterland 20045c51f124SMoriah Waterland if (!write_keystore_file(err, keystore->keypath, 20055c51f124SMoriah Waterland p12)) { 20065c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WRITE, 20075c51f124SMoriah Waterland gettext(ERR_KEYSTORE_WRITE), 20085c51f124SMoriah Waterland keystore->keypath); 20095c51f124SMoriah Waterland ret = B_FALSE; 20105c51f124SMoriah Waterland goto cleanup; 20115c51f124SMoriah Waterland } 20125c51f124SMoriah Waterland 20135c51f124SMoriah Waterland PKCS12_free(p12); 20145c51f124SMoriah Waterland } else { 20155c51f124SMoriah Waterland if ((remove(keystore->keypath) != 0) && 20165c51f124SMoriah Waterland (errno != ENOENT)) { 20175c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WRITE, 20185c51f124SMoriah Waterland gettext(ERR_KEYSTORE_REMOVE), 20195c51f124SMoriah Waterland keystore->keypath); 20205c51f124SMoriah Waterland ret = B_FALSE; 20215c51f124SMoriah Waterland goto cleanup; 20225c51f124SMoriah Waterland } 20235c51f124SMoriah Waterland } 20245c51f124SMoriah Waterland 20255c51f124SMoriah Waterland /* do user certs next */ 20265c51f124SMoriah Waterland if (keystore->clcerts != NULL) { 20275c51f124SMoriah Waterland p12 = sunw_PKCS12_create(passbuf, NULL, 20285c51f124SMoriah Waterland keystore->clcerts, NULL); 20295c51f124SMoriah Waterland 20305c51f124SMoriah Waterland if (p12 == NULL) { 20315c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WRITE, 20325c51f124SMoriah Waterland gettext(ERR_KEYSTORE_FORM), 20335c51f124SMoriah Waterland keystore->clpath); 20345c51f124SMoriah Waterland ret = B_FALSE; 20355c51f124SMoriah Waterland goto cleanup; 20365c51f124SMoriah Waterland } 20375c51f124SMoriah Waterland 20385c51f124SMoriah Waterland if (!write_keystore_file(err, keystore->clpath, p12)) { 20395c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WRITE, 20405c51f124SMoriah Waterland gettext(ERR_KEYSTORE_WRITE), 20415c51f124SMoriah Waterland keystore->clpath); 20425c51f124SMoriah Waterland ret = B_FALSE; 20435c51f124SMoriah Waterland goto cleanup; 20445c51f124SMoriah Waterland } 20455c51f124SMoriah Waterland 20465c51f124SMoriah Waterland PKCS12_free(p12); 20475c51f124SMoriah Waterland } else { 20485c51f124SMoriah Waterland if ((remove(keystore->clpath) != 0) && 20495c51f124SMoriah Waterland (errno != ENOENT)) { 20505c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WRITE, 20515c51f124SMoriah Waterland gettext(ERR_KEYSTORE_REMOVE), 20525c51f124SMoriah Waterland keystore->clpath); 20535c51f124SMoriah Waterland ret = B_FALSE; 20545c51f124SMoriah Waterland goto cleanup; 20555c51f124SMoriah Waterland } 20565c51f124SMoriah Waterland } 20575c51f124SMoriah Waterland 20585c51f124SMoriah Waterland 20595c51f124SMoriah Waterland /* finally do CA cert file */ 20605c51f124SMoriah Waterland if (keystore->cacerts != NULL) { 20615c51f124SMoriah Waterland p12 = sunw_PKCS12_create(passbuf, NULL, 20625c51f124SMoriah Waterland NULL, keystore->cacerts); 20635c51f124SMoriah Waterland 20645c51f124SMoriah Waterland if (p12 == NULL) { 20655c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WRITE, 20665c51f124SMoriah Waterland gettext(ERR_KEYSTORE_FORM), 20675c51f124SMoriah Waterland keystore->capath); 20685c51f124SMoriah Waterland ret = B_FALSE; 20695c51f124SMoriah Waterland goto cleanup; 20705c51f124SMoriah Waterland } 20715c51f124SMoriah Waterland 20725c51f124SMoriah Waterland if (!write_keystore_file(err, keystore->capath, p12)) { 20735c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WRITE, 20745c51f124SMoriah Waterland gettext(ERR_KEYSTORE_WRITE), 20755c51f124SMoriah Waterland keystore->capath); 20765c51f124SMoriah Waterland ret = B_FALSE; 20775c51f124SMoriah Waterland goto cleanup; 20785c51f124SMoriah Waterland } 20795c51f124SMoriah Waterland 20805c51f124SMoriah Waterland PKCS12_free(p12); 20815c51f124SMoriah Waterland p12 = NULL; 20825c51f124SMoriah Waterland } else { 20835c51f124SMoriah Waterland /* 20845c51f124SMoriah Waterland * nothing to write out, so truncate the file 20855c51f124SMoriah Waterland * (it will be deleted during close_keystore) 20865c51f124SMoriah Waterland */ 20875c51f124SMoriah Waterland if (!clear_keystore_file(err, keystore->capath)) { 20885c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WRITE, 20895c51f124SMoriah Waterland gettext(ERR_KEYSTORE_WRITE), 20905c51f124SMoriah Waterland keystore->capath); 20915c51f124SMoriah Waterland ret = B_FALSE; 20925c51f124SMoriah Waterland goto cleanup; 20935c51f124SMoriah Waterland } 20945c51f124SMoriah Waterland } 20955c51f124SMoriah Waterland } 20965c51f124SMoriah Waterland 20975c51f124SMoriah Waterland cleanup: 20985c51f124SMoriah Waterland if (p12 != NULL) 20995c51f124SMoriah Waterland PKCS12_free(p12); 21005c51f124SMoriah Waterland 21015c51f124SMoriah Waterland return (ret); 21025c51f124SMoriah Waterland } 21035c51f124SMoriah Waterland 21045c51f124SMoriah Waterland /* 21055c51f124SMoriah Waterland * clear_keystore_file - Clears (zeros out) a keystore file. 21065c51f124SMoriah Waterland * 21075c51f124SMoriah Waterland * Arguments: 21085c51f124SMoriah Waterland * err - Error object to add errors to 21095c51f124SMoriah Waterland * dest - Path of keystore file to zero out. 21105c51f124SMoriah Waterland * Returns: 21115c51f124SMoriah Waterland * 0 - Success - Keystore file is truncated to zero length 21125c51f124SMoriah Waterland * non-zero - Failure, errors and reasons recorded in err 21135c51f124SMoriah Waterland */ 21145c51f124SMoriah Waterland static boolean_t 21155c51f124SMoriah Waterland clear_keystore_file(PKG_ERR *err, char *dest) 21165c51f124SMoriah Waterland { 21175c51f124SMoriah Waterland int fd; 21185c51f124SMoriah Waterland struct stat buf; 21195c51f124SMoriah Waterland 21205c51f124SMoriah Waterland fd = open(dest, O_RDWR|O_NONBLOCK); 21215c51f124SMoriah Waterland if (fd == -1) { 21225c51f124SMoriah Waterland /* can't open for writing */ 21235c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WRITE, gettext(MSG_OPEN), 21245c51f124SMoriah Waterland errno); 21255c51f124SMoriah Waterland return (B_FALSE); 21265c51f124SMoriah Waterland } 21275c51f124SMoriah Waterland 21285c51f124SMoriah Waterland if ((fstat(fd, &buf) == -1) || !S_ISREG(buf.st_mode)) { 21295c51f124SMoriah Waterland /* not a regular file */ 21305c51f124SMoriah Waterland (void) close(fd); 21315c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WRITE, gettext(ERR_NOT_REG), 21325c51f124SMoriah Waterland dest); 21335c51f124SMoriah Waterland return (B_FALSE); 21345c51f124SMoriah Waterland } 21355c51f124SMoriah Waterland 21365c51f124SMoriah Waterland if (ftruncate(fd, 0) == -1) { 21375c51f124SMoriah Waterland (void) close(fd); 21385c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WRITE, gettext(ERR_WRITE), 21395c51f124SMoriah Waterland dest, strerror(errno)); 21405c51f124SMoriah Waterland return (B_FALSE); 21415c51f124SMoriah Waterland } 21425c51f124SMoriah Waterland 21435c51f124SMoriah Waterland (void) close(fd); 21445c51f124SMoriah Waterland return (B_TRUE); 21455c51f124SMoriah Waterland } 21465c51f124SMoriah Waterland 21475c51f124SMoriah Waterland /* 21485c51f124SMoriah Waterland * write_keystore_file - Writes keystore file to disk. 21495c51f124SMoriah Waterland * 21505c51f124SMoriah Waterland * Keystore files can possibly be corrupted by a variety 21515c51f124SMoriah Waterland * of error conditions during reading/writing. This 21525c51f124SMoriah Waterland * routine, along with restore_keystore_file, tries to 21535c51f124SMoriah Waterland * maintain keystore integity by writing the files 21545c51f124SMoriah Waterland * out in a particular order, minimizing the time period 21555c51f124SMoriah Waterland * that the keystore is in an indeterminate state. 21565c51f124SMoriah Waterland * 21575c51f124SMoriah Waterland * With the current implementation, there are some failures 21585c51f124SMoriah Waterland * that are wholly unrecoverable, such as disk corruption. 21595c51f124SMoriah Waterland * These routines attempt to minimize the risk, but not 21605c51f124SMoriah Waterland * eliminate it. When better, atomic operations are available 21615c51f124SMoriah Waterland * (such as a true database with commit, rollback, and 21625c51f124SMoriah Waterland * guaranteed atomicity), this implementation should use that. 21635c51f124SMoriah Waterland * 21645c51f124SMoriah Waterland * 21655c51f124SMoriah Waterland * Arguments: 21665c51f124SMoriah Waterland * err - Error object to add errors to 21675c51f124SMoriah Waterland * dest - Destination filename 21685c51f124SMoriah Waterland * contents - Contents to write to the file 21695c51f124SMoriah Waterland * Returns: 21705c51f124SMoriah Waterland * 0 - Success - Keystore contents are written out to 21715c51f124SMoriah Waterland * the destination. 21725c51f124SMoriah Waterland * non-zero - Failure, errors and reasons recorded in err 21735c51f124SMoriah Waterland */ 21745c51f124SMoriah Waterland static boolean_t 21755c51f124SMoriah Waterland write_keystore_file(PKG_ERR *err, char *dest, PKCS12 *contents) 21765c51f124SMoriah Waterland { 21775c51f124SMoriah Waterland FILE *newfile = NULL; 21785c51f124SMoriah Waterland boolean_t ret = B_TRUE; 21795c51f124SMoriah Waterland char newpath[MAXPATHLEN]; 21805c51f124SMoriah Waterland char backuppath[MAXPATHLEN]; 21815c51f124SMoriah Waterland struct stat buf; 21825c51f124SMoriah Waterland int fd; 21835c51f124SMoriah Waterland 21845c51f124SMoriah Waterland (void) snprintf(newpath, MAXPATHLEN, "%s.new", dest); 21855c51f124SMoriah Waterland (void) snprintf(backuppath, MAXPATHLEN, "%s.bak", dest); 21865c51f124SMoriah Waterland 21875c51f124SMoriah Waterland if ((fd = open(newpath, O_CREAT|O_EXCL|O_WRONLY|O_NONBLOCK, 21885c51f124SMoriah Waterland S_IRUSR|S_IWUSR)) == -1) { 21895c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN), 21905c51f124SMoriah Waterland newpath, strerror(errno)); 21915c51f124SMoriah Waterland ret = B_FALSE; 21925c51f124SMoriah Waterland goto cleanup; 21935c51f124SMoriah Waterland } 21945c51f124SMoriah Waterland 21955c51f124SMoriah Waterland if (fstat(fd, &buf) == -1) { 21965c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN), 21975c51f124SMoriah Waterland newpath, strerror(errno)); 21985c51f124SMoriah Waterland ret = B_FALSE; 21995c51f124SMoriah Waterland goto cleanup; 22005c51f124SMoriah Waterland } 22015c51f124SMoriah Waterland 22025c51f124SMoriah Waterland if (!S_ISREG(buf.st_mode)) { 22035c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, gettext(ERR_NOT_REG), 22045c51f124SMoriah Waterland newpath); 22055c51f124SMoriah Waterland ret = B_FALSE; 22065c51f124SMoriah Waterland goto cleanup; 22075c51f124SMoriah Waterland } 22085c51f124SMoriah Waterland 22095c51f124SMoriah Waterland if ((newfile = fdopen(fd, "w")) == NULL) { 22105c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN), 22115c51f124SMoriah Waterland newpath, strerror(errno)); 22125c51f124SMoriah Waterland ret = B_FALSE; 22135c51f124SMoriah Waterland goto cleanup; 22145c51f124SMoriah Waterland } 22155c51f124SMoriah Waterland 22165c51f124SMoriah Waterland if (i2d_PKCS12_fp(newfile, contents) == 0) { 22175c51f124SMoriah Waterland pkgerr_add(err, PKGERR_WRITE, gettext(ERR_KEYSTORE_WRITE), 22185c51f124SMoriah Waterland newpath); 22195c51f124SMoriah Waterland ret = B_FALSE; 22205c51f124SMoriah Waterland goto cleanup; 22215c51f124SMoriah Waterland } 22225c51f124SMoriah Waterland 22235c51f124SMoriah Waterland /* flush, then close */ 22245c51f124SMoriah Waterland (void) fflush(newfile); 22255c51f124SMoriah Waterland (void) fclose(newfile); 22265c51f124SMoriah Waterland newfile = NULL; 22275c51f124SMoriah Waterland 22285c51f124SMoriah Waterland /* now back up the original file */ 22295c51f124SMoriah Waterland (void) rename(dest, backuppath); 22305c51f124SMoriah Waterland 22315c51f124SMoriah Waterland /* put new one in its place */ 22325c51f124SMoriah Waterland (void) rename(newpath, dest); 22335c51f124SMoriah Waterland 22345c51f124SMoriah Waterland /* remove backup */ 22355c51f124SMoriah Waterland (void) remove(backuppath); 22365c51f124SMoriah Waterland 22375c51f124SMoriah Waterland cleanup: 22385c51f124SMoriah Waterland if (newfile != NULL) 22395c51f124SMoriah Waterland (void) fclose(newfile); 22405c51f124SMoriah Waterland if (fd != -1) 22415c51f124SMoriah Waterland (void) close(fd); 22425c51f124SMoriah Waterland 22435c51f124SMoriah Waterland return (ret); 22445c51f124SMoriah Waterland } 22455c51f124SMoriah Waterland 22465c51f124SMoriah Waterland /* 22475c51f124SMoriah Waterland * read_keystore_file - Reads single keystore file 22485c51f124SMoriah Waterland * off disk in PKCS12 format. 22495c51f124SMoriah Waterland * 22505c51f124SMoriah Waterland * Arguments: 22515c51f124SMoriah Waterland * err - Error object to add errors to 22525c51f124SMoriah Waterland * file - File path to read 22535c51f124SMoriah Waterland * Returns: 22545c51f124SMoriah Waterland * PKCS12 contents of file, or NULL if an error occurred. 22555c51f124SMoriah Waterland * errors recorded in 'err'. 22565c51f124SMoriah Waterland */ 22575c51f124SMoriah Waterland static PKCS12 22585c51f124SMoriah Waterland *read_keystore_file(PKG_ERR *err, char *file) 22595c51f124SMoriah Waterland { 22605c51f124SMoriah Waterland int fd; 22615c51f124SMoriah Waterland struct stat buf; 22625c51f124SMoriah Waterland FILE *newfile; 22635c51f124SMoriah Waterland PKCS12 *p12 = NULL; 22645c51f124SMoriah Waterland 22655c51f124SMoriah Waterland if ((fd = open(file, O_RDONLY|O_NONBLOCK)) == -1) { 22665c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN), 22675c51f124SMoriah Waterland file, strerror(errno)); 22685c51f124SMoriah Waterland goto cleanup; 22695c51f124SMoriah Waterland } 22705c51f124SMoriah Waterland 22715c51f124SMoriah Waterland if (fstat(fd, &buf) == -1) { 22725c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN), 22735c51f124SMoriah Waterland file, strerror(errno)); 22745c51f124SMoriah Waterland goto cleanup; 22755c51f124SMoriah Waterland } 22765c51f124SMoriah Waterland 22775c51f124SMoriah Waterland if (!S_ISREG(buf.st_mode)) { 22785c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, gettext(ERR_NOT_REG), 22795c51f124SMoriah Waterland file); 22805c51f124SMoriah Waterland goto cleanup; 22815c51f124SMoriah Waterland } 22825c51f124SMoriah Waterland 22835c51f124SMoriah Waterland if ((newfile = fdopen(fd, "r")) == NULL) { 22845c51f124SMoriah Waterland pkgerr_add(err, PKGERR_READ, gettext(ERR_KEYSTORE_OPEN), 22855c51f124SMoriah Waterland file, strerror(errno)); 22865c51f124SMoriah Waterland goto cleanup; 22875c51f124SMoriah Waterland } 22885c51f124SMoriah Waterland 22895c51f124SMoriah Waterland if ((p12 = d2i_PKCS12_fp(newfile, NULL)) == NULL) { 22905c51f124SMoriah Waterland pkgerr_add(err, PKGERR_CORRUPT, 22915c51f124SMoriah Waterland gettext(ERR_KEYSTORE_CORRUPT), file); 22925c51f124SMoriah Waterland goto cleanup; 22935c51f124SMoriah Waterland } 22945c51f124SMoriah Waterland 22955c51f124SMoriah Waterland cleanup: 22965c51f124SMoriah Waterland if (newfile != NULL) 22975c51f124SMoriah Waterland (void) fclose(newfile); 22985c51f124SMoriah Waterland if (fd != -1) 22995c51f124SMoriah Waterland (void) close(fd); 23005c51f124SMoriah Waterland 23015c51f124SMoriah Waterland return (p12); 23025c51f124SMoriah Waterland } 23035c51f124SMoriah Waterland 23045c51f124SMoriah Waterland 23055c51f124SMoriah Waterland /* 23065c51f124SMoriah Waterland * Locks the specified file. 23075c51f124SMoriah Waterland */ 23085c51f124SMoriah Waterland static int 23095c51f124SMoriah Waterland file_lock(int fd, int type, int wait) 23105c51f124SMoriah Waterland { 23115c51f124SMoriah Waterland struct flock lock; 23125c51f124SMoriah Waterland 23135c51f124SMoriah Waterland lock.l_type = type; 23145c51f124SMoriah Waterland lock.l_start = 0; 23155c51f124SMoriah Waterland lock.l_whence = SEEK_SET; 23165c51f124SMoriah Waterland lock.l_len = 0; 23175c51f124SMoriah Waterland 23185c51f124SMoriah Waterland if (!wait) { 23195c51f124SMoriah Waterland if (file_lock_test(fd, type)) { 23205c51f124SMoriah Waterland /* 23215c51f124SMoriah Waterland * The caller would have to wait to get the 23225c51f124SMoriah Waterland * lock on this file. 23235c51f124SMoriah Waterland */ 23245c51f124SMoriah Waterland return (-1); 23255c51f124SMoriah Waterland } 23265c51f124SMoriah Waterland } 23275c51f124SMoriah Waterland 23285c51f124SMoriah Waterland return (fcntl(fd, F_SETLKW, &lock)); 23295c51f124SMoriah Waterland } 23305c51f124SMoriah Waterland 23315c51f124SMoriah Waterland /* 23325c51f124SMoriah Waterland * Returns FALSE if the file is not locked; TRUE 23335c51f124SMoriah Waterland * otherwise. 23345c51f124SMoriah Waterland */ 23355c51f124SMoriah Waterland static boolean_t 23365c51f124SMoriah Waterland file_lock_test(int fd, int type) 23375c51f124SMoriah Waterland { 23385c51f124SMoriah Waterland struct flock lock; 23395c51f124SMoriah Waterland 23405c51f124SMoriah Waterland lock.l_type = type; 23415c51f124SMoriah Waterland lock.l_start = 0; 23425c51f124SMoriah Waterland lock.l_whence = SEEK_SET; 23435c51f124SMoriah Waterland lock.l_len = 0; 23445c51f124SMoriah Waterland 23455c51f124SMoriah Waterland if (fcntl(fd, F_GETLK, &lock) != -1) { 23465c51f124SMoriah Waterland if (lock.l_type != F_UNLCK) { 23475c51f124SMoriah Waterland /* 23485c51f124SMoriah Waterland * The caller would have to wait to get the 23495c51f124SMoriah Waterland * lock on this file. 23505c51f124SMoriah Waterland */ 23515c51f124SMoriah Waterland return (B_TRUE); 23525c51f124SMoriah Waterland } 23535c51f124SMoriah Waterland } 23545c51f124SMoriah Waterland 23555c51f124SMoriah Waterland /* 23565c51f124SMoriah Waterland * The file is not locked. 23575c51f124SMoriah Waterland */ 23585c51f124SMoriah Waterland return (B_FALSE); 23595c51f124SMoriah Waterland } 23605c51f124SMoriah Waterland 23615c51f124SMoriah Waterland /* 23625c51f124SMoriah Waterland * Unlocks the specified file. 23635c51f124SMoriah Waterland */ 23645c51f124SMoriah Waterland static int 23655c51f124SMoriah Waterland file_unlock(int fd) 23665c51f124SMoriah Waterland { 23675c51f124SMoriah Waterland struct flock lock; 23685c51f124SMoriah Waterland 23695c51f124SMoriah Waterland lock.l_type = F_UNLCK; 23705c51f124SMoriah Waterland lock.l_start = 0; 23715c51f124SMoriah Waterland lock.l_whence = SEEK_SET; 23725c51f124SMoriah Waterland lock.l_len = 0; 23735c51f124SMoriah Waterland 23745c51f124SMoriah Waterland return (fcntl(fd, F_SETLK, &lock)); 23755c51f124SMoriah Waterland } 23765c51f124SMoriah Waterland 23775c51f124SMoriah Waterland /* 23785c51f124SMoriah Waterland * Determines if file has a length of 0 or not 23795c51f124SMoriah Waterland */ 23805c51f124SMoriah Waterland static boolean_t 23815c51f124SMoriah Waterland file_empty(char *path) 23825c51f124SMoriah Waterland { 23835c51f124SMoriah Waterland struct stat buf; 23845c51f124SMoriah Waterland 23855c51f124SMoriah Waterland /* file is empty if size = 0 or it doesn't exist */ 23865c51f124SMoriah Waterland if (lstat(path, &buf) == 0) { 23875c51f124SMoriah Waterland if (buf.st_size == 0) { 23885c51f124SMoriah Waterland return (B_TRUE); 23895c51f124SMoriah Waterland } 23905c51f124SMoriah Waterland } else { 23915c51f124SMoriah Waterland if (errno == ENOENT) { 23925c51f124SMoriah Waterland return (B_TRUE); 23935c51f124SMoriah Waterland } 23945c51f124SMoriah Waterland } 23955c51f124SMoriah Waterland 23965c51f124SMoriah Waterland return (B_FALSE); 23975c51f124SMoriah Waterland } 23985c51f124SMoriah Waterland 23995c51f124SMoriah Waterland /* 24005c51f124SMoriah Waterland * Name: get_time_string 24015c51f124SMoriah Waterland * Description: Generates a human-readable string from an ASN1_TIME 24025c51f124SMoriah Waterland * 24035c51f124SMoriah Waterland * Arguments: intime - The time to convert 24045c51f124SMoriah Waterland * 24055c51f124SMoriah Waterland * Returns : A pointer to a static string representing the passed-in time. 24065c51f124SMoriah Waterland */ 24075c51f124SMoriah Waterland static char 24085c51f124SMoriah Waterland *get_time_string(ASN1_TIME *intime) 24095c51f124SMoriah Waterland { 24105c51f124SMoriah Waterland 24115c51f124SMoriah Waterland static char time[ATTR_MAX]; 24125c51f124SMoriah Waterland BIO *mem; 24135c51f124SMoriah Waterland char *p; 24145c51f124SMoriah Waterland 24155c51f124SMoriah Waterland if (intime == NULL) { 24165c51f124SMoriah Waterland return (NULL); 24175c51f124SMoriah Waterland } 24185c51f124SMoriah Waterland if ((mem = BIO_new(BIO_s_mem())) == NULL) { 24195c51f124SMoriah Waterland return (NULL); 24205c51f124SMoriah Waterland } 24215c51f124SMoriah Waterland 24225c51f124SMoriah Waterland if (ASN1_TIME_print(mem, intime) == 0) { 24235c51f124SMoriah Waterland (void) BIO_free(mem); 24245c51f124SMoriah Waterland return (NULL); 24255c51f124SMoriah Waterland } 24265c51f124SMoriah Waterland 24275c51f124SMoriah Waterland if (BIO_gets(mem, time, ATTR_MAX) <= 0) { 24285c51f124SMoriah Waterland (void) BIO_free(mem); 24295c51f124SMoriah Waterland return (NULL); 24305c51f124SMoriah Waterland } 24315c51f124SMoriah Waterland 24325c51f124SMoriah Waterland (void) BIO_free(mem); 24335c51f124SMoriah Waterland 24345c51f124SMoriah Waterland /* trim the end of the string */ 24355c51f124SMoriah Waterland for (p = time + strlen(time) - 1; isspace(*p); p--) { 24365c51f124SMoriah Waterland *p = '\0'; 24375c51f124SMoriah Waterland } 24385c51f124SMoriah Waterland 24395c51f124SMoriah Waterland return (time); 24405c51f124SMoriah Waterland } 24415c51f124SMoriah Waterland 24425c51f124SMoriah Waterland /* 24435c51f124SMoriah Waterland * check_password - do various password checks to see if the current password 24445c51f124SMoriah Waterland * will work or we need to prompt for a new one. 24455c51f124SMoriah Waterland * 24465c51f124SMoriah Waterland * Arguments: 24475c51f124SMoriah Waterland * pass - password to check 24485c51f124SMoriah Waterland * 24495c51f124SMoriah Waterland * Returns: 24505c51f124SMoriah Waterland * B_TRUE - Password is OK. 24515c51f124SMoriah Waterland * B_FALSE - Password not valid. 24525c51f124SMoriah Waterland */ 24535c51f124SMoriah Waterland static boolean_t 24545c51f124SMoriah Waterland check_password(PKCS12 *p12, char *pass) 24555c51f124SMoriah Waterland { 24565c51f124SMoriah Waterland boolean_t ret = B_TRUE; 24575c51f124SMoriah Waterland 24585c51f124SMoriah Waterland /* 24595c51f124SMoriah Waterland * If password is zero length or NULL then try verifying both cases 24605c51f124SMoriah Waterland * to determine which password is correct. The reason for this is that 24615c51f124SMoriah Waterland * under PKCS#12 password based encryption no password and a zero 24625c51f124SMoriah Waterland * length password are two different things... 24635c51f124SMoriah Waterland */ 24645c51f124SMoriah Waterland 24655c51f124SMoriah Waterland /* Check the mac */ 24665c51f124SMoriah Waterland if (pass == NULL || *pass == '\0') { 24675c51f124SMoriah Waterland if (PKCS12_verify_mac(p12, NULL, 0) == 0 && 24685c51f124SMoriah Waterland PKCS12_verify_mac(p12, "", 0) == 0) 24695c51f124SMoriah Waterland ret = B_FALSE; 24705c51f124SMoriah Waterland } else if (PKCS12_verify_mac(p12, pass, -1) == 0) { 24715c51f124SMoriah Waterland ret = B_FALSE; 24725c51f124SMoriah Waterland } 24735c51f124SMoriah Waterland return (ret); 24745c51f124SMoriah Waterland } 2475