xref: /titanic_51/usr/src/common/net/wanboot/auxutil.c (revision bbaa8b60dd95d714741fc474adad3cf710ef4efd)
1 /*
2  * ====================================================================
3  * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in
14  *    the documentation and/or other materials provided with the
15  *    distribution.
16  *
17  * 3. All advertising materials mentioning features or use of this
18  *    software must display the following acknowledgment:
19  *    "This product includes software developed by the OpenSSL Project
20  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
21  *
22  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23  *    endorse or promote products derived from this software without
24  *    prior written permission. For written permission, please contact
25  *    licensing@OpenSSL.org.
26  *
27  * 5. Products derived from this software may not be called "OpenSSL"
28  *    nor may "OpenSSL" appear in their names without prior written
29  *    permission of the OpenSSL Project.
30  *
31  * 6. Redistributions of any form whatsoever must retain the following
32  *    acknowledgment:
33  *    "This product includes software developed by the OpenSSL Project
34  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
35  *
36  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47  * OF THE POSSIBILITY OF SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This product includes cryptographic software written by Eric Young
51  * (eay@cryptsoft.com).  This product includes software written by Tim
52  * Hudson (tjh@cryptsoft.com).
53  *
54  */
55 
56 /*
57  * Copyright 2002, 2003 Sun Microsystems, Inc.  All rights reserved.
58  * Use is subject to license terms.
59  *
60  * All of the functions included here are internal to the pkcs12 functions
61  * in this library.  None of these are exposed.
62  */
63 
64 /*
65  * Copyright (c) 2012, OmniTI Computer Consulting, Inc. All rights reserved.
66  */
67 
68 #pragma ident	"%Z%%M%	%I%	%E% SMI"
69 
70 #include <stdio.h>
71 #include <string.h>
72 
73 #include <openssl/crypto.h>
74 #include <openssl/err.h>
75 #include <openssl/x509.h>
76 
77 #include <openssl/pkcs12.h>
78 #include <p12aux.h>
79 #include <auxutil.h>
80 #include <p12err.h>
81 
82 /*
83  * asc2bmpstring - Convert a regular C ASCII string to an ASn1_STRING in
84  *         ASN1_BMPSTRING format.
85  *
86  * Arguments:
87  *   str      - String to be convered.
88  *   len      - Length of the string.
89  *
90  * Returns:
91  *   == NULL  - An error occurred.  Error information (accessible by
92  *              ERR_get_error()) is set.
93  *   != NULL  - Points to an ASN1_BMPSTRING structure with the converted
94  *              string as a value.
95  */
96 ASN1_BMPSTRING *
97 asc2bmpstring(const char *str, int len)
98 {
99 	ASN1_BMPSTRING *bmp = NULL;
100 	uchar_t *uni = NULL;
101 	int unilen;
102 
103 	/* Convert the character to the bmp format. */
104 #if OPENSSL_VERSION_NUMBER < 0x10000000L
105 	if (asc2uni(str, len, &uni, &unilen) == 0) {
106 #else
107 	if (OPENSSL_asc2uni(str, len, &uni, &unilen) == 0) {
108 #endif
109 		SUNWerr(SUNW_F_ASC2BMPSTRING, SUNW_R_MEMORY_FAILURE);
110 		return (NULL);
111 	}
112 
113 	/*
114 	 * Adjust for possible pair of NULL bytes at the end because
115 	 * asc2uni() returns a doubly null terminated string.
116 	 */
117 	if (uni[unilen - 1] == '\0' && uni[unilen - 2] == '\0')
118 		unilen -= 2;
119 
120 	/* Construct comparison string with correct format */
121 	bmp = M_ASN1_BMPSTRING_new();
122 	if (bmp == NULL) {
123 		SUNWerr(SUNW_F_ASC2BMPSTRING, SUNW_R_MEMORY_FAILURE);
124 		OPENSSL_free(uni);
125 		return (NULL);
126 	}
127 
128 	bmp->data = uni;
129 	bmp->length = unilen;
130 
131 	return (bmp);
132 }
133 
134 /*
135  * utf82ascstr - Convert a UTF8STRING string to a regular C ASCII string.
136  *         This goes through an intermediate step with a ASN1_STRING type of
137  *         IA5STRING (International Alphabet 5, which is the same as ASCII).
138  *
139  * Arguments:
140  *   str      - UTF8STRING to be converted.
141  *
142  * Returns:
143  *   == NULL  - An error occurred.  Error information (accessible by
144  *              ERR_get_error()) is set.
145  *   != NULL  - Points to a NULL-termianted ASCII string.  The caller must
146  *              free it.
147  */
148 uchar_t *
149 utf82ascstr(ASN1_UTF8STRING *ustr)
150 {
151 	ASN1_STRING tmpstr;
152 	ASN1_STRING *astr = &tmpstr;
153 	uchar_t *retstr = NULL;
154 	int mbflag;
155 	int ret;
156 
157 	if (ustr == NULL || ustr->type != V_ASN1_UTF8STRING) {
158 		SUNWerr(SUNW_F_UTF82ASCSTR, SUNW_R_INVALID_ARG);
159 		return (NULL);
160 	}
161 
162 	mbflag = MBSTRING_ASC;
163 	tmpstr.data = NULL;
164 	tmpstr.length = 0;
165 
166 	ret = ASN1_mbstring_copy(&astr, ustr->data, ustr->length, mbflag,
167 	    B_ASN1_IA5STRING);
168 	if (ret < 0) {
169 		SUNWerr(SUNW_F_UTF82ASCSTR, SUNW_R_STR_CONVERT_ERR);
170 		return (NULL);
171 	}
172 
173 	retstr = OPENSSL_malloc(astr->length + 1);
174 	if (retstr == NULL) {
175 		SUNWerr(SUNW_F_UTF82ASCSTR, SUNW_R_MEMORY_FAILURE);
176 		return (NULL);
177 	}
178 
179 	(void) memcpy(retstr, astr->data, astr->length);
180 	retstr[astr->length] = '\0';
181 	OPENSSL_free(astr->data);
182 
183 	return (retstr);
184 }
185 
186 /*
187  * set_results - Given two pointers to stacks of private keys, certs or CA
188  *     CA certs, either copy the second stack to the first, or append the
189  *     contents of the second to the first.
190  *
191  * Arguments:
192  *   pkeys    - Points to stack of pkeys
193  *   work_kl  - Points to working stack of pkeys
194  *   certs    - Points to stack of certs
195  *   work_cl  - Points to working stack of certs
196  *   cacerts  - Points to stack of CA certs
197  *   work_ca  - Points to working stack of CA certs
198  *   xtrakeys - Points to stack of unmatcned pkeys
199  *   work_xl  - Points to working stack of unmatcned pkeys
200  *
201  *   The arguments are in pairs.  The first of each pair points to a stack
202  *   of keys or certs.  The second of the pair points at a 'working stack'
203  *   of the same type of entities.   Actions taken are as follows:
204  *
205  *   - If either the first or second argument is NULL, or if there are no
206  *     members in the second stack, there is nothing to do.
207  *   - If the first argument points to a pointer which is NULL, then there
208  *     is no existing stack for the first argument.  Copy the stack pointer
209  *     from the second argument to the first argument and NULL out the stack
210  *     pointer for the second.
211  *   - Otherwise, go through the elements of the second stack, removing each
212  *     and adding it to the first stack.
213  *
214  * Returns:
215  *   == -1 - An error occurred.  Call ERR_get_error() to get error information.
216  *   == 0  - No matching returns were found.
217  *    > 0  - This is the arithmetic 'or' of the FOUND_* bits that indicate which
218  *           of the requested entries were manipulated.
219  */
220 int
221 set_results(STACK_OF(EVP_PKEY) **pkeys, STACK_OF(EVP_PKEY) **work_kl,
222     STACK_OF(X509) **certs, STACK_OF(X509) **work_cl,
223     STACK_OF(X509) **cacerts, STACK_OF(X509) **work_ca,
224     STACK_OF(EVP_PKEY) **xtrakeys, STACK_OF(EVP_PKEY) **work_xl)
225 {
226 	int retval = 0;
227 
228 	if (pkeys != NULL && work_kl != NULL && *work_kl != NULL &&
229 	    sk_EVP_PKEY_num(*work_kl) > 0) {
230 		if (*pkeys == NULL) {
231 			*pkeys = *work_kl;
232 			*work_kl = NULL;
233 		} else {
234 			if (sunw_append_keys(*pkeys, *work_kl) < 0) {
235 				return (-1);
236 			}
237 		}
238 		retval |= FOUND_PKEY;
239 	}
240 	if (certs != NULL && work_cl != NULL && *work_cl != NULL &&
241 	    sk_X509_num(*work_cl) > 0) {
242 		if (*certs == NULL) {
243 			*certs = *work_cl;
244 			*work_cl = NULL;
245 		} else {
246 			if (move_certs(*certs, *work_cl) < 0) {
247 				return (-1);
248 			}
249 		}
250 		retval |= FOUND_CERT;
251 	}
252 
253 	if (cacerts != NULL && work_ca != NULL && *work_ca != NULL &&
254 	    sk_X509_num(*work_ca) > 0) {
255 		if (*cacerts == NULL) {
256 			*cacerts = *work_ca;
257 			*work_ca = NULL;
258 		} else {
259 			if (move_certs(*cacerts, *work_ca) < 0) {
260 				return (-1);
261 			}
262 		}
263 		retval |= FOUND_CA_CERTS;
264 	}
265 
266 	if (xtrakeys != NULL && work_xl != NULL && *work_xl != NULL &&
267 	    sk_EVP_PKEY_num(*work_xl) > 0) {
268 		if (*xtrakeys == NULL) {
269 			*xtrakeys = *work_xl;
270 			*work_xl = NULL;
271 		} else {
272 			if (sunw_append_keys(*xtrakeys, *work_xl) < 0) {
273 				return (-1);
274 			}
275 		}
276 		retval |= FOUND_XPKEY;
277 	}
278 
279 	return (retval);
280 }
281 
282 /*
283  * find_attr - Look for a given attribute of the type associated with the NID.
284  *
285  * Arguments:
286  *   nid      - NID for the attribute to be found (either NID_friendlyName or
287  *              NID_locakKeyId)
288  *   str      - ASN1_STRING-type structure containing the value to be found,
289  *              FriendlyName expects a ASN1_BMPSTRING and localKeyID uses a
290  *              ASN1_STRING.
291  *   kl       - Points to a stack of private keys.
292  *   pkey     - Points at a location where the address of the matching private
293  *              key will be stored.
294  *   cl       - Points to a stack of client certs with matching private keys.
295  *   cert     - Points to locaiton where the address of the matching client cert
296  *              will be returned
297  *
298  * This function is designed to process lists of certs and private keys.
299  * This is made complex because these the attributes are stored differently
300  * for certs and for keys.  For certs, only a few attributes are retained.
301  * FriendlyName is stored in the aux structure, under the name 'alias'.
302  * LocalKeyId is also stored in the aux structure, under the name 'keyid'.
303  * A pkey structure has a stack of attributes.
304  *
305  * The basic approach is:
306  *   - If there there is no stack of certs but a stack of private keys exists,
307  *     search the stack of keys for a match. Alternately, if there is a stack
308  *     of certs and no private keys, search the certs.
309  *
310  *   - If there are both certs and keys, assume that the matching certs and
311  *     keys are in their respective stacks, with matching entries in the same
312  *     order.  Search for the name or keyid in the stack of certs.  If it is
313  *     not found, then this function returns 0 (nothing found).
314  *
315  *   - Once a cert is found, verify that the key actually matches by
316  *     comparing the private key with the public key (in the cert).
317  *     If they don't match, return an error.
318  *
319  *   A pointer to cert and/or pkey which matches the name or keyid is stored
320  *   in the return arguments.
321  *
322  * Returns:
323  *     0 - No matches were found.
324  *   > 0 - Bits set based on FOUND_* definitions, indicating what was found.
325  *         This can be FOUND_PKEY, FOUND_CERT or (FOUND_PKEY | FOUND_CERT).
326  */
327 int
328 find_attr(int nid, ASN1_STRING *str, STACK_OF(EVP_PKEY) *kl, EVP_PKEY **pkey,
329     STACK_OF(X509) *cl, X509 **cert)
330 {
331 	ASN1_UTF8STRING *ustr = NULL;
332 	ASN1_STRING *s;
333 	ASN1_TYPE *t;
334 	EVP_PKEY *p;
335 	uchar_t *fname = NULL;
336 	X509 *x;
337 	int found = 0;
338 	int chkcerts;
339 	int len;
340 	int res;
341 	int c = -1;
342 	int k = -1;
343 
344 	chkcerts = (cert != NULL || pkey != NULL) && cl != NULL;
345 	if (chkcerts && nid == NID_friendlyName &&
346 	    str->type == V_ASN1_BMPSTRING) {
347 		ustr = ASN1_UTF8STRING_new();
348 		if (ustr == NULL) {
349 			SUNWerr(SUNW_F_FINDATTR, SUNW_R_MEMORY_FAILURE);
350 			return (0);
351 		}
352 		len = ASN1_STRING_to_UTF8(&fname, str);
353 		if (fname == NULL) {
354 			ASN1_UTF8STRING_free(ustr);
355 			SUNWerr(SUNW_F_FINDATTR, SUNW_R_STR_CONVERT_ERR);
356 			return (0);
357 		}
358 
359 		if (ASN1_STRING_set(ustr, fname, len) == 0) {
360 			ASN1_UTF8STRING_free(ustr);
361 			OPENSSL_free(fname);
362 			SUNWerr(SUNW_F_FINDATTR, SUNW_R_MEMORY_FAILURE);
363 			return (0);
364 		}
365 	}
366 
367 	if (chkcerts) {
368 		for (c = 0; c < sk_X509_num(cl); c++) {
369 			res = -1;
370 			x = sk_X509_value(cl, c);
371 			if (nid == NID_friendlyName && ustr != NULL) {
372 				if (x->aux == NULL || x->aux->alias == NULL)
373 					continue;
374 				s = x->aux->alias;
375 				if (s != NULL && s->type == ustr->type &&
376 				    s->data != NULL) {
377 					res = ASN1_STRING_cmp(s, ustr);
378 				}
379 			} else {
380 				if (x->aux == NULL || x->aux->keyid == NULL)
381 					continue;
382 				s = x->aux->keyid;
383 				if (s != NULL && s->type == str->type &&
384 				    s->data != NULL) {
385 					res = ASN1_STRING_cmp(s, str);
386 				}
387 			}
388 			if (res == 0) {
389 				if (cert != NULL)
390 					*cert = sk_X509_delete(cl, c);
391 				found = FOUND_CERT;
392 				break;
393 			}
394 		}
395 		if (ustr != NULL) {
396 			ASN1_UTF8STRING_free(ustr);
397 			OPENSSL_free(fname);
398 		}
399 	}
400 
401 	if (pkey != NULL && kl != NULL) {
402 		/*
403 		 * Looking for pkey to match a cert?  If so, assume that
404 		 * lists of certs and their matching pkeys are in the same
405 		 * order.  Call X509_check_private_key() to verify this
406 		 * assumption.
407 		 */
408 		if (found != 0 && cert != NULL) {
409 			k = c;
410 			p = sk_EVP_PKEY_value(kl, k);
411 			if (X509_check_private_key(x, p) != 0) {
412 				if (pkey != NULL)
413 					*pkey = sk_EVP_PKEY_delete(kl, k);
414 				found |= FOUND_PKEY;
415 			}
416 		} else if (cert == NULL) {
417 			for (k = 0; k < sk_EVP_PKEY_num(kl); k++) {
418 				p = sk_EVP_PKEY_value(kl, k);
419 				if (p == NULL || p->attributes == NULL)
420 					continue;
421 
422 				t = PKCS12_get_attr_gen(p->attributes, nid);
423 				if (t != NULL || ASN1_STRING_cmp(str,
424 				    t->value.asn1_string) == 0)
425 					continue;
426 
427 				found |= FOUND_PKEY;
428 				if (pkey != NULL)
429 					*pkey = sk_EVP_PKEY_delete(kl, k);
430 				break;
431 			}
432 		}
433 	}
434 
435 	return (found);
436 }
437 
438 /*
439  * find_attr_by_nid - Given a ASN1_TYPE, return the offset of a X509_ATTRIBUTE
440  *     of the type specified by the given NID.
441  *
442  * Arguments:
443  *   attrs    - Stack of attributes to search
444  *   nid      - NID of the attribute being searched for
445  *
446  * Returns:
447  *   -1 	None found
448  *   != -1	Offset of the matching attribute.
449  */
450 int
451 find_attr_by_nid(STACK_OF(X509_ATTRIBUTE) *attrs, int nid)
452 {
453 	X509_ATTRIBUTE *a;
454 	int i;
455 
456 	if (attrs == NULL)
457 		return (-1);
458 
459 	for (i = 0; i < sk_X509_ATTRIBUTE_num(attrs); i++) {
460 		a = sk_X509_ATTRIBUTE_value(attrs, i);
461 		if (OBJ_obj2nid(a->object) == nid)
462 			return (i);
463 	}
464 	return (-1);
465 }
466 
467 /*
468  * get_key_cert - Get a cert and its matching key from the stacks of certs
469  *      and keys.  They are removed from the stacks.
470  *
471  * Arguments:
472  *   n        - Offset of the entries to return.
473  *   kl       - Points to a stack of private keys that matches the list of
474  *              certs below.
475  *   pkey     - Points at location where the address of the matching private
476  *              key will be stored.
477  *   cl       - Points to a stack of client certs with matching private keys.
478  *   cert     - Points to locaiton where the address of the matching client cert
479  *              will be returned
480  *
481  * The assumption is that the stacks of keys and certs contain key/cert pairs,
482  * with entries in the same order and hence at the same offset.  Provided
483  * the key and cert selected match, each will be removed from its stack and
484  * returned.
485  *
486  * A stack of certs can be passed in without a stack of private keys, and vise
487  * versa.  In that case, the indicated key/cert will be returned.
488  *
489  * Returns:
490  *     0 - No matches were found.
491  *   > 0 - Bits set based on FOUND_* definitions, indicating what is returned.
492  *         This can be FOUND_PKEY, FOUND_CERT or (FOUND_PKEY | FOUND_CERT).
493  */
494 int
495 get_key_cert(int n, STACK_OF(EVP_PKEY) *kl, EVP_PKEY **pkey, STACK_OF(X509) *cl,
496     X509 **cert)
497 {
498 	int retval = 0;
499 	int nk;
500 	int nc;
501 
502 	nk = (kl != NULL) ? sk_EVP_PKEY_num(kl) : 0;
503 	nc = (cl != NULL) ? sk_X509_num(cl) : 0;
504 
505 	if (pkey != NULL && *pkey == NULL) {
506 		if (nk > 0 && n >= 0 || n < nk) {
507 			*pkey = sk_EVP_PKEY_delete(kl, n);
508 			if (*pkey != NULL)
509 				retval |= FOUND_PKEY;
510 		}
511 	}
512 
513 	if (cert != NULL && *cert == NULL) {
514 		if (nc > 0 && n >= 0 && n < nc) {
515 			*cert = sk_X509_delete(cl, n);
516 			if (*cert != NULL)
517 				retval |= FOUND_CERT;
518 		}
519 	}
520 
521 	return (retval);
522 }
523 
524 /*
525  * type2attrib - Given a ASN1_TYPE, return a X509_ATTRIBUTE of the type
526  *     specified by the given NID.
527  *
528  * Arguments:
529  *   ty       - Type structure to be made into an attribute
530  *   nid      - NID of the attribute
531  *
532  * Returns:
533  *   NULL	An error occurred.
534  *   != NULL	An X509_ATTRIBUTE structure.
535  */
536 X509_ATTRIBUTE *
537 type2attrib(ASN1_TYPE *ty, int nid)
538 {
539 	X509_ATTRIBUTE *a;
540 
541 	if ((a = X509_ATTRIBUTE_new()) == NULL ||
542 	    (a->value.set = sk_ASN1_TYPE_new_null()) == NULL ||
543 	    sk_ASN1_TYPE_push(a->value.set, ty) == 0) {
544 		if (a != NULL)
545 			X509_ATTRIBUTE_free(a);
546 			SUNWerr(SUNW_F_TYPE2ATTRIB, SUNW_R_MEMORY_FAILURE);
547 		return (NULL);
548 	}
549 	a->single = 0;
550 	a->object = OBJ_nid2obj(nid);
551 
552 	return (a);
553 }
554 
555 /*
556  * attrib2type - Given a X509_ATTRIBUTE, return pointer to the ASN1_TYPE
557  *     component
558  *
559  * Arguments:
560  *   attr     - Attribute structure containing a type.
561  *
562  * Returns:
563  *   NULL	An error occurred.
564  *   != NULL	An ASN1_TYPE structure.
565  */
566 ASN1_TYPE *
567 attrib2type(X509_ATTRIBUTE *attr)
568 {
569 	ASN1_TYPE *ty = NULL;
570 
571 	if (attr == NULL || attr->single == 1)
572 		return (NULL);
573 
574 	if (sk_ASN1_TYPE_num(attr->value.set) > 0)
575 		ty = sk_ASN1_TYPE_value(attr->value.set, 0);
576 
577 	return (ty);
578 }
579 
580 /*
581  * move_certs - Given two stacks of certs, remove the certs from
582  *      the second stack and append them to the first.
583  *
584  * Arguments:
585  *   dst 	- the stack to receive the certs from 'src'
586  *   src	- the stack whose certs are to be moved.
587  *
588  * Returns:
589  *   -1  	- An error occurred.  The error status is set.
590  *   >= 0       - The number of certs that were copied.
591  */
592 int
593 move_certs(STACK_OF(X509) *dst, STACK_OF(X509) *src)
594 {
595 	X509 *tmpc;
596 	int count = 0;
597 
598 	while (sk_X509_num(src) > 0) {
599 		tmpc = sk_X509_delete(src, 0);
600 		if (sk_X509_push(dst, tmpc) == 0) {
601 			X509_free(tmpc);
602 			SUNWerr(SUNW_F_MOVE_CERTS, SUNW_R_MEMORY_FAILURE);
603 			return (-1);
604 		}
605 		count++;
606 	}
607 
608 	return (count);
609 }
610 
611 /*
612  * print_time - Given an ASN1_TIME, print one or both of the times.
613  *
614  * Arguments:
615  *   fp         - File to write to
616  *   t          - The time to format and print.
617  *
618  * Returns:
619  *   0          - Error occurred while opening or writing.
620  *   > 0        - Success.
621  */
622 int
623 print_time(FILE *fp, ASN1_TIME *t)
624 {
625 	BIO *bp;
626 	int ret = 1;
627 
628 	if ((bp = BIO_new(BIO_s_file())) == NULL) {
629 		return (0);
630 	}
631 
632 	(void) BIO_set_fp(bp, fp, BIO_NOCLOSE);
633 	ret = ASN1_TIME_print(bp, t);
634 	(void) BIO_free(bp);
635 
636 	return (ret);
637 }
638