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                 /* LINTED pointer cast may result in improper alignment */
 114                 ca_cert = sk_X509_value(cas, i);
 115                 if (X509_STORE_add_cert(ca_store, ca_cert) == 0) {
 116                         pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM));
 117                         ret = 1;
 118                         goto cleanup;
 119                 }
 120         }
 121 
 122         /* initialize context object used during the chain resolution */
 123 
 124         if ((store_ctx = X509_STORE_CTX_new()) == NULL) {
 125                 pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM));
 126                 ret = 1;
 127                 goto cleanup;
 128         }
 129 
 130         (void) X509_STORE_CTX_init(store_ctx, ca_store, cert, clcerts);
 131         /* attempt to verify the cert, which builds the cert chain */
 132         if (X509_verify_cert(store_ctx) <= 0) {
 133                 pkgerr_add(err, PKGERR_CHAIN,
 134                     gettext(ERR_CERTCHAIN),
 135                     get_subject_display_name(cert),
 136                     X509_verify_cert_error_string(store_ctx->error));
 137                 ret = 1;
 138                 goto cleanup;
 139         }
 140         *chain = X509_STORE_CTX_get1_chain(store_ctx);
 141 
 142 cleanup:
 143         if (ca_store != NULL)
 144                 (void) X509_STORE_free(ca_store);
 145         if (store_ctx != NULL) {
 146                 (void) X509_STORE_CTX_cleanup(store_ctx);
 147                 (void) X509_STORE_CTX_free(store_ctx);
 148         }
 149 
 150         return (ret);
 151 }
 152 
 153 /*
 154  * Name:                get_subject_name
 155  * Description: Retrieves a name used for identifying a certificate's subject.
 156  *
 157  * Arguments:   cert - The certificate to get the name from
 158  *
 159  * Returns :    A static buffer containing the common name (CN) of the
 160  *              subject of the cert.
 161  *
 162  *              if the CN is not available, returns a string with the entire
 163  * X509 distinguished name.
 164  */
 165 char
 166 *get_subject_display_name(X509 *cert)
 167 {
 168 
 169         X509_NAME       *xname;
 170         static char     sname[ATTR_MAX];
 171 
 172         xname = X509_get_subject_name(cert);
 173         if (X509_NAME_get_text_by_NID(xname,
 174             NID_commonName, sname,
 175             ATTR_MAX) <= 0) {
 176                 (void) strncpy(sname,
 177                     X509_NAME_oneline(xname,
 178                         NULL, 0), ATTR_MAX);
 179                 sname[ATTR_MAX - 1] = '\0';
 180         }
 181         return (sname);
 182 }
 183 
 184 /*
 185  * Name:                get_display_name
 186  * Description: Retrieves a name used for identifying a certificate's issuer.
 187  *
 188  * Arguments:   cert - The certificate to get the name from
 189  *
 190  * Returns :    A static buffer containing the common name (CN)
 191  *              of the issuer of the cert.
 192  *
 193  *              if the CN is not available, returns a string with the entire
 194  *              X509 distinguished name.
 195  */
 196 char
 197 *get_issuer_display_name(X509 *cert)
 198 {
 199 
 200         X509_NAME       *xname;
 201         static char     sname[ATTR_MAX];
 202 
 203         xname = X509_get_issuer_name(cert);
 204         if (X509_NAME_get_text_by_NID(xname,
 205             NID_commonName, sname,
 206             ATTR_MAX) <= 0) {
 207                 (void) strncpy(sname,
 208                     X509_NAME_oneline(xname,
 209                         NULL, 0), ATTR_MAX);
 210                 sname[ATTR_MAX - 1] = '\0';
 211         }
 212         return (sname);
 213 }
 214 
 215 
 216 /*
 217  * Name:                get_serial_num
 218  * Description: Retrieves the serial number of an X509 cert
 219  *
 220  * Arguments:   cert - The certificate to get the data from
 221  *
 222  * Returns :    A static buffer containing the serial number
 223  *              of the cert
 224  *
 225  *              if the SN is not available, returns NULL
 226  */
 227 char
 228 *get_serial_num(X509 *cert)
 229 {
 230         static char      sn_str[ATTR_MAX];
 231         ASN1_INTEGER    *sn;
 232 
 233         if ((sn = X509_get_serialNumber(cert)) != 0) {
 234                 return (NULL);
 235         } else {
 236                 (void) snprintf(sn_str, ATTR_MAX, "%ld",
 237                     ASN1_INTEGER_get(sn));
 238         }
 239 
 240         return (sn_str);
 241 }
 242 
 243 /*
 244  * Name:                get_fingerprint
 245  * Description: Generates a fingerprint string given
 246  *              a digest algorithm with which to calculate
 247  *              the fingerprint
 248  *
 249  * Arguments:   cert - The certificate to get the data from
 250  * Arguments:   alg - The algorithm to use to calculate the fingerprint
 251  *
 252  * Returns :    A static buffer containing the digest
 253  *              NULL if cert is NULL, or digest cannot be calculated
 254  */
 255 char
 256 *get_fingerprint(X509 *cert, const EVP_MD *alg)
 257 {
 258         static char      fp_str[ATTR_MAX];
 259         char             tmp[ATTR_MAX] = "";
 260         unsigned int n;
 261         unsigned char md[EVP_MAX_MD_SIZE];
 262         int i;
 263 
 264         if (!X509_digest(cert, alg, md, &n)) {
 265                 return (NULL);
 266         }
 267 
 268         /* start with empty string */
 269         fp_str[0] = '\0';
 270 
 271         for (i = 0; i < (int)n; i++) {
 272                 /* form a byte of the fingerprint */
 273                 (void) snprintf(tmp, ATTR_MAX, "%02X:", md[i]);
 274                 /* cat it onto the end of the result */
 275                 (void) strlcat(fp_str, tmp, ATTR_MAX);
 276         }
 277 
 278         /* nuke trailing ':' */
 279         fp_str[strlen(fp_str) - 1] = '\0';
 280 
 281         return (fp_str);
 282 }