xref: /titanic_44/usr/src/common/net/wanboot/p12access.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * This file includes interfaces to be used together with SSL to get PKCS#12
24  * certs and pass them to SSL.  They replace similar functions for PEM,
25  * already provided for within SSL.
26  *
27  * The interfaces included here are:
28  *   sunw_p12_use_certfile - gets the user's cert from a pkcs12 file & pass
29  *                it to SSL.
30  *   sunw_p12_use_keyfile - gets the RSA private key from a pkcs12 file and
31  *                pass it to SSL
32  *   sunw_p12_use_trustfile - read the pkcs12 trust anchor (aka certificate
33  *                authority certs) file into memory and hand them off to SSL.
34  *
35  * These functions use the sunw_PKCS12_parse to read the certs.
36  *
37  * Copyright 2002-2003 Sun Microsystems, Inc.  All rights reserved.
38  * Use is subject to license terms.
39  */
40 
41 #pragma ident	"%Z%%M%	%I%	%E% SMI"
42 
43 #include <stdio.h>
44 #include <strings.h>
45 #include <stdlib.h>
46 #include <sys/stat.h>
47 #include <unistd.h>
48 
49 #include <openssl/crypto.h>
50 #include <openssl/err.h>
51 #include <openssl/x509.h>
52 #include <openssl/ssl.h>
53 
54 #include <openssl/pkcs12.h>
55 #include <p12access.h>
56 #include <p12err.h>
57 
58 static PKCS12 *p12_read_file(char *);
59 static int p12_doparse(PKCS12 *, char *, int, EVP_PKEY **,
60     X509 **, STACK_OF(X509) **);
61 static int checkfile(char *);
62 static int check_password(PKCS12 *, char *);
63 
64 /*
65  * sunw_use_x509cert - pass an x509 client certificate to ssl
66  *
67  * Arguments:
68  *   ctx        - SSL's context structure
69  *   cert	- Certificate to pass in x509 format
70  *
71  * Returns:
72  *   <=0 	- Error occurred.  Check the error stack for specifics.
73  *   >0         - Success.  Cert was successfully added.
74  */
75 static int
sunw_use_x509cert(SSL_CTX * ctx,X509 * cert)76 sunw_use_x509cert(SSL_CTX *ctx, X509 *cert)
77 {
78 	ERR_clear_error();
79 
80 	if (ctx == NULL || cert == NULL) {
81 		SUNWerr(SUNW_F_USE_X509CERT, SUNW_R_INVALID_ARG);
82 		return (-1);
83 	}
84 
85 	if (SSL_CTX_use_certificate(ctx, cert) != 1) {
86 		SUNWerr(SUNW_F_USE_X509CERT, SUNW_R_CERT_ERR);
87 		return (-1);
88 	}
89 	return (1);
90 }
91 
92 /*
93  * sunw_use_pkey - pass an EVP_PKEY private key to ssl
94  *
95  * Arguments:
96  *   ctx        - SSL's context structure
97  *   pkey	- EVP_PKEY formatted private key
98  *
99  * Returns:
100  *   <=0 	- Error occurred.  Check the error stack for specifics.
101  *   >0         - Success.
102  */
103 static int
sunw_use_pkey(SSL_CTX * ctx,EVP_PKEY * pkey)104 sunw_use_pkey(SSL_CTX *ctx, EVP_PKEY *pkey)
105 {
106 	ERR_clear_error();
107 	if (ctx == NULL || pkey == NULL) {
108 		SUNWerr(SUNW_F_USE_PKEY, SUNW_R_INVALID_ARG);
109 		return (-1);
110 	}
111 
112 	if (SSL_CTX_use_PrivateKey(ctx, pkey) != 1) {
113 		SUNWerr(SUNW_F_USE_PKEY, SUNW_R_PKEY_ERR);
114 		return (-1);
115 	}
116 
117 	return (1);
118 }
119 
120 /*
121  * sunw_use_tastore - take a stack of X509 certs and add them to the
122  *              SSL store of trust anchors (aka CA certs).
123  *
124  * This function takes the certs in the stack and passes them into
125  * SSL for addition to the cache of TA certs.
126  *
127  * Arguments:
128  *   ctx        - SSL's context structure
129  *   ta_certs   - Stack of certs to add to the list of SSL trust anchors.
130  *
131  * Returns:
132  *   <=0 	- Error occurred.  Check the error stack for specifics.
133  *   >0         - Success.  Certs were successfully added.
134  */
135 static int
sunw_use_tastore(SSL_CTX * ctx,STACK_OF (X509)* ta_certs)136 sunw_use_tastore(SSL_CTX *ctx, STACK_OF(X509) *ta_certs)
137 {
138 	X509 *tmp;
139 	int ret = -1;
140 	int i;
141 
142 	ERR_clear_error();
143 	if (ctx == NULL || ctx->cert_store == NULL || ta_certs == NULL) {
144 		SUNWerr(SUNW_F_USE_TASTORE, SUNW_R_INVALID_ARG);
145 		return (-1);
146 	}
147 
148 	if (sk_X509_num(ta_certs) == 0) {
149 		SUNWerr(SUNW_F_USE_TASTORE, SUNW_R_NO_TRUST_ANCHOR);
150 		return (-1);
151 	}
152 
153 	for (i = 0; i < sk_X509_num(ta_certs); i++) {
154 		tmp = sk_X509_value(ta_certs, i);
155 
156 		ret = X509_STORE_add_cert(ctx->cert_store, tmp);
157 		if (ret == 0) {
158 			if (ERR_GET_REASON(ERR_peek_error()) ==
159 					X509_R_CERT_ALREADY_IN_HASH_TABLE) {
160 				ERR_clear_error();
161 				continue;
162 			}
163 			SUNWerr(SUNW_F_USE_TASTORE, SUNW_R_ADD_TRUST_ERR);
164 			return (-1);
165 		} else if (ret < 0) {
166 			break;
167 		}
168 	}
169 
170 	if (ret < 0) {
171 		SUNWerr(SUNW_F_USE_TASTORE, SUNW_R_ADD_TRUST_ERR);
172 	}
173 
174 	return (ret);
175 }
176 
177 /*
178  * sunw_p12_use_certfile - read a client certificate from a pkcs12 file and
179  *              pass it in to SSL.
180  *
181  * Read in the certificate in pkcs12-formated file.  Use the provided
182  * passphrase to decrypt it. Pass the cert to SSL.
183  *
184  * Arguments:
185  *   ctx        - SSL's context structure
186  *   filename	- Name of file with the client certificate.
187  *   passwd     - Passphrase for pkcs12 data.
188  *
189  * Returns:
190  *   <=0 	- Error occurred.  Check the error stack for specifics.
191  *   >0         - Success.  Cert was successfully added.
192  */
193 int
sunw_p12_use_certfile(SSL_CTX * ctx,char * filename,char * passwd)194 sunw_p12_use_certfile(SSL_CTX *ctx, char *filename, char *passwd)
195 {
196 	PKCS12 *p12 = NULL;
197 	X509 *cert = NULL;
198 	int ret = -1;
199 
200 	ERR_clear_error();
201 	if (ctx == NULL || filename == NULL) {
202 		SUNWerr(SUNW_F_USE_CERTFILE, SUNW_R_INVALID_ARG);
203 		return (-1);
204 	}
205 
206 	p12 = p12_read_file(filename);
207 	if (p12 != NULL) {
208 		ret = p12_doparse(p12, passwd, DO_UNMATCHING, NULL,
209 		    &cert, NULL);
210 		if (ret > 0 && cert != NULL) {
211 			if (sunw_use_x509cert(ctx, cert) == -1) {
212 				/*
213 				 * Error already on stack
214 				 */
215 				ret = -1;
216 			}
217 		}
218 	}
219 
220 	if (p12 != NULL)
221 		PKCS12_free(p12);
222 
223 	if (ret == -1 && cert != NULL) {
224 		X509_free(cert);
225 		cert = NULL;
226 	}
227 
228 	return (ret);
229 }
230 
231 /*
232  * sunw_p12_use_keyfile - read a RSA private key from a pkcs12 file and pass
233  *              it in to SSL.
234  *
235  * Read in the RSA private key in pkcs12 format. Use the provided
236  * passphrase to decrypt it. Pass the cert to SSL.
237  *
238  * Arguments:
239  *   ctx        - SSL's context structure
240  *   filename	- Name of file with private key.
241  *   passwd     - Passphrase for pkcs12 data.
242  *
243  * Returns:
244  *   <=0 	- Error occurred.  Check the error stack for specifics.
245  *   >0         - Success.  Key was successfully added.
246  */
247 int
sunw_p12_use_keyfile(SSL_CTX * ctx,char * filename,char * passwd)248 sunw_p12_use_keyfile(SSL_CTX *ctx, char *filename, char *passwd)
249 {
250 	EVP_PKEY *pkey = NULL;
251 	PKCS12 *p12 = NULL;
252 	int ret = -1;
253 
254 	ERR_clear_error();
255 	if (ctx == NULL || filename == NULL) {
256 		SUNWerr(SUNW_F_USE_KEYFILE, SUNW_R_INVALID_ARG);
257 		return (-1);
258 	}
259 
260 	p12 = p12_read_file(filename);
261 	if (p12 != NULL) {
262 		ret = p12_doparse(p12, passwd, DO_UNMATCHING, &pkey, NULL,
263 		    NULL);
264 		if (ret > 0 && pkey != NULL) {
265 			if (sunw_use_pkey(ctx, pkey) != 1) {
266 				/*
267 				 * Error already on stack
268 				 */
269 				ret = -1;
270 			}
271 		} else {
272 			SUNWerr(SUNW_F_USE_KEYFILE, SUNW_R_BAD_PKEY);
273 		}
274 	} else {
275 		SUNWerr(SUNW_F_USE_KEYFILE, SUNW_R_PKEY_READ_ERR);
276 	}
277 
278 	if (p12 != NULL)
279 		PKCS12_free(p12);
280 
281 	if (ret == -1 && pkey != NULL) {
282 		sunw_evp_pkey_free(pkey);
283 		pkey = NULL;
284 	}
285 
286 	return (ret);
287 }
288 
289 /*
290  * sunw_p12_use_trustfile - read a list of trustanchors from a pkcs12 file and
291  *              pass the stack in to SSL.
292  *
293  * Read in the trust anchors from pkcs12-formated file. Use the provided
294  * passphrase to decrypt it. Pass the cert to SSL.
295  *
296  * Arguments:
297  *   ctx        - SSL's context structure
298  *   filename	- Name of file with the certificates.
299  *   passwd     - Passphrase for pkcs12 data.
300  *
301  * Returns:
302  *   <=0 	- Error occurred.  Check the error stack for specifics.
303  *   >0         - Success.  Trust anchors were successfully added.
304  */
305 int
sunw_p12_use_trustfile(SSL_CTX * ctx,char * filename,char * passwd)306 sunw_p12_use_trustfile(SSL_CTX *ctx, char *filename, char *passwd)
307 {
308 	PKCS12 *p12 = NULL;
309 	STACK_OF(X509) *ta_sk = NULL;
310 	int ret = -1;
311 
312 	ERR_clear_error();
313 	if (ctx == NULL || filename == NULL) {
314 		SUNWerr(SUNW_F_USE_TRUSTFILE, SUNW_R_INVALID_ARG);
315 		return (-1);
316 	}
317 
318 	p12 = p12_read_file(filename);
319 	if (p12 != NULL) {
320 		ret = p12_doparse(p12, passwd, DO_NONE, NULL, NULL,
321 		    &ta_sk);
322 		if (ret > 0 && ta_sk != NULL)
323 			ret = sunw_use_tastore(ctx, ta_sk);
324 		else {
325 			SUNWerr(SUNW_F_USE_TRUSTFILE, SUNW_R_BAD_TRUST);
326 			ret = -1;
327 		}
328 	} else {
329 		SUNWerr(SUNW_F_USE_TRUSTFILE, SUNW_R_READ_TRUST_ERR);
330 	}
331 
332 	if (p12 != NULL)
333 		PKCS12_free(p12);
334 
335 	if (ta_sk != NULL)
336 		sk_X509_pop_free(ta_sk, X509_free);
337 
338 	return (ret);
339 }
340 
341 /*
342  * p12_read_file - read a pkcs12 file and get its contents.  Return the
343  *                 pkcs12 structures.
344  *
345  * Arguments:
346  *   filename	- Name of file with the client certificate.
347  *
348  *
349  * Returns:
350  *   NULL 	- Error occurred.  Check the error stack for specifics.
351  *   != NULL	- Success.  The return value is the address of a pkcs12
352  *                structure.
353  */
354 static PKCS12 *
p12_read_file(char * filename)355 p12_read_file(char *filename)
356 {
357 	PKCS12 *p12 = NULL;
358 	FILE *fp = NULL;
359 	int ret = 0;
360 
361 	ERR_clear_error();
362 	if (checkfile(filename) == -1) {
363 		/*
364 		 * Error already on stack
365 		 */
366 		return (NULL);
367 	}
368 
369 	if ((fp = fopen(filename, "r")) == 0) {
370 		SYSerr(SYS_F_FOPEN, errno);
371 		return (NULL);
372 	}
373 
374 	p12 = d2i_PKCS12_fp(fp, NULL);
375 	if (p12 == NULL) {
376 		SUNWerr(SUNW_F_READ_FILE, SUNW_R_READ_ERR);
377 		ret = -1;
378 	}
379 
380 	if (fp != NULL)
381 		(void) fclose(fp);
382 
383 	if (ret == -1 && p12 != NULL) {
384 		PKCS12_free(p12);
385 		p12 = NULL;
386 	}
387 
388 	return (p12);
389 }
390 
391 /*
392  * p12_doparse - Given a pkcs12 structure, check the passphrase and then
393  *               parse it.
394  *
395  * Arguments:
396  *   p12	- Structure with pkcs12 data which has been read in
397  *   passwd     - Passphrase for pkcs12 data & key.
398  *   matchty    - How to decide which matching entry to take... See the
399  *                DO_* definitions for valid values.
400  *   pkey       - Points at pointer to private key structure.
401  *   cert       - Points at pointer to client certificate structure
402  *   ca         - Points at pointer to list of CA certs
403  *
404  * Returns:
405  *   <=0 	- Error occurred.  Check the error stack for specifics.
406  *   >0         - Success.  Bits set reflect the kind of information
407  *                returned.  (See the FOUND_* definitions.)
408  */
409 static int
p12_doparse(PKCS12 * p12,char * passwd,int matchty,EVP_PKEY ** pkey,X509 ** cert,STACK_OF (X509)** ca)410 p12_doparse(PKCS12 *p12, char *passwd, int matchty,
411     EVP_PKEY **pkey, X509 **cert, STACK_OF(X509) **ca)
412 {
413 	int ret = 0;
414 
415 	ERR_clear_error();
416 
417 	/*
418 	 * Check passphrase (including null one).
419 	 */
420 	if (check_password(p12, passwd) == 0)  {
421 		SUNWerr(SUNW_F_DOPARSE, SUNW_R_MAC_VERIFY_FAILURE);
422 		return (-1);
423 	}
424 
425 	ret = sunw_PKCS12_parse(p12, passwd, matchty, NULL, 0, NULL,
426 	    pkey, cert, ca);
427 	if (ret <= 0) {
428 		/*
429 		 * Error already on stack
430 		 */
431 		return (-1);
432 	}
433 
434 	return (ret);
435 }
436 
437 /*
438  * checkfile - given a file name, verify that the file exists and is
439  *             readable.
440  */
441 /* ARGSUSED */
442 static int
checkfile(char * filename)443 checkfile(char *filename)
444 {
445 #ifndef _BOOT
446 	struct stat sbuf;
447 
448 	if (access(filename, R_OK) == -1 || stat(filename, &sbuf) == -1) {
449 		SYSerr(SYS_F_FOPEN, errno);
450 		return (-1);
451 	}
452 
453 	if (!S_ISREG(sbuf.st_mode)) {
454 		SUNWerr(SUNW_F_CHECKFILE, SUNW_R_BAD_FILETYPE);
455 		return (-1);
456 	}
457 #endif
458 	return (0);
459 }
460 
461 /*
462  * check_password - do various password checks to see if the current password
463  *                  will work or we need to prompt for a new one.
464  *
465  * Arguments:
466  *   pass   - password to check
467  *
468  * Returns:
469  *   1      - Password is OK.
470  *   0      - Password not valid.  Error stack was set - use ERR_get_error() to
471  *            to get the error.
472  */
473 static int
check_password(PKCS12 * p12,char * pass)474 check_password(PKCS12 *p12, char *pass)
475 {
476 	int ret = 1;
477 
478 	/*
479 	 * If password is zero length or NULL then try verifying both cases
480 	 * to determine which password is correct. The reason for this is that
481 	 * under PKCS#12 password based encryption no password and a zero
482 	 * length password are two different things.  Otherwise, calling
483 	 * PKCS12_verify_mac() with a length of -1 means that the length
484 	 * can be determined via strlen().
485 	 */
486 	/* Check the mac */
487 	if (pass == NULL || *pass == '\0') {
488 		if (PKCS12_verify_mac(p12, NULL, 0) == 0 &&
489 		    PKCS12_verify_mac(p12, "", 0) == 0)
490 			ret = 0;
491 	} else if (PKCS12_verify_mac(p12, pass, -1) == 0) {
492 		ret = 0;
493 	}
494 
495 	return (ret);
496 }
497