xref: /titanic_51/usr/src/lib/libpkg/common/p12lib.c (revision 70f9559bd0c02885d84a425eaafc8c280df10efb)
15c51f124SMoriah Waterland /*
25c51f124SMoriah Waterland  * ====================================================================
35c51f124SMoriah Waterland  * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
45c51f124SMoriah Waterland  *
55c51f124SMoriah Waterland  * Redistribution and use in source and binary forms, with or without
65c51f124SMoriah Waterland  * modification, are permitted provided that the following conditions
75c51f124SMoriah Waterland  * are met:
85c51f124SMoriah Waterland  *
95c51f124SMoriah Waterland  * 1. Redistributions of source code must retain the above copyright
105c51f124SMoriah Waterland  *    notice, this list of conditions and the following disclaimer.
115c51f124SMoriah Waterland  *
125c51f124SMoriah Waterland  * 2. Redistributions in binary form must reproduce the above copyright
135c51f124SMoriah Waterland  *    notice, this list of conditions and the following disclaimer in
145c51f124SMoriah Waterland  *    the documentation and/or other materials provided with the
155c51f124SMoriah Waterland  *    distribution.
165c51f124SMoriah Waterland  *
175c51f124SMoriah Waterland  * 3. All advertising materials mentioning features or use of this
185c51f124SMoriah Waterland  *    software must display the following acknowledgment:
195c51f124SMoriah Waterland  *    "This product includes software developed by the OpenSSL Project
205c51f124SMoriah Waterland  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
215c51f124SMoriah Waterland  *
225c51f124SMoriah Waterland  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
235c51f124SMoriah Waterland  *    endorse or promote products derived from this software without
245c51f124SMoriah Waterland  *    prior written permission. For written permission, please contact
255c51f124SMoriah Waterland  *    licensing@OpenSSL.org.
265c51f124SMoriah Waterland  *
275c51f124SMoriah Waterland  * 5. Products derived from this software may not be called "OpenSSL"
285c51f124SMoriah Waterland  *    nor may "OpenSSL" appear in their names without prior written
295c51f124SMoriah Waterland  *    permission of the OpenSSL Project.
305c51f124SMoriah Waterland  *
315c51f124SMoriah Waterland  * 6. Redistributions of any form whatsoever must retain the following
325c51f124SMoriah Waterland  *    acknowledgment:
335c51f124SMoriah Waterland  *    "This product includes software developed by the OpenSSL Project
345c51f124SMoriah Waterland  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
355c51f124SMoriah Waterland  *
365c51f124SMoriah Waterland  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
375c51f124SMoriah Waterland  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
385c51f124SMoriah Waterland  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
395c51f124SMoriah Waterland  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
405c51f124SMoriah Waterland  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
415c51f124SMoriah Waterland  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
425c51f124SMoriah Waterland  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
435c51f124SMoriah Waterland  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
445c51f124SMoriah Waterland  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
455c51f124SMoriah Waterland  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
465c51f124SMoriah Waterland  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
475c51f124SMoriah Waterland  * OF THE POSSIBILITY OF SUCH DAMAGE.
485c51f124SMoriah Waterland  * ====================================================================
495c51f124SMoriah Waterland  *
505c51f124SMoriah Waterland  * This product includes cryptographic software written by Eric Young
515c51f124SMoriah Waterland  * (eay@cryptsoft.com).  This product includes software written by Tim
525c51f124SMoriah Waterland  * Hudson (tjh@cryptsoft.com).
535c51f124SMoriah Waterland  *
545c51f124SMoriah Waterland  */
555c51f124SMoriah Waterland 
565c51f124SMoriah Waterland /*
575c51f124SMoriah Waterland  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
585c51f124SMoriah Waterland  * Use is subject to license terms.
595c51f124SMoriah Waterland  */
605c51f124SMoriah Waterland 
61*70f9559bSTheo Schlossnagle /*
62*70f9559bSTheo Schlossnagle  * Copyright (c) 2012, OmniTI Computer Consulting, Inc. All rights reserved.
63*70f9559bSTheo Schlossnagle  */
64*70f9559bSTheo Schlossnagle 
655c51f124SMoriah Waterland 
665c51f124SMoriah Waterland #include <strings.h>
675c51f124SMoriah Waterland #include <stdlib.h>
685c51f124SMoriah Waterland #include <assert.h>
695c51f124SMoriah Waterland 
705c51f124SMoriah Waterland #include <openssl/crypto.h>
715c51f124SMoriah Waterland #include <openssl/err.h>
725c51f124SMoriah Waterland #include <openssl/x509.h>
735c51f124SMoriah Waterland #include <openssl/pem.h>
745c51f124SMoriah Waterland 
755c51f124SMoriah Waterland #include <openssl/pkcs12.h>
765c51f124SMoriah Waterland #include "p12lib.h"
775c51f124SMoriah Waterland 
785c51f124SMoriah Waterland /*
795c51f124SMoriah Waterland  * OpenSSL provides a framework for pushing error codes onto a stack.
805c51f124SMoriah Waterland  * When an error occurs, the consumer may use the framework to
815c51f124SMoriah Waterland  * pop the errors off the stack and provide a trace of where the
825c51f124SMoriah Waterland  * errors occurred.
835c51f124SMoriah Waterland  *
845c51f124SMoriah Waterland  * Our PKCS12 code plugs into this framework by calling
855c51f124SMoriah Waterland  * ERR_load_SUNW_strings(). To push an error (which by the way, consists
865c51f124SMoriah Waterland  * of a function code and an error code) onto the stack our PKCS12 code
875c51f124SMoriah Waterland  * calls SUNWerr().
885c51f124SMoriah Waterland  *
895c51f124SMoriah Waterland  * Consumers of our PKCS12 code can then call the OpenSSL error routines
905c51f124SMoriah Waterland  * when an error occurs and retrieve the stack of errors.
915c51f124SMoriah Waterland  */
925c51f124SMoriah Waterland 
935c51f124SMoriah Waterland #ifndef OPENSSL_NO_ERR
945c51f124SMoriah Waterland 
955c51f124SMoriah Waterland /* Function codes and their matching strings */
965c51f124SMoriah Waterland static ERR_STRING_DATA SUNW_str_functs[] = {
975c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_USE_X509CERT, 0),	   "sunw_use_x509cert" },
985c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_USE_PKEY, 0),	   "sunw_use_pkey" },
995c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_USE_TASTORE, 0),	   "sunw_use_tastore" },
1005c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_USE_CERTFILE, 0),	   "sunw_p12_use_certfile" },
1015c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_USE_KEYFILE, 0),	   "sunw_p12_use_keyfile" },
1025c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_USE_TRUSTFILE, 0),	   "sunw_p12_use_trustfile" },
1035c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_READ_FILE, 0),	   "p12_read_file" },
1045c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_DOPARSE, 0),	   "p12_doparse" },
1055c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_PKCS12_PARSE, 0),	   "sunw_PKCS12_parse" },
1065c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_PKCS12_CONTENTS, 0),  "sunw_PKCS12_contents" },
1075c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_PARSE_ONE_BAG, 0),	   "parse_one_bag" },
1085c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_PKCS12_CREATE, 0),	   "sunw_PKCS12_create" },
1095c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_SPLIT_CERTS, 0),	   "sunw_split_certs" },
1105c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_FIND_LOCALKEYID, 0),  "sunw_find_localkeyid" },
1115c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_SET_LOCALKEYID, 0),   "sunw_set_localkeyid" },
1125c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_GET_LOCALKEYID, 0),   "sunw_get_localkeyid" },
1135c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_SET_FNAME, 0),	   "sunw_set_fname" },
1145c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_GET_PKEY_FNAME, 0),   "sunw_get_pkey_fname" },
1155c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_APPEND_KEYS, 0),	   "sunw_append_keys" },
1165c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_PEM_CONTENTS, 0),	   "sunw_PEM_contents" },
1175c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_PEM_INFO, 0),	   "pem_info" },
1185c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_ASC2BMPSTRING, 0),	   "asc2bmpstring" },
1195c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_UTF82ASCSTR, 0),	   "utf82ascstr" },
1205c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_FINDATTR, 0),	   "findattr" },
1215c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_TYPE2ATTRIB, 0),	   "type2attrib" },
1225c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_MOVE_CERTS, 0),	   "move_certs" },
1235c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_FIND_FNAME, 0),	   "sunw_find_fname" },
1245c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_PARSE_OUTER, 0),	   "parse_outer" },
1255c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_CHECKFILE, 0),	   "checkfile" },
1265c51f124SMoriah Waterland 	{ 0, NULL }
1275c51f124SMoriah Waterland };
1285c51f124SMoriah Waterland 
1295c51f124SMoriah Waterland /* Error codes and their matching strings */
1305c51f124SMoriah Waterland static ERR_STRING_DATA SUNW_str_reasons[] = {
1315c51f124SMoriah Waterland 	{ SUNW_R_INVALID_ARG,		"invalid argument" },
1325c51f124SMoriah Waterland 	{ SUNW_R_MEMORY_FAILURE,	"memory failure" },
1335c51f124SMoriah Waterland 	{ SUNW_R_MAC_VERIFY_FAILURE,	"mac verify failure" },
1345c51f124SMoriah Waterland 	{ SUNW_R_MAC_CREATE_FAILURE,	"mac create failure" },
1355c51f124SMoriah Waterland 	{ SUNW_R_BAD_FILETYPE,		"bad file type" },
1365c51f124SMoriah Waterland 	{ SUNW_R_BAD_PKEY,		"bad or missing private key" },
1375c51f124SMoriah Waterland 	{ SUNW_R_BAD_PKEYTYPE,		"unsupported key type" },
1385c51f124SMoriah Waterland 	{ SUNW_R_PKEY_READ_ERR,		"unable to read private key" },
1395c51f124SMoriah Waterland 	{ SUNW_R_NO_TRUST_ANCHOR,	"no trust anchors found" },
1405c51f124SMoriah Waterland 	{ SUNW_R_READ_TRUST_ERR,	"unable to read trust anchor" },
1415c51f124SMoriah Waterland 	{ SUNW_R_ADD_TRUST_ERR,		"unable to add trust anchor" },
1425c51f124SMoriah Waterland 	{ SUNW_R_PKCS12_PARSE_ERR,	"PKCS12 parse error" },
1435c51f124SMoriah Waterland 	{ SUNW_R_PKCS12_CREATE_ERR,	"PKCS12 create error" },
1445c51f124SMoriah Waterland 	{ SUNW_R_BAD_CERTTYPE,		"unsupported certificate type" },
1455c51f124SMoriah Waterland 	{ SUNW_R_PARSE_CERT_ERR,	"error parsing PKCS12 certificate" },
1465c51f124SMoriah Waterland 	{ SUNW_R_PARSE_BAG_ERR,		"error parsing PKCS12 bag" },
1475c51f124SMoriah Waterland 	{ SUNW_R_MAKE_BAG_ERR,		"error making PKCS12 bag" },
1485c51f124SMoriah Waterland 	{ SUNW_R_BAD_LKID,		"bad localKeyID format" },
1495c51f124SMoriah Waterland 	{ SUNW_R_SET_LKID_ERR,		"error setting localKeyID" },
1505c51f124SMoriah Waterland 	{ SUNW_R_BAD_FNAME,		"bad friendlyName format" },
1515c51f124SMoriah Waterland 	{ SUNW_R_SET_FNAME_ERR,		"error setting friendlyName" },
1525c51f124SMoriah Waterland 	{ SUNW_R_BAD_TRUST,		"bad or missing trust anchor" },
1535c51f124SMoriah Waterland 	{ SUNW_R_BAD_BAGTYPE,		"unsupported bag type" },
1545c51f124SMoriah Waterland 	{ SUNW_R_CERT_ERR,		"certificate error" },
1555c51f124SMoriah Waterland 	{ SUNW_R_PKEY_ERR,		"private key error" },
1565c51f124SMoriah Waterland 	{ SUNW_R_READ_ERR,		"error reading file" },
1575c51f124SMoriah Waterland 	{ SUNW_R_ADD_ATTR_ERR,		"error adding attribute" },
1585c51f124SMoriah Waterland 	{ SUNW_R_STR_CONVERT_ERR,	"error converting string" },
1595c51f124SMoriah Waterland 	{ SUNW_R_PKCS12_EMPTY_ERR,	"empty PKCS12 structure" },
1605c51f124SMoriah Waterland 	{ SUNW_R_PASSWORD_ERR,		"bad password" },
1615c51f124SMoriah Waterland 	{ 0, NULL }
1625c51f124SMoriah Waterland };
1635c51f124SMoriah Waterland 
1645c51f124SMoriah Waterland /*
1655c51f124SMoriah Waterland  * The library name that our module will be known as. This name
1665c51f124SMoriah Waterland  * may be retrieved via OpenSSLs error APIs.
1675c51f124SMoriah Waterland  */
1685c51f124SMoriah Waterland static ERR_STRING_DATA SUNW_lib_name[] = {
1695c51f124SMoriah Waterland 	{ 0,	SUNW_LIB_NAME },
1705c51f124SMoriah Waterland 	{ 0, NULL }
1715c51f124SMoriah Waterland };
1725c51f124SMoriah Waterland #endif
1735c51f124SMoriah Waterland 
1745c51f124SMoriah Waterland /*
1755c51f124SMoriah Waterland  * The value of this variable (initialized by a call to
1765c51f124SMoriah Waterland  * ERR_load_SUNW_strings()) is what identifies our errors
1775c51f124SMoriah Waterland  * to OpenSSL as being ours.
1785c51f124SMoriah Waterland  */
1795c51f124SMoriah Waterland static int SUNW_lib_error_code = 0;
1805c51f124SMoriah Waterland 
1815c51f124SMoriah Waterland /* local routines */
1825c51f124SMoriah Waterland static int	parse_pkcs12(PKCS12 *, const char *, int, char *, int, char *,
1835c51f124SMoriah Waterland     EVP_PKEY **, X509 **, STACK_OF(X509) **);
1845c51f124SMoriah Waterland static int	pem_info(FILE *, pem_password_cb, void *,
1855c51f124SMoriah Waterland     STACK_OF(EVP_PKEY) **, STACK_OF(X509) **);
1865c51f124SMoriah Waterland 
1875c51f124SMoriah Waterland static int	parse_outer(PKCS12 *, const char *, STACK_OF(EVP_PKEY) *,
1885c51f124SMoriah Waterland     STACK_OF(X509) *);
1895c51f124SMoriah Waterland 
1905c51f124SMoriah Waterland static int	parse_all_bags(STACK_OF(PKCS12_SAFEBAG) *, const char *,
1915c51f124SMoriah Waterland     STACK_OF(EVP_PKEY) *, STACK_OF(X509) *);
1925c51f124SMoriah Waterland 
1935c51f124SMoriah Waterland static int	parse_one_bag(PKCS12_SAFEBAG *, const char *,
1945c51f124SMoriah Waterland     STACK_OF(EVP_PKEY) *, STACK_OF(X509) *);
1955c51f124SMoriah Waterland 
1965c51f124SMoriah Waterland static X509_ATTRIBUTE	*type2attrib(ASN1_TYPE *, int);
1975c51f124SMoriah Waterland static ASN1_TYPE	*attrib2type(X509_ATTRIBUTE *);
1985c51f124SMoriah Waterland static uchar_t		*utf82ascstr(ASN1_UTF8STRING *);
1995c51f124SMoriah Waterland static ASN1_BMPSTRING	*asc2bmpstring(const char *, int);
2005c51f124SMoriah Waterland static int		find_attr_by_nid(STACK_OF(X509_ATTRIBUTE) *, int);
2015c51f124SMoriah Waterland static int		find_attr(int, ASN1_STRING *, STACK_OF(EVP_PKEY) *,
2025c51f124SMoriah Waterland     EVP_PKEY **, STACK_OF(X509) *, X509 **);
2035c51f124SMoriah Waterland 
2045c51f124SMoriah Waterland static chk_errs_t	check_time(chk_actions_t, X509 *);
2055c51f124SMoriah Waterland static int		get_key_cert(int, STACK_OF(EVP_PKEY) *, EVP_PKEY **,
2065c51f124SMoriah Waterland     STACK_OF(X509) *, X509 **cert);
2075c51f124SMoriah Waterland static int		move_certs(STACK_OF(X509) *, STACK_OF(X509) *);
2085c51f124SMoriah Waterland static int		sunw_append_keys(STACK_OF(EVP_PKEY) *,
2095c51f124SMoriah Waterland     STACK_OF(EVP_PKEY) *);
2105c51f124SMoriah Waterland static int		set_results(STACK_OF(EVP_PKEY) **,
2115c51f124SMoriah Waterland     STACK_OF(EVP_PKEY) **, STACK_OF(X509) **, STACK_OF(X509) **,
2125c51f124SMoriah Waterland     STACK_OF(X509) **, STACK_OF(X509) **,
2135c51f124SMoriah Waterland     STACK_OF(EVP_PKEY) **, STACK_OF(EVP_PKEY) **);
2145c51f124SMoriah Waterland 
2155c51f124SMoriah Waterland /*
2165c51f124SMoriah Waterland  * ----------------------------------------------------------------------------
2175c51f124SMoriah Waterland  * Public routines
2185c51f124SMoriah Waterland  * ----------------------------------------------------------------------------
2195c51f124SMoriah Waterland  */
2205c51f124SMoriah Waterland 
2215c51f124SMoriah Waterland /*
2225c51f124SMoriah Waterland  * sunw_PKCS12_parse - Parse a PKCS12 structure and break it into its parts.
2235c51f124SMoriah Waterland  *
2245c51f124SMoriah Waterland  * Parse and decrypt a PKCS#12 structure returning user key, user cert and/or
2255c51f124SMoriah Waterland  * other (CA) certs. Note either ca should be NULL, *ca should be NULL,
2265c51f124SMoriah Waterland  * or it should point to a valid STACK_OF(X509) structure. pkey and cert can
2275c51f124SMoriah Waterland  * be passed uninitialized.
2285c51f124SMoriah Waterland  *
2295c51f124SMoriah Waterland  * Arguments:
2305c51f124SMoriah Waterland  *   p12      - Structure with pkcs12 info to be parsed
2315c51f124SMoriah Waterland  *   pass     - Pass phrase for the private key (possibly empty) or NULL if
2325c51f124SMoriah Waterland  *              there is none.
2335c51f124SMoriah Waterland  *   matchty  - Info about which certs/keys to return if many are in the file.
2345c51f124SMoriah Waterland  *   keyid    - If private key localkeyids friendlynames are to match a
2355c51f124SMoriah Waterland  *              predetermined value, the value to match. This value should
2365c51f124SMoriah Waterland  *		be an octet string.
2375c51f124SMoriah Waterland  *   keyid_len- Length of the keyid byte string.
2385c51f124SMoriah Waterland  *   name_str - If friendlynames are to match a predetermined value, the value
2395c51f124SMoriah Waterland  *		 to match. This value should be a NULL terminated string.
2405c51f124SMoriah Waterland  *   pkey     - Points to location pointing to the private key returned.
2415c51f124SMoriah Waterland  *   cert     - Points to locaiton which points to the client cert returned
2425c51f124SMoriah Waterland  *   ca       - Points to location that points to a stack of 'certificate
2435c51f124SMoriah Waterland  *               authority' certs/trust anchors.
2445c51f124SMoriah Waterland  *
2455c51f124SMoriah Waterland  * Match based on the value of 'matchty' and the contents of 'keyid'
2465c51f124SMoriah Waterland  * and/or 'name_str', as appropriate.  Go through the lists of certs and
2475c51f124SMoriah Waterland  * private keys which were taken from the pkcs12 structure, looking for
2485c51f124SMoriah Waterland  * matches of the requested type.  This function only searches the lists of
2495c51f124SMoriah Waterland  * matching private keys and client certificates.  Kinds of matches allowed,
2505c51f124SMoriah Waterland  * and the order in which they will be checked, are:
2515c51f124SMoriah Waterland  *
2525c51f124SMoriah Waterland  *   1) Find the key and/or cert whose localkeyid attributes matches
2535c51f124SMoriah Waterland  *      'keyid'.
2545c51f124SMoriah Waterland  *   2) Find the key and/or cert whose friendlyname attributes matches
2555c51f124SMoriah Waterland  *	'name_str'
2565c51f124SMoriah Waterland  *   3) Return the first matching key/cert pair found.
2575c51f124SMoriah Waterland  *   4) Return the last matching key/cert pair found.
2585c51f124SMoriah Waterland  *   5) Return whatever cert and/or key are available, even unmatching.
2595c51f124SMoriah Waterland  *
2605c51f124SMoriah Waterland  *   Append to the CA list, the certs which do not have matching private
2615c51f124SMoriah Waterland  *   keys and which were not selected.
2625c51f124SMoriah Waterland  *
2635c51f124SMoriah Waterland  * If none of the bits are set, no client certs or private keys will be
2645c51f124SMoriah Waterland  * returned.  CA (aka trust anchor) certs can be.
2655c51f124SMoriah Waterland  *
2665c51f124SMoriah Waterland  * Notes: If #3 is selected, then #4 will never occur.  CA certs will be
2675c51f124SMoriah Waterland  * selected after a cert/key pairs are isolated.
2685c51f124SMoriah Waterland  *
2695c51f124SMoriah Waterland  * Returns:
2705c51f124SMoriah Waterland  *  <  0 - An error returned.  Call ERR_get_error() to get errors information.
2715c51f124SMoriah Waterland  *         Where possible, memory has been freed.
2725c51f124SMoriah Waterland  *  >= 0 - Objects were found and returned.  Which objects are indicated by
2735c51f124SMoriah Waterland  *         which bits are set (FOUND_PKEY, FOUND_CERT, FOUND_CA_CERTS).
2745c51f124SMoriah Waterland  */
2755c51f124SMoriah Waterland int
2765c51f124SMoriah Waterland sunw_PKCS12_parse(PKCS12 *p12, const char *pass, int matchty, char *keyid,
2775c51f124SMoriah Waterland     int keyid_len, char *name_str, EVP_PKEY **pkey, X509 **cert,
2785c51f124SMoriah Waterland     STACK_OF(X509) **ca)
2795c51f124SMoriah Waterland {
2805c51f124SMoriah Waterland 	boolean_t ca_supplied;
2815c51f124SMoriah Waterland 	int retval = -1;
2825c51f124SMoriah Waterland 
2835c51f124SMoriah Waterland 	/* If NULL PKCS12 structure, this is an error */
2845c51f124SMoriah Waterland 	if (p12 == NULL) {
2855c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_PARSE, SUNW_R_INVALID_ARG);
2865c51f124SMoriah Waterland 		return (-1);
2875c51f124SMoriah Waterland 	}
2885c51f124SMoriah Waterland 
2895c51f124SMoriah Waterland 	/* Set up arguments....  These will be allocated if needed */
2905c51f124SMoriah Waterland 	if (pkey)
2915c51f124SMoriah Waterland 		*pkey = NULL;
2925c51f124SMoriah Waterland 	if (cert)
2935c51f124SMoriah Waterland 		*cert = NULL;
2945c51f124SMoriah Waterland 
2955c51f124SMoriah Waterland 	/*
2965c51f124SMoriah Waterland 	 * If there is already a ca list, use it.  Otherwise, allocate one
2975c51f124SMoriah Waterland 	 * and free is later if an error occurs or whatever.)
2985c51f124SMoriah Waterland 	 */
2995c51f124SMoriah Waterland 	ca_supplied = (ca != NULL && *ca != NULL);
3005c51f124SMoriah Waterland 	if (ca != NULL && *ca == NULL) {
3015c51f124SMoriah Waterland 		if ((*ca = sk_X509_new_null()) == NULL) {
3025c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PKCS12_PARSE, SUNW_R_MEMORY_FAILURE);
3035c51f124SMoriah Waterland 			return (-1);
3045c51f124SMoriah Waterland 		}
3055c51f124SMoriah Waterland 	}
3065c51f124SMoriah Waterland 
3075c51f124SMoriah Waterland 	/*
3085c51f124SMoriah Waterland 	 * If password is zero length or NULL then try verifying both cases
3095c51f124SMoriah Waterland 	 * to determine which password is correct. The reason for this is that
3105c51f124SMoriah Waterland 	 * under PKCS#12 password based encryption no password and a zero
3115c51f124SMoriah Waterland 	 * length password are two different things. If the password has a
3125c51f124SMoriah Waterland 	 * non-zero length and is not NULL then call PKCS12_verify_mac() with
3135c51f124SMoriah Waterland 	 * a length of '-1' and let it use strlen() to figure out the length
3145c51f124SMoriah Waterland 	 * of the password.
3155c51f124SMoriah Waterland 	 */
3165c51f124SMoriah Waterland 	/* Check the mac */
3175c51f124SMoriah Waterland 	if (pass == NULL || *pass == '\0') {
3185c51f124SMoriah Waterland 		if (PKCS12_verify_mac(p12, NULL, 0))
3195c51f124SMoriah Waterland 			pass = NULL;
3205c51f124SMoriah Waterland 		else if (PKCS12_verify_mac(p12, "", 0))
3215c51f124SMoriah Waterland 			pass = "";
3225c51f124SMoriah Waterland 		else {
3235c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PKCS12_PARSE,
3245c51f124SMoriah Waterland 			    SUNW_R_MAC_VERIFY_FAILURE);
3255c51f124SMoriah Waterland 			goto err;
3265c51f124SMoriah Waterland 		}
3275c51f124SMoriah Waterland 	} else if (PKCS12_verify_mac(p12, pass, -1) == 0) {
3285c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_PARSE, SUNW_R_MAC_VERIFY_FAILURE);
3295c51f124SMoriah Waterland 		goto err;
3305c51f124SMoriah Waterland 	}
3315c51f124SMoriah Waterland 
3325c51f124SMoriah Waterland 	retval = parse_pkcs12(p12, pass, matchty, keyid, keyid_len,
3335c51f124SMoriah Waterland 	    name_str, pkey, cert, ca);
3345c51f124SMoriah Waterland 	if (retval < 0) {
3355c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_PARSE, SUNW_R_PKCS12_PARSE_ERR);
3365c51f124SMoriah Waterland 		goto err;
3375c51f124SMoriah Waterland 	}
3385c51f124SMoriah Waterland 	return (retval);
3395c51f124SMoriah Waterland 
3405c51f124SMoriah Waterland err:
3415c51f124SMoriah Waterland 	if (pkey && *pkey) {
3425c51f124SMoriah Waterland 		sunw_evp_pkey_free(*pkey);
3435c51f124SMoriah Waterland 	}
3445c51f124SMoriah Waterland 	if (cert && *cert)
3455c51f124SMoriah Waterland 		X509_free(*cert);
3465c51f124SMoriah Waterland 	if (ca_supplied == B_FALSE && ca != NULL)
3475c51f124SMoriah Waterland 		sk_X509_pop_free(*ca, X509_free);
3485c51f124SMoriah Waterland 
3495c51f124SMoriah Waterland 	return (-1);
3505c51f124SMoriah Waterland 
3515c51f124SMoriah Waterland }
3525c51f124SMoriah Waterland 
3535c51f124SMoriah Waterland 
3545c51f124SMoriah Waterland /*
3555c51f124SMoriah Waterland  * sunw_PEM_contents() parses a PEM file and returns component parts found
3565c51f124SMoriah Waterland  *
3575c51f124SMoriah Waterland  * Parse and decrypt a PEM file, returning any user keys and certs.
3585c51f124SMoriah Waterland  *
3595c51f124SMoriah Waterland  * There are some limits to this function.  It will ignore the following:
3605c51f124SMoriah Waterland  * - certificates identified by "TRUSTED CERTIFICATE"
3615c51f124SMoriah Waterland  * - CERTIFICATE REQUEST and NEW CERTIFICATE REQUEST records.
3625c51f124SMoriah Waterland  * - X509 CRL
3635c51f124SMoriah Waterland  * - DH PARAMETERS
3645c51f124SMoriah Waterland  * - DSA PARAMETERS
3655c51f124SMoriah Waterland  * - Any PUBLIC KEY
3665c51f124SMoriah Waterland  * - PKCS7
3675c51f124SMoriah Waterland  * - PRIVATE KEY or ENCRYPTED PRIVATE KEY (PKCS 8)
3685c51f124SMoriah Waterland  *
3695c51f124SMoriah Waterland  * Arguments:
3705c51f124SMoriah Waterland  *   fp       - File pointer for file containing PEM data.
3715c51f124SMoriah Waterland  *   pass     - Pass phrase for the private key or NULL if there is none.
3725c51f124SMoriah Waterland  *   pkeys    - Points to address of a stack of private keys to return.
3735c51f124SMoriah Waterland  *   certs    - Points to address of a stack of client certs to return.
3745c51f124SMoriah Waterland  *
3755c51f124SMoriah Waterland  *   The pointers to stacks should either be NULL or their contents should
3765c51f124SMoriah Waterland  *   either be NULL or should point to a valid STACK_OF(X509) structure.
3775c51f124SMoriah Waterland  *   If the stacks contain information, corresponding information from the
3785c51f124SMoriah Waterland  *   file will be appended to the original contents.
3795c51f124SMoriah Waterland  *
3805c51f124SMoriah Waterland  *   Note:  Client certs and and their matching private keys will be in any
3815c51f124SMoriah Waterland  *   order.
3825c51f124SMoriah Waterland  *
3835c51f124SMoriah Waterland  *   Certs which have no matching private key are assumed to be ca certs.
3845c51f124SMoriah Waterland  *
3855c51f124SMoriah Waterland  * Returns:
3865c51f124SMoriah Waterland  *  <  0 - An error returned.  Call ERR_get_error() to get errors information.
3875c51f124SMoriah Waterland  *         Where possible, memory has been freed.
3885c51f124SMoriah Waterland  *  >= 0 - Objects were found and returned.  Which objects are indicated by
3895c51f124SMoriah Waterland  *         which bits are set (FOUND_PKEY, FOUND_CERT)
3905c51f124SMoriah Waterland  */
3915c51f124SMoriah Waterland int sunw_PEM_contents(FILE *fp, pem_password_cb *cb, void *userdata,
3925c51f124SMoriah Waterland     STACK_OF(EVP_PKEY) **pkey, STACK_OF(X509) **certs)
3935c51f124SMoriah Waterland {
3945c51f124SMoriah Waterland 	STACK_OF(EVP_PKEY) *work_kl = NULL;
3955c51f124SMoriah Waterland 	STACK_OF(X509) *work_ca = NULL;
3965c51f124SMoriah Waterland 	int retval = -1;
3975c51f124SMoriah Waterland 
3985c51f124SMoriah Waterland 	/*
3995c51f124SMoriah Waterland 	 * Allocate the working stacks for private key and for the
4005c51f124SMoriah Waterland 	 * ca certs.
4015c51f124SMoriah Waterland 	 */
4025c51f124SMoriah Waterland 	if ((work_kl = sk_EVP_PKEY_new_null()) == NULL) {
4035c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PEM_CONTENTS, SUNW_R_MEMORY_FAILURE);
4045c51f124SMoriah Waterland 		goto cleanup;
4055c51f124SMoriah Waterland 	}
4065c51f124SMoriah Waterland 
4075c51f124SMoriah Waterland 	if ((work_ca = sk_X509_new_null()) == NULL) {
4085c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PEM_CONTENTS, SUNW_R_MEMORY_FAILURE);
4095c51f124SMoriah Waterland 		goto cleanup;
4105c51f124SMoriah Waterland 	}
4115c51f124SMoriah Waterland 
4125c51f124SMoriah Waterland 	/* Error strings are set within the following. */
4135c51f124SMoriah Waterland 	if (pem_info(fp, cb, userdata, &work_kl, &work_ca) <= 0) {
4145c51f124SMoriah Waterland 		goto cleanup;
4155c51f124SMoriah Waterland 	}
4165c51f124SMoriah Waterland 
4175c51f124SMoriah Waterland 	/* on error, set_results() returns an error on the stack */
4185c51f124SMoriah Waterland 	retval = set_results(pkey, &work_kl, certs, &work_ca, NULL, NULL, NULL,
4195c51f124SMoriah Waterland 	    NULL);
4205c51f124SMoriah Waterland cleanup:
4215c51f124SMoriah Waterland 	if (work_kl != NULL) {
4225c51f124SMoriah Waterland 		sk_EVP_PKEY_pop_free(work_kl, sunw_evp_pkey_free);
4235c51f124SMoriah Waterland 	}
4245c51f124SMoriah Waterland 	if (work_ca != NULL)
4255c51f124SMoriah Waterland 		sk_X509_pop_free(work_ca, X509_free);
4265c51f124SMoriah Waterland 
4275c51f124SMoriah Waterland 	return (retval);
4285c51f124SMoriah Waterland }
4295c51f124SMoriah Waterland 
4305c51f124SMoriah Waterland 
4315c51f124SMoriah Waterland /*
4325c51f124SMoriah Waterland  * sunw_PKCS12_contents() parses a pkcs#12 structure and returns component
4335c51f124SMoriah Waterland  *     parts found, without evaluation.
4345c51f124SMoriah Waterland  *
4355c51f124SMoriah Waterland  * Parse and decrypt a PKCS#12 structure returning any user keys and/or
4365c51f124SMoriah Waterland  * various certs. Note these should either be NULL, *whatever should
4375c51f124SMoriah Waterland  * be NULL, or it should point to a valid STACK_OF(X509) structure.
4385c51f124SMoriah Waterland  *
4395c51f124SMoriah Waterland  * Arguments:
4405c51f124SMoriah Waterland  *   p12      - Structure with pkcs12 info to be parsed
4415c51f124SMoriah Waterland  *   pass     - Pass phrase for the private key and entire pkcs12 wad (possibly
4425c51f124SMoriah Waterland  *              empty) or NULL if there is none.
4435c51f124SMoriah Waterland  *   pkeys    - Points to address of a stack of private keys to return.
4445c51f124SMoriah Waterland  *   certs    - Points to address of a stack of client certs return.
4455c51f124SMoriah Waterland  *
4465c51f124SMoriah Waterland  *   Note:  The certs and keys being returned are in random order.
4475c51f124SMoriah Waterland  *
4485c51f124SMoriah Waterland  * Returns:
4495c51f124SMoriah Waterland  *  <  0 - An error returned.  Call ERR_get_error() to get errors information.
4505c51f124SMoriah Waterland  *         Where possible, memory has been freed.
4515c51f124SMoriah Waterland  *  >= 0 - Objects were found and returned.  Which objects are indicated by
4525c51f124SMoriah Waterland  *         which bits are set (FOUND_PKEY or FOUND_CERT)
4535c51f124SMoriah Waterland  */
4545c51f124SMoriah Waterland int
4555c51f124SMoriah Waterland sunw_PKCS12_contents(PKCS12 *p12, const char *pass, STACK_OF(EVP_PKEY) **pkey,
4565c51f124SMoriah Waterland     STACK_OF(X509) **certs)
4575c51f124SMoriah Waterland {
4585c51f124SMoriah Waterland 	STACK_OF(EVP_PKEY) *work_kl = NULL;
4595c51f124SMoriah Waterland 	STACK_OF(X509) *work_ca = NULL;
4605c51f124SMoriah Waterland 	int retval = -1;
4615c51f124SMoriah Waterland 
4625c51f124SMoriah Waterland 	/*
4635c51f124SMoriah Waterland 	 * Allocate the working stacks for private key and for the
4645c51f124SMoriah Waterland 	 * ca certs.
4655c51f124SMoriah Waterland 	 */
4665c51f124SMoriah Waterland 	if ((work_kl = sk_EVP_PKEY_new_null()) == NULL) {
4675c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_CONTENTS, SUNW_R_MEMORY_FAILURE);
4685c51f124SMoriah Waterland 		goto cleanup;
4695c51f124SMoriah Waterland 	}
4705c51f124SMoriah Waterland 
4715c51f124SMoriah Waterland 	if ((work_ca = sk_X509_new_null()) == NULL) {
4725c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_CONTENTS, SUNW_R_MEMORY_FAILURE);
4735c51f124SMoriah Waterland 		goto cleanup;
4745c51f124SMoriah Waterland 	}
4755c51f124SMoriah Waterland 
4765c51f124SMoriah Waterland 	if (parse_outer(p12, pass, work_kl, work_ca) == 0) {
4775c51f124SMoriah Waterland 		/*
4785c51f124SMoriah Waterland 		 * Error already on stack
4795c51f124SMoriah Waterland 		 */
4805c51f124SMoriah Waterland 		goto cleanup;
4815c51f124SMoriah Waterland 	}
4825c51f124SMoriah Waterland 
4835c51f124SMoriah Waterland 	/* on error, set_results() returns an error on the stack */
4845c51f124SMoriah Waterland 	retval = set_results(pkey, &work_kl, certs, &work_ca, NULL,
4855c51f124SMoriah Waterland 	    NULL, NULL, NULL);
4865c51f124SMoriah Waterland 
4875c51f124SMoriah Waterland cleanup:
4885c51f124SMoriah Waterland 	if (work_kl != NULL) {
4895c51f124SMoriah Waterland 		sk_EVP_PKEY_pop_free(work_kl, sunw_evp_pkey_free);
4905c51f124SMoriah Waterland 	}
4915c51f124SMoriah Waterland 
4925c51f124SMoriah Waterland 	return (retval);
4935c51f124SMoriah Waterland }
4945c51f124SMoriah Waterland 
4955c51f124SMoriah Waterland 
4965c51f124SMoriah Waterland 
4975c51f124SMoriah Waterland /*
4985c51f124SMoriah Waterland  * sunw_split_certs() - Given a list of certs and a list of private keys,
4995c51f124SMoriah Waterland  *     moves certs which match one of the keys to a different stack.
5005c51f124SMoriah Waterland  *
5015c51f124SMoriah Waterland  * Arguments:
5025c51f124SMoriah Waterland  *   allkeys  - Points to a stack of private keys to search.
5035c51f124SMoriah Waterland  *   allcerts - Points to a stack of certs to be searched.
5045c51f124SMoriah Waterland  *   keycerts - Points to address of a stack of certs with matching private
5055c51f124SMoriah Waterland  *              keys.  They are moved from 'allcerts'.  This may not be NULL
5065c51f124SMoriah Waterland  *              when called.  If *keycerts is NULL upon entry, a new stack will
5075c51f124SMoriah Waterland  *              be allocated.  Otherwise, it must be a valid STACK_OF(509).
5085c51f124SMoriah Waterland  *   nocerts  - Points to address of a stack for keys which have no matching
5095c51f124SMoriah Waterland  *              certs.  Keys are moved from 'allkeys' here when they have no
5105c51f124SMoriah Waterland  *              matching certs.  If this is NULL, matchless keys will be
5115c51f124SMoriah Waterland  *              discarded.
5125c51f124SMoriah Waterland  *
5135c51f124SMoriah Waterland  *   Notes:  If an error occurs while moving certs, the cert being move may be
5145c51f124SMoriah Waterland  *   lost.  'keycerts' may only contain part of the matching certs.  The number
5155c51f124SMoriah Waterland  *   of certs successfully moved can be found by checking sk_X509_num(keycerts).
5165c51f124SMoriah Waterland  *
5175c51f124SMoriah Waterland  *   If there is a key which does not have a matching cert, it is moved to
5185c51f124SMoriah Waterland  *   the list nocerts.
5195c51f124SMoriah Waterland  *
5205c51f124SMoriah Waterland  *   If all certs are removed from 'certs' and/or 'pkeys', it will be the
5215c51f124SMoriah Waterland  *   caller's responsibility to free the empty stacks.
5225c51f124SMoriah Waterland  *
5235c51f124SMoriah Waterland  * Returns:
5245c51f124SMoriah Waterland  *  <  0 - An error returned.  Call ERR_get_error() to get errors information.
5255c51f124SMoriah Waterland  *         Where possible, memory has been freed.
5265c51f124SMoriah Waterland  *  >= 0 - The number of certs moved from 'cert' to 'pkcerts'.
5275c51f124SMoriah Waterland  */
5285c51f124SMoriah Waterland int
5295c51f124SMoriah Waterland sunw_split_certs(STACK_OF(EVP_PKEY) *allkeys, STACK_OF(X509) *allcerts,
5305c51f124SMoriah Waterland     STACK_OF(X509) **keycerts, STACK_OF(EVP_PKEY) **nocerts)
5315c51f124SMoriah Waterland {
5325c51f124SMoriah Waterland 	STACK_OF(X509) *matching;
5335c51f124SMoriah Waterland 	STACK_OF(EVP_PKEY) *nomatch;
5345c51f124SMoriah Waterland 	EVP_PKEY *tmpkey;
5355c51f124SMoriah Waterland 	X509 *tmpcert;
5365c51f124SMoriah Waterland 	int count = 0;
5375c51f124SMoriah Waterland 	int found;
5385c51f124SMoriah Waterland 	int res;
5395c51f124SMoriah Waterland 	int i;
5405c51f124SMoriah Waterland 	int k;
5415c51f124SMoriah Waterland 
5425c51f124SMoriah Waterland 	*keycerts = NULL;
5435c51f124SMoriah Waterland 	if (nocerts != NULL)
5445c51f124SMoriah Waterland 		*nocerts = NULL;
5455c51f124SMoriah Waterland 	nomatch = NULL;
5465c51f124SMoriah Waterland 
5475c51f124SMoriah Waterland 	if ((matching = sk_X509_new_null()) == NULL) {
5485c51f124SMoriah Waterland 		SUNWerr(SUNW_F_SPLIT_CERTS, SUNW_R_MEMORY_FAILURE);
5495c51f124SMoriah Waterland 		return (-1);
5505c51f124SMoriah Waterland 	}
5515c51f124SMoriah Waterland 	*keycerts = matching;
5525c51f124SMoriah Waterland 
5535c51f124SMoriah Waterland 	k = 0;
5545c51f124SMoriah Waterland 	while (k < sk_EVP_PKEY_num(allkeys)) {
5555c51f124SMoriah Waterland 		found = 0;
5565c51f124SMoriah Waterland 		tmpkey = sk_EVP_PKEY_value(allkeys, k);
5575c51f124SMoriah Waterland 
5585c51f124SMoriah Waterland 		for (i = 0; i < sk_X509_num(allcerts); i++) {
5595c51f124SMoriah Waterland 			tmpcert = sk_X509_value(allcerts, i);
5605c51f124SMoriah Waterland 			res = X509_check_private_key(tmpcert, tmpkey);
5615c51f124SMoriah Waterland 			if (res != 0) {
5625c51f124SMoriah Waterland 				count++;
5635c51f124SMoriah Waterland 				found = 1;
5645c51f124SMoriah Waterland 				tmpcert = sk_X509_delete(allcerts, i);
5655c51f124SMoriah Waterland 				if (sk_X509_push(matching, tmpcert) == 0) {
5665c51f124SMoriah Waterland 					X509_free(tmpcert);
5675c51f124SMoriah Waterland 					SUNWerr(SUNW_F_SPLIT_CERTS,
5685c51f124SMoriah Waterland 					    SUNW_R_MEMORY_FAILURE);
5695c51f124SMoriah Waterland 					return (-1);
5705c51f124SMoriah Waterland 				}
5715c51f124SMoriah Waterland 				break;
5725c51f124SMoriah Waterland 			}
5735c51f124SMoriah Waterland 		}
5745c51f124SMoriah Waterland 		if (found != 0) {
5755c51f124SMoriah Waterland 			/*
5765c51f124SMoriah Waterland 			 * Found a match - keep the key & check out the next
5775c51f124SMoriah Waterland 			 * one.
5785c51f124SMoriah Waterland 			 */
5795c51f124SMoriah Waterland 			k++;
5805c51f124SMoriah Waterland 		} else {
5815c51f124SMoriah Waterland 			/*
5825c51f124SMoriah Waterland 			 * No cert matching this key.  Move the key if
5835c51f124SMoriah Waterland 			 * possible or discard it.  Don't increment the
5845c51f124SMoriah Waterland 			 * index.
5855c51f124SMoriah Waterland 			 */
5865c51f124SMoriah Waterland 			if (nocerts == NULL) {
5875c51f124SMoriah Waterland 				tmpkey = sk_EVP_PKEY_delete(allkeys, k);
5885c51f124SMoriah Waterland 				sunw_evp_pkey_free(tmpkey);
5895c51f124SMoriah Waterland 			} else {
5905c51f124SMoriah Waterland 				if (*nocerts == NULL) {
5915c51f124SMoriah Waterland 					nomatch = sk_EVP_PKEY_new_null();
5925c51f124SMoriah Waterland 					if (nomatch == NULL) {
5935c51f124SMoriah Waterland 						SUNWerr(SUNW_F_SPLIT_CERTS,
5945c51f124SMoriah Waterland 						    SUNW_R_MEMORY_FAILURE);
5955c51f124SMoriah Waterland 						return (-1);
5965c51f124SMoriah Waterland 					}
5975c51f124SMoriah Waterland 					*nocerts = nomatch;
5985c51f124SMoriah Waterland 				}
5995c51f124SMoriah Waterland 				tmpkey = sk_EVP_PKEY_delete(allkeys, k);
6005c51f124SMoriah Waterland 				if (sk_EVP_PKEY_push(nomatch, tmpkey) == 0) {
6015c51f124SMoriah Waterland 					sunw_evp_pkey_free(tmpkey);
6025c51f124SMoriah Waterland 					SUNWerr(SUNW_F_SPLIT_CERTS,
6035c51f124SMoriah Waterland 					    SUNW_R_MEMORY_FAILURE);
6045c51f124SMoriah Waterland 					return (-1);
6055c51f124SMoriah Waterland 				}
6065c51f124SMoriah Waterland 			}
6075c51f124SMoriah Waterland 		}
6085c51f124SMoriah Waterland 	}
6095c51f124SMoriah Waterland 
6105c51f124SMoriah Waterland 	return (count);
6115c51f124SMoriah Waterland }
6125c51f124SMoriah Waterland 
6135c51f124SMoriah Waterland /*
6145c51f124SMoriah Waterland  * sunw_PKCS12_create() creates a pkcs#12 structure and given component parts.
6155c51f124SMoriah Waterland  *
6165c51f124SMoriah Waterland  * Given one or more of user private key, user cert and/or other (CA) certs,
6175c51f124SMoriah Waterland  * return an encrypted PKCS12 structure containing them.
6185c51f124SMoriah Waterland  *
6195c51f124SMoriah Waterland  * Arguments:
6205c51f124SMoriah Waterland  *   pass     - Pass phrase for the pkcs12 structure and private key (possibly
6215c51f124SMoriah Waterland  *              empty) or NULL if there is none.  It will be used to encrypt
6225c51f124SMoriah Waterland  *              both the private key(s) and as the pass phrase for the whole
6235c51f124SMoriah Waterland  *              pkcs12 wad.
6245c51f124SMoriah Waterland  *   pkeys    - Points to stack of private keys.
6255c51f124SMoriah Waterland  *   certs    - Points to stack of client (public ke) certs
6265c51f124SMoriah Waterland  *   cacerts  - Points to stack of 'certificate authority' certs (or trust
6275c51f124SMoriah Waterland  *              anchors).
6285c51f124SMoriah Waterland  *
6295c51f124SMoriah Waterland  *   Note that any of these may be NULL.
6305c51f124SMoriah Waterland  *
6315c51f124SMoriah Waterland  * Returns:
6325c51f124SMoriah Waterland  *   NULL     - An error occurred.
6335c51f124SMoriah Waterland  *   != NULL  - Address of PKCS12 structure.  The user is responsible for
6345c51f124SMoriah Waterland  *              freeing the memory when done.
6355c51f124SMoriah Waterland  */
6365c51f124SMoriah Waterland PKCS12 *
6375c51f124SMoriah Waterland sunw_PKCS12_create(const char *pass, STACK_OF(EVP_PKEY) *pkeys,
6385c51f124SMoriah Waterland     STACK_OF(X509) *certs, STACK_OF(X509) *cacerts)
6395c51f124SMoriah Waterland {
6405c51f124SMoriah Waterland 	int nid_cert = NID_pbe_WithSHA1And40BitRC2_CBC;
6415c51f124SMoriah Waterland 	int nid_key = NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
6425c51f124SMoriah Waterland 	STACK_OF(PKCS12_SAFEBAG) *bags = NULL;
6435c51f124SMoriah Waterland 	STACK_OF(PKCS7) *safes = NULL;
6445c51f124SMoriah Waterland 	PKCS12_SAFEBAG *bag = NULL;
6455c51f124SMoriah Waterland 	PKCS8_PRIV_KEY_INFO *p8 = NULL;
6465c51f124SMoriah Waterland 	EVP_PKEY *pkey = NULL;
6475c51f124SMoriah Waterland 	PKCS12 *ret_p12 = NULL;
6485c51f124SMoriah Waterland 	PKCS12 *p12 = NULL;
6495c51f124SMoriah Waterland 	PKCS7 *authsafe = NULL;
6505c51f124SMoriah Waterland 	X509 *cert = NULL;
6515c51f124SMoriah Waterland 	uchar_t *str = NULL;
6525c51f124SMoriah Waterland 	int certs_there = 0;
6535c51f124SMoriah Waterland 	int keys_there = 0;
6545c51f124SMoriah Waterland 	int len;
6555c51f124SMoriah Waterland 	int i;
6565c51f124SMoriah Waterland 
6575c51f124SMoriah Waterland 	if ((safes = sk_PKCS7_new_null()) == NULL) {
6585c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_MEMORY_FAILURE);
6595c51f124SMoriah Waterland 		return (NULL);
6605c51f124SMoriah Waterland 	}
6615c51f124SMoriah Waterland 
6625c51f124SMoriah Waterland 	if ((bags = sk_PKCS12_SAFEBAG_new_null()) == NULL) {
6635c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_MEMORY_FAILURE);
6645c51f124SMoriah Waterland 		goto err_ret;
6655c51f124SMoriah Waterland 	}
6665c51f124SMoriah Waterland 
6675c51f124SMoriah Waterland 	if (certs != NULL && sk_X509_num(certs) > 0) {
6685c51f124SMoriah Waterland 
6695c51f124SMoriah Waterland 		for (i = 0; i < sk_X509_num(certs); i++) {
6705c51f124SMoriah Waterland 			cert = sk_X509_value(certs, i);
6715c51f124SMoriah Waterland 
6725c51f124SMoriah Waterland 			/* Add user certificate */
6735c51f124SMoriah Waterland 			if ((bag = M_PKCS12_x5092certbag(cert)) == NULL) {
6745c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_CERT_ERR);
6755c51f124SMoriah Waterland 				goto err_ret;
6765c51f124SMoriah Waterland 			}
6775c51f124SMoriah Waterland 			if (cert->aux != NULL && cert->aux->alias != NULL &&
6785c51f124SMoriah Waterland 			    cert->aux->alias->type == V_ASN1_UTF8STRING) {
6795c51f124SMoriah Waterland 				str = utf82ascstr(cert->aux->alias);
6805c51f124SMoriah Waterland 				if (str == NULL) {
6815c51f124SMoriah Waterland 					/*
6825c51f124SMoriah Waterland 					 * Error already on stack
6835c51f124SMoriah Waterland 					 */
6845c51f124SMoriah Waterland 					goto err_ret;
6855c51f124SMoriah Waterland 				}
6865c51f124SMoriah Waterland 				if (PKCS12_add_friendlyname_asc(bag,
6875c51f124SMoriah Waterland 				    (char const *) str,
6885c51f124SMoriah Waterland 				    strlen((char const *) str)) == 0) {
6895c51f124SMoriah Waterland 					SUNWerr(SUNW_F_PKCS12_CREATE,
6905c51f124SMoriah Waterland 					    SUNW_R_ADD_ATTR_ERR);
6915c51f124SMoriah Waterland 					goto err_ret;
6925c51f124SMoriah Waterland 				}
6935c51f124SMoriah Waterland 			}
6945c51f124SMoriah Waterland 			if (cert->aux != NULL && cert->aux->keyid != NULL &&
6955c51f124SMoriah Waterland 			    cert->aux->keyid->type == V_ASN1_OCTET_STRING) {
6965c51f124SMoriah Waterland 				str = cert->aux->keyid->data;
6975c51f124SMoriah Waterland 				len = cert->aux->keyid->length;
6985c51f124SMoriah Waterland 
6995c51f124SMoriah Waterland 				if (str != NULL &&
7005c51f124SMoriah Waterland 				    PKCS12_add_localkeyid(bag, str, len) == 0) {
7015c51f124SMoriah Waterland 					SUNWerr(SUNW_F_PKCS12_CREATE,
7025c51f124SMoriah Waterland 					    SUNW_R_ADD_ATTR_ERR);
7035c51f124SMoriah Waterland 					goto err_ret;
7045c51f124SMoriah Waterland 				}
7055c51f124SMoriah Waterland 			}
7065c51f124SMoriah Waterland 			if (sk_PKCS12_SAFEBAG_push(bags, bag) == 0) {
7075c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PKCS12_CREATE,
7085c51f124SMoriah Waterland 				    SUNW_R_MEMORY_FAILURE);
7095c51f124SMoriah Waterland 				goto err_ret;
7105c51f124SMoriah Waterland 			}
7115c51f124SMoriah Waterland 			certs_there++;
7125c51f124SMoriah Waterland 			bag = NULL;
7135c51f124SMoriah Waterland 		}
7145c51f124SMoriah Waterland 	}
7155c51f124SMoriah Waterland 
7165c51f124SMoriah Waterland 	if (cacerts != NULL && sk_X509_num(cacerts) > 0) {
7175c51f124SMoriah Waterland 
7185c51f124SMoriah Waterland 		/* Put all certs in structure */
7195c51f124SMoriah Waterland 		for (i = 0; i < sk_X509_num(cacerts); i++) {
7205c51f124SMoriah Waterland 			cert = sk_X509_value(cacerts, i);
7215c51f124SMoriah Waterland 			if ((bag = M_PKCS12_x5092certbag(cert)) == NULL) {
7225c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_CERT_ERR);
7235c51f124SMoriah Waterland 				goto err_ret;
7245c51f124SMoriah Waterland 			}
7255c51f124SMoriah Waterland 
7265c51f124SMoriah Waterland 			if (cert->aux != NULL && cert->aux->alias != NULL &&
7275c51f124SMoriah Waterland 			    cert->aux->alias->type == V_ASN1_UTF8STRING) {
7285c51f124SMoriah Waterland 				str = utf82ascstr(cert->aux->alias);
7295c51f124SMoriah Waterland 				if (str == NULL) {
7305c51f124SMoriah Waterland 					/*
7315c51f124SMoriah Waterland 					 * Error already on stack
7325c51f124SMoriah Waterland 					 */
7335c51f124SMoriah Waterland 					goto err_ret;
7345c51f124SMoriah Waterland 				}
7355c51f124SMoriah Waterland 				if (PKCS12_add_friendlyname_asc(
7365c51f124SMoriah Waterland 				    bag, (char const *) str,
7375c51f124SMoriah Waterland 				    strlen((char const *) str)) == 0) {
7385c51f124SMoriah Waterland 					SUNWerr(SUNW_F_PKCS12_CREATE,
7395c51f124SMoriah Waterland 					    SUNW_R_ADD_ATTR_ERR);
7405c51f124SMoriah Waterland 					goto err_ret;
7415c51f124SMoriah Waterland 				}
7425c51f124SMoriah Waterland 			}
7435c51f124SMoriah Waterland 			if (cert->aux != NULL && cert->aux->keyid != NULL &&
7445c51f124SMoriah Waterland 			    cert->aux->keyid->type == V_ASN1_OCTET_STRING) {
7455c51f124SMoriah Waterland 				str = cert->aux->keyid->data;
7465c51f124SMoriah Waterland 				len = cert->aux->keyid->length;
7475c51f124SMoriah Waterland 
7485c51f124SMoriah Waterland 				if (str != NULL &&
7495c51f124SMoriah Waterland 				    PKCS12_add_localkeyid(bag, str, len) == 0) {
7505c51f124SMoriah Waterland 					SUNWerr(SUNW_F_PKCS12_CREATE,
7515c51f124SMoriah Waterland 					    SUNW_R_ADD_ATTR_ERR);
7525c51f124SMoriah Waterland 					goto err_ret;
7535c51f124SMoriah Waterland 				}
7545c51f124SMoriah Waterland 			}
7555c51f124SMoriah Waterland 			if (sk_PKCS12_SAFEBAG_push(bags, bag) == 0) {
7565c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PKCS12_CREATE,
7575c51f124SMoriah Waterland 				    SUNW_R_MEMORY_FAILURE);
7585c51f124SMoriah Waterland 				goto err_ret;
7595c51f124SMoriah Waterland 			}
7605c51f124SMoriah Waterland 			certs_there++;
7615c51f124SMoriah Waterland 			bag = NULL;
7625c51f124SMoriah Waterland 		}
7635c51f124SMoriah Waterland 	}
7645c51f124SMoriah Waterland 
7655c51f124SMoriah Waterland 	if (certs != NULL || cacerts != NULL && certs_there) {
7665c51f124SMoriah Waterland 		/* Turn certbags into encrypted authsafe */
7675c51f124SMoriah Waterland 		authsafe = PKCS12_pack_p7encdata(nid_cert, pass, -1,
7685c51f124SMoriah Waterland 		    NULL, 0, PKCS12_DEFAULT_ITER, bags);
7695c51f124SMoriah Waterland 		if (authsafe == NULL) {
7705c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_CERT_ERR);
7715c51f124SMoriah Waterland 			goto err_ret;
7725c51f124SMoriah Waterland 		}
7735c51f124SMoriah Waterland 		sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
7745c51f124SMoriah Waterland 		bags = NULL;
7755c51f124SMoriah Waterland 
7765c51f124SMoriah Waterland 		if (sk_PKCS7_push(safes, authsafe) == 0) {
7775c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_MEMORY_FAILURE);
7785c51f124SMoriah Waterland 			goto err_ret;
7795c51f124SMoriah Waterland 		}
7805c51f124SMoriah Waterland 		authsafe = NULL;
7815c51f124SMoriah Waterland 	}
7825c51f124SMoriah Waterland 
7835c51f124SMoriah Waterland 	if (pkeys != NULL && sk_EVP_PKEY_num(pkeys) > 0) {
7845c51f124SMoriah Waterland 
7855c51f124SMoriah Waterland 		if (bags == NULL &&
7865c51f124SMoriah Waterland 		    (bags = sk_PKCS12_SAFEBAG_new_null()) == NULL) {
7875c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_MEMORY_FAILURE);
7885c51f124SMoriah Waterland 			goto err_ret;
7895c51f124SMoriah Waterland 		}
7905c51f124SMoriah Waterland 
7915c51f124SMoriah Waterland 		for (i = 0; i < sk_EVP_PKEY_num(pkeys); i++) {
7925c51f124SMoriah Waterland 
7935c51f124SMoriah Waterland 			pkey = sk_EVP_PKEY_value(pkeys, i);
7945c51f124SMoriah Waterland 
7955c51f124SMoriah Waterland 			/* Make a shrouded key bag */
7965c51f124SMoriah Waterland 			if ((p8 = EVP_PKEY2PKCS8(pkey)) == NULL) {
7975c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_PKEY_ERR);
7985c51f124SMoriah Waterland 				goto err_ret;
7995c51f124SMoriah Waterland 			}
8005c51f124SMoriah Waterland 
8015c51f124SMoriah Waterland 			bag = PKCS12_MAKE_SHKEYBAG(nid_key, pass, -1, NULL, 0,
8025c51f124SMoriah Waterland 			    PKCS12_DEFAULT_ITER, p8);
8035c51f124SMoriah Waterland 			if (bag == NULL) {
8045c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PKCS12_CREATE,
8055c51f124SMoriah Waterland 				    SUNW_R_MAKE_BAG_ERR);
8065c51f124SMoriah Waterland 				goto err_ret;
8075c51f124SMoriah Waterland 			}
8085c51f124SMoriah Waterland 			PKCS8_PRIV_KEY_INFO_free(p8);
8095c51f124SMoriah Waterland 			p8 = NULL;
8105c51f124SMoriah Waterland 
8115c51f124SMoriah Waterland 			len = sunw_get_pkey_fname(GETDO_COPY, pkey,
8125c51f124SMoriah Waterland 			    (char **)&str);
8135c51f124SMoriah Waterland 			if (str != NULL) {
8145c51f124SMoriah Waterland 				if (PKCS12_add_friendlyname_asc(bag,
8155c51f124SMoriah Waterland 				    (const char *)str, len) == 0) {
8165c51f124SMoriah Waterland 					SUNWerr(SUNW_F_PKCS12_CREATE,
8175c51f124SMoriah Waterland 					    SUNW_R_ADD_ATTR_ERR);
8185c51f124SMoriah Waterland 					goto err_ret;
8195c51f124SMoriah Waterland 				}
8205c51f124SMoriah Waterland 			}
8215c51f124SMoriah Waterland 			str = NULL;
8225c51f124SMoriah Waterland 
8235c51f124SMoriah Waterland 			len = sunw_get_pkey_localkeyid(GETDO_COPY, pkey,
8245c51f124SMoriah Waterland 			    (char **)&str, &len);
8255c51f124SMoriah Waterland 			if (str != NULL) {
8265c51f124SMoriah Waterland 				if (PKCS12_add_localkeyid(bag, str, len) == 0) {
8275c51f124SMoriah Waterland 					SUNWerr(SUNW_F_PKCS12_CREATE,
8285c51f124SMoriah Waterland 					    SUNW_R_ADD_ATTR_ERR);
8295c51f124SMoriah Waterland 					goto err_ret;
8305c51f124SMoriah Waterland 				}
8315c51f124SMoriah Waterland 			}
8325c51f124SMoriah Waterland 			str = NULL;
8335c51f124SMoriah Waterland 
8345c51f124SMoriah Waterland 			if (sk_PKCS12_SAFEBAG_push(bags, bag) == 0) {
8355c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PKCS12_CREATE,
8365c51f124SMoriah Waterland 				    SUNW_R_MEMORY_FAILURE);
8375c51f124SMoriah Waterland 				goto err_ret;
8385c51f124SMoriah Waterland 			}
8395c51f124SMoriah Waterland 			keys_there++;
8405c51f124SMoriah Waterland 			bag = NULL;
8415c51f124SMoriah Waterland 		}
8425c51f124SMoriah Waterland 
8435c51f124SMoriah Waterland 		if (keys_there) {
8445c51f124SMoriah Waterland 			/* Turn into unencrypted authsafe */
8455c51f124SMoriah Waterland 			authsafe = PKCS12_pack_p7data(bags);
8465c51f124SMoriah Waterland 			if (authsafe == NULL) {
8475c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PKCS12_CREATE,
8485c51f124SMoriah Waterland 				    SUNW_R_PKCS12_CREATE_ERR);
8495c51f124SMoriah Waterland 				goto err_ret;
8505c51f124SMoriah Waterland 			}
8515c51f124SMoriah Waterland 			sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
8525c51f124SMoriah Waterland 			bags = NULL;
8535c51f124SMoriah Waterland 
8545c51f124SMoriah Waterland 			if (sk_PKCS7_push(safes, authsafe) == 0) {
8555c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PKCS12_CREATE,
8565c51f124SMoriah Waterland 				    SUNW_R_MEMORY_FAILURE);
8575c51f124SMoriah Waterland 			}
8585c51f124SMoriah Waterland 			authsafe = NULL;
8595c51f124SMoriah Waterland 		}
8605c51f124SMoriah Waterland 	}
8615c51f124SMoriah Waterland 
8625c51f124SMoriah Waterland 	if (certs_there == 0 && keys_there == 0) {
8635c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_PKCS12_EMPTY_ERR);
8645c51f124SMoriah Waterland 		goto err_ret;
8655c51f124SMoriah Waterland 	}
8665c51f124SMoriah Waterland 
8675c51f124SMoriah Waterland 	if ((p12 = PKCS12_init(NID_pkcs7_data)) == NULL) {
8685c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_PKCS12_CREATE_ERR);
8695c51f124SMoriah Waterland 		goto err_ret;
8705c51f124SMoriah Waterland 	}
8715c51f124SMoriah Waterland 
8725c51f124SMoriah Waterland 	/*
8735c51f124SMoriah Waterland 	 * Note that safes is copied by the following.  Therefore, it needs
8745c51f124SMoriah Waterland 	 * to be freed whether or not the following succeeds.
8755c51f124SMoriah Waterland 	 */
8765c51f124SMoriah Waterland 	if (M_PKCS12_pack_authsafes(p12, safes) == 0) {
8775c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_PKCS12_CREATE_ERR);
8785c51f124SMoriah Waterland 		goto err_ret;
8795c51f124SMoriah Waterland 	}
8805c51f124SMoriah Waterland 	if (PKCS12_set_mac(p12, pass, -1, NULL, 0, 2048, NULL) == 0) {
8815c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_MAC_CREATE_FAILURE);
8825c51f124SMoriah Waterland 		goto err_ret;
8835c51f124SMoriah Waterland 	}
8845c51f124SMoriah Waterland 
8855c51f124SMoriah Waterland 	ret_p12 = p12;
8865c51f124SMoriah Waterland 	p12 = NULL;
8875c51f124SMoriah Waterland 
8885c51f124SMoriah Waterland 	/* Fallthrough is intentional */
8895c51f124SMoriah Waterland 
8905c51f124SMoriah Waterland err_ret:
8915c51f124SMoriah Waterland 
8925c51f124SMoriah Waterland 	if (str != NULL)
8935c51f124SMoriah Waterland 		free(str);
8945c51f124SMoriah Waterland 
8955c51f124SMoriah Waterland 	if (p8 != NULL)
8965c51f124SMoriah Waterland 		PKCS8_PRIV_KEY_INFO_free(p8);
8975c51f124SMoriah Waterland 
8985c51f124SMoriah Waterland 	if (bag != NULL)
8995c51f124SMoriah Waterland 		PKCS12_SAFEBAG_free(bag);
9005c51f124SMoriah Waterland 	if (bags != NULL)
9015c51f124SMoriah Waterland 		sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
9025c51f124SMoriah Waterland 	if (authsafe != NULL)
9035c51f124SMoriah Waterland 		PKCS7_free(authsafe);
9045c51f124SMoriah Waterland 	if (safes != NULL)
9055c51f124SMoriah Waterland 		sk_PKCS7_pop_free(safes, PKCS7_free);
9065c51f124SMoriah Waterland 	if (p12 != NULL)
9075c51f124SMoriah Waterland 		PKCS12_free(p12);
9085c51f124SMoriah Waterland 
9095c51f124SMoriah Waterland 	return (ret_p12);
9105c51f124SMoriah Waterland }
9115c51f124SMoriah Waterland 
9125c51f124SMoriah Waterland /*
9135c51f124SMoriah Waterland  * sunw_evp_pkey_free() Given an EVP_PKEY structure, free any attributes
9145c51f124SMoriah Waterland  *     that are attached.  Then free the EVP_PKEY itself.
9155c51f124SMoriah Waterland  *
9165c51f124SMoriah Waterland  *     This is a replacement for EVP_PKEY_free() for the sunw stuff.
9175c51f124SMoriah Waterland  *     It should be used in places where EVP_PKEY_free would be used,
9185c51f124SMoriah Waterland  *     including calls to sk_EVP_PKEY_pop_free().
9195c51f124SMoriah Waterland  *
9205c51f124SMoriah Waterland  * Arguments:
9215c51f124SMoriah Waterland  *   pkey     - Entry which potentially has attributes to be freed.
9225c51f124SMoriah Waterland  *
9235c51f124SMoriah Waterland  * Returns:
9245c51f124SMoriah Waterland  *   None.
9255c51f124SMoriah Waterland  */
9265c51f124SMoriah Waterland void
9275c51f124SMoriah Waterland sunw_evp_pkey_free(EVP_PKEY *pkey)
9285c51f124SMoriah Waterland {
9295c51f124SMoriah Waterland 	if (pkey != NULL) {
9305c51f124SMoriah Waterland 		if (pkey->attributes != NULL) {
9315c51f124SMoriah Waterland 			sk_X509_ATTRIBUTE_pop_free(pkey->attributes,
9325c51f124SMoriah Waterland 			    X509_ATTRIBUTE_free);
9335c51f124SMoriah Waterland 			pkey->attributes = NULL;
9345c51f124SMoriah Waterland 		}
9355c51f124SMoriah Waterland 		EVP_PKEY_free(pkey);
9365c51f124SMoriah Waterland 	}
9375c51f124SMoriah Waterland }
9385c51f124SMoriah Waterland 
9395c51f124SMoriah Waterland /*
9405c51f124SMoriah Waterland  * sunw_set_localkeyid() sets the localkeyid in a cert, a private key or
9415c51f124SMoriah Waterland  *     both.  Any existing localkeyid will be discarded.
9425c51f124SMoriah Waterland  *
9435c51f124SMoriah Waterland  * Arguments:
9445c51f124SMoriah Waterland  *   keyid_str- A byte string with the localkeyid to set
9455c51f124SMoriah Waterland  *   keyid_len- Length of the keyid byte string.
9465c51f124SMoriah Waterland  *   pkey     - Points to a private key to set the keyidstr in.
9475c51f124SMoriah Waterland  *   cert     - Points to a cert to set the keyidstr in.
9485c51f124SMoriah Waterland  *
9495c51f124SMoriah Waterland  * Note that setting a keyid into a cert which will not be written out as
9505c51f124SMoriah Waterland  * a PKCS12 cert is pointless since it will be lost.
9515c51f124SMoriah Waterland  *
9525c51f124SMoriah Waterland  * Returns:
9535c51f124SMoriah Waterland  *   0        - Success.
9545c51f124SMoriah Waterland  *   < 0      - An error occurred.  It was probably an error in allocating
9555c51f124SMoriah Waterland  *              memory.  The error will be set in the error stack.  Call
9565c51f124SMoriah Waterland  *              ERR_get_error() to get specific information.
9575c51f124SMoriah Waterland  */
9585c51f124SMoriah Waterland int
9595c51f124SMoriah Waterland sunw_set_localkeyid(const char *keyid_str, int keyid_len, EVP_PKEY *pkey,
9605c51f124SMoriah Waterland     X509 *cert)
9615c51f124SMoriah Waterland {
9625c51f124SMoriah Waterland 	X509_ATTRIBUTE *attr = NULL;
9635c51f124SMoriah Waterland 	ASN1_STRING *str = NULL;
9645c51f124SMoriah Waterland 	ASN1_TYPE *keyid = NULL;
9655c51f124SMoriah Waterland 	int retval = -1;
9665c51f124SMoriah Waterland 	int i;
9675c51f124SMoriah Waterland 
9685c51f124SMoriah Waterland 	if (cert != NULL) {
9695c51f124SMoriah Waterland 		if (X509_keyid_set1(cert, (uchar_t *)keyid_str, keyid_len)
9705c51f124SMoriah Waterland 		    == 0) {
9715c51f124SMoriah Waterland 			SUNWerr(SUNW_F_SET_LOCALKEYID, SUNW_R_SET_LKID_ERR);
9725c51f124SMoriah Waterland 			goto cleanup;
9735c51f124SMoriah Waterland 		}
9745c51f124SMoriah Waterland 	}
9755c51f124SMoriah Waterland 	if (pkey != NULL) {
9765c51f124SMoriah Waterland 		str = (ASN1_STRING *)M_ASN1_OCTET_STRING_new();
9775c51f124SMoriah Waterland 		if (str == NULL ||
9785c51f124SMoriah Waterland 		    M_ASN1_OCTET_STRING_set(str, keyid_str, keyid_len) == 0 ||
9795c51f124SMoriah Waterland 		    (keyid = ASN1_TYPE_new()) == NULL) {
9805c51f124SMoriah Waterland 			SUNWerr(SUNW_F_SET_LOCALKEYID, SUNW_R_MEMORY_FAILURE);
9815c51f124SMoriah Waterland 			goto cleanup;
9825c51f124SMoriah Waterland 		}
9835c51f124SMoriah Waterland 
9845c51f124SMoriah Waterland 		ASN1_TYPE_set(keyid, V_ASN1_OCTET_STRING, str);
9855c51f124SMoriah Waterland 		str = NULL;
9865c51f124SMoriah Waterland 
9875c51f124SMoriah Waterland 		attr = type2attrib(keyid, NID_localKeyID);
9885c51f124SMoriah Waterland 		if (attr == NULL) {
9895c51f124SMoriah Waterland 			/*
9905c51f124SMoriah Waterland 			 * Error already on stack
9915c51f124SMoriah Waterland 			 */
9925c51f124SMoriah Waterland 			goto cleanup;
9935c51f124SMoriah Waterland 		}
9945c51f124SMoriah Waterland 		keyid = NULL;
9955c51f124SMoriah Waterland 
9965c51f124SMoriah Waterland 		if (pkey->attributes == NULL) {
9975c51f124SMoriah Waterland 			pkey->attributes = sk_X509_ATTRIBUTE_new_null();
9985c51f124SMoriah Waterland 			if (pkey->attributes == NULL) {
9995c51f124SMoriah Waterland 				SUNWerr(SUNW_F_SET_LOCALKEYID,
10005c51f124SMoriah Waterland 				    SUNW_R_MEMORY_FAILURE);
10015c51f124SMoriah Waterland 				goto cleanup;
10025c51f124SMoriah Waterland 			}
10035c51f124SMoriah Waterland 		} else {
10045c51f124SMoriah Waterland 			i = find_attr_by_nid(pkey->attributes, NID_localKeyID);
10055c51f124SMoriah Waterland 			if (i >= 0)
10065c51f124SMoriah Waterland 				sk_X509_ATTRIBUTE_delete(pkey->attributes, i);
10075c51f124SMoriah Waterland 		}
10085c51f124SMoriah Waterland 		if (sk_X509_ATTRIBUTE_push(pkey->attributes, attr) == 0) {
10095c51f124SMoriah Waterland 			SUNWerr(SUNW_F_SET_LOCALKEYID, SUNW_R_MEMORY_FAILURE);
10105c51f124SMoriah Waterland 			goto cleanup;
10115c51f124SMoriah Waterland 		}
10125c51f124SMoriah Waterland 		attr = NULL;
10135c51f124SMoriah Waterland 	}
10145c51f124SMoriah Waterland 	retval = 0;
10155c51f124SMoriah Waterland 
10165c51f124SMoriah Waterland cleanup:
10175c51f124SMoriah Waterland 	if (str != NULL)
10185c51f124SMoriah Waterland 		ASN1_STRING_free(str);
10195c51f124SMoriah Waterland 	if (keyid != NULL)
10205c51f124SMoriah Waterland 		ASN1_TYPE_free(keyid);
10215c51f124SMoriah Waterland 	if (attr != NULL)
10225c51f124SMoriah Waterland 		X509_ATTRIBUTE_free(attr);
10235c51f124SMoriah Waterland 
10245c51f124SMoriah Waterland 	return (retval);
10255c51f124SMoriah Waterland }
10265c51f124SMoriah Waterland 
10275c51f124SMoriah Waterland /*
10285c51f124SMoriah Waterland  * sunw_get_pkey_localkeyid() gets the localkeyid from a private key.  It can
10295c51f124SMoriah Waterland  *     optionally remove the value found.
10305c51f124SMoriah Waterland  *
10315c51f124SMoriah Waterland  * Arguments:
10325c51f124SMoriah Waterland  *   dowhat   - What to do with the attributes (remove them or copy them).
10335c51f124SMoriah Waterland  *   pkey     - Points to a private key to set the keyidstr in.
10345c51f124SMoriah Waterland  *   keyid_str- Points to a location which will receive the pointer to
10355c51f124SMoriah Waterland  *              a byte string containing the binary localkeyid.  Note that
10365c51f124SMoriah Waterland  *              this is a copy, and the caller must free it.
10375c51f124SMoriah Waterland  *   keyid_len- Length of keyid_str.
10385c51f124SMoriah Waterland  *
10395c51f124SMoriah Waterland  * Returns:
10405c51f124SMoriah Waterland  *   >= 0     - The number of characters in the keyid returned.
10415c51f124SMoriah Waterland  *   < 0      - An error occurred.  It was probably an error in allocating
10425c51f124SMoriah Waterland  *              memory.  The error will be set in the error stack.  Call
10435c51f124SMoriah Waterland  *              ERR_get_error() to get specific information.
10445c51f124SMoriah Waterland  */
10455c51f124SMoriah Waterland int
10465c51f124SMoriah Waterland sunw_get_pkey_localkeyid(getdo_actions_t dowhat, EVP_PKEY *pkey,
10475c51f124SMoriah Waterland     char **keyid_str, int *keyid_len)
10485c51f124SMoriah Waterland {
10495c51f124SMoriah Waterland 	X509_ATTRIBUTE *attr = NULL;
10505c51f124SMoriah Waterland 	ASN1_OCTET_STRING *str = NULL;
10515c51f124SMoriah Waterland 	ASN1_TYPE *ty = NULL;
10525c51f124SMoriah Waterland 	int len = 0;
10535c51f124SMoriah Waterland 	int i;
10545c51f124SMoriah Waterland 
10555c51f124SMoriah Waterland 	if (keyid_str != NULL)
10565c51f124SMoriah Waterland 		*keyid_str = NULL;
10575c51f124SMoriah Waterland 	if (keyid_len != NULL)
10585c51f124SMoriah Waterland 		*keyid_len = 0;
10595c51f124SMoriah Waterland 
10605c51f124SMoriah Waterland 	if (pkey == NULL || pkey->attributes == NULL) {
10615c51f124SMoriah Waterland 		return (0);
10625c51f124SMoriah Waterland 	}
10635c51f124SMoriah Waterland 
10645c51f124SMoriah Waterland 	if ((i = find_attr_by_nid(pkey->attributes, NID_localKeyID)) < 0) {
10655c51f124SMoriah Waterland 		return (0);
10665c51f124SMoriah Waterland 	}
10675c51f124SMoriah Waterland 	attr = sk_X509_ATTRIBUTE_value(pkey->attributes, i);
10685c51f124SMoriah Waterland 
10695c51f124SMoriah Waterland 	if ((ty = attrib2type(attr)) == NULL ||
10705c51f124SMoriah Waterland 	    ty->type != V_ASN1_OCTET_STRING) {
10715c51f124SMoriah Waterland 		return (0);
10725c51f124SMoriah Waterland 	}
10735c51f124SMoriah Waterland 
10745c51f124SMoriah Waterland 	if (dowhat == GETDO_DEL) {
10755c51f124SMoriah Waterland 		attr = sk_X509_ATTRIBUTE_delete(pkey->attributes, i);
10765c51f124SMoriah Waterland 		if (attr != NULL)
10775c51f124SMoriah Waterland 			X509_ATTRIBUTE_free(attr);
10785c51f124SMoriah Waterland 		return (0);
10795c51f124SMoriah Waterland 	}
10805c51f124SMoriah Waterland 
10815c51f124SMoriah Waterland 	str = ty->value.octet_string;
10825c51f124SMoriah Waterland 	len = str->length;
10835c51f124SMoriah Waterland 	if ((*keyid_str = malloc(len)) == NULL) {
10845c51f124SMoriah Waterland 		SUNWerr(SUNW_F_GET_LOCALKEYID, SUNW_R_MEMORY_FAILURE);
10855c51f124SMoriah Waterland 		return (-1);
10865c51f124SMoriah Waterland 	}
10875c51f124SMoriah Waterland 
10885c51f124SMoriah Waterland 	(void) memcpy(*keyid_str, str->data, len);
10895c51f124SMoriah Waterland 	*keyid_len = len;
10905c51f124SMoriah Waterland 
10915c51f124SMoriah Waterland 	return (len);
10925c51f124SMoriah Waterland }
10935c51f124SMoriah Waterland 
10945c51f124SMoriah Waterland /*
10955c51f124SMoriah Waterland  * sunw_get_pkey_fname() gets the friendlyName from a private key.  It can
10965c51f124SMoriah Waterland  *     optionally remove the value found.
10975c51f124SMoriah Waterland  *
10985c51f124SMoriah Waterland  * Arguments:
10995c51f124SMoriah Waterland  *   dowhat   - What to do with the attributes (remove them or copy them).
11005c51f124SMoriah Waterland  *   pkey     - Points to a private key to get the frientlyname from
11015c51f124SMoriah Waterland  *   fname    - Points to a location which will receive the pointer to a
11025c51f124SMoriah Waterland  *              byte string with the ASCII friendlyname
11035c51f124SMoriah Waterland  *
11045c51f124SMoriah Waterland  * Returns:
11055c51f124SMoriah Waterland  *   >= 0     - The number of characters in the frienlyname returned.
11065c51f124SMoriah Waterland  *   < 0      - An error occurred.  It was probably an error in allocating
11075c51f124SMoriah Waterland  *              memory.  The error will be set in the error stack.  Call
11085c51f124SMoriah Waterland  *              ERR_get_error() to get specific information.
11095c51f124SMoriah Waterland  */
11105c51f124SMoriah Waterland int
11115c51f124SMoriah Waterland sunw_get_pkey_fname(getdo_actions_t dowhat, EVP_PKEY *pkey, char **fname)
11125c51f124SMoriah Waterland {
11135c51f124SMoriah Waterland 	X509_ATTRIBUTE *attr = NULL;
11145c51f124SMoriah Waterland 	ASN1_BMPSTRING *str = NULL;
11155c51f124SMoriah Waterland 	ASN1_TYPE *ty = NULL;
11165c51f124SMoriah Waterland 	int len = 0;
11175c51f124SMoriah Waterland 	int i;
11185c51f124SMoriah Waterland 
11195c51f124SMoriah Waterland 	if (fname != NULL)
11205c51f124SMoriah Waterland 		*fname = NULL;
11215c51f124SMoriah Waterland 
11225c51f124SMoriah Waterland 	if (pkey == NULL || pkey->attributes == NULL) {
11235c51f124SMoriah Waterland 		return (0);
11245c51f124SMoriah Waterland 	}
11255c51f124SMoriah Waterland 
11265c51f124SMoriah Waterland 	if ((i = find_attr_by_nid(pkey->attributes, NID_friendlyName)) < 0) {
11275c51f124SMoriah Waterland 		return (0);
11285c51f124SMoriah Waterland 	}
11295c51f124SMoriah Waterland 	attr = sk_X509_ATTRIBUTE_value(pkey->attributes, i);
11305c51f124SMoriah Waterland 
11315c51f124SMoriah Waterland 	if ((ty = attrib2type(attr)) == NULL ||
11325c51f124SMoriah Waterland 	    ty->type != V_ASN1_BMPSTRING) {
11335c51f124SMoriah Waterland 		return (0);
11345c51f124SMoriah Waterland 	}
11355c51f124SMoriah Waterland 
11365c51f124SMoriah Waterland 	if (dowhat == GETDO_DEL) {
11375c51f124SMoriah Waterland 		attr = sk_X509_ATTRIBUTE_delete(pkey->attributes, i);
11385c51f124SMoriah Waterland 		if (attr != NULL)
11395c51f124SMoriah Waterland 			X509_ATTRIBUTE_free(attr);
11405c51f124SMoriah Waterland 		return (0);
11415c51f124SMoriah Waterland 	}
11425c51f124SMoriah Waterland 
11435c51f124SMoriah Waterland 	str = ty->value.bmpstring;
1144*70f9559bSTheo Schlossnagle #if OPENSSL_VERSION_NUMBER < 0x10000000L
11455c51f124SMoriah Waterland 	*fname = uni2asc(str->data, str->length);
1146*70f9559bSTheo Schlossnagle #else
1147*70f9559bSTheo Schlossnagle 	*fname = OPENSSL_uni2asc(str->data, str->length);
1148*70f9559bSTheo Schlossnagle #endif
11495c51f124SMoriah Waterland 	if (*fname == NULL) {
11505c51f124SMoriah Waterland 		SUNWerr(SUNW_F_GET_PKEY_FNAME, SUNW_R_MEMORY_FAILURE);
11515c51f124SMoriah Waterland 		return (-1);
11525c51f124SMoriah Waterland 	}
11535c51f124SMoriah Waterland 
11545c51f124SMoriah Waterland 	len = strlen(*fname);
11555c51f124SMoriah Waterland 
11565c51f124SMoriah Waterland 	return (len);
11575c51f124SMoriah Waterland }
11585c51f124SMoriah Waterland 
11595c51f124SMoriah Waterland /*
11605c51f124SMoriah Waterland  * sunw_find_localkeyid() searches stacks of certs and private keys,
11615c51f124SMoriah Waterland  *     and returns  the first matching cert/private key found.
11625c51f124SMoriah Waterland  *
11635c51f124SMoriah Waterland  * Look for a keyid in a stack of certs.  if 'certs' is NULL and 'pkeys' is
11645c51f124SMoriah Waterland  * not NULL, search the list of private keys.  Move the matching cert to
11655c51f124SMoriah Waterland  * 'matching_cert' and its matching private key to 'matching_pkey'.  If no
11665c51f124SMoriah Waterland  * cert or keys match, no match occurred.
11675c51f124SMoriah Waterland  *
11685c51f124SMoriah Waterland  * Arguments:
11695c51f124SMoriah Waterland  *   keyid_str- A byte string with the localkeyid to match
11705c51f124SMoriah Waterland  *   keyid_len- Length of the keyid byte string.
11715c51f124SMoriah Waterland  *   pkeys    - Points to a stack of private keys which match the certs.
11725c51f124SMoriah Waterland  *              This may be NULL, in which case no keys are returned.
11735c51f124SMoriah Waterland  *   certs    - Points to a stack of certs to search.  If NULL, search the
11745c51f124SMoriah Waterland  *              stack of keys instead.
11755c51f124SMoriah Waterland  *   matching_pkey
11765c51f124SMoriah Waterland  *            - Pointer to receive address of first matching pkey found.
11775c51f124SMoriah Waterland  *              'matching_pkey' must not be NULL; '*matching_pkey' will be
11785c51f124SMoriah Waterland  *              reset.
11795c51f124SMoriah Waterland  *   matching_cert
11805c51f124SMoriah Waterland  *            - Pointer to receive address of first matching cert found.
11815c51f124SMoriah Waterland  *              'matching_cert' must not be NULL; '*matching_cert' will be
11825c51f124SMoriah Waterland  *              reset.
11835c51f124SMoriah Waterland  *
11845c51f124SMoriah Waterland  * Returns:
11855c51f124SMoriah Waterland  *  <  0 - An error returned.  Call ERR_get_error() to get errors information.
11865c51f124SMoriah Waterland  *         Where possible, memory has been freed.
11875c51f124SMoriah Waterland  *  >= 0 - Objects were found and returned.  Which objects are indicated by
11885c51f124SMoriah Waterland  *         which bits are set (FOUND_PKEY and/or FOUND_CERT).
11895c51f124SMoriah Waterland  */
11905c51f124SMoriah Waterland int
11915c51f124SMoriah Waterland sunw_find_localkeyid(char *keyid_str, int len, STACK_OF(EVP_PKEY) *pkeys,
11925c51f124SMoriah Waterland STACK_OF(X509) *certs, EVP_PKEY **matching_pkey, X509 **matching_cert)
11935c51f124SMoriah Waterland {
11945c51f124SMoriah Waterland 	ASN1_STRING *cmpstr = NULL;
11955c51f124SMoriah Waterland 	EVP_PKEY *tmp_pkey = NULL;
11965c51f124SMoriah Waterland 	X509 *tmp_cert = NULL;
11975c51f124SMoriah Waterland 	int retval = 0;
11985c51f124SMoriah Waterland 
11995c51f124SMoriah Waterland 	/* If NULL arguments, this is an error */
12005c51f124SMoriah Waterland 	if (keyid_str == NULL ||
12015c51f124SMoriah Waterland 	    (pkeys == NULL || certs == NULL) ||
12025c51f124SMoriah Waterland 	    (pkeys != NULL && matching_pkey == NULL) ||
12035c51f124SMoriah Waterland 	    (certs != NULL && matching_cert == NULL)) {
12045c51f124SMoriah Waterland 		SUNWerr(SUNW_F_FIND_LOCALKEYID, SUNW_R_INVALID_ARG);
12055c51f124SMoriah Waterland 		return (-1);
12065c51f124SMoriah Waterland 	}
12075c51f124SMoriah Waterland 
12085c51f124SMoriah Waterland 	if (matching_pkey != NULL)
12095c51f124SMoriah Waterland 		*matching_pkey = NULL;
12105c51f124SMoriah Waterland 	if (matching_cert != NULL)
12115c51f124SMoriah Waterland 		*matching_cert = NULL;
12125c51f124SMoriah Waterland 
12135c51f124SMoriah Waterland 	cmpstr = (ASN1_STRING *)M_ASN1_OCTET_STRING_new();
12145c51f124SMoriah Waterland 	if (cmpstr == NULL ||
12155c51f124SMoriah Waterland 	    M_ASN1_OCTET_STRING_set(cmpstr, keyid_str, len) == 0) {
12165c51f124SMoriah Waterland 		SUNWerr(SUNW_F_FIND_LOCALKEYID, SUNW_R_MEMORY_FAILURE);
12175c51f124SMoriah Waterland 		return (-1);
12185c51f124SMoriah Waterland 	}
12195c51f124SMoriah Waterland 
12205c51f124SMoriah Waterland 	retval = find_attr(NID_localKeyID, cmpstr, pkeys, &tmp_pkey, certs,
12215c51f124SMoriah Waterland 	    &tmp_cert);
12225c51f124SMoriah Waterland 	if (retval == 0) {
12235c51f124SMoriah Waterland 		ASN1_STRING_free(cmpstr);
12245c51f124SMoriah Waterland 		return (retval);
12255c51f124SMoriah Waterland 	}
12265c51f124SMoriah Waterland 
12275c51f124SMoriah Waterland 	if (matching_pkey != NULL)
12285c51f124SMoriah Waterland 		*matching_pkey = tmp_pkey;
12295c51f124SMoriah Waterland 	if (matching_cert != NULL)
12305c51f124SMoriah Waterland 		*matching_cert = tmp_cert;
12315c51f124SMoriah Waterland 
12325c51f124SMoriah Waterland 	return (retval);
12335c51f124SMoriah Waterland }
12345c51f124SMoriah Waterland 
12355c51f124SMoriah Waterland /*
12365c51f124SMoriah Waterland  * sunw_find_fname() searches stacks of certs and private keys for one with
12375c51f124SMoriah Waterland  *     a matching friendlyname and returns the first matching cert/private
12385c51f124SMoriah Waterland  *     key found.
12395c51f124SMoriah Waterland  *
12405c51f124SMoriah Waterland  * Look for a friendlyname in a stack of certs.  if 'certs' is NULL and 'pkeys'
12415c51f124SMoriah Waterland  * is not NULL, search the list of private keys.  Move the matching cert to
12425c51f124SMoriah Waterland  * 'matching_cert' and its matching private key to 'matching_pkey'.  If no
12435c51f124SMoriah Waterland  * cert or keys match, no match occurred.
12445c51f124SMoriah Waterland  *
12455c51f124SMoriah Waterland  * Arguments:
12465c51f124SMoriah Waterland  *   fname    - Friendlyname to find (NULL-terminated ASCII string).
12475c51f124SMoriah Waterland  *   pkeys    - Points to a stack of private keys which match the certs.
12485c51f124SMoriah Waterland  *              This may be NULL, in which case no keys are returned.
12495c51f124SMoriah Waterland  *   certs    - Points to a stack of certs to search.  If NULL, search the
12505c51f124SMoriah Waterland  *              stack of keys instead.
12515c51f124SMoriah Waterland  *   matching_pkey
12525c51f124SMoriah Waterland  *            - Pointer to receive address of first matching pkey found.
12535c51f124SMoriah Waterland  *   matching_cert
12545c51f124SMoriah Waterland  *            - Pointer to receive address of first matching cert found.
12555c51f124SMoriah Waterland  *
12565c51f124SMoriah Waterland  * Returns:
12575c51f124SMoriah Waterland  *  <  0 - An error returned.  Call ERR_get_error() to get errors information.
12585c51f124SMoriah Waterland  *         Where possible, memory has been freed.
12595c51f124SMoriah Waterland  *  >= 0 - Objects were found and returned.  Which objects are indicated by
12605c51f124SMoriah Waterland  *         which bits are set (FOUND_PKEY and/or FOUND_CERT).
12615c51f124SMoriah Waterland  */
12625c51f124SMoriah Waterland int
12635c51f124SMoriah Waterland sunw_find_fname(char *fname, STACK_OF(EVP_PKEY) *pkeys, STACK_OF(X509) *certs,
12645c51f124SMoriah Waterland     EVP_PKEY **matching_pkey, X509 ** matching_cert)
12655c51f124SMoriah Waterland {
12665c51f124SMoriah Waterland 	ASN1_STRING *cmpstr = NULL;
12675c51f124SMoriah Waterland 	EVP_PKEY *tmp_pkey = NULL;
12685c51f124SMoriah Waterland 	X509 *tmp_cert = NULL;
12695c51f124SMoriah Waterland 	int retval = 0;
12705c51f124SMoriah Waterland 
12715c51f124SMoriah Waterland 	/* If NULL arguments, this is an error */
12725c51f124SMoriah Waterland 	if (fname == NULL ||
12735c51f124SMoriah Waterland 	    (pkeys == NULL && certs == NULL) ||
12745c51f124SMoriah Waterland 	    (pkeys != NULL && matching_pkey == NULL) ||
12755c51f124SMoriah Waterland 	    (certs != NULL && matching_cert == NULL)) {
12765c51f124SMoriah Waterland 		SUNWerr(SUNW_F_FIND_FNAME, SUNW_R_INVALID_ARG);
12775c51f124SMoriah Waterland 		return (-1);
12785c51f124SMoriah Waterland 	}
12795c51f124SMoriah Waterland 
12805c51f124SMoriah Waterland 	if (matching_pkey != NULL)
12815c51f124SMoriah Waterland 		*matching_pkey = NULL;
12825c51f124SMoriah Waterland 	if (matching_cert != NULL)
12835c51f124SMoriah Waterland 		*matching_cert = NULL;
12845c51f124SMoriah Waterland 
12855c51f124SMoriah Waterland 	cmpstr = (ASN1_STRING *)asc2bmpstring(fname, strlen(fname));
12865c51f124SMoriah Waterland 	if (cmpstr == NULL) {
12875c51f124SMoriah Waterland 		/*
12885c51f124SMoriah Waterland 		 * Error already on stack
12895c51f124SMoriah Waterland 		 */
12905c51f124SMoriah Waterland 		return (-1);
12915c51f124SMoriah Waterland 	}
12925c51f124SMoriah Waterland 
12935c51f124SMoriah Waterland 	retval = find_attr(NID_friendlyName, cmpstr, pkeys, &tmp_pkey, certs,
12945c51f124SMoriah Waterland 	    &tmp_cert);
12955c51f124SMoriah Waterland 	if (retval == 0) {
12965c51f124SMoriah Waterland 		ASN1_STRING_free(cmpstr);
12975c51f124SMoriah Waterland 		return (retval);
12985c51f124SMoriah Waterland 	}
12995c51f124SMoriah Waterland 
13005c51f124SMoriah Waterland 	if (matching_pkey != NULL)
13015c51f124SMoriah Waterland 		*matching_pkey = tmp_pkey;
13025c51f124SMoriah Waterland 	if (matching_cert != NULL)
13035c51f124SMoriah Waterland 		*matching_cert = tmp_cert;
13045c51f124SMoriah Waterland 
13055c51f124SMoriah Waterland 	return (retval);
13065c51f124SMoriah Waterland }
13075c51f124SMoriah Waterland 
13085c51f124SMoriah Waterland /*
13095c51f124SMoriah Waterland  * sunw_get_cert_fname() gets the fiendlyname from a cert.  It can
13105c51f124SMoriah Waterland  *     optionally remove the value found.
13115c51f124SMoriah Waterland  *
13125c51f124SMoriah Waterland  * Arguments:
13135c51f124SMoriah Waterland  *   dowhat   - What to do with the attributes (remove them or copy them).
13145c51f124SMoriah Waterland  *   cert     - Points to a cert to get the friendlyName from.
13155c51f124SMoriah Waterland  *   fname    - Points to a location which will receive the pointer to a
13165c51f124SMoriah Waterland  *              byte string with the ASCII friendlyname
13175c51f124SMoriah Waterland  *
13185c51f124SMoriah Waterland  * Returns:
13195c51f124SMoriah Waterland  *   >= 0     - The number of characters in the friendlyname returned.
13205c51f124SMoriah Waterland  *   < 0      - An error occurred.  It was probably an error in allocating
13215c51f124SMoriah Waterland  *              memory.  The error will be set in the error stack.  Call
13225c51f124SMoriah Waterland  *              ERR_get_error() to get specific information.
13235c51f124SMoriah Waterland  */
13245c51f124SMoriah Waterland int
13255c51f124SMoriah Waterland sunw_get_cert_fname(getdo_actions_t dowhat, X509 *cert, char **fname)
13265c51f124SMoriah Waterland {
13275c51f124SMoriah Waterland 	int len;
13285c51f124SMoriah Waterland 
13295c51f124SMoriah Waterland 	if (fname != NULL)
13305c51f124SMoriah Waterland 		*fname = NULL;
13315c51f124SMoriah Waterland 
13325c51f124SMoriah Waterland 	if (cert == NULL || cert->aux == NULL || cert->aux->alias == NULL) {
13335c51f124SMoriah Waterland 		return (0);
13345c51f124SMoriah Waterland 	}
13355c51f124SMoriah Waterland 
13365c51f124SMoriah Waterland 	if (dowhat == GETDO_DEL) {
13375c51f124SMoriah Waterland 		/* Delete the entry */
13385c51f124SMoriah Waterland 		ASN1_UTF8STRING_free(cert->aux->alias);
13395c51f124SMoriah Waterland 		cert->aux->alias = NULL;
13405c51f124SMoriah Waterland 		return (0);
13415c51f124SMoriah Waterland 	}
13425c51f124SMoriah Waterland 
13435c51f124SMoriah Waterland 	*((uchar_t **)fname) = utf82ascstr(cert->aux->alias);
13445c51f124SMoriah Waterland 	if (*fname == NULL) {
13455c51f124SMoriah Waterland 		/*
13465c51f124SMoriah Waterland 		 * Error already on stack
13475c51f124SMoriah Waterland 		 */
13485c51f124SMoriah Waterland 		return (-1);
13495c51f124SMoriah Waterland 	}
13505c51f124SMoriah Waterland 
13515c51f124SMoriah Waterland 	len = strlen(*fname);
13525c51f124SMoriah Waterland 
13535c51f124SMoriah Waterland 	return (len);
13545c51f124SMoriah Waterland }
13555c51f124SMoriah Waterland 
13565c51f124SMoriah Waterland /*
13575c51f124SMoriah Waterland  * sunw_set_fname() sets the friendlyName in a cert, a private key or
13585c51f124SMoriah Waterland  *     both.  Any existing friendlyname will be discarded.
13595c51f124SMoriah Waterland  *
13605c51f124SMoriah Waterland  * Arguments:
13615c51f124SMoriah Waterland  *   ascname  - An ASCII string with the friendlyName to set
13625c51f124SMoriah Waterland  *   pkey     - Points to a private key to set the fname in.
13635c51f124SMoriah Waterland  *   cert     - Points to a cert to set the fname in.
13645c51f124SMoriah Waterland  *
13655c51f124SMoriah Waterland  * Note that setting a friendlyName into a cert which will not be written out
13665c51f124SMoriah Waterland  * as a PKCS12 cert is pointless since it will be lost.
13675c51f124SMoriah Waterland  *
13685c51f124SMoriah Waterland  * Returns:
13695c51f124SMoriah Waterland  *   0        - Success.
13705c51f124SMoriah Waterland  *   <0       - An error occurred.  It was probably an error in allocating
13715c51f124SMoriah Waterland  *              memory.  The error will be set in the error stack.  Call
13725c51f124SMoriah Waterland  *              ERR_get_error() to get specific information.
13735c51f124SMoriah Waterland  */
13745c51f124SMoriah Waterland int
13755c51f124SMoriah Waterland sunw_set_fname(const char *ascname, EVP_PKEY *pkey, X509 *cert)
13765c51f124SMoriah Waterland {
13775c51f124SMoriah Waterland 	X509_ATTRIBUTE *attr = NULL;
13785c51f124SMoriah Waterland 	ASN1_BMPSTRING *str = NULL;
13795c51f124SMoriah Waterland 	ASN1_TYPE *fname = NULL;
13805c51f124SMoriah Waterland 	unsigned char *data = NULL;
13815c51f124SMoriah Waterland 	int retval = -1;
13825c51f124SMoriah Waterland 	int len;
13835c51f124SMoriah Waterland 	int i;
13845c51f124SMoriah Waterland 
13855c51f124SMoriah Waterland 	str = asc2bmpstring(ascname, strlen(ascname));
13865c51f124SMoriah Waterland 	if (str == NULL) {
13875c51f124SMoriah Waterland 		/*
13885c51f124SMoriah Waterland 		 * Error already on stack
13895c51f124SMoriah Waterland 		 */
13905c51f124SMoriah Waterland 		return (-1);
13915c51f124SMoriah Waterland 	}
13925c51f124SMoriah Waterland 
13935c51f124SMoriah Waterland 	if (cert != NULL) {
13945c51f124SMoriah Waterland 		if (cert->aux != NULL && cert->aux->alias != NULL) {
13955c51f124SMoriah Waterland 			ASN1_UTF8STRING_free(cert->aux->alias);
13965c51f124SMoriah Waterland 		}
13975c51f124SMoriah Waterland 
13985c51f124SMoriah Waterland 		len = ASN1_STRING_to_UTF8(&data, str);
13995c51f124SMoriah Waterland 		i = -23;
14005c51f124SMoriah Waterland 		if (len <= 0 || (i = X509_alias_set1(cert, data, len)) == 0) {
14015c51f124SMoriah Waterland 			SUNWerr(SUNW_F_SET_FNAME, SUNW_R_SET_FNAME_ERR);
14025c51f124SMoriah Waterland 			goto cleanup;
14035c51f124SMoriah Waterland 		}
14045c51f124SMoriah Waterland 	}
14055c51f124SMoriah Waterland 	if (pkey != NULL) {
14065c51f124SMoriah Waterland 		if ((fname = ASN1_TYPE_new()) == NULL) {
14075c51f124SMoriah Waterland 			SUNWerr(SUNW_F_SET_FNAME, SUNW_R_MEMORY_FAILURE);
14085c51f124SMoriah Waterland 			goto cleanup;
14095c51f124SMoriah Waterland 		}
14105c51f124SMoriah Waterland 
14115c51f124SMoriah Waterland 		ASN1_TYPE_set(fname, V_ASN1_BMPSTRING, str);
14125c51f124SMoriah Waterland 		str = NULL;
14135c51f124SMoriah Waterland 
14145c51f124SMoriah Waterland 		attr = type2attrib(fname, NID_friendlyName);
14155c51f124SMoriah Waterland 		if (attr == NULL) {
14165c51f124SMoriah Waterland 			/*
14175c51f124SMoriah Waterland 			 * Error already on stack
14185c51f124SMoriah Waterland 			 */
14195c51f124SMoriah Waterland 			goto cleanup;
14205c51f124SMoriah Waterland 		}
14215c51f124SMoriah Waterland 		fname = NULL;
14225c51f124SMoriah Waterland 
14235c51f124SMoriah Waterland 		if (pkey->attributes == NULL) {
14245c51f124SMoriah Waterland 			pkey->attributes = sk_X509_ATTRIBUTE_new_null();
14255c51f124SMoriah Waterland 			if (pkey->attributes == NULL) {
14265c51f124SMoriah Waterland 				SUNWerr(SUNW_F_SET_FNAME,
14275c51f124SMoriah Waterland 				    SUNW_R_MEMORY_FAILURE);
14285c51f124SMoriah Waterland 				goto cleanup;
14295c51f124SMoriah Waterland 			}
14305c51f124SMoriah Waterland 		} else if ((i = find_attr_by_nid(pkey->attributes,
14315c51f124SMoriah Waterland 		    NID_friendlyName)) >= 0) {
14325c51f124SMoriah Waterland 			(void) sk_X509_ATTRIBUTE_delete(pkey->attributes, i);
14335c51f124SMoriah Waterland 		}
14345c51f124SMoriah Waterland 
14355c51f124SMoriah Waterland 		if (sk_X509_ATTRIBUTE_push(pkey->attributes, attr) == 0) {
14365c51f124SMoriah Waterland 			SUNWerr(SUNW_F_SET_FNAME, SUNW_R_MEMORY_FAILURE);
14375c51f124SMoriah Waterland 			goto cleanup;
14385c51f124SMoriah Waterland 		}
14395c51f124SMoriah Waterland 
14405c51f124SMoriah Waterland 		attr = NULL;
14415c51f124SMoriah Waterland 	}
14425c51f124SMoriah Waterland 	retval = 0;
14435c51f124SMoriah Waterland 
14445c51f124SMoriah Waterland cleanup:
14455c51f124SMoriah Waterland 	if (data != NULL)
14465c51f124SMoriah Waterland 		OPENSSL_free(data);
14475c51f124SMoriah Waterland 	if (str != NULL)
14485c51f124SMoriah Waterland 		ASN1_BMPSTRING_free(str);
14495c51f124SMoriah Waterland 	if (fname != NULL)
14505c51f124SMoriah Waterland 		ASN1_TYPE_free(fname);
14515c51f124SMoriah Waterland 	if (attr != NULL)
14525c51f124SMoriah Waterland 		X509_ATTRIBUTE_free(attr);
14535c51f124SMoriah Waterland 
14545c51f124SMoriah Waterland 	return (retval);
14555c51f124SMoriah Waterland }
14565c51f124SMoriah Waterland 
14575c51f124SMoriah Waterland /*
14585c51f124SMoriah Waterland  * sunw_check_keys() compares the public key in the certificate and a
14595c51f124SMoriah Waterland  *     private key to ensure that they match.
14605c51f124SMoriah Waterland  *
14615c51f124SMoriah Waterland  * Arguments:
14625c51f124SMoriah Waterland  *   cert     - Points to a certificate.
14635c51f124SMoriah Waterland  *   pkey     - Points to a private key.
14645c51f124SMoriah Waterland  *
14655c51f124SMoriah Waterland  * Returns:
14665c51f124SMoriah Waterland  *  == 0 - These do not match.
14675c51f124SMoriah Waterland  *  != 0 - The cert's public key and the private key match.
14685c51f124SMoriah Waterland  */
14695c51f124SMoriah Waterland int
14705c51f124SMoriah Waterland sunw_check_keys(X509 *cert, EVP_PKEY *pkey)
14715c51f124SMoriah Waterland {
14725c51f124SMoriah Waterland 	int retval = 0;
14735c51f124SMoriah Waterland 
14745c51f124SMoriah Waterland 	if (pkey != NULL && cert != NULL)
14755c51f124SMoriah Waterland 		retval = X509_check_private_key(cert, pkey);
14765c51f124SMoriah Waterland 
14775c51f124SMoriah Waterland 	return (retval);
14785c51f124SMoriah Waterland }
14795c51f124SMoriah Waterland 
14805c51f124SMoriah Waterland /*
14815c51f124SMoriah Waterland  * sunw_check_cert_times() compares the time fields in a certificate
14825c51f124SMoriah Waterland  *
14835c51f124SMoriah Waterland  * Compare the 'not before' and the 'not after' times in the cert
14845c51f124SMoriah Waterland  * to the current time.  Return the results of the comparison (bad time formats,
14855c51f124SMoriah Waterland  * cert not yet in force, cert expired or in range)
14865c51f124SMoriah Waterland  *
14875c51f124SMoriah Waterland  * Arguments:
14885c51f124SMoriah Waterland  *   dowhat   - what field(s) to check.
14895c51f124SMoriah Waterland  *   cert     - Points to a cert to check
14905c51f124SMoriah Waterland  *
14915c51f124SMoriah Waterland  * Returns:
14925c51f124SMoriah Waterland  *   Results of the comparison.
14935c51f124SMoriah Waterland  */
14945c51f124SMoriah Waterland chk_errs_t
14955c51f124SMoriah Waterland sunw_check_cert_times(chk_actions_t chkwhat, X509 *cert)
14965c51f124SMoriah Waterland {
14975c51f124SMoriah Waterland 	return (check_time(chkwhat, cert));
14985c51f124SMoriah Waterland }
14995c51f124SMoriah Waterland 
15005c51f124SMoriah Waterland /*
15015c51f124SMoriah Waterland  * ----------------------------------------------------------------------------
15025c51f124SMoriah Waterland  * Local routines
15035c51f124SMoriah Waterland  * ----------------------------------------------------------------------------
15045c51f124SMoriah Waterland  */
15055c51f124SMoriah Waterland 
15065c51f124SMoriah Waterland 
15075c51f124SMoriah Waterland /*
15085c51f124SMoriah Waterland  * parse_pkcs12 - Oversee parsing of the pkcs12 structure.  Get it
15095c51f124SMoriah Waterland  *         parsed.  After that either return what's found directly, or
15105c51f124SMoriah Waterland  *         do any required matching.
15115c51f124SMoriah Waterland  *
15125c51f124SMoriah Waterland  * Arguments:
15135c51f124SMoriah Waterland  *   p12      - Structure with pkcs12 info to be parsed
15145c51f124SMoriah Waterland  *   pass     - Pass phrase for the private key (possibly empty) or NULL if
15155c51f124SMoriah Waterland  *              there is none.
15165c51f124SMoriah Waterland  *   matchty  - Info about which certs/keys to return if many are in the file.
15175c51f124SMoriah Waterland  *   keyid    - If private key localkeyids friendlynames are to match a
15185c51f124SMoriah Waterland  *              predetermined value, the value to match. This value should
15195c51f124SMoriah Waterland  *		be an octet string.
15205c51f124SMoriah Waterland  *   keyid_len- Length of the keyid byte string.
15215c51f124SMoriah Waterland  *   name_str - If friendlynames are to match a predetermined value, the value
15225c51f124SMoriah Waterland  *		 to match. This value should be a NULL terminated string.
15235c51f124SMoriah Waterland  *   pkey     - Points to location pointing to the private key returned.
15245c51f124SMoriah Waterland  *   cert     - Points to locaiton which points to the client cert returned
15255c51f124SMoriah Waterland  *   ca       - Points to location that points to a stack of 'certificate
15265c51f124SMoriah Waterland  *              authority' certs/trust anchors.
15275c51f124SMoriah Waterland  *
15285c51f124SMoriah Waterland  *   Note about error codes:  This function is an internal function, and the
15295c51f124SMoriah Waterland  *   place where it is called sets error codes.  Therefore only set an error
15305c51f124SMoriah Waterland  *   code if it is something that is unique or if the function which detected
15315c51f124SMoriah Waterland  *   the error doesn't set one.
15325c51f124SMoriah Waterland  *
15335c51f124SMoriah Waterland  * Returns:
15345c51f124SMoriah Waterland  *   == -1 - An error occurred.  Call ERR_get_error() to get error information.
15355c51f124SMoriah Waterland  *           Where possible, memory has been freed.
15365c51f124SMoriah Waterland  *   == 0  - No matching returns were found.
15375c51f124SMoriah Waterland  *    > 0  - This is the aithmetic 'or' of the FOUND_* bits that indicate which
15385c51f124SMoriah Waterland  *           of the requested entries were found.
15395c51f124SMoriah Waterland  */
15405c51f124SMoriah Waterland static int
15415c51f124SMoriah Waterland parse_pkcs12(PKCS12 *p12, const char *pass, int matchty, char *keyid,
15425c51f124SMoriah Waterland     int kstr_len, char *name_str, EVP_PKEY **pkey, X509 **cert,
15435c51f124SMoriah Waterland     STACK_OF(X509) **ca)
15445c51f124SMoriah Waterland {
15455c51f124SMoriah Waterland 	STACK_OF(EVP_PKEY) *work_kl = NULL;	/* Head for private key list */
15465c51f124SMoriah Waterland 	STACK_OF(EVP_PKEY) *nocerts = NULL;	/* Head for alt. key list */
15475c51f124SMoriah Waterland 	STACK_OF(X509) *work_ca = NULL;		/* Head for cert list */
15485c51f124SMoriah Waterland 	STACK_OF(X509) *work_cl = NULL;
15495c51f124SMoriah Waterland 	int retval = 0;
15505c51f124SMoriah Waterland 	int n;
15515c51f124SMoriah Waterland 
15525c51f124SMoriah Waterland 	retval = sunw_PKCS12_contents(p12, pass, &work_kl, &work_ca);
15535c51f124SMoriah Waterland 	if (retval < 0) {
15545c51f124SMoriah Waterland 		goto cleanup;
15555c51f124SMoriah Waterland 	} else if (retval == 0) {
15565c51f124SMoriah Waterland 		/*
15575c51f124SMoriah Waterland 		 * Not really an error here - its just that nothing was found.
15585c51f124SMoriah Waterland 		 */
15595c51f124SMoriah Waterland 		goto cleanup;
15605c51f124SMoriah Waterland 	}
15615c51f124SMoriah Waterland 
15625c51f124SMoriah Waterland 	if (sk_EVP_PKEY_num(work_kl) > 0) {
15635c51f124SMoriah Waterland 
15645c51f124SMoriah Waterland 		if (sunw_split_certs(work_kl, work_ca, &work_cl, &nocerts)
15655c51f124SMoriah Waterland 		    < 0) {
15665c51f124SMoriah Waterland 			goto cleanup;
15675c51f124SMoriah Waterland 		}
15685c51f124SMoriah Waterland 	}
15695c51f124SMoriah Waterland 
15705c51f124SMoriah Waterland 	/*
15715c51f124SMoriah Waterland 	 * Go through the lists of certs and private keys which were
15725c51f124SMoriah Waterland 	 * returned, looking for matches of the appropriate type.  Do these
15735c51f124SMoriah Waterland 	 * in the order described above.
15745c51f124SMoriah Waterland 	 */
15755c51f124SMoriah Waterland 	if ((matchty & DO_FIND_KEYID) != 0) {
15765c51f124SMoriah Waterland 
15775c51f124SMoriah Waterland 		if (keyid == NULL) {
15785c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PKCS12_PARSE, SUNW_R_INVALID_ARG);
15795c51f124SMoriah Waterland 			retval = -1;
15805c51f124SMoriah Waterland 			goto cleanup;
15815c51f124SMoriah Waterland 		}
15825c51f124SMoriah Waterland 
15835c51f124SMoriah Waterland 		/* See if string matches localkeyid's */
15845c51f124SMoriah Waterland 		retval = sunw_find_localkeyid(keyid, kstr_len,
15855c51f124SMoriah Waterland 		    work_kl, work_cl, pkey, cert);
15865c51f124SMoriah Waterland 		if (retval != 0) {
15875c51f124SMoriah Waterland 			if (retval == -1)
15885c51f124SMoriah Waterland 				goto cleanup;
15895c51f124SMoriah Waterland 			else
15905c51f124SMoriah Waterland 				goto last_part;
15915c51f124SMoriah Waterland 		}
15925c51f124SMoriah Waterland 	}
15935c51f124SMoriah Waterland 	if ((matchty & DO_FIND_FN) != 0) {
15945c51f124SMoriah Waterland 
15955c51f124SMoriah Waterland 		if (name_str == NULL) {
15965c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PKCS12_PARSE, SUNW_R_INVALID_ARG);
15975c51f124SMoriah Waterland 			retval = -1;
15985c51f124SMoriah Waterland 			goto cleanup;
15995c51f124SMoriah Waterland 		}
16005c51f124SMoriah Waterland 
16015c51f124SMoriah Waterland 		/* See if string matches friendly names */
16025c51f124SMoriah Waterland 		retval = sunw_find_fname(name_str, work_kl, work_cl,
16035c51f124SMoriah Waterland 		    pkey, cert);
16045c51f124SMoriah Waterland 		if (retval != 0) {
16055c51f124SMoriah Waterland 			if (retval == -1)
16065c51f124SMoriah Waterland 				goto cleanup;
16075c51f124SMoriah Waterland 			else
16085c51f124SMoriah Waterland 				goto last_part;
16095c51f124SMoriah Waterland 		}
16105c51f124SMoriah Waterland 	}
16115c51f124SMoriah Waterland 
16125c51f124SMoriah Waterland 	if (matchty & DO_FIRST_PAIR) {
16135c51f124SMoriah Waterland 
16145c51f124SMoriah Waterland 		/* Find the first cert and private key and return them */
16155c51f124SMoriah Waterland 		retval = get_key_cert(0, work_kl, pkey, work_cl, cert);
16165c51f124SMoriah Waterland 		if (retval != 0) {
16175c51f124SMoriah Waterland 			if (retval == -1)
16185c51f124SMoriah Waterland 				goto cleanup;
16195c51f124SMoriah Waterland 			else
16205c51f124SMoriah Waterland 				goto last_part;
16215c51f124SMoriah Waterland 		}
16225c51f124SMoriah Waterland 	}
16235c51f124SMoriah Waterland 
16245c51f124SMoriah Waterland 	if (matchty & DO_LAST_PAIR) {
16255c51f124SMoriah Waterland 
16265c51f124SMoriah Waterland 		/*
16275c51f124SMoriah Waterland 		 * Find the last matching cert and private key and return
16285c51f124SMoriah Waterland 		 * them.  Since keys which don't have matching client certs
16295c51f124SMoriah Waterland 		 * are at the end of the list of keys, use the number of
16305c51f124SMoriah Waterland 		 * client certs to compute the position of the last private
16315c51f124SMoriah Waterland 		 * key which matches a client cert.
16325c51f124SMoriah Waterland 		 */
16335c51f124SMoriah Waterland 		n = sk_X509_num(work_cl) - 1;
16345c51f124SMoriah Waterland 		retval = get_key_cert(n, work_kl, pkey, work_cl, cert);
16355c51f124SMoriah Waterland 		if (retval != 0) {
16365c51f124SMoriah Waterland 			if (retval == -1)
16375c51f124SMoriah Waterland 				goto cleanup;
16385c51f124SMoriah Waterland 			else
16395c51f124SMoriah Waterland 				goto last_part;
16405c51f124SMoriah Waterland 		}
16415c51f124SMoriah Waterland 	}
16425c51f124SMoriah Waterland 
16435c51f124SMoriah Waterland 	if (matchty & DO_UNMATCHING) {
16445c51f124SMoriah Waterland 		STACK_OF(EVP_PKEY) *tmpk;
16455c51f124SMoriah Waterland 		STACK_OF(X509) *tmpc;
16465c51f124SMoriah Waterland 
16475c51f124SMoriah Waterland 		/* Find the first cert and private key and return them */
16485c51f124SMoriah Waterland 		tmpc = work_cl;
16495c51f124SMoriah Waterland 		if (work_cl == NULL || sk_X509_num(work_cl) == 0)
16505c51f124SMoriah Waterland 			tmpc = work_ca;
16515c51f124SMoriah Waterland 		tmpk = work_kl;
16525c51f124SMoriah Waterland 		if (work_kl == NULL || sk_EVP_PKEY_num(work_kl) == 0)
16535c51f124SMoriah Waterland 			tmpk = nocerts;
16545c51f124SMoriah Waterland 		retval = get_key_cert(0, tmpk, pkey, tmpc, cert);
16555c51f124SMoriah Waterland 		if (retval != 0) {
16565c51f124SMoriah Waterland 			if (retval == -1)
16575c51f124SMoriah Waterland 				goto cleanup;
16585c51f124SMoriah Waterland 			else
16595c51f124SMoriah Waterland 				goto last_part;
16605c51f124SMoriah Waterland 		}
16615c51f124SMoriah Waterland 	}
16625c51f124SMoriah Waterland 
16635c51f124SMoriah Waterland last_part:
16645c51f124SMoriah Waterland 	/* If no errors, terminate normally */
16655c51f124SMoriah Waterland 	if (retval != -1)
16665c51f124SMoriah Waterland 		retval |= set_results(NULL, NULL, NULL, NULL, ca, &work_ca,
16675c51f124SMoriah Waterland 		    NULL, NULL);
16685c51f124SMoriah Waterland 	if (retval >= 0) {
16695c51f124SMoriah Waterland 		goto clean_part;
16705c51f124SMoriah Waterland 	}
16715c51f124SMoriah Waterland 
16725c51f124SMoriah Waterland 	/* Fallthrough is intentional in error cases. */
16735c51f124SMoriah Waterland cleanup:
16745c51f124SMoriah Waterland 	if (pkey != NULL && *pkey != NULL) {
16755c51f124SMoriah Waterland 		sunw_evp_pkey_free(*pkey);
16765c51f124SMoriah Waterland 		*pkey = NULL;
16775c51f124SMoriah Waterland 	}
16785c51f124SMoriah Waterland 	if (cert != NULL && *cert != NULL) {
16795c51f124SMoriah Waterland 		X509_free(*cert);
16805c51f124SMoriah Waterland 		*cert = NULL;
16815c51f124SMoriah Waterland 	}
16825c51f124SMoriah Waterland 
16835c51f124SMoriah Waterland clean_part:
16845c51f124SMoriah Waterland 
16855c51f124SMoriah Waterland 	if (work_kl != NULL) {
16865c51f124SMoriah Waterland 		sk_EVP_PKEY_pop_free(work_kl, sunw_evp_pkey_free);
16875c51f124SMoriah Waterland 	}
16885c51f124SMoriah Waterland 	if (work_ca != NULL)
16895c51f124SMoriah Waterland 		sk_X509_pop_free(work_ca, X509_free);
16905c51f124SMoriah Waterland 	if (work_cl != NULL)
16915c51f124SMoriah Waterland 		sk_X509_pop_free(work_cl, X509_free);
16925c51f124SMoriah Waterland 
16935c51f124SMoriah Waterland 	return (retval);
16945c51f124SMoriah Waterland }
16955c51f124SMoriah Waterland 
16965c51f124SMoriah Waterland /*
16975c51f124SMoriah Waterland  * parse_outer - Unpack the outer PKCS#12 structure and go through the
16985c51f124SMoriah Waterland  *         individual bags.  Return stacks of certs, private keys found and
16995c51f124SMoriah Waterland  *         CA certs found.
17005c51f124SMoriah Waterland  *
17015c51f124SMoriah Waterland  *   Note about error codes:  This function is an internal function, and the
17025c51f124SMoriah Waterland  *   place where it is called sets error codes.
17035c51f124SMoriah Waterland  *
17045c51f124SMoriah Waterland  * Returns:
17055c51f124SMoriah Waterland  *    0 - An error returned.  Call ERR_get_error() to get errors information.
17065c51f124SMoriah Waterland  *        Where possible, memory has been freed.
17075c51f124SMoriah Waterland  *    1 - PKCS12 data object was parsed and lists of certs and private keys
17085c51f124SMoriah Waterland  *        were returned.
17095c51f124SMoriah Waterland  */
17105c51f124SMoriah Waterland static int
17115c51f124SMoriah Waterland parse_outer(PKCS12 *p12, const char *pass, STACK_OF(EVP_PKEY) *kl,
17125c51f124SMoriah Waterland     STACK_OF(X509) *cl)
17135c51f124SMoriah Waterland {
17145c51f124SMoriah Waterland 	STACK_OF(PKCS12_SAFEBAG) *bags;
17155c51f124SMoriah Waterland 	STACK_OF(PKCS7) *asafes;
17165c51f124SMoriah Waterland 	int i, bagnid;
17175c51f124SMoriah Waterland 	PKCS7 *p7;
17185c51f124SMoriah Waterland 
17195c51f124SMoriah Waterland 	if ((asafes = M_PKCS12_unpack_authsafes(p12)) == NULL)
17205c51f124SMoriah Waterland 		return (0);
17215c51f124SMoriah Waterland 
17225c51f124SMoriah Waterland 	for (i = 0; i < sk_PKCS7_num(asafes); i++) {
17235c51f124SMoriah Waterland 		p7 = sk_PKCS7_value(asafes, i);
17245c51f124SMoriah Waterland 		bagnid = OBJ_obj2nid(p7->type);
17255c51f124SMoriah Waterland 		if (bagnid == NID_pkcs7_data) {
17265c51f124SMoriah Waterland 			bags = M_PKCS12_unpack_p7data(p7);
17275c51f124SMoriah Waterland 		} else if (bagnid == NID_pkcs7_encrypted) {
17285c51f124SMoriah Waterland 			/*
17295c51f124SMoriah Waterland 			 * A length of '-1' means strlen() can be used
17305c51f124SMoriah Waterland 			 * to determine the password length.
17315c51f124SMoriah Waterland 			 */
17325c51f124SMoriah Waterland 			bags = M_PKCS12_unpack_p7encdata(p7, pass, -1);
17335c51f124SMoriah Waterland 		} else {
17345c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PARSE_OUTER, SUNW_R_BAD_BAGTYPE);
17355c51f124SMoriah Waterland 			return (0);
17365c51f124SMoriah Waterland 		}
17375c51f124SMoriah Waterland 
17385c51f124SMoriah Waterland 		if (bags == NULL) {
17395c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PARSE_OUTER, SUNW_R_PARSE_BAG_ERR);
17405c51f124SMoriah Waterland 			sk_PKCS7_pop_free(asafes, PKCS7_free);
17415c51f124SMoriah Waterland 			return (0);
17425c51f124SMoriah Waterland 		}
17435c51f124SMoriah Waterland 		if (parse_all_bags(bags, pass, kl, cl) == 0) {
17445c51f124SMoriah Waterland 			sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
17455c51f124SMoriah Waterland 			sk_PKCS7_pop_free(asafes, PKCS7_free);
17465c51f124SMoriah Waterland 			return (0);
17475c51f124SMoriah Waterland 		}
17485c51f124SMoriah Waterland 	}
17495c51f124SMoriah Waterland 
17505c51f124SMoriah Waterland 	return (1);
17515c51f124SMoriah Waterland }
17525c51f124SMoriah Waterland 
17535c51f124SMoriah Waterland /*
17545c51f124SMoriah Waterland  * parse_all_bags - go through the stack of bags, parsing each.
17555c51f124SMoriah Waterland  *
17565c51f124SMoriah Waterland  *   Note about error codes:  This function is an internal function, and the
17575c51f124SMoriah Waterland  *   place where it is called sets error codes.
17585c51f124SMoriah Waterland  *
17595c51f124SMoriah Waterland  * Returns:
17605c51f124SMoriah Waterland  *    0 - An error returned.  Call ERR_get_error() to get errors information.
17615c51f124SMoriah Waterland  *        Where possible, memory has been freed.
17625c51f124SMoriah Waterland  *    1 - Stack of safebags was parsed and lists of certs and private keys
17635c51f124SMoriah Waterland  *        were returned.
17645c51f124SMoriah Waterland  */
17655c51f124SMoriah Waterland static int
17665c51f124SMoriah Waterland parse_all_bags(STACK_OF(PKCS12_SAFEBAG) *bags, const char *pass,
17675c51f124SMoriah Waterland     STACK_OF(EVP_PKEY) *kl, STACK_OF(X509) *cl)
17685c51f124SMoriah Waterland {
17695c51f124SMoriah Waterland 	int i;
17705c51f124SMoriah Waterland 	for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) {
17715c51f124SMoriah Waterland 		if (parse_one_bag(sk_PKCS12_SAFEBAG_value(bags, i),
17725c51f124SMoriah Waterland 		    pass, kl, cl) == 0)
17735c51f124SMoriah Waterland 			return (0);
17745c51f124SMoriah Waterland 	}
17755c51f124SMoriah Waterland 	return (1);
17765c51f124SMoriah Waterland }
17775c51f124SMoriah Waterland 
17785c51f124SMoriah Waterland /*
17795c51f124SMoriah Waterland  * parse_one_bag - Parse an individual bag
17805c51f124SMoriah Waterland  *
17815c51f124SMoriah Waterland  *   i = parse_one_bag(bag, pass, kl, cl);
17825c51f124SMoriah Waterland  *
17835c51f124SMoriah Waterland  * Arguments:
17845c51f124SMoriah Waterland  *   bag	- pkcs12 safebag to parse.
17855c51f124SMoriah Waterland  *   pass 	- password for use in decryption of shrouded keybag
17865c51f124SMoriah Waterland  *   kl         - Stack of private keys found so far.  New private keys will
17875c51f124SMoriah Waterland  *                be added here if found.
17885c51f124SMoriah Waterland  *   cl         - Stack of certs found so far.  New certificates will be
17895c51f124SMoriah Waterland  *                added here if found.
17905c51f124SMoriah Waterland  *
17915c51f124SMoriah Waterland  * Returns:
17925c51f124SMoriah Waterland  *    0 - An error returned.  Call ERR_get_error() to get errors information.
17935c51f124SMoriah Waterland  *        Where possible, memory has been freed.
17945c51f124SMoriah Waterland  *    1 - one safebag was parsed. If it contained a cert or private key, it
17955c51f124SMoriah Waterland  *        was added to the stack of certs or private keys found, respectively.
17965c51f124SMoriah Waterland  *        localKeyId or friendlyName attributes are returned with the
17975c51f124SMoriah Waterland  *        private key or certificate.
17985c51f124SMoriah Waterland  */
17995c51f124SMoriah Waterland static int
18005c51f124SMoriah Waterland parse_one_bag(PKCS12_SAFEBAG *bag, const char *pass, STACK_OF(EVP_PKEY) *kl,
18015c51f124SMoriah Waterland     STACK_OF(X509) *cl)
18025c51f124SMoriah Waterland {
18035c51f124SMoriah Waterland 	X509_ATTRIBUTE *attr = NULL;
18045c51f124SMoriah Waterland 	ASN1_TYPE *keyid = NULL;
18055c51f124SMoriah Waterland 	ASN1_TYPE *fname = NULL;
18065c51f124SMoriah Waterland 	PKCS8_PRIV_KEY_INFO *p8;
18075c51f124SMoriah Waterland 	EVP_PKEY *pkey = NULL;
18085c51f124SMoriah Waterland 	X509 *x509 = NULL;
18095c51f124SMoriah Waterland 	uchar_t *data = NULL;
18105c51f124SMoriah Waterland 	char *str = NULL;
18115c51f124SMoriah Waterland 	int retval = 1;
18125c51f124SMoriah Waterland 
18135c51f124SMoriah Waterland 	keyid = PKCS12_get_attr(bag, NID_localKeyID);
18145c51f124SMoriah Waterland 	fname = PKCS12_get_attr(bag, NID_friendlyName);
18155c51f124SMoriah Waterland 
18165c51f124SMoriah Waterland 	switch (M_PKCS12_bag_type(bag)) {
18175c51f124SMoriah Waterland 	case NID_keyBag:
18185c51f124SMoriah Waterland 		if ((pkey = EVP_PKCS82PKEY(bag->value.keybag)) == NULL) {
18195c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PARSE_ONE_BAG, SUNW_R_PARSE_BAG_ERR);
18205c51f124SMoriah Waterland 			retval = 0;
18215c51f124SMoriah Waterland 			break;
18225c51f124SMoriah Waterland 		}
18235c51f124SMoriah Waterland 		break;
18245c51f124SMoriah Waterland 
18255c51f124SMoriah Waterland 	case NID_pkcs8ShroudedKeyBag:
18265c51f124SMoriah Waterland 		/*
18275c51f124SMoriah Waterland 		 * A length of '-1' means strlen() can be used
18285c51f124SMoriah Waterland 		 * to determine the password length.
18295c51f124SMoriah Waterland 		 */
18305c51f124SMoriah Waterland 		if ((p8 = M_PKCS12_decrypt_skey(bag, pass, -1)) == NULL) {
18315c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PARSE_ONE_BAG, SUNW_R_PARSE_BAG_ERR);
18325c51f124SMoriah Waterland 			retval = 0;
18335c51f124SMoriah Waterland 			break;
18345c51f124SMoriah Waterland 		}
18355c51f124SMoriah Waterland 		pkey = EVP_PKCS82PKEY(p8);
18365c51f124SMoriah Waterland 		PKCS8_PRIV_KEY_INFO_free(p8);
18375c51f124SMoriah Waterland 		if (pkey == NULL) {
18385c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PARSE_ONE_BAG, SUNW_R_PARSE_BAG_ERR);
18395c51f124SMoriah Waterland 			retval = 0;
18405c51f124SMoriah Waterland 		}
18415c51f124SMoriah Waterland 		break;
18425c51f124SMoriah Waterland 
18435c51f124SMoriah Waterland 	case NID_certBag:
18445c51f124SMoriah Waterland 		if (M_PKCS12_cert_bag_type(bag) != NID_x509Certificate) {
18455c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PARSE_ONE_BAG, SUNW_R_BAD_CERTTYPE);
18465c51f124SMoriah Waterland 			break;
18475c51f124SMoriah Waterland 		}
18485c51f124SMoriah Waterland 		if ((x509 = M_PKCS12_certbag2x509(bag)) == NULL) {
18495c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PARSE_ONE_BAG,
18505c51f124SMoriah Waterland 			    SUNW_R_PARSE_CERT_ERR);
18515c51f124SMoriah Waterland 			retval = 0;
18525c51f124SMoriah Waterland 			break;
18535c51f124SMoriah Waterland 		}
18545c51f124SMoriah Waterland 
18555c51f124SMoriah Waterland 		if (keyid != NULL) {
18565c51f124SMoriah Waterland 			if (keyid->type != V_ASN1_OCTET_STRING) {
18575c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PARSE_ONE_BAG,
18585c51f124SMoriah Waterland 				    SUNW_R_BAD_LKID);
18595c51f124SMoriah Waterland 				retval = 0;
18605c51f124SMoriah Waterland 				break;
18615c51f124SMoriah Waterland 			}
18625c51f124SMoriah Waterland 			if (X509_keyid_set1(x509,
18635c51f124SMoriah Waterland 			    keyid->value.octet_string->data,
18645c51f124SMoriah Waterland 			    keyid->value.octet_string->length) == 0) {
18655c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PARSE_ONE_BAG,
18665c51f124SMoriah Waterland 				    SUNW_R_SET_LKID_ERR);
18675c51f124SMoriah Waterland 				retval = 0;
18685c51f124SMoriah Waterland 				break;
18695c51f124SMoriah Waterland 			}
18705c51f124SMoriah Waterland 		}
18715c51f124SMoriah Waterland 
18725c51f124SMoriah Waterland 		if (fname != NULL) {
18735c51f124SMoriah Waterland 			ASN1_STRING *tmpstr = NULL;
18745c51f124SMoriah Waterland 			int len;
18755c51f124SMoriah Waterland 
18765c51f124SMoriah Waterland 			if (fname->type != V_ASN1_BMPSTRING) {
18775c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PARSE_ONE_BAG,
18785c51f124SMoriah Waterland 				    SUNW_R_BAD_FNAME);
18795c51f124SMoriah Waterland 				retval = 0;
18805c51f124SMoriah Waterland 				break;
18815c51f124SMoriah Waterland 			}
18825c51f124SMoriah Waterland 
18835c51f124SMoriah Waterland 			tmpstr = fname->value.asn1_string;
18845c51f124SMoriah Waterland 			len = ASN1_STRING_to_UTF8(&data, tmpstr);
18855c51f124SMoriah Waterland 			if (len < 0) {
18865c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PARSE_ONE_BAG,
18875c51f124SMoriah Waterland 				    SUNW_R_SET_FNAME_ERR);
18885c51f124SMoriah Waterland 				retval = 0;
18895c51f124SMoriah Waterland 				break;
18905c51f124SMoriah Waterland 			}
18915c51f124SMoriah Waterland 
18925c51f124SMoriah Waterland 			if (X509_alias_set1(x509, data, len) == 0) {
18935c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PARSE_ONE_BAG,
18945c51f124SMoriah Waterland 				    SUNW_R_SET_FNAME_ERR);
18955c51f124SMoriah Waterland 				retval = 0;
18965c51f124SMoriah Waterland 				break;
18975c51f124SMoriah Waterland 			}
18985c51f124SMoriah Waterland 		}
18995c51f124SMoriah Waterland 
19005c51f124SMoriah Waterland 		if (sk_X509_push(cl, x509) == 0) {
19015c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PARSE_ONE_BAG, SUNW_R_MEMORY_FAILURE);
19025c51f124SMoriah Waterland 			retval = 0;
19035c51f124SMoriah Waterland 			break;
19045c51f124SMoriah Waterland 		}
19055c51f124SMoriah Waterland 		x509 = NULL;
19065c51f124SMoriah Waterland 		break;
19075c51f124SMoriah Waterland 
19085c51f124SMoriah Waterland 	case NID_safeContentsBag:
19095c51f124SMoriah Waterland 		if (keyid != NULL)
19105c51f124SMoriah Waterland 			ASN1_TYPE_free(keyid);
19115c51f124SMoriah Waterland 		if (fname != NULL)
19125c51f124SMoriah Waterland 			ASN1_TYPE_free(fname);
19135c51f124SMoriah Waterland 		if (parse_all_bags(bag->value.safes, pass, kl, cl) == 0) {
19145c51f124SMoriah Waterland 			/*
19155c51f124SMoriah Waterland 			 * Error already on stack
19165c51f124SMoriah Waterland 			 */
19175c51f124SMoriah Waterland 			return (0);
19185c51f124SMoriah Waterland 		}
19195c51f124SMoriah Waterland 		return (1);
19205c51f124SMoriah Waterland 
19215c51f124SMoriah Waterland 	default:
19225c51f124SMoriah Waterland 		if (keyid != NULL)
19235c51f124SMoriah Waterland 			ASN1_TYPE_free(keyid);
19245c51f124SMoriah Waterland 		if (fname != NULL)
19255c51f124SMoriah Waterland 			ASN1_TYPE_free(fname);
19265c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PARSE_ONE_BAG, SUNW_R_BAD_BAGTYPE);
19275c51f124SMoriah Waterland 		return (0);
19285c51f124SMoriah Waterland 	}
19295c51f124SMoriah Waterland 
19305c51f124SMoriah Waterland 
19315c51f124SMoriah Waterland 	if (pkey != NULL) {
19325c51f124SMoriah Waterland 		if (retval != 0 && (keyid != NULL || fname != NULL) &&
19335c51f124SMoriah Waterland 		    pkey->attributes == NULL) {
19345c51f124SMoriah Waterland 			pkey->attributes = sk_X509_ATTRIBUTE_new_null();
19355c51f124SMoriah Waterland 			if (pkey->attributes == NULL) {
19365c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PARSE_ONE_BAG,
19375c51f124SMoriah Waterland 				    SUNW_R_MEMORY_FAILURE);
19385c51f124SMoriah Waterland 				retval = 0;
19395c51f124SMoriah Waterland 			}
19405c51f124SMoriah Waterland 		}
19415c51f124SMoriah Waterland 
19425c51f124SMoriah Waterland 		if (retval != 0 && keyid != NULL) {
19435c51f124SMoriah Waterland 			attr = type2attrib(keyid, NID_localKeyID);
19445c51f124SMoriah Waterland 			if (attr == NULL)
19455c51f124SMoriah Waterland 				/*
19465c51f124SMoriah Waterland 				 * Error already on stack
19475c51f124SMoriah Waterland 				 */
19485c51f124SMoriah Waterland 				retval = 0;
19495c51f124SMoriah Waterland 			else {
19505c51f124SMoriah Waterland 				keyid = NULL;
19515c51f124SMoriah Waterland 				if (sk_X509_ATTRIBUTE_push(pkey->attributes,
19525c51f124SMoriah Waterland 				    attr) == 0) {
19535c51f124SMoriah Waterland 					SUNWerr(SUNW_F_PARSE_ONE_BAG,
19545c51f124SMoriah Waterland 					    SUNW_R_MEMORY_FAILURE);
19555c51f124SMoriah Waterland 					retval = 0;
19565c51f124SMoriah Waterland 				} else {
19575c51f124SMoriah Waterland 					attr = NULL;
19585c51f124SMoriah Waterland 				}
19595c51f124SMoriah Waterland 			}
19605c51f124SMoriah Waterland 		}
19615c51f124SMoriah Waterland 
19625c51f124SMoriah Waterland 		if (retval != 0 && fname != NULL) {
19635c51f124SMoriah Waterland 			attr = type2attrib(fname, NID_friendlyName);
19645c51f124SMoriah Waterland 			if (attr == NULL) {
19655c51f124SMoriah Waterland 				/*
19665c51f124SMoriah Waterland 				 * Error already on stack
19675c51f124SMoriah Waterland 				 */
19685c51f124SMoriah Waterland 				retval = 0;
19695c51f124SMoriah Waterland 			} else {
19705c51f124SMoriah Waterland 				fname = NULL;
19715c51f124SMoriah Waterland 				if (sk_X509_ATTRIBUTE_push(pkey->attributes,
19725c51f124SMoriah Waterland 				    attr) == 0) {
19735c51f124SMoriah Waterland 					SUNWerr(SUNW_F_PARSE_ONE_BAG,
19745c51f124SMoriah Waterland 					    SUNW_R_MEMORY_FAILURE);
19755c51f124SMoriah Waterland 					retval = 0;
19765c51f124SMoriah Waterland 				} else {
19775c51f124SMoriah Waterland 					attr = NULL;
19785c51f124SMoriah Waterland 				}
19795c51f124SMoriah Waterland 			}
19805c51f124SMoriah Waterland 		}
19815c51f124SMoriah Waterland 
19825c51f124SMoriah Waterland 		/* Save the private key */
19835c51f124SMoriah Waterland 		if (retval != 0) {
19845c51f124SMoriah Waterland 			if (sk_EVP_PKEY_push(kl, pkey) == 0) {
19855c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PARSE_ONE_BAG,
19865c51f124SMoriah Waterland 				    SUNW_R_MEMORY_FAILURE);
19875c51f124SMoriah Waterland 				retval = 0;
19885c51f124SMoriah Waterland 			} else {
19895c51f124SMoriah Waterland 				pkey = NULL;
19905c51f124SMoriah Waterland 			}
19915c51f124SMoriah Waterland 		}
19925c51f124SMoriah Waterland 	}
19935c51f124SMoriah Waterland 
19945c51f124SMoriah Waterland 	if (pkey != NULL) {
19955c51f124SMoriah Waterland 		sunw_evp_pkey_free(pkey);
19965c51f124SMoriah Waterland 	}
19975c51f124SMoriah Waterland 
19985c51f124SMoriah Waterland 	if (x509 != NULL)
19995c51f124SMoriah Waterland 		X509_free(x509);
20005c51f124SMoriah Waterland 
20015c51f124SMoriah Waterland 	if (keyid != NULL)
20025c51f124SMoriah Waterland 		ASN1_TYPE_free(keyid);
20035c51f124SMoriah Waterland 
20045c51f124SMoriah Waterland 	if (fname != NULL)
20055c51f124SMoriah Waterland 		ASN1_TYPE_free(fname);
20065c51f124SMoriah Waterland 
20075c51f124SMoriah Waterland 	if (attr != NULL)
20085c51f124SMoriah Waterland 		X509_ATTRIBUTE_free(attr);
20095c51f124SMoriah Waterland 
20105c51f124SMoriah Waterland 	if (data != NULL)
20115c51f124SMoriah Waterland 		OPENSSL_free(data);
20125c51f124SMoriah Waterland 
20135c51f124SMoriah Waterland 	if (str != NULL)
20145c51f124SMoriah Waterland 		OPENSSL_free(str);
20155c51f124SMoriah Waterland 
20165c51f124SMoriah Waterland 	return (retval);
20175c51f124SMoriah Waterland }
20185c51f124SMoriah Waterland 
20195c51f124SMoriah Waterland /*
20205c51f124SMoriah Waterland  * This function uses the only function that reads PEM files, regardless of
20215c51f124SMoriah Waterland  * the kinds of information included (private keys, public keys, cert requests,
20225c51f124SMoriah Waterland  * certs).  Other interfaces that read files require that the application
20235c51f124SMoriah Waterland  * specifically know what kinds of things to read next, and call different
20245c51f124SMoriah Waterland  * interfaces for the different kinds of entities.
20255c51f124SMoriah Waterland  *
20265c51f124SMoriah Waterland  * There is only one aspect of this function that's a bit problematic.
20275c51f124SMoriah Waterland  * If it finds an encrypted private key, it does not decrypt it.  It returns
20285c51f124SMoriah Waterland  * the encrypted data and other information needed to decrypt it.  The caller
20295c51f124SMoriah Waterland  * must do the decryption.  This function does the decoding.
20305c51f124SMoriah Waterland  */
20315c51f124SMoriah Waterland static int
20325c51f124SMoriah Waterland pem_info(FILE *fp, pem_password_cb cb, void *userdata,
20335c51f124SMoriah Waterland     STACK_OF(EVP_PKEY) **pkeys, STACK_OF(X509) **certs)
20345c51f124SMoriah Waterland {
20355c51f124SMoriah Waterland 	STACK_OF(X509_INFO) *info;
20365c51f124SMoriah Waterland 	STACK_OF(EVP_PKEY) *work_kl;
20375c51f124SMoriah Waterland 	STACK_OF(X509) *work_cl;
20385c51f124SMoriah Waterland 	X509_INFO *x;
20395c51f124SMoriah Waterland 	int retval = 0;
20405c51f124SMoriah Waterland 	int i;
20415c51f124SMoriah Waterland 
20425c51f124SMoriah Waterland 	info = PEM_X509_INFO_read(fp, NULL, cb, userdata);
20435c51f124SMoriah Waterland 	if (info == NULL) {
20445c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PEM_INFO, SUNW_R_READ_ERR);
20455c51f124SMoriah Waterland 		return (-1);
20465c51f124SMoriah Waterland 	}
20475c51f124SMoriah Waterland 
20485c51f124SMoriah Waterland 	/*
20495c51f124SMoriah Waterland 	 * Allocate the working stacks for private key(s) and for the cert(s).
20505c51f124SMoriah Waterland 	 */
20515c51f124SMoriah Waterland 	if ((work_kl = sk_EVP_PKEY_new_null()) == NULL) {
20525c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PEM_INFO, SUNW_R_MEMORY_FAILURE);
20535c51f124SMoriah Waterland 		retval = -1;
20545c51f124SMoriah Waterland 		goto cleanup;
20555c51f124SMoriah Waterland 	}
20565c51f124SMoriah Waterland 
20575c51f124SMoriah Waterland 	if ((work_cl = sk_X509_new_null()) == NULL) {
20585c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PEM_INFO, SUNW_R_MEMORY_FAILURE);
20595c51f124SMoriah Waterland 		retval = -1;
20605c51f124SMoriah Waterland 		goto cleanup;
20615c51f124SMoriah Waterland 	}
20625c51f124SMoriah Waterland 
20635c51f124SMoriah Waterland 	/*
20645c51f124SMoriah Waterland 	 * Go through the entries in the info structure.
20655c51f124SMoriah Waterland 	 */
20665c51f124SMoriah Waterland 	for (i = 0; i < sk_X509_INFO_num(info); i++) {
20675c51f124SMoriah Waterland 		x = sk_X509_INFO_value(info, i);
20685c51f124SMoriah Waterland 		if (x->x509) {
20695c51f124SMoriah Waterland 			if (sk_X509_push(work_cl, x->x509) == 0) {
20705c51f124SMoriah Waterland 				retval = -1;
20715c51f124SMoriah Waterland 				break;
20725c51f124SMoriah Waterland 			}
20735c51f124SMoriah Waterland 			x->x509 = NULL;
20745c51f124SMoriah Waterland 		}
20755c51f124SMoriah Waterland 		if (x->x_pkey != NULL && x->x_pkey->dec_pkey != NULL &&
20765c51f124SMoriah Waterland 		    (x->x_pkey->dec_pkey->type == EVP_PKEY_RSA ||
20775c51f124SMoriah Waterland 		    x->x_pkey->dec_pkey->type == EVP_PKEY_DSA)) {
20785c51f124SMoriah Waterland 			const uchar_t *p;
20795c51f124SMoriah Waterland 
20805c51f124SMoriah Waterland 			/*
20815c51f124SMoriah Waterland 			 * If the key was encrypted, PEM_X509_INFO_read does
20825c51f124SMoriah Waterland 			 * not decrypt it.  If that is the case, the 'enc_pkey'
20835c51f124SMoriah Waterland 			 * field is set to point to the unencrypted key data.
20845c51f124SMoriah Waterland 			 * Go through the additional steps to decode it before
20855c51f124SMoriah Waterland 			 * going on.
20865c51f124SMoriah Waterland 			 */
20875c51f124SMoriah Waterland 			if (x->x_pkey->enc_pkey != NULL) {
20885c51f124SMoriah Waterland 
20895c51f124SMoriah Waterland 				if (PEM_do_header(&x->enc_cipher,
20905c51f124SMoriah Waterland 				    (uchar_t *)x->enc_data,
20915c51f124SMoriah Waterland 				    (long *)&x->enc_len,
20925c51f124SMoriah Waterland 				    cb, userdata) == 0) {
20935c51f124SMoriah Waterland 					if (ERR_GET_REASON(ERR_peek_error()) ==
20945c51f124SMoriah Waterland 					    PEM_R_BAD_PASSWORD_READ) {
20955c51f124SMoriah Waterland 						SUNWerr(SUNW_F_PEM_INFO,
20965c51f124SMoriah Waterland 						    SUNW_R_PASSWORD_ERR);
20975c51f124SMoriah Waterland 					} else {
20985c51f124SMoriah Waterland 						SUNWerr(SUNW_F_PEM_INFO,
20995c51f124SMoriah Waterland 						    SUNW_R_PKEY_READ_ERR);
21005c51f124SMoriah Waterland 					}
21015c51f124SMoriah Waterland 					retval = -1;
21025c51f124SMoriah Waterland 					break;
21035c51f124SMoriah Waterland 				}
21045c51f124SMoriah Waterland 				if (x->x_pkey->dec_pkey->type == EVP_PKEY_RSA) {
21055c51f124SMoriah Waterland 					RSA **pp;
21065c51f124SMoriah Waterland 
21075c51f124SMoriah Waterland 					pp = &(x->x_pkey->dec_pkey->pkey.rsa);
21085c51f124SMoriah Waterland 					p = (uchar_t *)x->enc_data;
21095c51f124SMoriah Waterland 					if (d2i_RSAPrivateKey(pp, &p,
21105c51f124SMoriah Waterland 					    x->enc_len) == NULL) {
21115c51f124SMoriah Waterland 						SUNWerr(SUNW_F_PEM_INFO,
21125c51f124SMoriah Waterland 						    SUNW_R_PKEY_READ_ERR);
21135c51f124SMoriah Waterland 						retval = -1;
21145c51f124SMoriah Waterland 						break;
21155c51f124SMoriah Waterland 					}
21165c51f124SMoriah Waterland 				} else {
21175c51f124SMoriah Waterland 					DSA **pp;
21185c51f124SMoriah Waterland 
21195c51f124SMoriah Waterland 					pp = &(x->x_pkey->dec_pkey->pkey.dsa);
21205c51f124SMoriah Waterland 					p = (uchar_t *)x->enc_data;
21215c51f124SMoriah Waterland 					if (d2i_DSAPrivateKey(pp, &p,
21225c51f124SMoriah Waterland 					    x->enc_len) == NULL) {
21235c51f124SMoriah Waterland 						SUNWerr(SUNW_F_PEM_INFO,
21245c51f124SMoriah Waterland 						    SUNW_R_PKEY_READ_ERR);
21255c51f124SMoriah Waterland 						retval = -1;
21265c51f124SMoriah Waterland 						break;
21275c51f124SMoriah Waterland 					}
21285c51f124SMoriah Waterland 				}
21295c51f124SMoriah Waterland 			}
21305c51f124SMoriah Waterland 
21315c51f124SMoriah Waterland 			/* Save the key. */
21325c51f124SMoriah Waterland 			retval = sk_EVP_PKEY_push(work_kl, x->x_pkey->dec_pkey);
21335c51f124SMoriah Waterland 			if (retval == 0) {
21345c51f124SMoriah Waterland 				retval = -1;
21355c51f124SMoriah Waterland 				break;
21365c51f124SMoriah Waterland 			}
21375c51f124SMoriah Waterland 			x->x_pkey->dec_pkey = NULL;
21385c51f124SMoriah Waterland 		} else if (x->x_pkey != NULL) {
21395c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PEM_INFO, SUNW_R_BAD_PKEYTYPE);
21405c51f124SMoriah Waterland 			retval = -1;
21415c51f124SMoriah Waterland 			break;
21425c51f124SMoriah Waterland 		}
21435c51f124SMoriah Waterland 	}
21445c51f124SMoriah Waterland 	if (retval == -1)
21455c51f124SMoriah Waterland 		goto cleanup;
21465c51f124SMoriah Waterland 
21475c51f124SMoriah Waterland 	/* If error occurs, then error already on stack */
21485c51f124SMoriah Waterland 	retval = set_results(pkeys, &work_kl, certs, &work_cl, NULL, NULL,
21495c51f124SMoriah Waterland 	    NULL, NULL);
21505c51f124SMoriah Waterland 
21515c51f124SMoriah Waterland cleanup:
21525c51f124SMoriah Waterland 	if (work_kl != NULL) {
21535c51f124SMoriah Waterland 		sk_EVP_PKEY_pop_free(work_kl, sunw_evp_pkey_free);
21545c51f124SMoriah Waterland 	}
21555c51f124SMoriah Waterland 	if (work_cl != NULL)
21565c51f124SMoriah Waterland 		sk_X509_pop_free(work_cl, X509_free);
21575c51f124SMoriah Waterland 
21585c51f124SMoriah Waterland 	sk_X509_INFO_pop_free(info, X509_INFO_free);
21595c51f124SMoriah Waterland 
21605c51f124SMoriah Waterland 	return (retval);
21615c51f124SMoriah Waterland }
21625c51f124SMoriah Waterland 
21635c51f124SMoriah Waterland /*
21645c51f124SMoriah Waterland  * sunw_append_keys - Given two stacks of private keys, remove the keys from
21655c51f124SMoriah Waterland  *      the second stack and append them to the first.  Both stacks must exist
21665c51f124SMoriah Waterland  *      at time of call.
21675c51f124SMoriah Waterland  *
21685c51f124SMoriah Waterland  * Arguments:
21695c51f124SMoriah Waterland  *   dst 	- the stack to receive the keys from 'src'
21705c51f124SMoriah Waterland  *   src	- the stack whose keys are to be moved.
21715c51f124SMoriah Waterland  *
21725c51f124SMoriah Waterland  * Returns:
21735c51f124SMoriah Waterland  *   -1  	- An error occurred.  The error status is set.
21745c51f124SMoriah Waterland  *   >= 0       - The number of keys that were copied.
21755c51f124SMoriah Waterland  */
21765c51f124SMoriah Waterland static int
21775c51f124SMoriah Waterland sunw_append_keys(STACK_OF(EVP_PKEY) *dst, STACK_OF(EVP_PKEY) *src)
21785c51f124SMoriah Waterland {
21795c51f124SMoriah Waterland 	EVP_PKEY *tmpk;
21805c51f124SMoriah Waterland 	int count = 0;
21815c51f124SMoriah Waterland 
21825c51f124SMoriah Waterland 	while (sk_EVP_PKEY_num(src) > 0) {
21835c51f124SMoriah Waterland 		tmpk = sk_EVP_PKEY_delete(src, 0);
21845c51f124SMoriah Waterland 		if (sk_EVP_PKEY_push(dst, tmpk) == 0) {
21855c51f124SMoriah Waterland 			sunw_evp_pkey_free(tmpk);
21865c51f124SMoriah Waterland 			SUNWerr(SUNW_F_APPEND_KEYS, SUNW_R_MEMORY_FAILURE);
21875c51f124SMoriah Waterland 			return (-1);
21885c51f124SMoriah Waterland 		}
21895c51f124SMoriah Waterland 		count ++;
21905c51f124SMoriah Waterland 	}
21915c51f124SMoriah Waterland 
21925c51f124SMoriah Waterland 	return (count);
21935c51f124SMoriah Waterland }
21945c51f124SMoriah Waterland 
21955c51f124SMoriah Waterland /*
21965c51f124SMoriah Waterland  * move_certs - Given two stacks of certs, remove the certs from
21975c51f124SMoriah Waterland  *      the second stack and append them to the first.
21985c51f124SMoriah Waterland  *
21995c51f124SMoriah Waterland  * Arguments:
22005c51f124SMoriah Waterland  *   dst 	- the stack to receive the certs from 'src'
22015c51f124SMoriah Waterland  *   src	- the stack whose certs are to be moved.
22025c51f124SMoriah Waterland  *
22035c51f124SMoriah Waterland  * Returns:
22045c51f124SMoriah Waterland  *   -1  	- An error occurred.  The error status is set.
22055c51f124SMoriah Waterland  *   >= 0       - The number of certs that were copied.
22065c51f124SMoriah Waterland  */
22075c51f124SMoriah Waterland static int
22085c51f124SMoriah Waterland move_certs(STACK_OF(X509) *dst, STACK_OF(X509) *src)
22095c51f124SMoriah Waterland {
22105c51f124SMoriah Waterland 	X509 *tmpc;
22115c51f124SMoriah Waterland 	int count = 0;
22125c51f124SMoriah Waterland 
22135c51f124SMoriah Waterland 	while (sk_X509_num(src) > 0) {
22145c51f124SMoriah Waterland 		tmpc = sk_X509_delete(src, 0);
22155c51f124SMoriah Waterland 		if (sk_X509_push(dst, tmpc) == 0) {
22165c51f124SMoriah Waterland 			X509_free(tmpc);
22175c51f124SMoriah Waterland 			SUNWerr(SUNW_F_MOVE_CERTS, SUNW_R_MEMORY_FAILURE);
22185c51f124SMoriah Waterland 			return (-1);
22195c51f124SMoriah Waterland 		}
22205c51f124SMoriah Waterland 		count++;
22215c51f124SMoriah Waterland 	}
22225c51f124SMoriah Waterland 
22235c51f124SMoriah Waterland 	return (count);
22245c51f124SMoriah Waterland }
22255c51f124SMoriah Waterland 
22265c51f124SMoriah Waterland /*
22275c51f124SMoriah Waterland  * get_key_cert - Get a cert and its matching key from the stacks of certs
22285c51f124SMoriah Waterland  *      and keys.  They are removed from the stacks.
22295c51f124SMoriah Waterland  *
22305c51f124SMoriah Waterland  * Arguments:
22315c51f124SMoriah Waterland  *   n        - Offset of the entries to return.
22325c51f124SMoriah Waterland  *   kl       - Points to a stack of private keys that matches the list of
22335c51f124SMoriah Waterland  *              certs below.
22345c51f124SMoriah Waterland  *   pkey     - Points at location where the address of the matching private
22355c51f124SMoriah Waterland  *              key will be stored.
22365c51f124SMoriah Waterland  *   cl       - Points to a stack of client certs with matching private keys.
22375c51f124SMoriah Waterland  *   cert     - Points to locaiton where the address of the matching client cert
22385c51f124SMoriah Waterland  *              will be returned
22395c51f124SMoriah Waterland  *
22405c51f124SMoriah Waterland  * The assumption is that the stacks of keys and certs contain key/cert pairs,
22415c51f124SMoriah Waterland  * with entries in the same order and hence at the same offset.  Provided
22425c51f124SMoriah Waterland  * the key and cert selected match, each will be removed from its stack and
22435c51f124SMoriah Waterland  * returned.
22445c51f124SMoriah Waterland  *
22455c51f124SMoriah Waterland  * A stack of certs can be passed in without a stack of private keys, and vise
22465c51f124SMoriah Waterland  * versa.  In that case, the indicated key/cert will be returned.
22475c51f124SMoriah Waterland  *
22485c51f124SMoriah Waterland  * Returns:
22495c51f124SMoriah Waterland  *     0 - No matches were found.
22505c51f124SMoriah Waterland  *   > 0 - Bits set based on FOUND_* definitions, indicating what is returned.
22515c51f124SMoriah Waterland  *         This can be FOUND_PKEY, FOUND_CERT or (FOUND_PKEY | FOUND_CERT).
22525c51f124SMoriah Waterland  */
22535c51f124SMoriah Waterland static int
22545c51f124SMoriah Waterland get_key_cert(int n, STACK_OF(EVP_PKEY) *kl, EVP_PKEY **pkey, STACK_OF(X509) *cl,
22555c51f124SMoriah Waterland     X509 **cert)
22565c51f124SMoriah Waterland {
22575c51f124SMoriah Waterland 	int retval = 0;
22585c51f124SMoriah Waterland 	int nk;
22595c51f124SMoriah Waterland 	int nc;
22605c51f124SMoriah Waterland 
22615c51f124SMoriah Waterland 	nk = (kl != NULL) ? sk_EVP_PKEY_num(kl) : 0;
22625c51f124SMoriah Waterland 	nc = (cl != NULL) ? sk_X509_num(cl) : 0;
22635c51f124SMoriah Waterland 
22645c51f124SMoriah Waterland 	if (pkey != NULL && *pkey == NULL) {
22655c51f124SMoriah Waterland 		if (nk > 0 && n >= 0 || n < nk) {
22665c51f124SMoriah Waterland 			*pkey = sk_EVP_PKEY_delete(kl, n);
22675c51f124SMoriah Waterland 			if (*pkey != NULL)
22685c51f124SMoriah Waterland 				retval |= FOUND_PKEY;
22695c51f124SMoriah Waterland 		}
22705c51f124SMoriah Waterland 	}
22715c51f124SMoriah Waterland 
22725c51f124SMoriah Waterland 	if (cert != NULL && *cert == NULL) {
22735c51f124SMoriah Waterland 		if (nc > 0 && n >= 0 && n < nc) {
22745c51f124SMoriah Waterland 			*cert = sk_X509_delete(cl, n);
22755c51f124SMoriah Waterland 			if (*cert != NULL)
22765c51f124SMoriah Waterland 				retval |= FOUND_CERT;
22775c51f124SMoriah Waterland 		}
22785c51f124SMoriah Waterland 	}
22795c51f124SMoriah Waterland 
22805c51f124SMoriah Waterland 	return (retval);
22815c51f124SMoriah Waterland }
22825c51f124SMoriah Waterland 
22835c51f124SMoriah Waterland 
22845c51f124SMoriah Waterland /*
22855c51f124SMoriah Waterland  * asc2bmpstring - Convert a regular C ASCII string to an ASn1_STRING in
22865c51f124SMoriah Waterland  *         ASN1_BMPSTRING format.
22875c51f124SMoriah Waterland  *
22885c51f124SMoriah Waterland  * Arguments:
22895c51f124SMoriah Waterland  *   str      - String to be convered.
22905c51f124SMoriah Waterland  *   len      - Length of the string.
22915c51f124SMoriah Waterland  *
22925c51f124SMoriah Waterland  * Returns:
22935c51f124SMoriah Waterland  *   == NULL  - An error occurred.  Error information (accessible by
22945c51f124SMoriah Waterland  *              ERR_get_error()) is set.
22955c51f124SMoriah Waterland  *   != NULL  - Points to an ASN1_BMPSTRING structure with the converted
22965c51f124SMoriah Waterland  *              string as a value.
22975c51f124SMoriah Waterland  */
22985c51f124SMoriah Waterland static ASN1_BMPSTRING *
22995c51f124SMoriah Waterland asc2bmpstring(const char *str, int len)
23005c51f124SMoriah Waterland {
23015c51f124SMoriah Waterland 	ASN1_BMPSTRING *bmp = NULL;
23025c51f124SMoriah Waterland 	uchar_t *uni = NULL;
23035c51f124SMoriah Waterland 	int unilen;
23045c51f124SMoriah Waterland 
23055c51f124SMoriah Waterland 	/* Convert the character to the bmp format. */
2306*70f9559bSTheo Schlossnagle #if OPENSSL_VERSION_NUMBER < 0x10000000L
23075c51f124SMoriah Waterland 	if (asc2uni(str, len, &uni, &unilen) == 0) {
2308*70f9559bSTheo Schlossnagle #else
2309*70f9559bSTheo Schlossnagle 	if (OPENSSL_asc2uni(str, len, &uni, &unilen) == 0) {
2310*70f9559bSTheo Schlossnagle #endif
23115c51f124SMoriah Waterland 		SUNWerr(SUNW_F_ASC2BMPSTRING, SUNW_R_MEMORY_FAILURE);
23125c51f124SMoriah Waterland 		return (NULL);
23135c51f124SMoriah Waterland 	}
23145c51f124SMoriah Waterland 
23155c51f124SMoriah Waterland 	/*
23165c51f124SMoriah Waterland 	 * Adjust for possible pair of NULL bytes at the end because
23175c51f124SMoriah Waterland 	 * asc2uni() returns a doubly null terminated string.
23185c51f124SMoriah Waterland 	 */
23195c51f124SMoriah Waterland 	if (uni[unilen - 1] == '\0' && uni[unilen - 2] == '\0')
23205c51f124SMoriah Waterland 		unilen -= 2;
23215c51f124SMoriah Waterland 
23225c51f124SMoriah Waterland 	/* Construct comparison string with correct format */
23235c51f124SMoriah Waterland 	bmp = M_ASN1_BMPSTRING_new();
23245c51f124SMoriah Waterland 	if (bmp == NULL) {
23255c51f124SMoriah Waterland 		SUNWerr(SUNW_F_ASC2BMPSTRING, SUNW_R_MEMORY_FAILURE);
23265c51f124SMoriah Waterland 		OPENSSL_free(uni);
23275c51f124SMoriah Waterland 		return (NULL);
23285c51f124SMoriah Waterland 	}
23295c51f124SMoriah Waterland 
23305c51f124SMoriah Waterland 	bmp->data = uni;
23315c51f124SMoriah Waterland 	bmp->length = unilen;
23325c51f124SMoriah Waterland 
23335c51f124SMoriah Waterland 	return (bmp);
23345c51f124SMoriah Waterland }
23355c51f124SMoriah Waterland 
23365c51f124SMoriah Waterland /*
23375c51f124SMoriah Waterland  * utf82ascstr - Convert a UTF8STRING string to a regular C ASCII string.
23385c51f124SMoriah Waterland  *         This goes through an intermediate step with a ASN1_STRING type of
23395c51f124SMoriah Waterland  *         IA5STRING (International Alphabet 5, which is the same as ASCII).
23405c51f124SMoriah Waterland  *
23415c51f124SMoriah Waterland  * Arguments:
23425c51f124SMoriah Waterland  *   str      - UTF8STRING to be converted.
23435c51f124SMoriah Waterland  *
23445c51f124SMoriah Waterland  * Returns:
23455c51f124SMoriah Waterland  *   == NULL  - An error occurred.  Error information (accessible by
23465c51f124SMoriah Waterland  *              ERR_get_error()) is set.
23475c51f124SMoriah Waterland  *   != NULL  - Points to a NULL-termianted ASCII string.  The caller must
23485c51f124SMoriah Waterland  *              free it.
23495c51f124SMoriah Waterland  */
23505c51f124SMoriah Waterland static uchar_t *
23515c51f124SMoriah Waterland utf82ascstr(ASN1_UTF8STRING *ustr)
23525c51f124SMoriah Waterland {
23535c51f124SMoriah Waterland 	ASN1_STRING tmpstr;
23545c51f124SMoriah Waterland 	ASN1_STRING *astr = &tmpstr;
23555c51f124SMoriah Waterland 	uchar_t *retstr = NULL;
23565c51f124SMoriah Waterland 	int mbflag;
23575c51f124SMoriah Waterland 	int ret;
23585c51f124SMoriah Waterland 
23595c51f124SMoriah Waterland 	if (ustr == NULL || ustr->type != V_ASN1_UTF8STRING) {
23605c51f124SMoriah Waterland 		SUNWerr(SUNW_F_UTF82ASCSTR, SUNW_R_INVALID_ARG);
23615c51f124SMoriah Waterland 		return (NULL);
23625c51f124SMoriah Waterland 	}
23635c51f124SMoriah Waterland 
23645c51f124SMoriah Waterland 	mbflag = MBSTRING_ASC;
23655c51f124SMoriah Waterland 	tmpstr.data = NULL;
23665c51f124SMoriah Waterland 	tmpstr.length = 0;
23675c51f124SMoriah Waterland 
23685c51f124SMoriah Waterland 	ret = ASN1_mbstring_copy(&astr, ustr->data, ustr->length, mbflag,
23695c51f124SMoriah Waterland 	    B_ASN1_IA5STRING);
23705c51f124SMoriah Waterland 	if (ret < 0) {
23715c51f124SMoriah Waterland 		SUNWerr(SUNW_F_UTF82ASCSTR, SUNW_R_STR_CONVERT_ERR);
23725c51f124SMoriah Waterland 		return (NULL);
23735c51f124SMoriah Waterland 	}
23745c51f124SMoriah Waterland 
23755c51f124SMoriah Waterland 	retstr = OPENSSL_malloc(astr->length + 1);
23765c51f124SMoriah Waterland 	if (retstr == NULL) {
23775c51f124SMoriah Waterland 		SUNWerr(SUNW_F_UTF82ASCSTR, SUNW_R_MEMORY_FAILURE);
23785c51f124SMoriah Waterland 		return (NULL);
23795c51f124SMoriah Waterland 	}
23805c51f124SMoriah Waterland 
23815c51f124SMoriah Waterland 	(void) memcpy(retstr, astr->data, astr->length);
23825c51f124SMoriah Waterland 	retstr[astr->length] = '\0';
23835c51f124SMoriah Waterland 	OPENSSL_free(astr->data);
23845c51f124SMoriah Waterland 
23855c51f124SMoriah Waterland 	return (retstr);
23865c51f124SMoriah Waterland }
23875c51f124SMoriah Waterland 
23885c51f124SMoriah Waterland 
23895c51f124SMoriah Waterland /*
23905c51f124SMoriah Waterland  * type2attrib - Given a ASN1_TYPE, return a X509_ATTRIBUTE of the type
23915c51f124SMoriah Waterland  *     specified by the given NID.
23925c51f124SMoriah Waterland  *
23935c51f124SMoriah Waterland  * Arguments:
23945c51f124SMoriah Waterland  *   ty       - Type structure to be made into an attribute
23955c51f124SMoriah Waterland  *   nid      - NID of the attribute
23965c51f124SMoriah Waterland  *
23975c51f124SMoriah Waterland  * Returns:
23985c51f124SMoriah Waterland  *   NULL	An error occurred.
23995c51f124SMoriah Waterland  *   != NULL	An X509_ATTRIBUTE structure.
24005c51f124SMoriah Waterland  */
24015c51f124SMoriah Waterland X509_ATTRIBUTE *
24025c51f124SMoriah Waterland type2attrib(ASN1_TYPE *ty, int nid)
24035c51f124SMoriah Waterland {
24045c51f124SMoriah Waterland 	X509_ATTRIBUTE *a;
24055c51f124SMoriah Waterland 
24065c51f124SMoriah Waterland 	if ((a = X509_ATTRIBUTE_new()) == NULL ||
24075c51f124SMoriah Waterland 	    (a->value.set = sk_ASN1_TYPE_new_null()) == NULL ||
24085c51f124SMoriah Waterland 	    sk_ASN1_TYPE_push(a->value.set, ty) == 0) {
24095c51f124SMoriah Waterland 		if (a != NULL)
24105c51f124SMoriah Waterland 			X509_ATTRIBUTE_free(a);
24115c51f124SMoriah Waterland 			SUNWerr(SUNW_F_TYPE2ATTRIB, SUNW_R_MEMORY_FAILURE);
24125c51f124SMoriah Waterland 		return (NULL);
24135c51f124SMoriah Waterland 	}
24145c51f124SMoriah Waterland 	a->single = 0;
24155c51f124SMoriah Waterland 	a->object = OBJ_nid2obj(nid);
24165c51f124SMoriah Waterland 
24175c51f124SMoriah Waterland 	return (a);
24185c51f124SMoriah Waterland }
24195c51f124SMoriah Waterland 
24205c51f124SMoriah Waterland /*
24215c51f124SMoriah Waterland  * attrib2type - Given a X509_ATTRIBUTE, return pointer to the ASN1_TYPE
24225c51f124SMoriah Waterland  *     component
24235c51f124SMoriah Waterland  *
24245c51f124SMoriah Waterland  * Arguments:
24255c51f124SMoriah Waterland  *   attr     - Attribute structure containing a type.
24265c51f124SMoriah Waterland  *
24275c51f124SMoriah Waterland  * Returns:
24285c51f124SMoriah Waterland  *   NULL	An error occurred.
24295c51f124SMoriah Waterland  *   != NULL	An ASN1_TYPE structure.
24305c51f124SMoriah Waterland  */
24315c51f124SMoriah Waterland static ASN1_TYPE *
24325c51f124SMoriah Waterland attrib2type(X509_ATTRIBUTE *attr)
24335c51f124SMoriah Waterland {
24345c51f124SMoriah Waterland 	ASN1_TYPE *ty = NULL;
24355c51f124SMoriah Waterland 
24365c51f124SMoriah Waterland 	if (attr == NULL || attr->single == 1)
24375c51f124SMoriah Waterland 		return (NULL);
24385c51f124SMoriah Waterland 
24395c51f124SMoriah Waterland 	if (sk_ASN1_TYPE_num(attr->value.set) > 0)
24405c51f124SMoriah Waterland 		ty = sk_ASN1_TYPE_value(attr->value.set, 0);
24415c51f124SMoriah Waterland 
24425c51f124SMoriah Waterland 	return (ty);
24435c51f124SMoriah Waterland }
24445c51f124SMoriah Waterland 
24455c51f124SMoriah Waterland /*
24465c51f124SMoriah Waterland  * find_attr_by_nid - Given a ASN1_TYPE, return the offset of a X509_ATTRIBUTE
24475c51f124SMoriah Waterland  *     of the type specified by the given NID.
24485c51f124SMoriah Waterland  *
24495c51f124SMoriah Waterland  * Arguments:
24505c51f124SMoriah Waterland  *   attrs    - Stack of attributes to search
24515c51f124SMoriah Waterland  *   nid      - NID of the attribute being searched for
24525c51f124SMoriah Waterland  *
24535c51f124SMoriah Waterland  * Returns:
24545c51f124SMoriah Waterland  *   -1 	None found
24555c51f124SMoriah Waterland  *   != -1	Offset of the matching attribute.
24565c51f124SMoriah Waterland  */
24575c51f124SMoriah Waterland static int
24585c51f124SMoriah Waterland find_attr_by_nid(STACK_OF(X509_ATTRIBUTE) *attrs, int nid)
24595c51f124SMoriah Waterland {
24605c51f124SMoriah Waterland 	X509_ATTRIBUTE *a;
24615c51f124SMoriah Waterland 	int i;
24625c51f124SMoriah Waterland 
24635c51f124SMoriah Waterland 	if (attrs == NULL)
24645c51f124SMoriah Waterland 		return (-1);
24655c51f124SMoriah Waterland 
24665c51f124SMoriah Waterland 	for (i = 0; i < sk_X509_ATTRIBUTE_num(attrs); i++) {
24675c51f124SMoriah Waterland 		a = sk_X509_ATTRIBUTE_value(attrs, i);
24685c51f124SMoriah Waterland 		if (OBJ_obj2nid(a->object) == nid)
24695c51f124SMoriah Waterland 			return (i);
24705c51f124SMoriah Waterland 	}
24715c51f124SMoriah Waterland 	return (-1);
24725c51f124SMoriah Waterland }
24735c51f124SMoriah Waterland 
24745c51f124SMoriah Waterland /*
24755c51f124SMoriah Waterland  * Called by our PKCS12 code to read our function and error codes
24765c51f124SMoriah Waterland  * into memory so that the OpenSSL framework can retrieve them.
24775c51f124SMoriah Waterland  */
24785c51f124SMoriah Waterland void
24795c51f124SMoriah Waterland ERR_load_SUNW_strings(void)
24805c51f124SMoriah Waterland {
24815c51f124SMoriah Waterland 	assert(SUNW_lib_error_code == 0);
24825c51f124SMoriah Waterland #ifndef OPENSSL_NO_ERR
24835c51f124SMoriah Waterland 	/*
24845c51f124SMoriah Waterland 	 * Have OpenSSL provide us with a unique ID.
24855c51f124SMoriah Waterland 	 */
24865c51f124SMoriah Waterland 	SUNW_lib_error_code = ERR_get_next_error_library();
24875c51f124SMoriah Waterland 
24885c51f124SMoriah Waterland 	ERR_load_strings(SUNW_lib_error_code, SUNW_str_functs);
24895c51f124SMoriah Waterland 	ERR_load_strings(SUNW_lib_error_code, SUNW_str_reasons);
24905c51f124SMoriah Waterland 
24915c51f124SMoriah Waterland 	SUNW_lib_name->error = ERR_PACK(SUNW_lib_error_code, 0, 0);
24925c51f124SMoriah Waterland 	ERR_load_strings(0, SUNW_lib_name);
24935c51f124SMoriah Waterland #endif
24945c51f124SMoriah Waterland }
24955c51f124SMoriah Waterland 
24965c51f124SMoriah Waterland /*
24975c51f124SMoriah Waterland  * The SUNWerr macro resolves to this routine. So when we need
24985c51f124SMoriah Waterland  * to push an error, this routine does it for us. Notice that
24995c51f124SMoriah Waterland  * the SUNWerr macro provides a filename and line #.
25005c51f124SMoriah Waterland  */
25015c51f124SMoriah Waterland void
25025c51f124SMoriah Waterland ERR_SUNW_error(int function, int reason, char *file, int line)
25035c51f124SMoriah Waterland {
25045c51f124SMoriah Waterland 	assert(SUNW_lib_error_code != 0);
25055c51f124SMoriah Waterland #ifndef OPENSSL_NO_ERR
25065c51f124SMoriah Waterland 	ERR_PUT_error(SUNW_lib_error_code, function, reason, file, line);
25075c51f124SMoriah Waterland #endif
25085c51f124SMoriah Waterland }
25095c51f124SMoriah Waterland 
25105c51f124SMoriah Waterland /*
25115c51f124SMoriah Waterland  * check_time - Given an indication of the which time(s) to check, check
25125c51f124SMoriah Waterland  *      that time or those times against the current time and return the
25135c51f124SMoriah Waterland  *      relationship.
25145c51f124SMoriah Waterland  *
25155c51f124SMoriah Waterland  * Arguments:
25165c51f124SMoriah Waterland  *   chkwhat    - What kind of check to do.
25175c51f124SMoriah Waterland  *   cert	- The cert to check.
25185c51f124SMoriah Waterland  *
25195c51f124SMoriah Waterland  * Returns:
25205c51f124SMoriah Waterland  *   CHKERR_* values.
25215c51f124SMoriah Waterland  */
25225c51f124SMoriah Waterland static chk_errs_t
25235c51f124SMoriah Waterland check_time(chk_actions_t chkwhat, X509 *cert)
25245c51f124SMoriah Waterland {
25255c51f124SMoriah Waterland 	int i;
25265c51f124SMoriah Waterland 
25275c51f124SMoriah Waterland 	if (chkwhat == CHK_NOT_BEFORE || chkwhat == CHK_BOTH) {
25285c51f124SMoriah Waterland 		i = X509_cmp_time(X509_get_notBefore(cert), NULL);
25295c51f124SMoriah Waterland 		if (i == 0)
25305c51f124SMoriah Waterland 			return (CHKERR_TIME_BEFORE_BAD);
25315c51f124SMoriah Waterland 		if (i > 0)
25325c51f124SMoriah Waterland 			return (CHKERR_TIME_IS_BEFORE);
25335c51f124SMoriah Waterland 
25345c51f124SMoriah Waterland 		/* The current time is after the 'not before' time */
25355c51f124SMoriah Waterland 	}
25365c51f124SMoriah Waterland 
25375c51f124SMoriah Waterland 	if (chkwhat == CHK_NOT_AFTER || chkwhat == CHK_BOTH) {
25385c51f124SMoriah Waterland 		i = X509_cmp_time(X509_get_notAfter(cert), NULL);
25395c51f124SMoriah Waterland 		if (i == 0)
25405c51f124SMoriah Waterland 			return (CHKERR_TIME_AFTER_BAD);
25415c51f124SMoriah Waterland 		if (i < 0)
25425c51f124SMoriah Waterland 			return (CHKERR_TIME_HAS_EXPIRED);
25435c51f124SMoriah Waterland 	}
25445c51f124SMoriah Waterland 
25455c51f124SMoriah Waterland 	return (CHKERR_TIME_OK);
25465c51f124SMoriah Waterland }
25475c51f124SMoriah Waterland 
25485c51f124SMoriah Waterland /*
25495c51f124SMoriah Waterland  * find_attr - Look for a given attribute of the type associated with the NID.
25505c51f124SMoriah Waterland  *
25515c51f124SMoriah Waterland  * Arguments:
25525c51f124SMoriah Waterland  *   nid      - NID for the attribute to be found (either NID_friendlyName or
25535c51f124SMoriah Waterland  *              NID_locakKeyId)
25545c51f124SMoriah Waterland  *   str      - ASN1_STRING-type structure containing the value to be found,
25555c51f124SMoriah Waterland  *              FriendlyName expects a ASN1_BMPSTRING and localKeyID uses a
25565c51f124SMoriah Waterland  *              ASN1_STRING.
25575c51f124SMoriah Waterland  *   kl       - Points to a stack of private keys.
25585c51f124SMoriah Waterland  *   pkey     - Points at a location where the address of the matching private
25595c51f124SMoriah Waterland  *              key will be stored.
25605c51f124SMoriah Waterland  *   cl       - Points to a stack of client certs with matching private keys.
25615c51f124SMoriah Waterland  *   cert     - Points to locaiton where the address of the matching client cert
25625c51f124SMoriah Waterland  *              will be returned
25635c51f124SMoriah Waterland  *
25645c51f124SMoriah Waterland  * This function is designed to process lists of certs and private keys.
25655c51f124SMoriah Waterland  * This is made complex because these the attributes are stored differently
25665c51f124SMoriah Waterland  * for certs and for keys.  For certs, only a few attributes are retained.
25675c51f124SMoriah Waterland  * FriendlyName is stored in the aux structure, under the name 'alias'.
25685c51f124SMoriah Waterland  * LocalKeyId is also stored in the aux structure, under the name 'keyid'.
25695c51f124SMoriah Waterland  * A pkey structure has a stack of attributes.
25705c51f124SMoriah Waterland  *
25715c51f124SMoriah Waterland  * The basic approach is:
25725c51f124SMoriah Waterland  *   - If there there is no stack of certs but a stack of private keys exists,
25735c51f124SMoriah Waterland  *     search the stack of keys for a match. Alternately, if there is a stack
25745c51f124SMoriah Waterland  *     of certs and no private keys, search the certs.
25755c51f124SMoriah Waterland  *
25765c51f124SMoriah Waterland  *   - If there are both certs and keys, assume that the matching certs and
25775c51f124SMoriah Waterland  *     keys are in their respective stacks, with matching entries in the same
25785c51f124SMoriah Waterland  *     order.  Search for the name or keyid in the stack of certs.  If it is
25795c51f124SMoriah Waterland  *     not found, then this function returns 0 (nothing found).
25805c51f124SMoriah Waterland  *
25815c51f124SMoriah Waterland  *   - Once a cert is found, verify that the key actually matches by
25825c51f124SMoriah Waterland  *     comparing the private key with the public key (in the cert).
25835c51f124SMoriah Waterland  *     If they don't match, return an error.
25845c51f124SMoriah Waterland  *
25855c51f124SMoriah Waterland  *   A pointer to cert and/or pkey which matches the name or keyid is stored
25865c51f124SMoriah Waterland  *   in the return arguments.
25875c51f124SMoriah Waterland  *
25885c51f124SMoriah Waterland  * Returns:
25895c51f124SMoriah Waterland  *     0 - No matches were found.
25905c51f124SMoriah Waterland  *   > 0 - Bits set based on FOUND_* definitions, indicating what was found.
25915c51f124SMoriah Waterland  *         This can be FOUND_PKEY, FOUND_CERT or (FOUND_PKEY | FOUND_CERT).
25925c51f124SMoriah Waterland  */
25935c51f124SMoriah Waterland static int
25945c51f124SMoriah Waterland find_attr(int nid, ASN1_STRING *str, STACK_OF(EVP_PKEY) *kl, EVP_PKEY **pkey,
25955c51f124SMoriah Waterland     STACK_OF(X509) *cl, X509 **cert)
25965c51f124SMoriah Waterland {
25975c51f124SMoriah Waterland 	ASN1_UTF8STRING *ustr = NULL;
25985c51f124SMoriah Waterland 	ASN1_STRING *s;
25995c51f124SMoriah Waterland 	ASN1_TYPE *t;
26005c51f124SMoriah Waterland 	EVP_PKEY *p;
26015c51f124SMoriah Waterland 	uchar_t *fname = NULL;
26025c51f124SMoriah Waterland 	X509 *x;
26035c51f124SMoriah Waterland 	int found = 0;
26045c51f124SMoriah Waterland 	int chkcerts;
26055c51f124SMoriah Waterland 	int len;
26065c51f124SMoriah Waterland 	int res;
26075c51f124SMoriah Waterland 	int c = -1;
26085c51f124SMoriah Waterland 	int k = -1;
26095c51f124SMoriah Waterland 
26105c51f124SMoriah Waterland 	chkcerts = (cert != NULL || pkey != NULL) && cl != NULL;
26115c51f124SMoriah Waterland 	if (chkcerts && nid == NID_friendlyName &&
26125c51f124SMoriah Waterland 	    str->type == V_ASN1_BMPSTRING) {
26135c51f124SMoriah Waterland 		ustr = ASN1_UTF8STRING_new();
26145c51f124SMoriah Waterland 		if (ustr == NULL) {
26155c51f124SMoriah Waterland 			SUNWerr(SUNW_F_FINDATTR, SUNW_R_MEMORY_FAILURE);
26165c51f124SMoriah Waterland 			return (0);
26175c51f124SMoriah Waterland 		}
26185c51f124SMoriah Waterland 		len = ASN1_STRING_to_UTF8(&fname, str);
26195c51f124SMoriah Waterland 		if (fname == NULL) {
26205c51f124SMoriah Waterland 			ASN1_UTF8STRING_free(ustr);
26215c51f124SMoriah Waterland 			SUNWerr(SUNW_F_FINDATTR, SUNW_R_STR_CONVERT_ERR);
26225c51f124SMoriah Waterland 			return (0);
26235c51f124SMoriah Waterland 		}
26245c51f124SMoriah Waterland 
26255c51f124SMoriah Waterland 		if (ASN1_STRING_set(ustr, fname, len) == 0) {
26265c51f124SMoriah Waterland 			ASN1_UTF8STRING_free(ustr);
26275c51f124SMoriah Waterland 			OPENSSL_free(fname);
26285c51f124SMoriah Waterland 			SUNWerr(SUNW_F_FINDATTR, SUNW_R_MEMORY_FAILURE);
26295c51f124SMoriah Waterland 			return (0);
26305c51f124SMoriah Waterland 		}
26315c51f124SMoriah Waterland 	}
26325c51f124SMoriah Waterland 
26335c51f124SMoriah Waterland 	if (chkcerts) {
26345c51f124SMoriah Waterland 		for (c = 0; c < sk_X509_num(cl); c++) {
26355c51f124SMoriah Waterland 			res = -1;
26365c51f124SMoriah Waterland 			x = sk_X509_value(cl, c);
26375c51f124SMoriah Waterland 			if (nid == NID_friendlyName && ustr != NULL) {
26385c51f124SMoriah Waterland 				if (x->aux == NULL || x->aux->alias == NULL)
26395c51f124SMoriah Waterland 					continue;
26405c51f124SMoriah Waterland 				s = x->aux->alias;
26415c51f124SMoriah Waterland 				if (s != NULL && s->type == ustr->type &&
26425c51f124SMoriah Waterland 				    s->data != NULL) {
26435c51f124SMoriah Waterland 					res = ASN1_STRING_cmp(s, ustr);
26445c51f124SMoriah Waterland 				}
26455c51f124SMoriah Waterland 			} else {
26465c51f124SMoriah Waterland 				if (x->aux == NULL || x->aux->keyid == NULL)
26475c51f124SMoriah Waterland 					continue;
26485c51f124SMoriah Waterland 				s = x->aux->keyid;
26495c51f124SMoriah Waterland 				if (s != NULL && s->type == str->type &&
26505c51f124SMoriah Waterland 				    s->data != NULL) {
26515c51f124SMoriah Waterland 					res = ASN1_STRING_cmp(s, str);
26525c51f124SMoriah Waterland 				}
26535c51f124SMoriah Waterland 			}
26545c51f124SMoriah Waterland 			if (res == 0) {
26555c51f124SMoriah Waterland 				if (cert != NULL)
26565c51f124SMoriah Waterland 					*cert = sk_X509_delete(cl, c);
26575c51f124SMoriah Waterland 				found = FOUND_CERT;
26585c51f124SMoriah Waterland 				break;
26595c51f124SMoriah Waterland 			}
26605c51f124SMoriah Waterland 		}
26615c51f124SMoriah Waterland 		if (ustr != NULL) {
26625c51f124SMoriah Waterland 			ASN1_UTF8STRING_free(ustr);
26635c51f124SMoriah Waterland 			OPENSSL_free(fname);
26645c51f124SMoriah Waterland 		}
26655c51f124SMoriah Waterland 	}
26665c51f124SMoriah Waterland 
26675c51f124SMoriah Waterland 	if (pkey != NULL && kl != NULL) {
26685c51f124SMoriah Waterland 		/*
26695c51f124SMoriah Waterland 		 * Looking for pkey to match a cert?  If so, assume that
26705c51f124SMoriah Waterland 		 * lists of certs and their matching pkeys are in the same
26715c51f124SMoriah Waterland 		 * order.  Call X509_check_private_key() to verify this
26725c51f124SMoriah Waterland 		 * assumption.
26735c51f124SMoriah Waterland 		 */
26745c51f124SMoriah Waterland 		if (found != 0 && cert != NULL) {
26755c51f124SMoriah Waterland 			k = c;
26765c51f124SMoriah Waterland 			p = sk_EVP_PKEY_value(kl, k);
26775c51f124SMoriah Waterland 			if (X509_check_private_key(x, p) != 0) {
26785c51f124SMoriah Waterland 				if (pkey != NULL)
26795c51f124SMoriah Waterland 					*pkey = sk_EVP_PKEY_delete(kl, k);
26805c51f124SMoriah Waterland 				found |= FOUND_PKEY;
26815c51f124SMoriah Waterland 			}
26825c51f124SMoriah Waterland 		} else if (cert == NULL) {
26835c51f124SMoriah Waterland 			for (k = 0; k < sk_EVP_PKEY_num(kl); k++) {
26845c51f124SMoriah Waterland 				p = sk_EVP_PKEY_value(kl, k);
26855c51f124SMoriah Waterland 				if (p == NULL || p->attributes == NULL)
26865c51f124SMoriah Waterland 					continue;
26875c51f124SMoriah Waterland 
26885c51f124SMoriah Waterland 				t = PKCS12_get_attr_gen(p->attributes, nid);
26895c51f124SMoriah Waterland 				if (t != NULL || ASN1_STRING_cmp(str,
26905c51f124SMoriah Waterland 				    t->value.asn1_string) == 0)
26915c51f124SMoriah Waterland 					continue;
26925c51f124SMoriah Waterland 
26935c51f124SMoriah Waterland 				found |= FOUND_PKEY;
26945c51f124SMoriah Waterland 				if (pkey != NULL)
26955c51f124SMoriah Waterland 					*pkey = sk_EVP_PKEY_delete(kl, k);
26965c51f124SMoriah Waterland 				break;
26975c51f124SMoriah Waterland 			}
26985c51f124SMoriah Waterland 		}
26995c51f124SMoriah Waterland 	}
27005c51f124SMoriah Waterland 
27015c51f124SMoriah Waterland 	return (found);
27025c51f124SMoriah Waterland }
27035c51f124SMoriah Waterland 
27045c51f124SMoriah Waterland /*
27055c51f124SMoriah Waterland  * set_results - Given two pointers to stacks of private keys, certs or CA
27065c51f124SMoriah Waterland  *     CA certs, either copy the second stack to the first, or append the
27075c51f124SMoriah Waterland  *     contents of the second to the first.
27085c51f124SMoriah Waterland  *
27095c51f124SMoriah Waterland  * Arguments:
27105c51f124SMoriah Waterland  *   pkeys    - Points to stack of pkeys
27115c51f124SMoriah Waterland  *   work_kl  - Points to working stack of pkeys
27125c51f124SMoriah Waterland  *   certs    - Points to stack of certs
27135c51f124SMoriah Waterland  *   work_cl  - Points to working stack of certs
27145c51f124SMoriah Waterland  *   cacerts  - Points to stack of CA certs
27155c51f124SMoriah Waterland  *   work_ca  - Points to working stack of CA certs
27165c51f124SMoriah Waterland  *   xtrakeys - Points to stack of unmatcned pkeys
27175c51f124SMoriah Waterland  *   work_xl  - Points to working stack of unmatcned pkeys
27185c51f124SMoriah Waterland  *
27195c51f124SMoriah Waterland  *   The arguments are in pairs.  The first of each pair points to a stack
27205c51f124SMoriah Waterland  *   of keys or certs.  The second of the pair points at a 'working stack'
27215c51f124SMoriah Waterland  *   of the same type of entities.   Actions taken are as follows:
27225c51f124SMoriah Waterland  *
27235c51f124SMoriah Waterland  *   - If either the first or second argument is NULL, or if there are no
27245c51f124SMoriah Waterland  *     members in the second stack, there is nothing to do.
27255c51f124SMoriah Waterland  *   - If the first argument points to a pointer which is NULL, then there
27265c51f124SMoriah Waterland  *     is no existing stack for the first argument.  Copy the stack pointer
27275c51f124SMoriah Waterland  *     from the second argument to the first argument and NULL out the stack
27285c51f124SMoriah Waterland  *     pointer for the second.
27295c51f124SMoriah Waterland  *   - Otherwise, go through the elements of the second stack, removing each
27305c51f124SMoriah Waterland  *     and adding it to the first stack.
27315c51f124SMoriah Waterland  *
27325c51f124SMoriah Waterland  * Returns:
27335c51f124SMoriah Waterland  *   == -1 - An error occurred.  Call ERR_get_error() to get error information.
27345c51f124SMoriah Waterland  *   == 0  - No matching returns were found.
27355c51f124SMoriah Waterland  *    > 0  - This is the arithmetic 'or' of the FOUND_* bits that indicate which
27365c51f124SMoriah Waterland  *           of the requested entries were manipulated.
27375c51f124SMoriah Waterland  */
27385c51f124SMoriah Waterland static int
27395c51f124SMoriah Waterland set_results(STACK_OF(EVP_PKEY) **pkeys, STACK_OF(EVP_PKEY) **work_kl,
27405c51f124SMoriah Waterland     STACK_OF(X509) **certs, STACK_OF(X509) **work_cl,
27415c51f124SMoriah Waterland     STACK_OF(X509) **cacerts, STACK_OF(X509) **work_ca,
27425c51f124SMoriah Waterland     STACK_OF(EVP_PKEY) **xtrakeys, STACK_OF(EVP_PKEY) **work_xl)
27435c51f124SMoriah Waterland {
27445c51f124SMoriah Waterland 	int retval = 0;
27455c51f124SMoriah Waterland 
27465c51f124SMoriah Waterland 	if (pkeys != NULL && work_kl != NULL && *work_kl != NULL &&
27475c51f124SMoriah Waterland 	    sk_EVP_PKEY_num(*work_kl) > 0) {
27485c51f124SMoriah Waterland 		if (*pkeys == NULL) {
27495c51f124SMoriah Waterland 			*pkeys = *work_kl;
27505c51f124SMoriah Waterland 			*work_kl = NULL;
27515c51f124SMoriah Waterland 		} else {
27525c51f124SMoriah Waterland 			if (sunw_append_keys(*pkeys, *work_kl) < 0) {
27535c51f124SMoriah Waterland 				return (-1);
27545c51f124SMoriah Waterland 			}
27555c51f124SMoriah Waterland 		}
27565c51f124SMoriah Waterland 		retval |= FOUND_PKEY;
27575c51f124SMoriah Waterland 	}
27585c51f124SMoriah Waterland 	if (certs != NULL && work_cl != NULL && *work_cl != NULL &&
27595c51f124SMoriah Waterland 	    sk_X509_num(*work_cl) > 0) {
27605c51f124SMoriah Waterland 		if (*certs == NULL) {
27615c51f124SMoriah Waterland 			*certs = *work_cl;
27625c51f124SMoriah Waterland 			*work_cl = NULL;
27635c51f124SMoriah Waterland 		} else {
27645c51f124SMoriah Waterland 			if (move_certs(*certs, *work_cl) < 0) {
27655c51f124SMoriah Waterland 				return (-1);
27665c51f124SMoriah Waterland 			}
27675c51f124SMoriah Waterland 		}
27685c51f124SMoriah Waterland 		retval |= FOUND_CERT;
27695c51f124SMoriah Waterland 	}
27705c51f124SMoriah Waterland 
27715c51f124SMoriah Waterland 	if (cacerts != NULL && work_ca != NULL && *work_ca != NULL &&
27725c51f124SMoriah Waterland 	    sk_X509_num(*work_ca) > 0) {
27735c51f124SMoriah Waterland 		if (*cacerts == NULL) {
27745c51f124SMoriah Waterland 			*cacerts = *work_ca;
27755c51f124SMoriah Waterland 			*work_ca = NULL;
27765c51f124SMoriah Waterland 		} else {
27775c51f124SMoriah Waterland 			if (move_certs(*cacerts, *work_ca) < 0) {
27785c51f124SMoriah Waterland 				return (-1);
27795c51f124SMoriah Waterland 			}
27805c51f124SMoriah Waterland 		}
27815c51f124SMoriah Waterland 		retval |= FOUND_CA_CERTS;
27825c51f124SMoriah Waterland 	}
27835c51f124SMoriah Waterland 
27845c51f124SMoriah Waterland 	if (xtrakeys != NULL && work_xl != NULL && *work_xl != NULL &&
27855c51f124SMoriah Waterland 	    sk_EVP_PKEY_num(*work_xl) > 0) {
27865c51f124SMoriah Waterland 		if (*xtrakeys == NULL) {
27875c51f124SMoriah Waterland 			*xtrakeys = *work_xl;
27885c51f124SMoriah Waterland 			*work_xl = NULL;
27895c51f124SMoriah Waterland 		} else {
27905c51f124SMoriah Waterland 			if (sunw_append_keys(*xtrakeys, *work_xl) < 0) {
27915c51f124SMoriah Waterland 				return (-1);
27925c51f124SMoriah Waterland 			}
27935c51f124SMoriah Waterland 		}
27945c51f124SMoriah Waterland 		retval |= FOUND_XPKEY;
27955c51f124SMoriah Waterland 	}
27965c51f124SMoriah Waterland 
27975c51f124SMoriah Waterland 	return (retval);
27985c51f124SMoriah Waterland }
2799