xref: /titanic_52/usr/src/common/net/wanboot/p12auxutl.c (revision 587644a8567e6a9533f88401daa59cbd78c4632f)
1 /*
2  * Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
3  * project 1999.
4  */
5 /*
6  * ====================================================================
7  * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in
18  *    the documentation and/or other materials provided with the
19  *    distribution.
20  *
21  * 3. All advertising materials mentioning features or use of this
22  *    software must display the following acknowledgment:
23  *    "This product includes software developed by the OpenSSL Project
24  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25  *
26  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27  *    endorse or promote products derived from this software without
28  *    prior written permission. For written permission, please contact
29  *    licensing@OpenSSL.org.
30  *
31  * 5. Products derived from this software may not be called "OpenSSL"
32  *    nor may "OpenSSL" appear in their names without prior written
33  *    permission of the OpenSSL Project.
34  *
35  * 6. Redistributions of any form whatsoever must retain the following
36  *    acknowledgment:
37  *    "This product includes software developed by the OpenSSL Project
38  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39  *
40  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51  * OF THE POSSIBILITY OF SUCH DAMAGE.
52  * ====================================================================
53  *
54  * This product includes cryptographic software written by Eric Young
55  * (eay@cryptsoft.com).  This product includes software written by Tim
56  * Hudson (tjh@cryptsoft.com).
57  *
58  */
59 
60 /*
61  * Copyright 2002, 2003 Sun Microsystems, Inc.  All rights reserved.
62  * Use is subject to license terms.
63  */
64 
65 #pragma ident	"%Z%%M%	%I%	%E% SMI"
66 
67 #include <stdio.h>
68 #include <strings.h>
69 
70 #include <openssl/crypto.h>
71 #include <openssl/err.h>
72 #include <openssl/x509.h>
73 
74 #include <openssl/pkcs12.h>
75 #include <p12aux.h>
76 #include <auxutil.h>
77 #include <p12err.h>
78 
79 /*
80  * sunw_PKCS12_create() creates a pkcs#12 structure and given component parts.
81  *
82  * Given one or more of user private key, user cert and/or other (CA) certs,
83  * return an encrypted PKCS12 structure containing them.
84  *
85  * Arguments:
86  *   pass     - Pass phrase for the pkcs12 structure and private key (possibly
87  *              empty) or NULL if there is none.  It will be used to encrypt
88  *              both the private key(s) and as the pass phrase for the whole
89  *              pkcs12 wad.
90  *   pkeys    - Points to stack of private keys.
91  *   certs    - Points to stack of client (public ke) certs
92  *   cacerts  - Points to stack of 'certificate authority' certs (or trust
93  *              anchors).
94  *
95  *   Note that any of these may be NULL.
96  *
97  * Returns:
98  *   NULL     - An error occurred.
99  *   != NULL  - Address of PKCS12 structure.  The user is responsible for
100  *              freeing the memory when done.
101  */
102 PKCS12 *
103 sunw_PKCS12_create(const char *pass, STACK_OF(EVP_PKEY) *pkeys,
104     STACK_OF(X509) *certs, STACK_OF(X509) *cacerts)
105 {
106 	int nid_cert = NID_pbe_WithSHA1And40BitRC2_CBC;
107 	int nid_key = NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
108 	STACK_OF(PKCS12_SAFEBAG) *bags = NULL;
109 	STACK_OF(PKCS7) *safes = NULL;
110 	PKCS12_SAFEBAG *bag = NULL;
111 	PKCS8_PRIV_KEY_INFO *p8 = NULL;
112 	EVP_PKEY *pkey = NULL;
113 	PKCS12 *ret_p12 = NULL;
114 	PKCS12 *p12 = NULL;
115 	PKCS7 *authsafe = NULL;
116 	X509 *cert = NULL;
117 	uchar_t *str = NULL;
118 	int certs_there = 0;
119 	int keys_there = 0;
120 	int len;
121 	int i;
122 
123 	if ((safes = sk_PKCS7_new_null()) == NULL) {
124 		SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_MEMORY_FAILURE);
125 		return (NULL);
126 	}
127 
128 	if ((bags = sk_PKCS12_SAFEBAG_new_null()) == NULL) {
129 		SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_MEMORY_FAILURE);
130 		goto err_ret;
131 	}
132 
133 	if (certs != NULL && sk_X509_num(certs) > 0) {
134 
135 		for (i = 0; i < sk_X509_num(certs); i++) {
136 			cert = sk_X509_value(certs, i);
137 
138 			/* Add user certificate */
139 			if ((bag = M_PKCS12_x5092certbag(cert)) == NULL) {
140 				SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_CERT_ERR);
141 				goto err_ret;
142 			}
143 			if (cert->aux != NULL && cert->aux->alias != NULL &&
144 			    cert->aux->alias->type == V_ASN1_UTF8STRING) {
145 				str = utf82ascstr(cert->aux->alias);
146 				if (str == NULL) {
147 					/*
148 					 * Error already on stack
149 					 */
150 					goto err_ret;
151 				}
152 				if (PKCS12_add_friendlyname_asc(bag,
153 				    (char const *) str,
154 				    strlen((char const *) str)) == 0) {
155 					SUNWerr(SUNW_F_PKCS12_CREATE,
156 					    SUNW_R_ADD_ATTR_ERR);
157 					goto err_ret;
158 				}
159 			}
160 			if (cert->aux != NULL && cert->aux->keyid != NULL &&
161 			    cert->aux->keyid->type == V_ASN1_OCTET_STRING) {
162 				str = cert->aux->keyid->data;
163 				len = cert->aux->keyid->length;
164 
165 				if (str != NULL &&
166 				    PKCS12_add_localkeyid(bag, str, len) == 0) {
167 					SUNWerr(SUNW_F_PKCS12_CREATE,
168 					    SUNW_R_ADD_ATTR_ERR);
169 					goto err_ret;
170 				}
171 			}
172 			if (sk_PKCS12_SAFEBAG_push(bags, bag) == 0) {
173 				SUNWerr(SUNW_F_PKCS12_CREATE,
174 				    SUNW_R_MEMORY_FAILURE);
175 				goto err_ret;
176 			}
177 			certs_there++;
178 			bag = NULL;
179 		}
180 	}
181 
182 	if (cacerts != NULL && sk_X509_num(cacerts) > 0) {
183 
184 		/* Put all certs in structure */
185 		for (i = 0; i < sk_X509_num(cacerts); i++) {
186 			cert = sk_X509_value(cacerts, i);
187 			if ((bag = M_PKCS12_x5092certbag(cert)) == NULL) {
188 				SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_CERT_ERR);
189 				goto err_ret;
190 			}
191 
192 			if (cert->aux != NULL && cert->aux->alias != NULL &&
193 			    cert->aux->alias->type == V_ASN1_UTF8STRING) {
194 				str = utf82ascstr(cert->aux->alias);
195 				if (str == NULL) {
196 					/*
197 					 * Error already on stack
198 					 */
199 					goto err_ret;
200 				}
201 				if (PKCS12_add_friendlyname_asc(
202 				    bag, (char const *) str,
203 				    strlen((char const *) str)) == 0) {
204 					SUNWerr(SUNW_F_PKCS12_CREATE,
205 					    SUNW_R_ADD_ATTR_ERR);
206 					goto err_ret;
207 				}
208 			}
209 			if (cert->aux != NULL && cert->aux->keyid != NULL &&
210 			    cert->aux->keyid->type == V_ASN1_OCTET_STRING) {
211 				str = cert->aux->keyid->data;
212 				len = cert->aux->keyid->length;
213 
214 				if (str != NULL &&
215 				    PKCS12_add_localkeyid(bag, str, len) == 0) {
216 					SUNWerr(SUNW_F_PKCS12_CREATE,
217 					    SUNW_R_ADD_ATTR_ERR);
218 					goto err_ret;
219 				}
220 			}
221 			if (sk_PKCS12_SAFEBAG_push(bags, bag) == 0) {
222 				SUNWerr(SUNW_F_PKCS12_CREATE,
223 				    SUNW_R_MEMORY_FAILURE);
224 				goto err_ret;
225 			}
226 			certs_there++;
227 			bag = NULL;
228 		}
229 	}
230 
231 	if (certs != NULL || cacerts != NULL && certs_there) {
232 		/* Turn certbags into encrypted authsafe */
233 		authsafe = PKCS12_pack_p7encdata(nid_cert, pass, -1,
234 		    NULL, 0, PKCS12_DEFAULT_ITER, bags);
235 		if (authsafe == NULL) {
236 			SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_CERT_ERR);
237 			goto err_ret;
238 		}
239 		sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
240 		bags = NULL;
241 
242 		if (sk_PKCS7_push(safes, authsafe) == 0) {
243 			SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_MEMORY_FAILURE);
244 			goto err_ret;
245 		}
246 		authsafe = NULL;
247 	}
248 
249 	if (pkeys != NULL && sk_EVP_PKEY_num(pkeys) > 0) {
250 
251 		if (bags == NULL &&
252 		    (bags = sk_PKCS12_SAFEBAG_new_null()) == NULL) {
253 			SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_MEMORY_FAILURE);
254 			goto err_ret;
255 		}
256 
257 		for (i = 0; i < sk_EVP_PKEY_num(pkeys); i++) {
258 
259 			pkey = sk_EVP_PKEY_value(pkeys, i);
260 
261 			/* Make a shrouded key bag */
262 			if ((p8 = EVP_PKEY2PKCS8(pkey)) == NULL) {
263 				SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_PKEY_ERR);
264 				goto err_ret;
265 			}
266 
267 			bag = PKCS12_MAKE_SHKEYBAG(nid_key, pass, -1, NULL, 0,
268 			    PKCS12_DEFAULT_ITER, p8);
269 			if (bag == NULL) {
270 				SUNWerr(SUNW_F_PKCS12_CREATE,
271 				    SUNW_R_MAKE_BAG_ERR);
272 				goto err_ret;
273 			}
274 			PKCS8_PRIV_KEY_INFO_free(p8);
275 			p8 = NULL;
276 
277 			len = sunw_get_pkey_fname(GETDO_COPY, pkey,
278 			    (char **)&str);
279 			if (str != NULL) {
280 				if (PKCS12_add_friendlyname_asc(bag,
281 				    (const char *)str, len) == 0) {
282 					SUNWerr(SUNW_F_PKCS12_CREATE,
283 					    SUNW_R_ADD_ATTR_ERR);
284 					goto err_ret;
285 				}
286 			}
287 			str = NULL;
288 
289 			len = sunw_get_pkey_localkeyid(GETDO_COPY, pkey,
290 			    (char **)&str, &len);
291 			if (str != NULL) {
292 				if (PKCS12_add_localkeyid(bag, str, len) == 0) {
293 					SUNWerr(SUNW_F_PKCS12_CREATE,
294 					    SUNW_R_ADD_ATTR_ERR);
295 					goto err_ret;
296 				}
297 			}
298 			str = NULL;
299 
300 			if (sk_PKCS12_SAFEBAG_push(bags, bag) == 0) {
301 				SUNWerr(SUNW_F_PKCS12_CREATE,
302 				    SUNW_R_MEMORY_FAILURE);
303 				goto err_ret;
304 			}
305 			keys_there++;
306 			bag = NULL;
307 		}
308 
309 		if (keys_there) {
310 			/* Turn into unencrypted authsafe */
311 			authsafe = PKCS12_pack_p7data(bags);
312 			if (authsafe == NULL) {
313 				SUNWerr(SUNW_F_PKCS12_CREATE,
314 				    SUNW_R_PKCS12_CREATE_ERR);
315 				goto err_ret;
316 			}
317 			sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
318 			bags = NULL;
319 
320 			if (sk_PKCS7_push(safes, authsafe) == 0) {
321 				SUNWerr(SUNW_F_PKCS12_CREATE,
322 				    SUNW_R_MEMORY_FAILURE);
323 			}
324 			authsafe = NULL;
325 		}
326 	}
327 
328 	if (certs_there == 0 && keys_there == 0) {
329 		SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_PKCS12_EMPTY_ERR);
330 		goto err_ret;
331 	}
332 
333 	if ((p12 = PKCS12_init(NID_pkcs7_data)) == NULL) {
334 		SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_PKCS12_CREATE_ERR);
335 		goto err_ret;
336 	}
337 
338 	/*
339 	 * Note that safes is copied by the following.  Therefore, it needs
340 	 * to be freed whether or not the following succeeds.
341 	 */
342 	if (M_PKCS12_pack_authsafes(p12, safes) == 0) {
343 		SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_PKCS12_CREATE_ERR);
344 		goto err_ret;
345 	}
346 	if (PKCS12_set_mac(p12, pass, -1, NULL, 0, 2048, NULL) == 0) {
347 		SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_MAC_CREATE_FAILURE);
348 		goto err_ret;
349 	}
350 
351 	ret_p12 = p12;
352 	p12 = NULL;
353 
354 	/* Fallthrough is intentional */
355 
356 err_ret:
357 
358 	if (str != NULL)
359 		free(str);
360 
361 	if (p8 != NULL)
362 		PKCS8_PRIV_KEY_INFO_free(p8);
363 
364 	if (bag != NULL)
365 		PKCS12_SAFEBAG_free(bag);
366 	if (bags != NULL)
367 		sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
368 	if (authsafe != NULL)
369 		PKCS7_free(authsafe);
370 	if (safes != NULL)
371 		sk_PKCS7_pop_free(safes, PKCS7_free);
372 	if (p12 != NULL)
373 		PKCS12_free(p12);
374 
375 	return (ret_p12);
376 }
377