1*9781SMoriah.Waterland@Sun.COM /* 2*9781SMoriah.Waterland@Sun.COM * CDDL HEADER START 3*9781SMoriah.Waterland@Sun.COM * 4*9781SMoriah.Waterland@Sun.COM * The contents of this file are subject to the terms of the 5*9781SMoriah.Waterland@Sun.COM * Common Development and Distribution License (the "License"). 6*9781SMoriah.Waterland@Sun.COM * You may not use this file except in compliance with the License. 7*9781SMoriah.Waterland@Sun.COM * 8*9781SMoriah.Waterland@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*9781SMoriah.Waterland@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*9781SMoriah.Waterland@Sun.COM * See the License for the specific language governing permissions 11*9781SMoriah.Waterland@Sun.COM * and limitations under the License. 12*9781SMoriah.Waterland@Sun.COM * 13*9781SMoriah.Waterland@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*9781SMoriah.Waterland@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*9781SMoriah.Waterland@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*9781SMoriah.Waterland@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*9781SMoriah.Waterland@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*9781SMoriah.Waterland@Sun.COM * 19*9781SMoriah.Waterland@Sun.COM * CDDL HEADER END 20*9781SMoriah.Waterland@Sun.COM */ 21*9781SMoriah.Waterland@Sun.COM 22*9781SMoriah.Waterland@Sun.COM /* 23*9781SMoriah.Waterland@Sun.COM * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 24*9781SMoriah.Waterland@Sun.COM * Use is subject to license terms. 25*9781SMoriah.Waterland@Sun.COM */ 26*9781SMoriah.Waterland@Sun.COM 27*9781SMoriah.Waterland@Sun.COM 28*9781SMoriah.Waterland@Sun.COM /* 29*9781SMoriah.Waterland@Sun.COM * Module: security.c 30*9781SMoriah.Waterland@Sun.COM * Description: 31*9781SMoriah.Waterland@Sun.COM * Module for handling certificates and various 32*9781SMoriah.Waterland@Sun.COM * utilities to access their data. 33*9781SMoriah.Waterland@Sun.COM */ 34*9781SMoriah.Waterland@Sun.COM 35*9781SMoriah.Waterland@Sun.COM #include <stdio.h> 36*9781SMoriah.Waterland@Sun.COM #include <string.h> 37*9781SMoriah.Waterland@Sun.COM #include <errno.h> 38*9781SMoriah.Waterland@Sun.COM #include <ctype.h> 39*9781SMoriah.Waterland@Sun.COM #include <sys/types.h> 40*9781SMoriah.Waterland@Sun.COM #include <sys/stat.h> 41*9781SMoriah.Waterland@Sun.COM #include <limits.h> 42*9781SMoriah.Waterland@Sun.COM #include <pkgstrct.h> 43*9781SMoriah.Waterland@Sun.COM #include <pkginfo.h> 44*9781SMoriah.Waterland@Sun.COM #include <locale.h> 45*9781SMoriah.Waterland@Sun.COM #include <libintl.h> 46*9781SMoriah.Waterland@Sun.COM #include <unistd.h> 47*9781SMoriah.Waterland@Sun.COM #include <stdlib.h> 48*9781SMoriah.Waterland@Sun.COM 49*9781SMoriah.Waterland@Sun.COM #include <openssl/bio.h> 50*9781SMoriah.Waterland@Sun.COM #include <openssl/pkcs12.h> 51*9781SMoriah.Waterland@Sun.COM #include <openssl/pkcs7.h> 52*9781SMoriah.Waterland@Sun.COM #include <openssl/x509.h> 53*9781SMoriah.Waterland@Sun.COM #include <openssl/err.h> 54*9781SMoriah.Waterland@Sun.COM #include <openssl/ssl.h> 55*9781SMoriah.Waterland@Sun.COM #include "pkgerr.h" 56*9781SMoriah.Waterland@Sun.COM #include "pkglib.h" 57*9781SMoriah.Waterland@Sun.COM #include "pkglibmsgs.h" 58*9781SMoriah.Waterland@Sun.COM #include "pkglocale.h" 59*9781SMoriah.Waterland@Sun.COM #include "p12lib.h" 60*9781SMoriah.Waterland@Sun.COM 61*9781SMoriah.Waterland@Sun.COM /* length of allowable passwords */ 62*9781SMoriah.Waterland@Sun.COM #define MAX_PASSLEN 128 63*9781SMoriah.Waterland@Sun.COM 64*9781SMoriah.Waterland@Sun.COM /* 65*9781SMoriah.Waterland@Sun.COM * Name: init_security 66*9781SMoriah.Waterland@Sun.COM * Description: Initializes structures, libraries, for security operations 67*9781SMoriah.Waterland@Sun.COM * Arguments: none 68*9781SMoriah.Waterland@Sun.COM * Returns: 0 if we couldn't initialize, non-zero otherwise 69*9781SMoriah.Waterland@Sun.COM */ 70*9781SMoriah.Waterland@Sun.COM void 71*9781SMoriah.Waterland@Sun.COM sec_init(void) 72*9781SMoriah.Waterland@Sun.COM { 73*9781SMoriah.Waterland@Sun.COM OpenSSL_add_all_algorithms(); 74*9781SMoriah.Waterland@Sun.COM SSL_load_error_strings(); 75*9781SMoriah.Waterland@Sun.COM ERR_load_SUNW_strings(); 76*9781SMoriah.Waterland@Sun.COM (void) SSL_library_init(); 77*9781SMoriah.Waterland@Sun.COM } 78*9781SMoriah.Waterland@Sun.COM 79*9781SMoriah.Waterland@Sun.COM /* 80*9781SMoriah.Waterland@Sun.COM * get_cert_chain - Builds a chain of certificates, from a given 81*9781SMoriah.Waterland@Sun.COM * user certificate to a trusted certificate. 82*9781SMoriah.Waterland@Sun.COM * 83*9781SMoriah.Waterland@Sun.COM * Arguments: 84*9781SMoriah.Waterland@Sun.COM * err - Error object to add errors to 85*9781SMoriah.Waterland@Sun.COM * cert - User cert to start with 86*9781SMoriah.Waterland@Sun.COM * cas - Trusted certs to use as trust anchors 87*9781SMoriah.Waterland@Sun.COM * chain - The resulting chain of certs (in the form of an 88*9781SMoriah.Waterland@Sun.COM * ordered set) is placed here. 89*9781SMoriah.Waterland@Sun.COM * 90*9781SMoriah.Waterland@Sun.COM * Returns: 91*9781SMoriah.Waterland@Sun.COM * 0 - Success - chain is stored in 'chain'. 92*9781SMoriah.Waterland@Sun.COM * non-zero - Failure, errors recorded in err 93*9781SMoriah.Waterland@Sun.COM */ 94*9781SMoriah.Waterland@Sun.COM int 95*9781SMoriah.Waterland@Sun.COM get_cert_chain(PKG_ERR *err, X509 *cert, STACK_OF(X509) *clcerts, 96*9781SMoriah.Waterland@Sun.COM STACK_OF(X509) *cas, STACK_OF(X509) **chain) 97*9781SMoriah.Waterland@Sun.COM { 98*9781SMoriah.Waterland@Sun.COM X509_STORE_CTX *store_ctx = NULL; 99*9781SMoriah.Waterland@Sun.COM X509_STORE *ca_store = NULL; 100*9781SMoriah.Waterland@Sun.COM X509 *ca_cert = NULL; 101*9781SMoriah.Waterland@Sun.COM int i; 102*9781SMoriah.Waterland@Sun.COM int ret = 0; 103*9781SMoriah.Waterland@Sun.COM 104*9781SMoriah.Waterland@Sun.COM if ((ca_store = X509_STORE_new()) == NULL) { 105*9781SMoriah.Waterland@Sun.COM pkgerr_add(err, PKGERR_NOMEM, 106*9781SMoriah.Waterland@Sun.COM gettext(ERR_MEM)); 107*9781SMoriah.Waterland@Sun.COM ret = 1; 108*9781SMoriah.Waterland@Sun.COM goto cleanup; 109*9781SMoriah.Waterland@Sun.COM } 110*9781SMoriah.Waterland@Sun.COM 111*9781SMoriah.Waterland@Sun.COM /* add all ca certs into the store */ 112*9781SMoriah.Waterland@Sun.COM for (i = 0; i < sk_X509_num(cas); i++) { 113*9781SMoriah.Waterland@Sun.COM /* LINTED pointer cast may result in improper alignment */ 114*9781SMoriah.Waterland@Sun.COM ca_cert = sk_X509_value(cas, i); 115*9781SMoriah.Waterland@Sun.COM if (X509_STORE_add_cert(ca_store, ca_cert) == 0) { 116*9781SMoriah.Waterland@Sun.COM pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM)); 117*9781SMoriah.Waterland@Sun.COM ret = 1; 118*9781SMoriah.Waterland@Sun.COM goto cleanup; 119*9781SMoriah.Waterland@Sun.COM } 120*9781SMoriah.Waterland@Sun.COM } 121*9781SMoriah.Waterland@Sun.COM 122*9781SMoriah.Waterland@Sun.COM /* initialize context object used during the chain resolution */ 123*9781SMoriah.Waterland@Sun.COM 124*9781SMoriah.Waterland@Sun.COM if ((store_ctx = X509_STORE_CTX_new()) == NULL) { 125*9781SMoriah.Waterland@Sun.COM pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM)); 126*9781SMoriah.Waterland@Sun.COM ret = 1; 127*9781SMoriah.Waterland@Sun.COM goto cleanup; 128*9781SMoriah.Waterland@Sun.COM } 129*9781SMoriah.Waterland@Sun.COM 130*9781SMoriah.Waterland@Sun.COM (void) X509_STORE_CTX_init(store_ctx, ca_store, cert, clcerts); 131*9781SMoriah.Waterland@Sun.COM /* attempt to verify the cert, which builds the cert chain */ 132*9781SMoriah.Waterland@Sun.COM if (X509_verify_cert(store_ctx) <= 0) { 133*9781SMoriah.Waterland@Sun.COM pkgerr_add(err, PKGERR_CHAIN, 134*9781SMoriah.Waterland@Sun.COM gettext(ERR_CERTCHAIN), 135*9781SMoriah.Waterland@Sun.COM get_subject_display_name(cert), 136*9781SMoriah.Waterland@Sun.COM X509_verify_cert_error_string(store_ctx->error)); 137*9781SMoriah.Waterland@Sun.COM ret = 1; 138*9781SMoriah.Waterland@Sun.COM goto cleanup; 139*9781SMoriah.Waterland@Sun.COM } 140*9781SMoriah.Waterland@Sun.COM *chain = X509_STORE_CTX_get1_chain(store_ctx); 141*9781SMoriah.Waterland@Sun.COM 142*9781SMoriah.Waterland@Sun.COM cleanup: 143*9781SMoriah.Waterland@Sun.COM if (ca_store != NULL) 144*9781SMoriah.Waterland@Sun.COM (void) X509_STORE_free(ca_store); 145*9781SMoriah.Waterland@Sun.COM if (store_ctx != NULL) { 146*9781SMoriah.Waterland@Sun.COM (void) X509_STORE_CTX_cleanup(store_ctx); 147*9781SMoriah.Waterland@Sun.COM (void) X509_STORE_CTX_free(store_ctx); 148*9781SMoriah.Waterland@Sun.COM } 149*9781SMoriah.Waterland@Sun.COM 150*9781SMoriah.Waterland@Sun.COM return (ret); 151*9781SMoriah.Waterland@Sun.COM } 152*9781SMoriah.Waterland@Sun.COM 153*9781SMoriah.Waterland@Sun.COM /* 154*9781SMoriah.Waterland@Sun.COM * Name: get_subject_name 155*9781SMoriah.Waterland@Sun.COM * Description: Retrieves a name used for identifying a certificate's subject. 156*9781SMoriah.Waterland@Sun.COM * 157*9781SMoriah.Waterland@Sun.COM * Arguments: cert - The certificate to get the name from 158*9781SMoriah.Waterland@Sun.COM * 159*9781SMoriah.Waterland@Sun.COM * Returns : A static buffer containing the common name (CN) of the 160*9781SMoriah.Waterland@Sun.COM * subject of the cert. 161*9781SMoriah.Waterland@Sun.COM * 162*9781SMoriah.Waterland@Sun.COM * if the CN is not available, returns a string with the entire 163*9781SMoriah.Waterland@Sun.COM * X509 distinguished name. 164*9781SMoriah.Waterland@Sun.COM */ 165*9781SMoriah.Waterland@Sun.COM char 166*9781SMoriah.Waterland@Sun.COM *get_subject_display_name(X509 *cert) 167*9781SMoriah.Waterland@Sun.COM { 168*9781SMoriah.Waterland@Sun.COM 169*9781SMoriah.Waterland@Sun.COM X509_NAME *xname; 170*9781SMoriah.Waterland@Sun.COM static char sname[ATTR_MAX]; 171*9781SMoriah.Waterland@Sun.COM 172*9781SMoriah.Waterland@Sun.COM xname = X509_get_subject_name(cert); 173*9781SMoriah.Waterland@Sun.COM if (X509_NAME_get_text_by_NID(xname, 174*9781SMoriah.Waterland@Sun.COM NID_commonName, sname, 175*9781SMoriah.Waterland@Sun.COM ATTR_MAX) <= 0) { 176*9781SMoriah.Waterland@Sun.COM (void) strncpy(sname, 177*9781SMoriah.Waterland@Sun.COM X509_NAME_oneline(xname, 178*9781SMoriah.Waterland@Sun.COM NULL, 0), ATTR_MAX); 179*9781SMoriah.Waterland@Sun.COM sname[ATTR_MAX - 1] = '\0'; 180*9781SMoriah.Waterland@Sun.COM } 181*9781SMoriah.Waterland@Sun.COM return (sname); 182*9781SMoriah.Waterland@Sun.COM } 183*9781SMoriah.Waterland@Sun.COM 184*9781SMoriah.Waterland@Sun.COM /* 185*9781SMoriah.Waterland@Sun.COM * Name: get_display_name 186*9781SMoriah.Waterland@Sun.COM * Description: Retrieves a name used for identifying a certificate's issuer. 187*9781SMoriah.Waterland@Sun.COM * 188*9781SMoriah.Waterland@Sun.COM * Arguments: cert - The certificate to get the name from 189*9781SMoriah.Waterland@Sun.COM * 190*9781SMoriah.Waterland@Sun.COM * Returns : A static buffer containing the common name (CN) 191*9781SMoriah.Waterland@Sun.COM * of the issuer of the cert. 192*9781SMoriah.Waterland@Sun.COM * 193*9781SMoriah.Waterland@Sun.COM * if the CN is not available, returns a string with the entire 194*9781SMoriah.Waterland@Sun.COM * X509 distinguished name. 195*9781SMoriah.Waterland@Sun.COM */ 196*9781SMoriah.Waterland@Sun.COM char 197*9781SMoriah.Waterland@Sun.COM *get_issuer_display_name(X509 *cert) 198*9781SMoriah.Waterland@Sun.COM { 199*9781SMoriah.Waterland@Sun.COM 200*9781SMoriah.Waterland@Sun.COM X509_NAME *xname; 201*9781SMoriah.Waterland@Sun.COM static char sname[ATTR_MAX]; 202*9781SMoriah.Waterland@Sun.COM 203*9781SMoriah.Waterland@Sun.COM xname = X509_get_issuer_name(cert); 204*9781SMoriah.Waterland@Sun.COM if (X509_NAME_get_text_by_NID(xname, 205*9781SMoriah.Waterland@Sun.COM NID_commonName, sname, 206*9781SMoriah.Waterland@Sun.COM ATTR_MAX) <= 0) { 207*9781SMoriah.Waterland@Sun.COM (void) strncpy(sname, 208*9781SMoriah.Waterland@Sun.COM X509_NAME_oneline(xname, 209*9781SMoriah.Waterland@Sun.COM NULL, 0), ATTR_MAX); 210*9781SMoriah.Waterland@Sun.COM sname[ATTR_MAX - 1] = '\0'; 211*9781SMoriah.Waterland@Sun.COM } 212*9781SMoriah.Waterland@Sun.COM return (sname); 213*9781SMoriah.Waterland@Sun.COM } 214*9781SMoriah.Waterland@Sun.COM 215*9781SMoriah.Waterland@Sun.COM 216*9781SMoriah.Waterland@Sun.COM /* 217*9781SMoriah.Waterland@Sun.COM * Name: get_serial_num 218*9781SMoriah.Waterland@Sun.COM * Description: Retrieves the serial number of an X509 cert 219*9781SMoriah.Waterland@Sun.COM * 220*9781SMoriah.Waterland@Sun.COM * Arguments: cert - The certificate to get the data from 221*9781SMoriah.Waterland@Sun.COM * 222*9781SMoriah.Waterland@Sun.COM * Returns : A static buffer containing the serial number 223*9781SMoriah.Waterland@Sun.COM * of the cert 224*9781SMoriah.Waterland@Sun.COM * 225*9781SMoriah.Waterland@Sun.COM * if the SN is not available, returns NULL 226*9781SMoriah.Waterland@Sun.COM */ 227*9781SMoriah.Waterland@Sun.COM char 228*9781SMoriah.Waterland@Sun.COM *get_serial_num(X509 *cert) 229*9781SMoriah.Waterland@Sun.COM { 230*9781SMoriah.Waterland@Sun.COM static char sn_str[ATTR_MAX]; 231*9781SMoriah.Waterland@Sun.COM ASN1_INTEGER *sn; 232*9781SMoriah.Waterland@Sun.COM 233*9781SMoriah.Waterland@Sun.COM if ((sn = X509_get_serialNumber(cert)) != 0) { 234*9781SMoriah.Waterland@Sun.COM return (NULL); 235*9781SMoriah.Waterland@Sun.COM } else { 236*9781SMoriah.Waterland@Sun.COM (void) snprintf(sn_str, ATTR_MAX, "%ld", 237*9781SMoriah.Waterland@Sun.COM ASN1_INTEGER_get(sn)); 238*9781SMoriah.Waterland@Sun.COM } 239*9781SMoriah.Waterland@Sun.COM 240*9781SMoriah.Waterland@Sun.COM return (sn_str); 241*9781SMoriah.Waterland@Sun.COM } 242*9781SMoriah.Waterland@Sun.COM 243*9781SMoriah.Waterland@Sun.COM /* 244*9781SMoriah.Waterland@Sun.COM * Name: get_fingerprint 245*9781SMoriah.Waterland@Sun.COM * Description: Generates a fingerprint string given 246*9781SMoriah.Waterland@Sun.COM * a digest algorithm with which to calculate 247*9781SMoriah.Waterland@Sun.COM * the fingerprint 248*9781SMoriah.Waterland@Sun.COM * 249*9781SMoriah.Waterland@Sun.COM * Arguments: cert - The certificate to get the data from 250*9781SMoriah.Waterland@Sun.COM * Arguments: alg - The algorithm to use to calculate the fingerprint 251*9781SMoriah.Waterland@Sun.COM * 252*9781SMoriah.Waterland@Sun.COM * Returns : A static buffer containing the digest 253*9781SMoriah.Waterland@Sun.COM * NULL if cert is NULL, or digest cannot be calculated 254*9781SMoriah.Waterland@Sun.COM */ 255*9781SMoriah.Waterland@Sun.COM char 256*9781SMoriah.Waterland@Sun.COM *get_fingerprint(X509 *cert, const EVP_MD *alg) 257*9781SMoriah.Waterland@Sun.COM { 258*9781SMoriah.Waterland@Sun.COM static char fp_str[ATTR_MAX]; 259*9781SMoriah.Waterland@Sun.COM char tmp[ATTR_MAX] = ""; 260*9781SMoriah.Waterland@Sun.COM unsigned int n; 261*9781SMoriah.Waterland@Sun.COM unsigned char md[EVP_MAX_MD_SIZE]; 262*9781SMoriah.Waterland@Sun.COM int i; 263*9781SMoriah.Waterland@Sun.COM 264*9781SMoriah.Waterland@Sun.COM if (!X509_digest(cert, alg, md, &n)) { 265*9781SMoriah.Waterland@Sun.COM return (NULL); 266*9781SMoriah.Waterland@Sun.COM } 267*9781SMoriah.Waterland@Sun.COM 268*9781SMoriah.Waterland@Sun.COM /* start with empty string */ 269*9781SMoriah.Waterland@Sun.COM fp_str[0] = '\0'; 270*9781SMoriah.Waterland@Sun.COM 271*9781SMoriah.Waterland@Sun.COM for (i = 0; i < (int)n; i++) { 272*9781SMoriah.Waterland@Sun.COM /* form a byte of the fingerprint */ 273*9781SMoriah.Waterland@Sun.COM (void) snprintf(tmp, ATTR_MAX, "%02X:", md[i]); 274*9781SMoriah.Waterland@Sun.COM /* cat it onto the end of the result */ 275*9781SMoriah.Waterland@Sun.COM (void) strlcat(fp_str, tmp, ATTR_MAX); 276*9781SMoriah.Waterland@Sun.COM } 277*9781SMoriah.Waterland@Sun.COM 278*9781SMoriah.Waterland@Sun.COM /* nuke trailing ':' */ 279*9781SMoriah.Waterland@Sun.COM fp_str[strlen(fp_str) - 1] = '\0'; 280*9781SMoriah.Waterland@Sun.COM 281*9781SMoriah.Waterland@Sun.COM return (fp_str); 282*9781SMoriah.Waterland@Sun.COM } 283