1*9781SMoriah.Waterland@Sun.COM /*
2*9781SMoriah.Waterland@Sun.COM * CDDL HEADER START
3*9781SMoriah.Waterland@Sun.COM *
4*9781SMoriah.Waterland@Sun.COM * The contents of this file are subject to the terms of the
5*9781SMoriah.Waterland@Sun.COM * Common Development and Distribution License (the "License").
6*9781SMoriah.Waterland@Sun.COM * You may not use this file except in compliance with the License.
7*9781SMoriah.Waterland@Sun.COM *
8*9781SMoriah.Waterland@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*9781SMoriah.Waterland@Sun.COM * or http://www.opensolaris.org/os/licensing.
10*9781SMoriah.Waterland@Sun.COM * See the License for the specific language governing permissions
11*9781SMoriah.Waterland@Sun.COM * and limitations under the License.
12*9781SMoriah.Waterland@Sun.COM *
13*9781SMoriah.Waterland@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
14*9781SMoriah.Waterland@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*9781SMoriah.Waterland@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
16*9781SMoriah.Waterland@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
17*9781SMoriah.Waterland@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
18*9781SMoriah.Waterland@Sun.COM *
19*9781SMoriah.Waterland@Sun.COM * CDDL HEADER END
20*9781SMoriah.Waterland@Sun.COM */
21*9781SMoriah.Waterland@Sun.COM
22*9781SMoriah.Waterland@Sun.COM /*
23*9781SMoriah.Waterland@Sun.COM * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24*9781SMoriah.Waterland@Sun.COM * Use is subject to license terms.
25*9781SMoriah.Waterland@Sun.COM */
26*9781SMoriah.Waterland@Sun.COM
27*9781SMoriah.Waterland@Sun.COM
28*9781SMoriah.Waterland@Sun.COM /*
29*9781SMoriah.Waterland@Sun.COM * Module: security.c
30*9781SMoriah.Waterland@Sun.COM * Description:
31*9781SMoriah.Waterland@Sun.COM * Module for handling certificates and various
32*9781SMoriah.Waterland@Sun.COM * utilities to access their data.
33*9781SMoriah.Waterland@Sun.COM */
34*9781SMoriah.Waterland@Sun.COM
35*9781SMoriah.Waterland@Sun.COM #include <stdio.h>
36*9781SMoriah.Waterland@Sun.COM #include <string.h>
37*9781SMoriah.Waterland@Sun.COM #include <errno.h>
38*9781SMoriah.Waterland@Sun.COM #include <ctype.h>
39*9781SMoriah.Waterland@Sun.COM #include <sys/types.h>
40*9781SMoriah.Waterland@Sun.COM #include <sys/stat.h>
41*9781SMoriah.Waterland@Sun.COM #include <limits.h>
42*9781SMoriah.Waterland@Sun.COM #include <pkgstrct.h>
43*9781SMoriah.Waterland@Sun.COM #include <pkginfo.h>
44*9781SMoriah.Waterland@Sun.COM #include <locale.h>
45*9781SMoriah.Waterland@Sun.COM #include <libintl.h>
46*9781SMoriah.Waterland@Sun.COM #include <unistd.h>
47*9781SMoriah.Waterland@Sun.COM #include <stdlib.h>
48*9781SMoriah.Waterland@Sun.COM
49*9781SMoriah.Waterland@Sun.COM #include <openssl/bio.h>
50*9781SMoriah.Waterland@Sun.COM #include <openssl/pkcs12.h>
51*9781SMoriah.Waterland@Sun.COM #include <openssl/pkcs7.h>
52*9781SMoriah.Waterland@Sun.COM #include <openssl/x509.h>
53*9781SMoriah.Waterland@Sun.COM #include <openssl/err.h>
54*9781SMoriah.Waterland@Sun.COM #include <openssl/ssl.h>
55*9781SMoriah.Waterland@Sun.COM #include "pkgerr.h"
56*9781SMoriah.Waterland@Sun.COM #include "pkglib.h"
57*9781SMoriah.Waterland@Sun.COM #include "pkglibmsgs.h"
58*9781SMoriah.Waterland@Sun.COM #include "pkglocale.h"
59*9781SMoriah.Waterland@Sun.COM #include "p12lib.h"
60*9781SMoriah.Waterland@Sun.COM
61*9781SMoriah.Waterland@Sun.COM /* length of allowable passwords */
62*9781SMoriah.Waterland@Sun.COM #define MAX_PASSLEN 128
63*9781SMoriah.Waterland@Sun.COM
64*9781SMoriah.Waterland@Sun.COM /*
65*9781SMoriah.Waterland@Sun.COM * Name: init_security
66*9781SMoriah.Waterland@Sun.COM * Description: Initializes structures, libraries, for security operations
67*9781SMoriah.Waterland@Sun.COM * Arguments: none
68*9781SMoriah.Waterland@Sun.COM * Returns: 0 if we couldn't initialize, non-zero otherwise
69*9781SMoriah.Waterland@Sun.COM */
70*9781SMoriah.Waterland@Sun.COM void
sec_init(void)71*9781SMoriah.Waterland@Sun.COM sec_init(void)
72*9781SMoriah.Waterland@Sun.COM {
73*9781SMoriah.Waterland@Sun.COM OpenSSL_add_all_algorithms();
74*9781SMoriah.Waterland@Sun.COM SSL_load_error_strings();
75*9781SMoriah.Waterland@Sun.COM ERR_load_SUNW_strings();
76*9781SMoriah.Waterland@Sun.COM (void) SSL_library_init();
77*9781SMoriah.Waterland@Sun.COM }
78*9781SMoriah.Waterland@Sun.COM
79*9781SMoriah.Waterland@Sun.COM /*
80*9781SMoriah.Waterland@Sun.COM * get_cert_chain - Builds a chain of certificates, from a given
81*9781SMoriah.Waterland@Sun.COM * user certificate to a trusted certificate.
82*9781SMoriah.Waterland@Sun.COM *
83*9781SMoriah.Waterland@Sun.COM * Arguments:
84*9781SMoriah.Waterland@Sun.COM * err - Error object to add errors to
85*9781SMoriah.Waterland@Sun.COM * cert - User cert to start with
86*9781SMoriah.Waterland@Sun.COM * cas - Trusted certs to use as trust anchors
87*9781SMoriah.Waterland@Sun.COM * chain - The resulting chain of certs (in the form of an
88*9781SMoriah.Waterland@Sun.COM * ordered set) is placed here.
89*9781SMoriah.Waterland@Sun.COM *
90*9781SMoriah.Waterland@Sun.COM * Returns:
91*9781SMoriah.Waterland@Sun.COM * 0 - Success - chain is stored in 'chain'.
92*9781SMoriah.Waterland@Sun.COM * non-zero - Failure, errors recorded in err
93*9781SMoriah.Waterland@Sun.COM */
94*9781SMoriah.Waterland@Sun.COM int
get_cert_chain(PKG_ERR * err,X509 * cert,STACK_OF (X509)* clcerts,STACK_OF (X509)* cas,STACK_OF (X509)** chain)95*9781SMoriah.Waterland@Sun.COM get_cert_chain(PKG_ERR *err, X509 *cert, STACK_OF(X509) *clcerts,
96*9781SMoriah.Waterland@Sun.COM STACK_OF(X509) *cas, STACK_OF(X509) **chain)
97*9781SMoriah.Waterland@Sun.COM {
98*9781SMoriah.Waterland@Sun.COM X509_STORE_CTX *store_ctx = NULL;
99*9781SMoriah.Waterland@Sun.COM X509_STORE *ca_store = NULL;
100*9781SMoriah.Waterland@Sun.COM X509 *ca_cert = NULL;
101*9781SMoriah.Waterland@Sun.COM int i;
102*9781SMoriah.Waterland@Sun.COM int ret = 0;
103*9781SMoriah.Waterland@Sun.COM
104*9781SMoriah.Waterland@Sun.COM if ((ca_store = X509_STORE_new()) == NULL) {
105*9781SMoriah.Waterland@Sun.COM pkgerr_add(err, PKGERR_NOMEM,
106*9781SMoriah.Waterland@Sun.COM gettext(ERR_MEM));
107*9781SMoriah.Waterland@Sun.COM ret = 1;
108*9781SMoriah.Waterland@Sun.COM goto cleanup;
109*9781SMoriah.Waterland@Sun.COM }
110*9781SMoriah.Waterland@Sun.COM
111*9781SMoriah.Waterland@Sun.COM /* add all ca certs into the store */
112*9781SMoriah.Waterland@Sun.COM for (i = 0; i < sk_X509_num(cas); i++) {
113*9781SMoriah.Waterland@Sun.COM /* LINTED pointer cast may result in improper alignment */
114*9781SMoriah.Waterland@Sun.COM ca_cert = sk_X509_value(cas, i);
115*9781SMoriah.Waterland@Sun.COM if (X509_STORE_add_cert(ca_store, ca_cert) == 0) {
116*9781SMoriah.Waterland@Sun.COM pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM));
117*9781SMoriah.Waterland@Sun.COM ret = 1;
118*9781SMoriah.Waterland@Sun.COM goto cleanup;
119*9781SMoriah.Waterland@Sun.COM }
120*9781SMoriah.Waterland@Sun.COM }
121*9781SMoriah.Waterland@Sun.COM
122*9781SMoriah.Waterland@Sun.COM /* initialize context object used during the chain resolution */
123*9781SMoriah.Waterland@Sun.COM
124*9781SMoriah.Waterland@Sun.COM if ((store_ctx = X509_STORE_CTX_new()) == NULL) {
125*9781SMoriah.Waterland@Sun.COM pkgerr_add(err, PKGERR_NOMEM, gettext(ERR_MEM));
126*9781SMoriah.Waterland@Sun.COM ret = 1;
127*9781SMoriah.Waterland@Sun.COM goto cleanup;
128*9781SMoriah.Waterland@Sun.COM }
129*9781SMoriah.Waterland@Sun.COM
130*9781SMoriah.Waterland@Sun.COM (void) X509_STORE_CTX_init(store_ctx, ca_store, cert, clcerts);
131*9781SMoriah.Waterland@Sun.COM /* attempt to verify the cert, which builds the cert chain */
132*9781SMoriah.Waterland@Sun.COM if (X509_verify_cert(store_ctx) <= 0) {
133*9781SMoriah.Waterland@Sun.COM pkgerr_add(err, PKGERR_CHAIN,
134*9781SMoriah.Waterland@Sun.COM gettext(ERR_CERTCHAIN),
135*9781SMoriah.Waterland@Sun.COM get_subject_display_name(cert),
136*9781SMoriah.Waterland@Sun.COM X509_verify_cert_error_string(store_ctx->error));
137*9781SMoriah.Waterland@Sun.COM ret = 1;
138*9781SMoriah.Waterland@Sun.COM goto cleanup;
139*9781SMoriah.Waterland@Sun.COM }
140*9781SMoriah.Waterland@Sun.COM *chain = X509_STORE_CTX_get1_chain(store_ctx);
141*9781SMoriah.Waterland@Sun.COM
142*9781SMoriah.Waterland@Sun.COM cleanup:
143*9781SMoriah.Waterland@Sun.COM if (ca_store != NULL)
144*9781SMoriah.Waterland@Sun.COM (void) X509_STORE_free(ca_store);
145*9781SMoriah.Waterland@Sun.COM if (store_ctx != NULL) {
146*9781SMoriah.Waterland@Sun.COM (void) X509_STORE_CTX_cleanup(store_ctx);
147*9781SMoriah.Waterland@Sun.COM (void) X509_STORE_CTX_free(store_ctx);
148*9781SMoriah.Waterland@Sun.COM }
149*9781SMoriah.Waterland@Sun.COM
150*9781SMoriah.Waterland@Sun.COM return (ret);
151*9781SMoriah.Waterland@Sun.COM }
152*9781SMoriah.Waterland@Sun.COM
153*9781SMoriah.Waterland@Sun.COM /*
154*9781SMoriah.Waterland@Sun.COM * Name: get_subject_name
155*9781SMoriah.Waterland@Sun.COM * Description: Retrieves a name used for identifying a certificate's subject.
156*9781SMoriah.Waterland@Sun.COM *
157*9781SMoriah.Waterland@Sun.COM * Arguments: cert - The certificate to get the name from
158*9781SMoriah.Waterland@Sun.COM *
159*9781SMoriah.Waterland@Sun.COM * Returns : A static buffer containing the common name (CN) of the
160*9781SMoriah.Waterland@Sun.COM * subject of the cert.
161*9781SMoriah.Waterland@Sun.COM *
162*9781SMoriah.Waterland@Sun.COM * if the CN is not available, returns a string with the entire
163*9781SMoriah.Waterland@Sun.COM * X509 distinguished name.
164*9781SMoriah.Waterland@Sun.COM */
165*9781SMoriah.Waterland@Sun.COM char
get_subject_display_name(X509 * cert)166*9781SMoriah.Waterland@Sun.COM *get_subject_display_name(X509 *cert)
167*9781SMoriah.Waterland@Sun.COM {
168*9781SMoriah.Waterland@Sun.COM
169*9781SMoriah.Waterland@Sun.COM X509_NAME *xname;
170*9781SMoriah.Waterland@Sun.COM static char sname[ATTR_MAX];
171*9781SMoriah.Waterland@Sun.COM
172*9781SMoriah.Waterland@Sun.COM xname = X509_get_subject_name(cert);
173*9781SMoriah.Waterland@Sun.COM if (X509_NAME_get_text_by_NID(xname,
174*9781SMoriah.Waterland@Sun.COM NID_commonName, sname,
175*9781SMoriah.Waterland@Sun.COM ATTR_MAX) <= 0) {
176*9781SMoriah.Waterland@Sun.COM (void) strncpy(sname,
177*9781SMoriah.Waterland@Sun.COM X509_NAME_oneline(xname,
178*9781SMoriah.Waterland@Sun.COM NULL, 0), ATTR_MAX);
179*9781SMoriah.Waterland@Sun.COM sname[ATTR_MAX - 1] = '\0';
180*9781SMoriah.Waterland@Sun.COM }
181*9781SMoriah.Waterland@Sun.COM return (sname);
182*9781SMoriah.Waterland@Sun.COM }
183*9781SMoriah.Waterland@Sun.COM
184*9781SMoriah.Waterland@Sun.COM /*
185*9781SMoriah.Waterland@Sun.COM * Name: get_display_name
186*9781SMoriah.Waterland@Sun.COM * Description: Retrieves a name used for identifying a certificate's issuer.
187*9781SMoriah.Waterland@Sun.COM *
188*9781SMoriah.Waterland@Sun.COM * Arguments: cert - The certificate to get the name from
189*9781SMoriah.Waterland@Sun.COM *
190*9781SMoriah.Waterland@Sun.COM * Returns : A static buffer containing the common name (CN)
191*9781SMoriah.Waterland@Sun.COM * of the issuer of the cert.
192*9781SMoriah.Waterland@Sun.COM *
193*9781SMoriah.Waterland@Sun.COM * if the CN is not available, returns a string with the entire
194*9781SMoriah.Waterland@Sun.COM * X509 distinguished name.
195*9781SMoriah.Waterland@Sun.COM */
196*9781SMoriah.Waterland@Sun.COM char
get_issuer_display_name(X509 * cert)197*9781SMoriah.Waterland@Sun.COM *get_issuer_display_name(X509 *cert)
198*9781SMoriah.Waterland@Sun.COM {
199*9781SMoriah.Waterland@Sun.COM
200*9781SMoriah.Waterland@Sun.COM X509_NAME *xname;
201*9781SMoriah.Waterland@Sun.COM static char sname[ATTR_MAX];
202*9781SMoriah.Waterland@Sun.COM
203*9781SMoriah.Waterland@Sun.COM xname = X509_get_issuer_name(cert);
204*9781SMoriah.Waterland@Sun.COM if (X509_NAME_get_text_by_NID(xname,
205*9781SMoriah.Waterland@Sun.COM NID_commonName, sname,
206*9781SMoriah.Waterland@Sun.COM ATTR_MAX) <= 0) {
207*9781SMoriah.Waterland@Sun.COM (void) strncpy(sname,
208*9781SMoriah.Waterland@Sun.COM X509_NAME_oneline(xname,
209*9781SMoriah.Waterland@Sun.COM NULL, 0), ATTR_MAX);
210*9781SMoriah.Waterland@Sun.COM sname[ATTR_MAX - 1] = '\0';
211*9781SMoriah.Waterland@Sun.COM }
212*9781SMoriah.Waterland@Sun.COM return (sname);
213*9781SMoriah.Waterland@Sun.COM }
214*9781SMoriah.Waterland@Sun.COM
215*9781SMoriah.Waterland@Sun.COM
216*9781SMoriah.Waterland@Sun.COM /*
217*9781SMoriah.Waterland@Sun.COM * Name: get_serial_num
218*9781SMoriah.Waterland@Sun.COM * Description: Retrieves the serial number of an X509 cert
219*9781SMoriah.Waterland@Sun.COM *
220*9781SMoriah.Waterland@Sun.COM * Arguments: cert - The certificate to get the data from
221*9781SMoriah.Waterland@Sun.COM *
222*9781SMoriah.Waterland@Sun.COM * Returns : A static buffer containing the serial number
223*9781SMoriah.Waterland@Sun.COM * of the cert
224*9781SMoriah.Waterland@Sun.COM *
225*9781SMoriah.Waterland@Sun.COM * if the SN is not available, returns NULL
226*9781SMoriah.Waterland@Sun.COM */
227*9781SMoriah.Waterland@Sun.COM char
get_serial_num(X509 * cert)228*9781SMoriah.Waterland@Sun.COM *get_serial_num(X509 *cert)
229*9781SMoriah.Waterland@Sun.COM {
230*9781SMoriah.Waterland@Sun.COM static char sn_str[ATTR_MAX];
231*9781SMoriah.Waterland@Sun.COM ASN1_INTEGER *sn;
232*9781SMoriah.Waterland@Sun.COM
233*9781SMoriah.Waterland@Sun.COM if ((sn = X509_get_serialNumber(cert)) != 0) {
234*9781SMoriah.Waterland@Sun.COM return (NULL);
235*9781SMoriah.Waterland@Sun.COM } else {
236*9781SMoriah.Waterland@Sun.COM (void) snprintf(sn_str, ATTR_MAX, "%ld",
237*9781SMoriah.Waterland@Sun.COM ASN1_INTEGER_get(sn));
238*9781SMoriah.Waterland@Sun.COM }
239*9781SMoriah.Waterland@Sun.COM
240*9781SMoriah.Waterland@Sun.COM return (sn_str);
241*9781SMoriah.Waterland@Sun.COM }
242*9781SMoriah.Waterland@Sun.COM
243*9781SMoriah.Waterland@Sun.COM /*
244*9781SMoriah.Waterland@Sun.COM * Name: get_fingerprint
245*9781SMoriah.Waterland@Sun.COM * Description: Generates a fingerprint string given
246*9781SMoriah.Waterland@Sun.COM * a digest algorithm with which to calculate
247*9781SMoriah.Waterland@Sun.COM * the fingerprint
248*9781SMoriah.Waterland@Sun.COM *
249*9781SMoriah.Waterland@Sun.COM * Arguments: cert - The certificate to get the data from
250*9781SMoriah.Waterland@Sun.COM * Arguments: alg - The algorithm to use to calculate the fingerprint
251*9781SMoriah.Waterland@Sun.COM *
252*9781SMoriah.Waterland@Sun.COM * Returns : A static buffer containing the digest
253*9781SMoriah.Waterland@Sun.COM * NULL if cert is NULL, or digest cannot be calculated
254*9781SMoriah.Waterland@Sun.COM */
255*9781SMoriah.Waterland@Sun.COM char
get_fingerprint(X509 * cert,const EVP_MD * alg)256*9781SMoriah.Waterland@Sun.COM *get_fingerprint(X509 *cert, const EVP_MD *alg)
257*9781SMoriah.Waterland@Sun.COM {
258*9781SMoriah.Waterland@Sun.COM static char fp_str[ATTR_MAX];
259*9781SMoriah.Waterland@Sun.COM char tmp[ATTR_MAX] = "";
260*9781SMoriah.Waterland@Sun.COM unsigned int n;
261*9781SMoriah.Waterland@Sun.COM unsigned char md[EVP_MAX_MD_SIZE];
262*9781SMoriah.Waterland@Sun.COM int i;
263*9781SMoriah.Waterland@Sun.COM
264*9781SMoriah.Waterland@Sun.COM if (!X509_digest(cert, alg, md, &n)) {
265*9781SMoriah.Waterland@Sun.COM return (NULL);
266*9781SMoriah.Waterland@Sun.COM }
267*9781SMoriah.Waterland@Sun.COM
268*9781SMoriah.Waterland@Sun.COM /* start with empty string */
269*9781SMoriah.Waterland@Sun.COM fp_str[0] = '\0';
270*9781SMoriah.Waterland@Sun.COM
271*9781SMoriah.Waterland@Sun.COM for (i = 0; i < (int)n; i++) {
272*9781SMoriah.Waterland@Sun.COM /* form a byte of the fingerprint */
273*9781SMoriah.Waterland@Sun.COM (void) snprintf(tmp, ATTR_MAX, "%02X:", md[i]);
274*9781SMoriah.Waterland@Sun.COM /* cat it onto the end of the result */
275*9781SMoriah.Waterland@Sun.COM (void) strlcat(fp_str, tmp, ATTR_MAX);
276*9781SMoriah.Waterland@Sun.COM }
277*9781SMoriah.Waterland@Sun.COM
278*9781SMoriah.Waterland@Sun.COM /* nuke trailing ':' */
279*9781SMoriah.Waterland@Sun.COM fp_str[strlen(fp_str) - 1] = '\0';
280*9781SMoriah.Waterland@Sun.COM
281*9781SMoriah.Waterland@Sun.COM return (fp_str);
282*9781SMoriah.Waterland@Sun.COM }
283