/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Module: security.c * Description: * Module for handling certificates and various * utilities to access their data. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pkgerr.h" #include "pkglib.h" #include "pkglibmsgs.h" #include "pkglocale.h" #include "p12lib.h" /* length of allowable passwords */ #define MAX_PASSLEN 128 /* * Name: init_security * Description: Initializes structures, libraries, for security operations * Arguments: none * Returns: 0 if we couldn't initialize, non-zero otherwise */ void sec_init(void) { OpenSSL_add_all_algorithms(); SSL_load_error_strings(); ERR_load_SUNW_strings(); (void) SSL_library_init(); } /* * get_cert_chain - Builds a chain of certificates, from a given * user certificate to a trusted certificate. * * Arguments: * err - Error object to add errors to * cert - User cert to start with * cas - Trusted certs to use as trust anchors * chain - The resulting chain of certs (in the form of an * ordered set) is placed here. * * Returns: * 0 - Success - chain is stored in 'chain'. * non-zero - Failure, errors recorded in err */ int get_cert_chain(PKG_ERR *err, X509 *cert, STACK_OF(X509) *clcerts, STACK_OF(X509) *cas, STACK_OF(X509) **chain) { X509_STORE_CTX *store_ctx = NULL; X509_STORE *ca_store = NULL; X509 *ca_cert = NULL; int i; int ret = 0; if ((ca_store = X509_STORE_new()) == NULL) { pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM)); ret = 1; goto cleanup; } /* add all ca certs into the store */ for (i = 0; i < sk_X509_num(cas); i++) { /* LINTED pointer cast may result in improper alignment */ ca_cert = sk_X509_value(cas, i); if (X509_STORE_add_cert(ca_store, ca_cert) == 0) { pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM)); ret = 1; goto cleanup; } } /* initialize context object used during the chain resolution */ if ((store_ctx = X509_STORE_CTX_new()) == NULL) { pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM)); ret = 1; goto cleanup; } (void) X509_STORE_CTX_init(store_ctx, ca_store, cert, clcerts); /* attempt to verify the cert, which builds the cert chain */ if (X509_verify_cert(store_ctx) <= 0) { pkgerr_add(err, PKGERR_CHAIN, gettext(ERR_CERTCHAIN), get_subject_display_name(cert), X509_verify_cert_error_string(store_ctx->error)); ret = 1; goto cleanup; } *chain = X509_STORE_CTX_get1_chain(store_ctx); cleanup: if (ca_store != NULL) (void) X509_STORE_free(ca_store); if (store_ctx != NULL) { (void) X509_STORE_CTX_cleanup(store_ctx); (void) X509_STORE_CTX_free(store_ctx); } return (ret); } /* * Name: get_subject_name * Description: Retrieves a name used for identifying a certificate's subject. * * Arguments: cert - The certificate to get the name from * * Returns : A static buffer containing the common name (CN) of the * subject of the cert. * * if the CN is not available, returns a string with the entire * X509 distinguished name. */ char *get_subject_display_name(X509 *cert) { X509_NAME *xname; static char sname[ATTR_MAX]; xname = X509_get_subject_name(cert); if (X509_NAME_get_text_by_NID(xname, NID_commonName, sname, ATTR_MAX) <= 0) { (void) strncpy(sname, X509_NAME_oneline(xname, NULL, 0), ATTR_MAX); sname[ATTR_MAX - 1] = '\0'; } return (sname); } /* * Name: get_display_name * Description: Retrieves a name used for identifying a certificate's issuer. * * Arguments: cert - The certificate to get the name from * * Returns : A static buffer containing the common name (CN) * of the issuer of the cert. * * if the CN is not available, returns a string with the entire * X509 distinguished name. */ char *get_issuer_display_name(X509 *cert) { X509_NAME *xname; static char sname[ATTR_MAX]; xname = X509_get_issuer_name(cert); if (X509_NAME_get_text_by_NID(xname, NID_commonName, sname, ATTR_MAX) <= 0) { (void) strncpy(sname, X509_NAME_oneline(xname, NULL, 0), ATTR_MAX); sname[ATTR_MAX - 1] = '\0'; } return (sname); } /* * Name: get_serial_num * Description: Retrieves the serial number of an X509 cert * * Arguments: cert - The certificate to get the data from * * Returns : A static buffer containing the serial number * of the cert * * if the SN is not available, returns NULL */ char *get_serial_num(X509 *cert) { static char sn_str[ATTR_MAX]; ASN1_INTEGER *sn; if ((sn = X509_get_serialNumber(cert)) != 0) { return (NULL); } else { (void) snprintf(sn_str, ATTR_MAX, "%ld", ASN1_INTEGER_get(sn)); } return (sn_str); } /* * Name: get_fingerprint * Description: Generates a fingerprint string given * a digest algorithm with which to calculate * the fingerprint * * Arguments: cert - The certificate to get the data from * Arguments: alg - The algorithm to use to calculate the fingerprint * * Returns : A static buffer containing the digest * NULL if cert is NULL, or digest cannot be calculated */ char *get_fingerprint(X509 *cert, const EVP_MD *alg) { static char fp_str[ATTR_MAX]; char tmp[ATTR_MAX] = ""; unsigned int n; unsigned char md[EVP_MAX_MD_SIZE]; int i; if (!X509_digest(cert, alg, md, &n)) { return (NULL); } /* start with empty string */ fp_str[0] = '\0'; for (i = 0; i < (int)n; i++) { /* form a byte of the fingerprint */ (void) snprintf(tmp, ATTR_MAX, "%02X:", md[i]); /* cat it onto the end of the result */ (void) strlcat(fp_str, tmp, ATTR_MAX); } /* nuke trailing ':' */ fp_str[strlen(fp_str) - 1] = '\0'; return (fp_str); }