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