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 }