xref: /titanic_44/usr/src/lib/libpkg/common/security.c (revision 22ce47f7854e0848adf05feb75b97e65da1c8d8f)
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  }
283