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