xref: /titanic_51/usr/src/lib/libpkg/common/p12lib.c (revision 5c51f1241dbbdf2656d0e10011981411ed0c9673)
1*5c51f124SMoriah Waterland /*
2*5c51f124SMoriah Waterland  * ====================================================================
3*5c51f124SMoriah Waterland  * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
4*5c51f124SMoriah Waterland  *
5*5c51f124SMoriah Waterland  * Redistribution and use in source and binary forms, with or without
6*5c51f124SMoriah Waterland  * modification, are permitted provided that the following conditions
7*5c51f124SMoriah Waterland  * are met:
8*5c51f124SMoriah Waterland  *
9*5c51f124SMoriah Waterland  * 1. Redistributions of source code must retain the above copyright
10*5c51f124SMoriah Waterland  *    notice, this list of conditions and the following disclaimer.
11*5c51f124SMoriah Waterland  *
12*5c51f124SMoriah Waterland  * 2. Redistributions in binary form must reproduce the above copyright
13*5c51f124SMoriah Waterland  *    notice, this list of conditions and the following disclaimer in
14*5c51f124SMoriah Waterland  *    the documentation and/or other materials provided with the
15*5c51f124SMoriah Waterland  *    distribution.
16*5c51f124SMoriah Waterland  *
17*5c51f124SMoriah Waterland  * 3. All advertising materials mentioning features or use of this
18*5c51f124SMoriah Waterland  *    software must display the following acknowledgment:
19*5c51f124SMoriah Waterland  *    "This product includes software developed by the OpenSSL Project
20*5c51f124SMoriah Waterland  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
21*5c51f124SMoriah Waterland  *
22*5c51f124SMoriah Waterland  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23*5c51f124SMoriah Waterland  *    endorse or promote products derived from this software without
24*5c51f124SMoriah Waterland  *    prior written permission. For written permission, please contact
25*5c51f124SMoriah Waterland  *    licensing@OpenSSL.org.
26*5c51f124SMoriah Waterland  *
27*5c51f124SMoriah Waterland  * 5. Products derived from this software may not be called "OpenSSL"
28*5c51f124SMoriah Waterland  *    nor may "OpenSSL" appear in their names without prior written
29*5c51f124SMoriah Waterland  *    permission of the OpenSSL Project.
30*5c51f124SMoriah Waterland  *
31*5c51f124SMoriah Waterland  * 6. Redistributions of any form whatsoever must retain the following
32*5c51f124SMoriah Waterland  *    acknowledgment:
33*5c51f124SMoriah Waterland  *    "This product includes software developed by the OpenSSL Project
34*5c51f124SMoriah Waterland  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
35*5c51f124SMoriah Waterland  *
36*5c51f124SMoriah Waterland  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37*5c51f124SMoriah Waterland  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38*5c51f124SMoriah Waterland  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39*5c51f124SMoriah Waterland  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
40*5c51f124SMoriah Waterland  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41*5c51f124SMoriah Waterland  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42*5c51f124SMoriah Waterland  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43*5c51f124SMoriah Waterland  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44*5c51f124SMoriah Waterland  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45*5c51f124SMoriah Waterland  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46*5c51f124SMoriah Waterland  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47*5c51f124SMoriah Waterland  * OF THE POSSIBILITY OF SUCH DAMAGE.
48*5c51f124SMoriah Waterland  * ====================================================================
49*5c51f124SMoriah Waterland  *
50*5c51f124SMoriah Waterland  * This product includes cryptographic software written by Eric Young
51*5c51f124SMoriah Waterland  * (eay@cryptsoft.com).  This product includes software written by Tim
52*5c51f124SMoriah Waterland  * Hudson (tjh@cryptsoft.com).
53*5c51f124SMoriah Waterland  *
54*5c51f124SMoriah Waterland  */
55*5c51f124SMoriah Waterland 
56*5c51f124SMoriah Waterland /*
57*5c51f124SMoriah Waterland  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
58*5c51f124SMoriah Waterland  * Use is subject to license terms.
59*5c51f124SMoriah Waterland  */
60*5c51f124SMoriah Waterland 
61*5c51f124SMoriah Waterland 
62*5c51f124SMoriah Waterland #include <strings.h>
63*5c51f124SMoriah Waterland #include <stdlib.h>
64*5c51f124SMoriah Waterland #include <assert.h>
65*5c51f124SMoriah Waterland 
66*5c51f124SMoriah Waterland #include <openssl/crypto.h>
67*5c51f124SMoriah Waterland #include <openssl/err.h>
68*5c51f124SMoriah Waterland #include <openssl/x509.h>
69*5c51f124SMoriah Waterland #include <openssl/pem.h>
70*5c51f124SMoriah Waterland 
71*5c51f124SMoriah Waterland #include <openssl/pkcs12.h>
72*5c51f124SMoriah Waterland #include "p12lib.h"
73*5c51f124SMoriah Waterland 
74*5c51f124SMoriah Waterland /*
75*5c51f124SMoriah Waterland  * OpenSSL provides a framework for pushing error codes onto a stack.
76*5c51f124SMoriah Waterland  * When an error occurs, the consumer may use the framework to
77*5c51f124SMoriah Waterland  * pop the errors off the stack and provide a trace of where the
78*5c51f124SMoriah Waterland  * errors occurred.
79*5c51f124SMoriah Waterland  *
80*5c51f124SMoriah Waterland  * Our PKCS12 code plugs into this framework by calling
81*5c51f124SMoriah Waterland  * ERR_load_SUNW_strings(). To push an error (which by the way, consists
82*5c51f124SMoriah Waterland  * of a function code and an error code) onto the stack our PKCS12 code
83*5c51f124SMoriah Waterland  * calls SUNWerr().
84*5c51f124SMoriah Waterland  *
85*5c51f124SMoriah Waterland  * Consumers of our PKCS12 code can then call the OpenSSL error routines
86*5c51f124SMoriah Waterland  * when an error occurs and retrieve the stack of errors.
87*5c51f124SMoriah Waterland  */
88*5c51f124SMoriah Waterland 
89*5c51f124SMoriah Waterland #ifndef OPENSSL_NO_ERR
90*5c51f124SMoriah Waterland 
91*5c51f124SMoriah Waterland /* Function codes and their matching strings */
92*5c51f124SMoriah Waterland static ERR_STRING_DATA SUNW_str_functs[] = {
93*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_USE_X509CERT, 0),	   "sunw_use_x509cert" },
94*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_USE_PKEY, 0),	   "sunw_use_pkey" },
95*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_USE_TASTORE, 0),	   "sunw_use_tastore" },
96*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_USE_CERTFILE, 0),	   "sunw_p12_use_certfile" },
97*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_USE_KEYFILE, 0),	   "sunw_p12_use_keyfile" },
98*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_USE_TRUSTFILE, 0),	   "sunw_p12_use_trustfile" },
99*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_READ_FILE, 0),	   "p12_read_file" },
100*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_DOPARSE, 0),	   "p12_doparse" },
101*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_PKCS12_PARSE, 0),	   "sunw_PKCS12_parse" },
102*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_PKCS12_CONTENTS, 0),  "sunw_PKCS12_contents" },
103*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_PARSE_ONE_BAG, 0),	   "parse_one_bag" },
104*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_PKCS12_CREATE, 0),	   "sunw_PKCS12_create" },
105*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_SPLIT_CERTS, 0),	   "sunw_split_certs" },
106*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_FIND_LOCALKEYID, 0),  "sunw_find_localkeyid" },
107*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_SET_LOCALKEYID, 0),   "sunw_set_localkeyid" },
108*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_GET_LOCALKEYID, 0),   "sunw_get_localkeyid" },
109*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_SET_FNAME, 0),	   "sunw_set_fname" },
110*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_GET_PKEY_FNAME, 0),   "sunw_get_pkey_fname" },
111*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_APPEND_KEYS, 0),	   "sunw_append_keys" },
112*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_PEM_CONTENTS, 0),	   "sunw_PEM_contents" },
113*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_PEM_INFO, 0),	   "pem_info" },
114*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_ASC2BMPSTRING, 0),	   "asc2bmpstring" },
115*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_UTF82ASCSTR, 0),	   "utf82ascstr" },
116*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_FINDATTR, 0),	   "findattr" },
117*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_TYPE2ATTRIB, 0),	   "type2attrib" },
118*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_MOVE_CERTS, 0),	   "move_certs" },
119*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_FIND_FNAME, 0),	   "sunw_find_fname" },
120*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_PARSE_OUTER, 0),	   "parse_outer" },
121*5c51f124SMoriah Waterland 	{ ERR_PACK(0, SUNW_F_CHECKFILE, 0),	   "checkfile" },
122*5c51f124SMoriah Waterland 	{ 0, NULL }
123*5c51f124SMoriah Waterland };
124*5c51f124SMoriah Waterland 
125*5c51f124SMoriah Waterland /* Error codes and their matching strings */
126*5c51f124SMoriah Waterland static ERR_STRING_DATA SUNW_str_reasons[] = {
127*5c51f124SMoriah Waterland 	{ SUNW_R_INVALID_ARG,		"invalid argument" },
128*5c51f124SMoriah Waterland 	{ SUNW_R_MEMORY_FAILURE,	"memory failure" },
129*5c51f124SMoriah Waterland 	{ SUNW_R_MAC_VERIFY_FAILURE,	"mac verify failure" },
130*5c51f124SMoriah Waterland 	{ SUNW_R_MAC_CREATE_FAILURE,	"mac create failure" },
131*5c51f124SMoriah Waterland 	{ SUNW_R_BAD_FILETYPE,		"bad file type" },
132*5c51f124SMoriah Waterland 	{ SUNW_R_BAD_PKEY,		"bad or missing private key" },
133*5c51f124SMoriah Waterland 	{ SUNW_R_BAD_PKEYTYPE,		"unsupported key type" },
134*5c51f124SMoriah Waterland 	{ SUNW_R_PKEY_READ_ERR,		"unable to read private key" },
135*5c51f124SMoriah Waterland 	{ SUNW_R_NO_TRUST_ANCHOR,	"no trust anchors found" },
136*5c51f124SMoriah Waterland 	{ SUNW_R_READ_TRUST_ERR,	"unable to read trust anchor" },
137*5c51f124SMoriah Waterland 	{ SUNW_R_ADD_TRUST_ERR,		"unable to add trust anchor" },
138*5c51f124SMoriah Waterland 	{ SUNW_R_PKCS12_PARSE_ERR,	"PKCS12 parse error" },
139*5c51f124SMoriah Waterland 	{ SUNW_R_PKCS12_CREATE_ERR,	"PKCS12 create error" },
140*5c51f124SMoriah Waterland 	{ SUNW_R_BAD_CERTTYPE,		"unsupported certificate type" },
141*5c51f124SMoriah Waterland 	{ SUNW_R_PARSE_CERT_ERR,	"error parsing PKCS12 certificate" },
142*5c51f124SMoriah Waterland 	{ SUNW_R_PARSE_BAG_ERR,		"error parsing PKCS12 bag" },
143*5c51f124SMoriah Waterland 	{ SUNW_R_MAKE_BAG_ERR,		"error making PKCS12 bag" },
144*5c51f124SMoriah Waterland 	{ SUNW_R_BAD_LKID,		"bad localKeyID format" },
145*5c51f124SMoriah Waterland 	{ SUNW_R_SET_LKID_ERR,		"error setting localKeyID" },
146*5c51f124SMoriah Waterland 	{ SUNW_R_BAD_FNAME,		"bad friendlyName format" },
147*5c51f124SMoriah Waterland 	{ SUNW_R_SET_FNAME_ERR,		"error setting friendlyName" },
148*5c51f124SMoriah Waterland 	{ SUNW_R_BAD_TRUST,		"bad or missing trust anchor" },
149*5c51f124SMoriah Waterland 	{ SUNW_R_BAD_BAGTYPE,		"unsupported bag type" },
150*5c51f124SMoriah Waterland 	{ SUNW_R_CERT_ERR,		"certificate error" },
151*5c51f124SMoriah Waterland 	{ SUNW_R_PKEY_ERR,		"private key error" },
152*5c51f124SMoriah Waterland 	{ SUNW_R_READ_ERR,		"error reading file" },
153*5c51f124SMoriah Waterland 	{ SUNW_R_ADD_ATTR_ERR,		"error adding attribute" },
154*5c51f124SMoriah Waterland 	{ SUNW_R_STR_CONVERT_ERR,	"error converting string" },
155*5c51f124SMoriah Waterland 	{ SUNW_R_PKCS12_EMPTY_ERR,	"empty PKCS12 structure" },
156*5c51f124SMoriah Waterland 	{ SUNW_R_PASSWORD_ERR,		"bad password" },
157*5c51f124SMoriah Waterland 	{ 0, NULL }
158*5c51f124SMoriah Waterland };
159*5c51f124SMoriah Waterland 
160*5c51f124SMoriah Waterland /*
161*5c51f124SMoriah Waterland  * The library name that our module will be known as. This name
162*5c51f124SMoriah Waterland  * may be retrieved via OpenSSLs error APIs.
163*5c51f124SMoriah Waterland  */
164*5c51f124SMoriah Waterland static ERR_STRING_DATA SUNW_lib_name[] = {
165*5c51f124SMoriah Waterland 	{ 0,	SUNW_LIB_NAME },
166*5c51f124SMoriah Waterland 	{ 0, NULL }
167*5c51f124SMoriah Waterland };
168*5c51f124SMoriah Waterland #endif
169*5c51f124SMoriah Waterland 
170*5c51f124SMoriah Waterland /*
171*5c51f124SMoriah Waterland  * The value of this variable (initialized by a call to
172*5c51f124SMoriah Waterland  * ERR_load_SUNW_strings()) is what identifies our errors
173*5c51f124SMoriah Waterland  * to OpenSSL as being ours.
174*5c51f124SMoriah Waterland  */
175*5c51f124SMoriah Waterland static int SUNW_lib_error_code = 0;
176*5c51f124SMoriah Waterland 
177*5c51f124SMoriah Waterland /* local routines */
178*5c51f124SMoriah Waterland static int	parse_pkcs12(PKCS12 *, const char *, int, char *, int, char *,
179*5c51f124SMoriah Waterland     EVP_PKEY **, X509 **, STACK_OF(X509) **);
180*5c51f124SMoriah Waterland static int	pem_info(FILE *, pem_password_cb, void *,
181*5c51f124SMoriah Waterland     STACK_OF(EVP_PKEY) **, STACK_OF(X509) **);
182*5c51f124SMoriah Waterland 
183*5c51f124SMoriah Waterland static int	parse_outer(PKCS12 *, const char *, STACK_OF(EVP_PKEY) *,
184*5c51f124SMoriah Waterland     STACK_OF(X509) *);
185*5c51f124SMoriah Waterland 
186*5c51f124SMoriah Waterland static int	parse_all_bags(STACK_OF(PKCS12_SAFEBAG) *, const char *,
187*5c51f124SMoriah Waterland     STACK_OF(EVP_PKEY) *, STACK_OF(X509) *);
188*5c51f124SMoriah Waterland 
189*5c51f124SMoriah Waterland static int	parse_one_bag(PKCS12_SAFEBAG *, const char *,
190*5c51f124SMoriah Waterland     STACK_OF(EVP_PKEY) *, STACK_OF(X509) *);
191*5c51f124SMoriah Waterland 
192*5c51f124SMoriah Waterland static X509_ATTRIBUTE	*type2attrib(ASN1_TYPE *, int);
193*5c51f124SMoriah Waterland static ASN1_TYPE	*attrib2type(X509_ATTRIBUTE *);
194*5c51f124SMoriah Waterland static uchar_t		*utf82ascstr(ASN1_UTF8STRING *);
195*5c51f124SMoriah Waterland static ASN1_BMPSTRING	*asc2bmpstring(const char *, int);
196*5c51f124SMoriah Waterland static int		find_attr_by_nid(STACK_OF(X509_ATTRIBUTE) *, int);
197*5c51f124SMoriah Waterland static int		find_attr(int, ASN1_STRING *, STACK_OF(EVP_PKEY) *,
198*5c51f124SMoriah Waterland     EVP_PKEY **, STACK_OF(X509) *, X509 **);
199*5c51f124SMoriah Waterland 
200*5c51f124SMoriah Waterland static chk_errs_t	check_time(chk_actions_t, X509 *);
201*5c51f124SMoriah Waterland static int		get_key_cert(int, STACK_OF(EVP_PKEY) *, EVP_PKEY **,
202*5c51f124SMoriah Waterland     STACK_OF(X509) *, X509 **cert);
203*5c51f124SMoriah Waterland static int		move_certs(STACK_OF(X509) *, STACK_OF(X509) *);
204*5c51f124SMoriah Waterland static int		sunw_append_keys(STACK_OF(EVP_PKEY) *,
205*5c51f124SMoriah Waterland     STACK_OF(EVP_PKEY) *);
206*5c51f124SMoriah Waterland static int		set_results(STACK_OF(EVP_PKEY) **,
207*5c51f124SMoriah Waterland     STACK_OF(EVP_PKEY) **, STACK_OF(X509) **, STACK_OF(X509) **,
208*5c51f124SMoriah Waterland     STACK_OF(X509) **, STACK_OF(X509) **,
209*5c51f124SMoriah Waterland     STACK_OF(EVP_PKEY) **, STACK_OF(EVP_PKEY) **);
210*5c51f124SMoriah Waterland 
211*5c51f124SMoriah Waterland /*
212*5c51f124SMoriah Waterland  * ----------------------------------------------------------------------------
213*5c51f124SMoriah Waterland  * Public routines
214*5c51f124SMoriah Waterland  * ----------------------------------------------------------------------------
215*5c51f124SMoriah Waterland  */
216*5c51f124SMoriah Waterland 
217*5c51f124SMoriah Waterland /*
218*5c51f124SMoriah Waterland  * sunw_PKCS12_parse - Parse a PKCS12 structure and break it into its parts.
219*5c51f124SMoriah Waterland  *
220*5c51f124SMoriah Waterland  * Parse and decrypt a PKCS#12 structure returning user key, user cert and/or
221*5c51f124SMoriah Waterland  * other (CA) certs. Note either ca should be NULL, *ca should be NULL,
222*5c51f124SMoriah Waterland  * or it should point to a valid STACK_OF(X509) structure. pkey and cert can
223*5c51f124SMoriah Waterland  * be passed uninitialized.
224*5c51f124SMoriah Waterland  *
225*5c51f124SMoriah Waterland  * Arguments:
226*5c51f124SMoriah Waterland  *   p12      - Structure with pkcs12 info to be parsed
227*5c51f124SMoriah Waterland  *   pass     - Pass phrase for the private key (possibly empty) or NULL if
228*5c51f124SMoriah Waterland  *              there is none.
229*5c51f124SMoriah Waterland  *   matchty  - Info about which certs/keys to return if many are in the file.
230*5c51f124SMoriah Waterland  *   keyid    - If private key localkeyids friendlynames are to match a
231*5c51f124SMoriah Waterland  *              predetermined value, the value to match. This value should
232*5c51f124SMoriah Waterland  *		be an octet string.
233*5c51f124SMoriah Waterland  *   keyid_len- Length of the keyid byte string.
234*5c51f124SMoriah Waterland  *   name_str - If friendlynames are to match a predetermined value, the value
235*5c51f124SMoriah Waterland  *		 to match. This value should be a NULL terminated string.
236*5c51f124SMoriah Waterland  *   pkey     - Points to location pointing to the private key returned.
237*5c51f124SMoriah Waterland  *   cert     - Points to locaiton which points to the client cert returned
238*5c51f124SMoriah Waterland  *   ca       - Points to location that points to a stack of 'certificate
239*5c51f124SMoriah Waterland  *               authority' certs/trust anchors.
240*5c51f124SMoriah Waterland  *
241*5c51f124SMoriah Waterland  * Match based on the value of 'matchty' and the contents of 'keyid'
242*5c51f124SMoriah Waterland  * and/or 'name_str', as appropriate.  Go through the lists of certs and
243*5c51f124SMoriah Waterland  * private keys which were taken from the pkcs12 structure, looking for
244*5c51f124SMoriah Waterland  * matches of the requested type.  This function only searches the lists of
245*5c51f124SMoriah Waterland  * matching private keys and client certificates.  Kinds of matches allowed,
246*5c51f124SMoriah Waterland  * and the order in which they will be checked, are:
247*5c51f124SMoriah Waterland  *
248*5c51f124SMoriah Waterland  *   1) Find the key and/or cert whose localkeyid attributes matches
249*5c51f124SMoriah Waterland  *      'keyid'.
250*5c51f124SMoriah Waterland  *   2) Find the key and/or cert whose friendlyname attributes matches
251*5c51f124SMoriah Waterland  *	'name_str'
252*5c51f124SMoriah Waterland  *   3) Return the first matching key/cert pair found.
253*5c51f124SMoriah Waterland  *   4) Return the last matching key/cert pair found.
254*5c51f124SMoriah Waterland  *   5) Return whatever cert and/or key are available, even unmatching.
255*5c51f124SMoriah Waterland  *
256*5c51f124SMoriah Waterland  *   Append to the CA list, the certs which do not have matching private
257*5c51f124SMoriah Waterland  *   keys and which were not selected.
258*5c51f124SMoriah Waterland  *
259*5c51f124SMoriah Waterland  * If none of the bits are set, no client certs or private keys will be
260*5c51f124SMoriah Waterland  * returned.  CA (aka trust anchor) certs can be.
261*5c51f124SMoriah Waterland  *
262*5c51f124SMoriah Waterland  * Notes: If #3 is selected, then #4 will never occur.  CA certs will be
263*5c51f124SMoriah Waterland  * selected after a cert/key pairs are isolated.
264*5c51f124SMoriah Waterland  *
265*5c51f124SMoriah Waterland  * Returns:
266*5c51f124SMoriah Waterland  *  <  0 - An error returned.  Call ERR_get_error() to get errors information.
267*5c51f124SMoriah Waterland  *         Where possible, memory has been freed.
268*5c51f124SMoriah Waterland  *  >= 0 - Objects were found and returned.  Which objects are indicated by
269*5c51f124SMoriah Waterland  *         which bits are set (FOUND_PKEY, FOUND_CERT, FOUND_CA_CERTS).
270*5c51f124SMoriah Waterland  */
271*5c51f124SMoriah Waterland int
272*5c51f124SMoriah Waterland sunw_PKCS12_parse(PKCS12 *p12, const char *pass, int matchty, char *keyid,
273*5c51f124SMoriah Waterland     int keyid_len, char *name_str, EVP_PKEY **pkey, X509 **cert,
274*5c51f124SMoriah Waterland     STACK_OF(X509) **ca)
275*5c51f124SMoriah Waterland {
276*5c51f124SMoriah Waterland 	boolean_t ca_supplied;
277*5c51f124SMoriah Waterland 	int retval = -1;
278*5c51f124SMoriah Waterland 
279*5c51f124SMoriah Waterland 	/* If NULL PKCS12 structure, this is an error */
280*5c51f124SMoriah Waterland 	if (p12 == NULL) {
281*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_PARSE, SUNW_R_INVALID_ARG);
282*5c51f124SMoriah Waterland 		return (-1);
283*5c51f124SMoriah Waterland 	}
284*5c51f124SMoriah Waterland 
285*5c51f124SMoriah Waterland 	/* Set up arguments....  These will be allocated if needed */
286*5c51f124SMoriah Waterland 	if (pkey)
287*5c51f124SMoriah Waterland 		*pkey = NULL;
288*5c51f124SMoriah Waterland 	if (cert)
289*5c51f124SMoriah Waterland 		*cert = NULL;
290*5c51f124SMoriah Waterland 
291*5c51f124SMoriah Waterland 	/*
292*5c51f124SMoriah Waterland 	 * If there is already a ca list, use it.  Otherwise, allocate one
293*5c51f124SMoriah Waterland 	 * and free is later if an error occurs or whatever.)
294*5c51f124SMoriah Waterland 	 */
295*5c51f124SMoriah Waterland 	ca_supplied = (ca != NULL && *ca != NULL);
296*5c51f124SMoriah Waterland 	if (ca != NULL && *ca == NULL) {
297*5c51f124SMoriah Waterland 		if ((*ca = sk_X509_new_null()) == NULL) {
298*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PKCS12_PARSE, SUNW_R_MEMORY_FAILURE);
299*5c51f124SMoriah Waterland 			return (-1);
300*5c51f124SMoriah Waterland 		}
301*5c51f124SMoriah Waterland 	}
302*5c51f124SMoriah Waterland 
303*5c51f124SMoriah Waterland 	/*
304*5c51f124SMoriah Waterland 	 * If password is zero length or NULL then try verifying both cases
305*5c51f124SMoriah Waterland 	 * to determine which password is correct. The reason for this is that
306*5c51f124SMoriah Waterland 	 * under PKCS#12 password based encryption no password and a zero
307*5c51f124SMoriah Waterland 	 * length password are two different things. If the password has a
308*5c51f124SMoriah Waterland 	 * non-zero length and is not NULL then call PKCS12_verify_mac() with
309*5c51f124SMoriah Waterland 	 * a length of '-1' and let it use strlen() to figure out the length
310*5c51f124SMoriah Waterland 	 * of the password.
311*5c51f124SMoriah Waterland 	 */
312*5c51f124SMoriah Waterland 	/* Check the mac */
313*5c51f124SMoriah Waterland 	if (pass == NULL || *pass == '\0') {
314*5c51f124SMoriah Waterland 		if (PKCS12_verify_mac(p12, NULL, 0))
315*5c51f124SMoriah Waterland 			pass = NULL;
316*5c51f124SMoriah Waterland 		else if (PKCS12_verify_mac(p12, "", 0))
317*5c51f124SMoriah Waterland 			pass = "";
318*5c51f124SMoriah Waterland 		else {
319*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PKCS12_PARSE,
320*5c51f124SMoriah Waterland 			    SUNW_R_MAC_VERIFY_FAILURE);
321*5c51f124SMoriah Waterland 			goto err;
322*5c51f124SMoriah Waterland 		}
323*5c51f124SMoriah Waterland 	} else if (PKCS12_verify_mac(p12, pass, -1) == 0) {
324*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_PARSE, SUNW_R_MAC_VERIFY_FAILURE);
325*5c51f124SMoriah Waterland 		goto err;
326*5c51f124SMoriah Waterland 	}
327*5c51f124SMoriah Waterland 
328*5c51f124SMoriah Waterland 	retval = parse_pkcs12(p12, pass, matchty, keyid, keyid_len,
329*5c51f124SMoriah Waterland 	    name_str, pkey, cert, ca);
330*5c51f124SMoriah Waterland 	if (retval < 0) {
331*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_PARSE, SUNW_R_PKCS12_PARSE_ERR);
332*5c51f124SMoriah Waterland 		goto err;
333*5c51f124SMoriah Waterland 	}
334*5c51f124SMoriah Waterland 	return (retval);
335*5c51f124SMoriah Waterland 
336*5c51f124SMoriah Waterland err:
337*5c51f124SMoriah Waterland 	if (pkey && *pkey) {
338*5c51f124SMoriah Waterland 		sunw_evp_pkey_free(*pkey);
339*5c51f124SMoriah Waterland 	}
340*5c51f124SMoriah Waterland 	if (cert && *cert)
341*5c51f124SMoriah Waterland 		X509_free(*cert);
342*5c51f124SMoriah Waterland 	if (ca_supplied == B_FALSE && ca != NULL)
343*5c51f124SMoriah Waterland 		sk_X509_pop_free(*ca, X509_free);
344*5c51f124SMoriah Waterland 
345*5c51f124SMoriah Waterland 	return (-1);
346*5c51f124SMoriah Waterland 
347*5c51f124SMoriah Waterland }
348*5c51f124SMoriah Waterland 
349*5c51f124SMoriah Waterland 
350*5c51f124SMoriah Waterland /*
351*5c51f124SMoriah Waterland  * sunw_PEM_contents() parses a PEM file and returns component parts found
352*5c51f124SMoriah Waterland  *
353*5c51f124SMoriah Waterland  * Parse and decrypt a PEM file, returning any user keys and certs.
354*5c51f124SMoriah Waterland  *
355*5c51f124SMoriah Waterland  * There are some limits to this function.  It will ignore the following:
356*5c51f124SMoriah Waterland  * - certificates identified by "TRUSTED CERTIFICATE"
357*5c51f124SMoriah Waterland  * - CERTIFICATE REQUEST and NEW CERTIFICATE REQUEST records.
358*5c51f124SMoriah Waterland  * - X509 CRL
359*5c51f124SMoriah Waterland  * - DH PARAMETERS
360*5c51f124SMoriah Waterland  * - DSA PARAMETERS
361*5c51f124SMoriah Waterland  * - Any PUBLIC KEY
362*5c51f124SMoriah Waterland  * - PKCS7
363*5c51f124SMoriah Waterland  * - PRIVATE KEY or ENCRYPTED PRIVATE KEY (PKCS 8)
364*5c51f124SMoriah Waterland  *
365*5c51f124SMoriah Waterland  * Arguments:
366*5c51f124SMoriah Waterland  *   fp       - File pointer for file containing PEM data.
367*5c51f124SMoriah Waterland  *   pass     - Pass phrase for the private key or NULL if there is none.
368*5c51f124SMoriah Waterland  *   pkeys    - Points to address of a stack of private keys to return.
369*5c51f124SMoriah Waterland  *   certs    - Points to address of a stack of client certs to return.
370*5c51f124SMoriah Waterland  *
371*5c51f124SMoriah Waterland  *   The pointers to stacks should either be NULL or their contents should
372*5c51f124SMoriah Waterland  *   either be NULL or should point to a valid STACK_OF(X509) structure.
373*5c51f124SMoriah Waterland  *   If the stacks contain information, corresponding information from the
374*5c51f124SMoriah Waterland  *   file will be appended to the original contents.
375*5c51f124SMoriah Waterland  *
376*5c51f124SMoriah Waterland  *   Note:  Client certs and and their matching private keys will be in any
377*5c51f124SMoriah Waterland  *   order.
378*5c51f124SMoriah Waterland  *
379*5c51f124SMoriah Waterland  *   Certs which have no matching private key are assumed to be ca certs.
380*5c51f124SMoriah Waterland  *
381*5c51f124SMoriah Waterland  * Returns:
382*5c51f124SMoriah Waterland  *  <  0 - An error returned.  Call ERR_get_error() to get errors information.
383*5c51f124SMoriah Waterland  *         Where possible, memory has been freed.
384*5c51f124SMoriah Waterland  *  >= 0 - Objects were found and returned.  Which objects are indicated by
385*5c51f124SMoriah Waterland  *         which bits are set (FOUND_PKEY, FOUND_CERT)
386*5c51f124SMoriah Waterland  */
387*5c51f124SMoriah Waterland int sunw_PEM_contents(FILE *fp, pem_password_cb *cb, void *userdata,
388*5c51f124SMoriah Waterland     STACK_OF(EVP_PKEY) **pkey, STACK_OF(X509) **certs)
389*5c51f124SMoriah Waterland {
390*5c51f124SMoriah Waterland 	STACK_OF(EVP_PKEY) *work_kl = NULL;
391*5c51f124SMoriah Waterland 	STACK_OF(X509) *work_ca = NULL;
392*5c51f124SMoriah Waterland 	int retval = -1;
393*5c51f124SMoriah Waterland 
394*5c51f124SMoriah Waterland 	/*
395*5c51f124SMoriah Waterland 	 * Allocate the working stacks for private key and for the
396*5c51f124SMoriah Waterland 	 * ca certs.
397*5c51f124SMoriah Waterland 	 */
398*5c51f124SMoriah Waterland 	if ((work_kl = sk_EVP_PKEY_new_null()) == NULL) {
399*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PEM_CONTENTS, SUNW_R_MEMORY_FAILURE);
400*5c51f124SMoriah Waterland 		goto cleanup;
401*5c51f124SMoriah Waterland 	}
402*5c51f124SMoriah Waterland 
403*5c51f124SMoriah Waterland 	if ((work_ca = sk_X509_new_null()) == NULL) {
404*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PEM_CONTENTS, SUNW_R_MEMORY_FAILURE);
405*5c51f124SMoriah Waterland 		goto cleanup;
406*5c51f124SMoriah Waterland 	}
407*5c51f124SMoriah Waterland 
408*5c51f124SMoriah Waterland 	/* Error strings are set within the following. */
409*5c51f124SMoriah Waterland 	if (pem_info(fp, cb, userdata, &work_kl, &work_ca) <= 0) {
410*5c51f124SMoriah Waterland 		goto cleanup;
411*5c51f124SMoriah Waterland 	}
412*5c51f124SMoriah Waterland 
413*5c51f124SMoriah Waterland 	/* on error, set_results() returns an error on the stack */
414*5c51f124SMoriah Waterland 	retval = set_results(pkey, &work_kl, certs, &work_ca, NULL, NULL, NULL,
415*5c51f124SMoriah Waterland 	    NULL);
416*5c51f124SMoriah Waterland cleanup:
417*5c51f124SMoriah Waterland 	if (work_kl != NULL) {
418*5c51f124SMoriah Waterland 		sk_EVP_PKEY_pop_free(work_kl, sunw_evp_pkey_free);
419*5c51f124SMoriah Waterland 	}
420*5c51f124SMoriah Waterland 	if (work_ca != NULL)
421*5c51f124SMoriah Waterland 		sk_X509_pop_free(work_ca, X509_free);
422*5c51f124SMoriah Waterland 
423*5c51f124SMoriah Waterland 	return (retval);
424*5c51f124SMoriah Waterland }
425*5c51f124SMoriah Waterland 
426*5c51f124SMoriah Waterland 
427*5c51f124SMoriah Waterland /*
428*5c51f124SMoriah Waterland  * sunw_PKCS12_contents() parses a pkcs#12 structure and returns component
429*5c51f124SMoriah Waterland  *     parts found, without evaluation.
430*5c51f124SMoriah Waterland  *
431*5c51f124SMoriah Waterland  * Parse and decrypt a PKCS#12 structure returning any user keys and/or
432*5c51f124SMoriah Waterland  * various certs. Note these should either be NULL, *whatever should
433*5c51f124SMoriah Waterland  * be NULL, or it should point to a valid STACK_OF(X509) structure.
434*5c51f124SMoriah Waterland  *
435*5c51f124SMoriah Waterland  * Arguments:
436*5c51f124SMoriah Waterland  *   p12      - Structure with pkcs12 info to be parsed
437*5c51f124SMoriah Waterland  *   pass     - Pass phrase for the private key and entire pkcs12 wad (possibly
438*5c51f124SMoriah Waterland  *              empty) or NULL if there is none.
439*5c51f124SMoriah Waterland  *   pkeys    - Points to address of a stack of private keys to return.
440*5c51f124SMoriah Waterland  *   certs    - Points to address of a stack of client certs return.
441*5c51f124SMoriah Waterland  *
442*5c51f124SMoriah Waterland  *   Note:  The certs and keys being returned are in random order.
443*5c51f124SMoriah Waterland  *
444*5c51f124SMoriah Waterland  * Returns:
445*5c51f124SMoriah Waterland  *  <  0 - An error returned.  Call ERR_get_error() to get errors information.
446*5c51f124SMoriah Waterland  *         Where possible, memory has been freed.
447*5c51f124SMoriah Waterland  *  >= 0 - Objects were found and returned.  Which objects are indicated by
448*5c51f124SMoriah Waterland  *         which bits are set (FOUND_PKEY or FOUND_CERT)
449*5c51f124SMoriah Waterland  */
450*5c51f124SMoriah Waterland int
451*5c51f124SMoriah Waterland sunw_PKCS12_contents(PKCS12 *p12, const char *pass, STACK_OF(EVP_PKEY) **pkey,
452*5c51f124SMoriah Waterland     STACK_OF(X509) **certs)
453*5c51f124SMoriah Waterland {
454*5c51f124SMoriah Waterland 	STACK_OF(EVP_PKEY) *work_kl = NULL;
455*5c51f124SMoriah Waterland 	STACK_OF(X509) *work_ca = NULL;
456*5c51f124SMoriah Waterland 	int retval = -1;
457*5c51f124SMoriah Waterland 
458*5c51f124SMoriah Waterland 	/*
459*5c51f124SMoriah Waterland 	 * Allocate the working stacks for private key and for the
460*5c51f124SMoriah Waterland 	 * ca certs.
461*5c51f124SMoriah Waterland 	 */
462*5c51f124SMoriah Waterland 	if ((work_kl = sk_EVP_PKEY_new_null()) == NULL) {
463*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_CONTENTS, SUNW_R_MEMORY_FAILURE);
464*5c51f124SMoriah Waterland 		goto cleanup;
465*5c51f124SMoriah Waterland 	}
466*5c51f124SMoriah Waterland 
467*5c51f124SMoriah Waterland 	if ((work_ca = sk_X509_new_null()) == NULL) {
468*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_CONTENTS, SUNW_R_MEMORY_FAILURE);
469*5c51f124SMoriah Waterland 		goto cleanup;
470*5c51f124SMoriah Waterland 	}
471*5c51f124SMoriah Waterland 
472*5c51f124SMoriah Waterland 	if (parse_outer(p12, pass, work_kl, work_ca) == 0) {
473*5c51f124SMoriah Waterland 		/*
474*5c51f124SMoriah Waterland 		 * Error already on stack
475*5c51f124SMoriah Waterland 		 */
476*5c51f124SMoriah Waterland 		goto cleanup;
477*5c51f124SMoriah Waterland 	}
478*5c51f124SMoriah Waterland 
479*5c51f124SMoriah Waterland 	/* on error, set_results() returns an error on the stack */
480*5c51f124SMoriah Waterland 	retval = set_results(pkey, &work_kl, certs, &work_ca, NULL,
481*5c51f124SMoriah Waterland 	    NULL, NULL, NULL);
482*5c51f124SMoriah Waterland 
483*5c51f124SMoriah Waterland cleanup:
484*5c51f124SMoriah Waterland 	if (work_kl != NULL) {
485*5c51f124SMoriah Waterland 		sk_EVP_PKEY_pop_free(work_kl, sunw_evp_pkey_free);
486*5c51f124SMoriah Waterland 	}
487*5c51f124SMoriah Waterland 
488*5c51f124SMoriah Waterland 	return (retval);
489*5c51f124SMoriah Waterland }
490*5c51f124SMoriah Waterland 
491*5c51f124SMoriah Waterland 
492*5c51f124SMoriah Waterland 
493*5c51f124SMoriah Waterland /*
494*5c51f124SMoriah Waterland  * sunw_split_certs() - Given a list of certs and a list of private keys,
495*5c51f124SMoriah Waterland  *     moves certs which match one of the keys to a different stack.
496*5c51f124SMoriah Waterland  *
497*5c51f124SMoriah Waterland  * Arguments:
498*5c51f124SMoriah Waterland  *   allkeys  - Points to a stack of private keys to search.
499*5c51f124SMoriah Waterland  *   allcerts - Points to a stack of certs to be searched.
500*5c51f124SMoriah Waterland  *   keycerts - Points to address of a stack of certs with matching private
501*5c51f124SMoriah Waterland  *              keys.  They are moved from 'allcerts'.  This may not be NULL
502*5c51f124SMoriah Waterland  *              when called.  If *keycerts is NULL upon entry, a new stack will
503*5c51f124SMoriah Waterland  *              be allocated.  Otherwise, it must be a valid STACK_OF(509).
504*5c51f124SMoriah Waterland  *   nocerts  - Points to address of a stack for keys which have no matching
505*5c51f124SMoriah Waterland  *              certs.  Keys are moved from 'allkeys' here when they have no
506*5c51f124SMoriah Waterland  *              matching certs.  If this is NULL, matchless keys will be
507*5c51f124SMoriah Waterland  *              discarded.
508*5c51f124SMoriah Waterland  *
509*5c51f124SMoriah Waterland  *   Notes:  If an error occurs while moving certs, the cert being move may be
510*5c51f124SMoriah Waterland  *   lost.  'keycerts' may only contain part of the matching certs.  The number
511*5c51f124SMoriah Waterland  *   of certs successfully moved can be found by checking sk_X509_num(keycerts).
512*5c51f124SMoriah Waterland  *
513*5c51f124SMoriah Waterland  *   If there is a key which does not have a matching cert, it is moved to
514*5c51f124SMoriah Waterland  *   the list nocerts.
515*5c51f124SMoriah Waterland  *
516*5c51f124SMoriah Waterland  *   If all certs are removed from 'certs' and/or 'pkeys', it will be the
517*5c51f124SMoriah Waterland  *   caller's responsibility to free the empty stacks.
518*5c51f124SMoriah Waterland  *
519*5c51f124SMoriah Waterland  * Returns:
520*5c51f124SMoriah Waterland  *  <  0 - An error returned.  Call ERR_get_error() to get errors information.
521*5c51f124SMoriah Waterland  *         Where possible, memory has been freed.
522*5c51f124SMoriah Waterland  *  >= 0 - The number of certs moved from 'cert' to 'pkcerts'.
523*5c51f124SMoriah Waterland  */
524*5c51f124SMoriah Waterland int
525*5c51f124SMoriah Waterland sunw_split_certs(STACK_OF(EVP_PKEY) *allkeys, STACK_OF(X509) *allcerts,
526*5c51f124SMoriah Waterland     STACK_OF(X509) **keycerts, STACK_OF(EVP_PKEY) **nocerts)
527*5c51f124SMoriah Waterland {
528*5c51f124SMoriah Waterland 	STACK_OF(X509) *matching;
529*5c51f124SMoriah Waterland 	STACK_OF(EVP_PKEY) *nomatch;
530*5c51f124SMoriah Waterland 	EVP_PKEY *tmpkey;
531*5c51f124SMoriah Waterland 	X509 *tmpcert;
532*5c51f124SMoriah Waterland 	int count = 0;
533*5c51f124SMoriah Waterland 	int found;
534*5c51f124SMoriah Waterland 	int res;
535*5c51f124SMoriah Waterland 	int i;
536*5c51f124SMoriah Waterland 	int k;
537*5c51f124SMoriah Waterland 
538*5c51f124SMoriah Waterland 	*keycerts = NULL;
539*5c51f124SMoriah Waterland 	if (nocerts != NULL)
540*5c51f124SMoriah Waterland 		*nocerts = NULL;
541*5c51f124SMoriah Waterland 	nomatch = NULL;
542*5c51f124SMoriah Waterland 
543*5c51f124SMoriah Waterland 	if ((matching = sk_X509_new_null()) == NULL) {
544*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_SPLIT_CERTS, SUNW_R_MEMORY_FAILURE);
545*5c51f124SMoriah Waterland 		return (-1);
546*5c51f124SMoriah Waterland 	}
547*5c51f124SMoriah Waterland 	*keycerts = matching;
548*5c51f124SMoriah Waterland 
549*5c51f124SMoriah Waterland 	k = 0;
550*5c51f124SMoriah Waterland 	while (k < sk_EVP_PKEY_num(allkeys)) {
551*5c51f124SMoriah Waterland 		found = 0;
552*5c51f124SMoriah Waterland 		tmpkey = sk_EVP_PKEY_value(allkeys, k);
553*5c51f124SMoriah Waterland 
554*5c51f124SMoriah Waterland 		for (i = 0; i < sk_X509_num(allcerts); i++) {
555*5c51f124SMoriah Waterland 			tmpcert = sk_X509_value(allcerts, i);
556*5c51f124SMoriah Waterland 			res = X509_check_private_key(tmpcert, tmpkey);
557*5c51f124SMoriah Waterland 			if (res != 0) {
558*5c51f124SMoriah Waterland 				count++;
559*5c51f124SMoriah Waterland 				found = 1;
560*5c51f124SMoriah Waterland 				tmpcert = sk_X509_delete(allcerts, i);
561*5c51f124SMoriah Waterland 				if (sk_X509_push(matching, tmpcert) == 0) {
562*5c51f124SMoriah Waterland 					X509_free(tmpcert);
563*5c51f124SMoriah Waterland 					SUNWerr(SUNW_F_SPLIT_CERTS,
564*5c51f124SMoriah Waterland 					    SUNW_R_MEMORY_FAILURE);
565*5c51f124SMoriah Waterland 					return (-1);
566*5c51f124SMoriah Waterland 				}
567*5c51f124SMoriah Waterland 				break;
568*5c51f124SMoriah Waterland 			}
569*5c51f124SMoriah Waterland 		}
570*5c51f124SMoriah Waterland 		if (found != 0) {
571*5c51f124SMoriah Waterland 			/*
572*5c51f124SMoriah Waterland 			 * Found a match - keep the key & check out the next
573*5c51f124SMoriah Waterland 			 * one.
574*5c51f124SMoriah Waterland 			 */
575*5c51f124SMoriah Waterland 			k++;
576*5c51f124SMoriah Waterland 		} else {
577*5c51f124SMoriah Waterland 			/*
578*5c51f124SMoriah Waterland 			 * No cert matching this key.  Move the key if
579*5c51f124SMoriah Waterland 			 * possible or discard it.  Don't increment the
580*5c51f124SMoriah Waterland 			 * index.
581*5c51f124SMoriah Waterland 			 */
582*5c51f124SMoriah Waterland 			if (nocerts == NULL) {
583*5c51f124SMoriah Waterland 				tmpkey = sk_EVP_PKEY_delete(allkeys, k);
584*5c51f124SMoriah Waterland 				sunw_evp_pkey_free(tmpkey);
585*5c51f124SMoriah Waterland 			} else {
586*5c51f124SMoriah Waterland 				if (*nocerts == NULL) {
587*5c51f124SMoriah Waterland 					nomatch = sk_EVP_PKEY_new_null();
588*5c51f124SMoriah Waterland 					if (nomatch == NULL) {
589*5c51f124SMoriah Waterland 						SUNWerr(SUNW_F_SPLIT_CERTS,
590*5c51f124SMoriah Waterland 						    SUNW_R_MEMORY_FAILURE);
591*5c51f124SMoriah Waterland 						return (-1);
592*5c51f124SMoriah Waterland 					}
593*5c51f124SMoriah Waterland 					*nocerts = nomatch;
594*5c51f124SMoriah Waterland 				}
595*5c51f124SMoriah Waterland 				tmpkey = sk_EVP_PKEY_delete(allkeys, k);
596*5c51f124SMoriah Waterland 				if (sk_EVP_PKEY_push(nomatch, tmpkey) == 0) {
597*5c51f124SMoriah Waterland 					sunw_evp_pkey_free(tmpkey);
598*5c51f124SMoriah Waterland 					SUNWerr(SUNW_F_SPLIT_CERTS,
599*5c51f124SMoriah Waterland 					    SUNW_R_MEMORY_FAILURE);
600*5c51f124SMoriah Waterland 					return (-1);
601*5c51f124SMoriah Waterland 				}
602*5c51f124SMoriah Waterland 			}
603*5c51f124SMoriah Waterland 		}
604*5c51f124SMoriah Waterland 	}
605*5c51f124SMoriah Waterland 
606*5c51f124SMoriah Waterland 	return (count);
607*5c51f124SMoriah Waterland }
608*5c51f124SMoriah Waterland 
609*5c51f124SMoriah Waterland /*
610*5c51f124SMoriah Waterland  * sunw_PKCS12_create() creates a pkcs#12 structure and given component parts.
611*5c51f124SMoriah Waterland  *
612*5c51f124SMoriah Waterland  * Given one or more of user private key, user cert and/or other (CA) certs,
613*5c51f124SMoriah Waterland  * return an encrypted PKCS12 structure containing them.
614*5c51f124SMoriah Waterland  *
615*5c51f124SMoriah Waterland  * Arguments:
616*5c51f124SMoriah Waterland  *   pass     - Pass phrase for the pkcs12 structure and private key (possibly
617*5c51f124SMoriah Waterland  *              empty) or NULL if there is none.  It will be used to encrypt
618*5c51f124SMoriah Waterland  *              both the private key(s) and as the pass phrase for the whole
619*5c51f124SMoriah Waterland  *              pkcs12 wad.
620*5c51f124SMoriah Waterland  *   pkeys    - Points to stack of private keys.
621*5c51f124SMoriah Waterland  *   certs    - Points to stack of client (public ke) certs
622*5c51f124SMoriah Waterland  *   cacerts  - Points to stack of 'certificate authority' certs (or trust
623*5c51f124SMoriah Waterland  *              anchors).
624*5c51f124SMoriah Waterland  *
625*5c51f124SMoriah Waterland  *   Note that any of these may be NULL.
626*5c51f124SMoriah Waterland  *
627*5c51f124SMoriah Waterland  * Returns:
628*5c51f124SMoriah Waterland  *   NULL     - An error occurred.
629*5c51f124SMoriah Waterland  *   != NULL  - Address of PKCS12 structure.  The user is responsible for
630*5c51f124SMoriah Waterland  *              freeing the memory when done.
631*5c51f124SMoriah Waterland  */
632*5c51f124SMoriah Waterland PKCS12 *
633*5c51f124SMoriah Waterland sunw_PKCS12_create(const char *pass, STACK_OF(EVP_PKEY) *pkeys,
634*5c51f124SMoriah Waterland     STACK_OF(X509) *certs, STACK_OF(X509) *cacerts)
635*5c51f124SMoriah Waterland {
636*5c51f124SMoriah Waterland 	int nid_cert = NID_pbe_WithSHA1And40BitRC2_CBC;
637*5c51f124SMoriah Waterland 	int nid_key = NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
638*5c51f124SMoriah Waterland 	STACK_OF(PKCS12_SAFEBAG) *bags = NULL;
639*5c51f124SMoriah Waterland 	STACK_OF(PKCS7) *safes = NULL;
640*5c51f124SMoriah Waterland 	PKCS12_SAFEBAG *bag = NULL;
641*5c51f124SMoriah Waterland 	PKCS8_PRIV_KEY_INFO *p8 = NULL;
642*5c51f124SMoriah Waterland 	EVP_PKEY *pkey = NULL;
643*5c51f124SMoriah Waterland 	PKCS12 *ret_p12 = NULL;
644*5c51f124SMoriah Waterland 	PKCS12 *p12 = NULL;
645*5c51f124SMoriah Waterland 	PKCS7 *authsafe = NULL;
646*5c51f124SMoriah Waterland 	X509 *cert = NULL;
647*5c51f124SMoriah Waterland 	uchar_t *str = NULL;
648*5c51f124SMoriah Waterland 	int certs_there = 0;
649*5c51f124SMoriah Waterland 	int keys_there = 0;
650*5c51f124SMoriah Waterland 	int len;
651*5c51f124SMoriah Waterland 	int i;
652*5c51f124SMoriah Waterland 
653*5c51f124SMoriah Waterland 	if ((safes = sk_PKCS7_new_null()) == NULL) {
654*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_MEMORY_FAILURE);
655*5c51f124SMoriah Waterland 		return (NULL);
656*5c51f124SMoriah Waterland 	}
657*5c51f124SMoriah Waterland 
658*5c51f124SMoriah Waterland 	if ((bags = sk_PKCS12_SAFEBAG_new_null()) == NULL) {
659*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_MEMORY_FAILURE);
660*5c51f124SMoriah Waterland 		goto err_ret;
661*5c51f124SMoriah Waterland 	}
662*5c51f124SMoriah Waterland 
663*5c51f124SMoriah Waterland 	if (certs != NULL && sk_X509_num(certs) > 0) {
664*5c51f124SMoriah Waterland 
665*5c51f124SMoriah Waterland 		for (i = 0; i < sk_X509_num(certs); i++) {
666*5c51f124SMoriah Waterland 			cert = sk_X509_value(certs, i);
667*5c51f124SMoriah Waterland 
668*5c51f124SMoriah Waterland 			/* Add user certificate */
669*5c51f124SMoriah Waterland 			if ((bag = M_PKCS12_x5092certbag(cert)) == NULL) {
670*5c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_CERT_ERR);
671*5c51f124SMoriah Waterland 				goto err_ret;
672*5c51f124SMoriah Waterland 			}
673*5c51f124SMoriah Waterland 			if (cert->aux != NULL && cert->aux->alias != NULL &&
674*5c51f124SMoriah Waterland 			    cert->aux->alias->type == V_ASN1_UTF8STRING) {
675*5c51f124SMoriah Waterland 				str = utf82ascstr(cert->aux->alias);
676*5c51f124SMoriah Waterland 				if (str == NULL) {
677*5c51f124SMoriah Waterland 					/*
678*5c51f124SMoriah Waterland 					 * Error already on stack
679*5c51f124SMoriah Waterland 					 */
680*5c51f124SMoriah Waterland 					goto err_ret;
681*5c51f124SMoriah Waterland 				}
682*5c51f124SMoriah Waterland 				if (PKCS12_add_friendlyname_asc(bag,
683*5c51f124SMoriah Waterland 				    (char const *) str,
684*5c51f124SMoriah Waterland 				    strlen((char const *) str)) == 0) {
685*5c51f124SMoriah Waterland 					SUNWerr(SUNW_F_PKCS12_CREATE,
686*5c51f124SMoriah Waterland 					    SUNW_R_ADD_ATTR_ERR);
687*5c51f124SMoriah Waterland 					goto err_ret;
688*5c51f124SMoriah Waterland 				}
689*5c51f124SMoriah Waterland 			}
690*5c51f124SMoriah Waterland 			if (cert->aux != NULL && cert->aux->keyid != NULL &&
691*5c51f124SMoriah Waterland 			    cert->aux->keyid->type == V_ASN1_OCTET_STRING) {
692*5c51f124SMoriah Waterland 				str = cert->aux->keyid->data;
693*5c51f124SMoriah Waterland 				len = cert->aux->keyid->length;
694*5c51f124SMoriah Waterland 
695*5c51f124SMoriah Waterland 				if (str != NULL &&
696*5c51f124SMoriah Waterland 				    PKCS12_add_localkeyid(bag, str, len) == 0) {
697*5c51f124SMoriah Waterland 					SUNWerr(SUNW_F_PKCS12_CREATE,
698*5c51f124SMoriah Waterland 					    SUNW_R_ADD_ATTR_ERR);
699*5c51f124SMoriah Waterland 					goto err_ret;
700*5c51f124SMoriah Waterland 				}
701*5c51f124SMoriah Waterland 			}
702*5c51f124SMoriah Waterland 			if (sk_PKCS12_SAFEBAG_push(bags, bag) == 0) {
703*5c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PKCS12_CREATE,
704*5c51f124SMoriah Waterland 				    SUNW_R_MEMORY_FAILURE);
705*5c51f124SMoriah Waterland 				goto err_ret;
706*5c51f124SMoriah Waterland 			}
707*5c51f124SMoriah Waterland 			certs_there++;
708*5c51f124SMoriah Waterland 			bag = NULL;
709*5c51f124SMoriah Waterland 		}
710*5c51f124SMoriah Waterland 	}
711*5c51f124SMoriah Waterland 
712*5c51f124SMoriah Waterland 	if (cacerts != NULL && sk_X509_num(cacerts) > 0) {
713*5c51f124SMoriah Waterland 
714*5c51f124SMoriah Waterland 		/* Put all certs in structure */
715*5c51f124SMoriah Waterland 		for (i = 0; i < sk_X509_num(cacerts); i++) {
716*5c51f124SMoriah Waterland 			cert = sk_X509_value(cacerts, i);
717*5c51f124SMoriah Waterland 			if ((bag = M_PKCS12_x5092certbag(cert)) == NULL) {
718*5c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_CERT_ERR);
719*5c51f124SMoriah Waterland 				goto err_ret;
720*5c51f124SMoriah Waterland 			}
721*5c51f124SMoriah Waterland 
722*5c51f124SMoriah Waterland 			if (cert->aux != NULL && cert->aux->alias != NULL &&
723*5c51f124SMoriah Waterland 			    cert->aux->alias->type == V_ASN1_UTF8STRING) {
724*5c51f124SMoriah Waterland 				str = utf82ascstr(cert->aux->alias);
725*5c51f124SMoriah Waterland 				if (str == NULL) {
726*5c51f124SMoriah Waterland 					/*
727*5c51f124SMoriah Waterland 					 * Error already on stack
728*5c51f124SMoriah Waterland 					 */
729*5c51f124SMoriah Waterland 					goto err_ret;
730*5c51f124SMoriah Waterland 				}
731*5c51f124SMoriah Waterland 				if (PKCS12_add_friendlyname_asc(
732*5c51f124SMoriah Waterland 				    bag, (char const *) str,
733*5c51f124SMoriah Waterland 				    strlen((char const *) str)) == 0) {
734*5c51f124SMoriah Waterland 					SUNWerr(SUNW_F_PKCS12_CREATE,
735*5c51f124SMoriah Waterland 					    SUNW_R_ADD_ATTR_ERR);
736*5c51f124SMoriah Waterland 					goto err_ret;
737*5c51f124SMoriah Waterland 				}
738*5c51f124SMoriah Waterland 			}
739*5c51f124SMoriah Waterland 			if (cert->aux != NULL && cert->aux->keyid != NULL &&
740*5c51f124SMoriah Waterland 			    cert->aux->keyid->type == V_ASN1_OCTET_STRING) {
741*5c51f124SMoriah Waterland 				str = cert->aux->keyid->data;
742*5c51f124SMoriah Waterland 				len = cert->aux->keyid->length;
743*5c51f124SMoriah Waterland 
744*5c51f124SMoriah Waterland 				if (str != NULL &&
745*5c51f124SMoriah Waterland 				    PKCS12_add_localkeyid(bag, str, len) == 0) {
746*5c51f124SMoriah Waterland 					SUNWerr(SUNW_F_PKCS12_CREATE,
747*5c51f124SMoriah Waterland 					    SUNW_R_ADD_ATTR_ERR);
748*5c51f124SMoriah Waterland 					goto err_ret;
749*5c51f124SMoriah Waterland 				}
750*5c51f124SMoriah Waterland 			}
751*5c51f124SMoriah Waterland 			if (sk_PKCS12_SAFEBAG_push(bags, bag) == 0) {
752*5c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PKCS12_CREATE,
753*5c51f124SMoriah Waterland 				    SUNW_R_MEMORY_FAILURE);
754*5c51f124SMoriah Waterland 				goto err_ret;
755*5c51f124SMoriah Waterland 			}
756*5c51f124SMoriah Waterland 			certs_there++;
757*5c51f124SMoriah Waterland 			bag = NULL;
758*5c51f124SMoriah Waterland 		}
759*5c51f124SMoriah Waterland 	}
760*5c51f124SMoriah Waterland 
761*5c51f124SMoriah Waterland 	if (certs != NULL || cacerts != NULL && certs_there) {
762*5c51f124SMoriah Waterland 		/* Turn certbags into encrypted authsafe */
763*5c51f124SMoriah Waterland 		authsafe = PKCS12_pack_p7encdata(nid_cert, pass, -1,
764*5c51f124SMoriah Waterland 		    NULL, 0, PKCS12_DEFAULT_ITER, bags);
765*5c51f124SMoriah Waterland 		if (authsafe == NULL) {
766*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_CERT_ERR);
767*5c51f124SMoriah Waterland 			goto err_ret;
768*5c51f124SMoriah Waterland 		}
769*5c51f124SMoriah Waterland 		sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
770*5c51f124SMoriah Waterland 		bags = NULL;
771*5c51f124SMoriah Waterland 
772*5c51f124SMoriah Waterland 		if (sk_PKCS7_push(safes, authsafe) == 0) {
773*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_MEMORY_FAILURE);
774*5c51f124SMoriah Waterland 			goto err_ret;
775*5c51f124SMoriah Waterland 		}
776*5c51f124SMoriah Waterland 		authsafe = NULL;
777*5c51f124SMoriah Waterland 	}
778*5c51f124SMoriah Waterland 
779*5c51f124SMoriah Waterland 	if (pkeys != NULL && sk_EVP_PKEY_num(pkeys) > 0) {
780*5c51f124SMoriah Waterland 
781*5c51f124SMoriah Waterland 		if (bags == NULL &&
782*5c51f124SMoriah Waterland 		    (bags = sk_PKCS12_SAFEBAG_new_null()) == NULL) {
783*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_MEMORY_FAILURE);
784*5c51f124SMoriah Waterland 			goto err_ret;
785*5c51f124SMoriah Waterland 		}
786*5c51f124SMoriah Waterland 
787*5c51f124SMoriah Waterland 		for (i = 0; i < sk_EVP_PKEY_num(pkeys); i++) {
788*5c51f124SMoriah Waterland 
789*5c51f124SMoriah Waterland 			pkey = sk_EVP_PKEY_value(pkeys, i);
790*5c51f124SMoriah Waterland 
791*5c51f124SMoriah Waterland 			/* Make a shrouded key bag */
792*5c51f124SMoriah Waterland 			if ((p8 = EVP_PKEY2PKCS8(pkey)) == NULL) {
793*5c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_PKEY_ERR);
794*5c51f124SMoriah Waterland 				goto err_ret;
795*5c51f124SMoriah Waterland 			}
796*5c51f124SMoriah Waterland 
797*5c51f124SMoriah Waterland 			bag = PKCS12_MAKE_SHKEYBAG(nid_key, pass, -1, NULL, 0,
798*5c51f124SMoriah Waterland 			    PKCS12_DEFAULT_ITER, p8);
799*5c51f124SMoriah Waterland 			if (bag == NULL) {
800*5c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PKCS12_CREATE,
801*5c51f124SMoriah Waterland 				    SUNW_R_MAKE_BAG_ERR);
802*5c51f124SMoriah Waterland 				goto err_ret;
803*5c51f124SMoriah Waterland 			}
804*5c51f124SMoriah Waterland 			PKCS8_PRIV_KEY_INFO_free(p8);
805*5c51f124SMoriah Waterland 			p8 = NULL;
806*5c51f124SMoriah Waterland 
807*5c51f124SMoriah Waterland 			len = sunw_get_pkey_fname(GETDO_COPY, pkey,
808*5c51f124SMoriah Waterland 			    (char **)&str);
809*5c51f124SMoriah Waterland 			if (str != NULL) {
810*5c51f124SMoriah Waterland 				if (PKCS12_add_friendlyname_asc(bag,
811*5c51f124SMoriah Waterland 				    (const char *)str, len) == 0) {
812*5c51f124SMoriah Waterland 					SUNWerr(SUNW_F_PKCS12_CREATE,
813*5c51f124SMoriah Waterland 					    SUNW_R_ADD_ATTR_ERR);
814*5c51f124SMoriah Waterland 					goto err_ret;
815*5c51f124SMoriah Waterland 				}
816*5c51f124SMoriah Waterland 			}
817*5c51f124SMoriah Waterland 			str = NULL;
818*5c51f124SMoriah Waterland 
819*5c51f124SMoriah Waterland 			len = sunw_get_pkey_localkeyid(GETDO_COPY, pkey,
820*5c51f124SMoriah Waterland 			    (char **)&str, &len);
821*5c51f124SMoriah Waterland 			if (str != NULL) {
822*5c51f124SMoriah Waterland 				if (PKCS12_add_localkeyid(bag, str, len) == 0) {
823*5c51f124SMoriah Waterland 					SUNWerr(SUNW_F_PKCS12_CREATE,
824*5c51f124SMoriah Waterland 					    SUNW_R_ADD_ATTR_ERR);
825*5c51f124SMoriah Waterland 					goto err_ret;
826*5c51f124SMoriah Waterland 				}
827*5c51f124SMoriah Waterland 			}
828*5c51f124SMoriah Waterland 			str = NULL;
829*5c51f124SMoriah Waterland 
830*5c51f124SMoriah Waterland 			if (sk_PKCS12_SAFEBAG_push(bags, bag) == 0) {
831*5c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PKCS12_CREATE,
832*5c51f124SMoriah Waterland 				    SUNW_R_MEMORY_FAILURE);
833*5c51f124SMoriah Waterland 				goto err_ret;
834*5c51f124SMoriah Waterland 			}
835*5c51f124SMoriah Waterland 			keys_there++;
836*5c51f124SMoriah Waterland 			bag = NULL;
837*5c51f124SMoriah Waterland 		}
838*5c51f124SMoriah Waterland 
839*5c51f124SMoriah Waterland 		if (keys_there) {
840*5c51f124SMoriah Waterland 			/* Turn into unencrypted authsafe */
841*5c51f124SMoriah Waterland 			authsafe = PKCS12_pack_p7data(bags);
842*5c51f124SMoriah Waterland 			if (authsafe == NULL) {
843*5c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PKCS12_CREATE,
844*5c51f124SMoriah Waterland 				    SUNW_R_PKCS12_CREATE_ERR);
845*5c51f124SMoriah Waterland 				goto err_ret;
846*5c51f124SMoriah Waterland 			}
847*5c51f124SMoriah Waterland 			sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
848*5c51f124SMoriah Waterland 			bags = NULL;
849*5c51f124SMoriah Waterland 
850*5c51f124SMoriah Waterland 			if (sk_PKCS7_push(safes, authsafe) == 0) {
851*5c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PKCS12_CREATE,
852*5c51f124SMoriah Waterland 				    SUNW_R_MEMORY_FAILURE);
853*5c51f124SMoriah Waterland 			}
854*5c51f124SMoriah Waterland 			authsafe = NULL;
855*5c51f124SMoriah Waterland 		}
856*5c51f124SMoriah Waterland 	}
857*5c51f124SMoriah Waterland 
858*5c51f124SMoriah Waterland 	if (certs_there == 0 && keys_there == 0) {
859*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_PKCS12_EMPTY_ERR);
860*5c51f124SMoriah Waterland 		goto err_ret;
861*5c51f124SMoriah Waterland 	}
862*5c51f124SMoriah Waterland 
863*5c51f124SMoriah Waterland 	if ((p12 = PKCS12_init(NID_pkcs7_data)) == NULL) {
864*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_PKCS12_CREATE_ERR);
865*5c51f124SMoriah Waterland 		goto err_ret;
866*5c51f124SMoriah Waterland 	}
867*5c51f124SMoriah Waterland 
868*5c51f124SMoriah Waterland 	/*
869*5c51f124SMoriah Waterland 	 * Note that safes is copied by the following.  Therefore, it needs
870*5c51f124SMoriah Waterland 	 * to be freed whether or not the following succeeds.
871*5c51f124SMoriah Waterland 	 */
872*5c51f124SMoriah Waterland 	if (M_PKCS12_pack_authsafes(p12, safes) == 0) {
873*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_PKCS12_CREATE_ERR);
874*5c51f124SMoriah Waterland 		goto err_ret;
875*5c51f124SMoriah Waterland 	}
876*5c51f124SMoriah Waterland 	if (PKCS12_set_mac(p12, pass, -1, NULL, 0, 2048, NULL) == 0) {
877*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PKCS12_CREATE, SUNW_R_MAC_CREATE_FAILURE);
878*5c51f124SMoriah Waterland 		goto err_ret;
879*5c51f124SMoriah Waterland 	}
880*5c51f124SMoriah Waterland 
881*5c51f124SMoriah Waterland 	ret_p12 = p12;
882*5c51f124SMoriah Waterland 	p12 = NULL;
883*5c51f124SMoriah Waterland 
884*5c51f124SMoriah Waterland 	/* Fallthrough is intentional */
885*5c51f124SMoriah Waterland 
886*5c51f124SMoriah Waterland err_ret:
887*5c51f124SMoriah Waterland 
888*5c51f124SMoriah Waterland 	if (str != NULL)
889*5c51f124SMoriah Waterland 		free(str);
890*5c51f124SMoriah Waterland 
891*5c51f124SMoriah Waterland 	if (p8 != NULL)
892*5c51f124SMoriah Waterland 		PKCS8_PRIV_KEY_INFO_free(p8);
893*5c51f124SMoriah Waterland 
894*5c51f124SMoriah Waterland 	if (bag != NULL)
895*5c51f124SMoriah Waterland 		PKCS12_SAFEBAG_free(bag);
896*5c51f124SMoriah Waterland 	if (bags != NULL)
897*5c51f124SMoriah Waterland 		sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
898*5c51f124SMoriah Waterland 	if (authsafe != NULL)
899*5c51f124SMoriah Waterland 		PKCS7_free(authsafe);
900*5c51f124SMoriah Waterland 	if (safes != NULL)
901*5c51f124SMoriah Waterland 		sk_PKCS7_pop_free(safes, PKCS7_free);
902*5c51f124SMoriah Waterland 	if (p12 != NULL)
903*5c51f124SMoriah Waterland 		PKCS12_free(p12);
904*5c51f124SMoriah Waterland 
905*5c51f124SMoriah Waterland 	return (ret_p12);
906*5c51f124SMoriah Waterland }
907*5c51f124SMoriah Waterland 
908*5c51f124SMoriah Waterland /*
909*5c51f124SMoriah Waterland  * sunw_evp_pkey_free() Given an EVP_PKEY structure, free any attributes
910*5c51f124SMoriah Waterland  *     that are attached.  Then free the EVP_PKEY itself.
911*5c51f124SMoriah Waterland  *
912*5c51f124SMoriah Waterland  *     This is a replacement for EVP_PKEY_free() for the sunw stuff.
913*5c51f124SMoriah Waterland  *     It should be used in places where EVP_PKEY_free would be used,
914*5c51f124SMoriah Waterland  *     including calls to sk_EVP_PKEY_pop_free().
915*5c51f124SMoriah Waterland  *
916*5c51f124SMoriah Waterland  * Arguments:
917*5c51f124SMoriah Waterland  *   pkey     - Entry which potentially has attributes to be freed.
918*5c51f124SMoriah Waterland  *
919*5c51f124SMoriah Waterland  * Returns:
920*5c51f124SMoriah Waterland  *   None.
921*5c51f124SMoriah Waterland  */
922*5c51f124SMoriah Waterland void
923*5c51f124SMoriah Waterland sunw_evp_pkey_free(EVP_PKEY *pkey)
924*5c51f124SMoriah Waterland {
925*5c51f124SMoriah Waterland 	if (pkey != NULL) {
926*5c51f124SMoriah Waterland 		if (pkey->attributes != NULL) {
927*5c51f124SMoriah Waterland 			sk_X509_ATTRIBUTE_pop_free(pkey->attributes,
928*5c51f124SMoriah Waterland 			    X509_ATTRIBUTE_free);
929*5c51f124SMoriah Waterland 			pkey->attributes = NULL;
930*5c51f124SMoriah Waterland 		}
931*5c51f124SMoriah Waterland 		EVP_PKEY_free(pkey);
932*5c51f124SMoriah Waterland 	}
933*5c51f124SMoriah Waterland }
934*5c51f124SMoriah Waterland 
935*5c51f124SMoriah Waterland /*
936*5c51f124SMoriah Waterland  * sunw_set_localkeyid() sets the localkeyid in a cert, a private key or
937*5c51f124SMoriah Waterland  *     both.  Any existing localkeyid will be discarded.
938*5c51f124SMoriah Waterland  *
939*5c51f124SMoriah Waterland  * Arguments:
940*5c51f124SMoriah Waterland  *   keyid_str- A byte string with the localkeyid to set
941*5c51f124SMoriah Waterland  *   keyid_len- Length of the keyid byte string.
942*5c51f124SMoriah Waterland  *   pkey     - Points to a private key to set the keyidstr in.
943*5c51f124SMoriah Waterland  *   cert     - Points to a cert to set the keyidstr in.
944*5c51f124SMoriah Waterland  *
945*5c51f124SMoriah Waterland  * Note that setting a keyid into a cert which will not be written out as
946*5c51f124SMoriah Waterland  * a PKCS12 cert is pointless since it will be lost.
947*5c51f124SMoriah Waterland  *
948*5c51f124SMoriah Waterland  * Returns:
949*5c51f124SMoriah Waterland  *   0        - Success.
950*5c51f124SMoriah Waterland  *   < 0      - An error occurred.  It was probably an error in allocating
951*5c51f124SMoriah Waterland  *              memory.  The error will be set in the error stack.  Call
952*5c51f124SMoriah Waterland  *              ERR_get_error() to get specific information.
953*5c51f124SMoriah Waterland  */
954*5c51f124SMoriah Waterland int
955*5c51f124SMoriah Waterland sunw_set_localkeyid(const char *keyid_str, int keyid_len, EVP_PKEY *pkey,
956*5c51f124SMoriah Waterland     X509 *cert)
957*5c51f124SMoriah Waterland {
958*5c51f124SMoriah Waterland 	X509_ATTRIBUTE *attr = NULL;
959*5c51f124SMoriah Waterland 	ASN1_STRING *str = NULL;
960*5c51f124SMoriah Waterland 	ASN1_TYPE *keyid = NULL;
961*5c51f124SMoriah Waterland 	int retval = -1;
962*5c51f124SMoriah Waterland 	int i;
963*5c51f124SMoriah Waterland 
964*5c51f124SMoriah Waterland 	if (cert != NULL) {
965*5c51f124SMoriah Waterland 		if (X509_keyid_set1(cert, (uchar_t *)keyid_str, keyid_len)
966*5c51f124SMoriah Waterland 		    == 0) {
967*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_SET_LOCALKEYID, SUNW_R_SET_LKID_ERR);
968*5c51f124SMoriah Waterland 			goto cleanup;
969*5c51f124SMoriah Waterland 		}
970*5c51f124SMoriah Waterland 	}
971*5c51f124SMoriah Waterland 	if (pkey != NULL) {
972*5c51f124SMoriah Waterland 		str = (ASN1_STRING *)M_ASN1_OCTET_STRING_new();
973*5c51f124SMoriah Waterland 		if (str == NULL ||
974*5c51f124SMoriah Waterland 		    M_ASN1_OCTET_STRING_set(str, keyid_str, keyid_len) == 0 ||
975*5c51f124SMoriah Waterland 		    (keyid = ASN1_TYPE_new()) == NULL) {
976*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_SET_LOCALKEYID, SUNW_R_MEMORY_FAILURE);
977*5c51f124SMoriah Waterland 			goto cleanup;
978*5c51f124SMoriah Waterland 		}
979*5c51f124SMoriah Waterland 
980*5c51f124SMoriah Waterland 		ASN1_TYPE_set(keyid, V_ASN1_OCTET_STRING, str);
981*5c51f124SMoriah Waterland 		str = NULL;
982*5c51f124SMoriah Waterland 
983*5c51f124SMoriah Waterland 		attr = type2attrib(keyid, NID_localKeyID);
984*5c51f124SMoriah Waterland 		if (attr == NULL) {
985*5c51f124SMoriah Waterland 			/*
986*5c51f124SMoriah Waterland 			 * Error already on stack
987*5c51f124SMoriah Waterland 			 */
988*5c51f124SMoriah Waterland 			goto cleanup;
989*5c51f124SMoriah Waterland 		}
990*5c51f124SMoriah Waterland 		keyid = NULL;
991*5c51f124SMoriah Waterland 
992*5c51f124SMoriah Waterland 		if (pkey->attributes == NULL) {
993*5c51f124SMoriah Waterland 			pkey->attributes = sk_X509_ATTRIBUTE_new_null();
994*5c51f124SMoriah Waterland 			if (pkey->attributes == NULL) {
995*5c51f124SMoriah Waterland 				SUNWerr(SUNW_F_SET_LOCALKEYID,
996*5c51f124SMoriah Waterland 				    SUNW_R_MEMORY_FAILURE);
997*5c51f124SMoriah Waterland 				goto cleanup;
998*5c51f124SMoriah Waterland 			}
999*5c51f124SMoriah Waterland 		} else {
1000*5c51f124SMoriah Waterland 			i = find_attr_by_nid(pkey->attributes, NID_localKeyID);
1001*5c51f124SMoriah Waterland 			if (i >= 0)
1002*5c51f124SMoriah Waterland 				sk_X509_ATTRIBUTE_delete(pkey->attributes, i);
1003*5c51f124SMoriah Waterland 		}
1004*5c51f124SMoriah Waterland 		if (sk_X509_ATTRIBUTE_push(pkey->attributes, attr) == 0) {
1005*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_SET_LOCALKEYID, SUNW_R_MEMORY_FAILURE);
1006*5c51f124SMoriah Waterland 			goto cleanup;
1007*5c51f124SMoriah Waterland 		}
1008*5c51f124SMoriah Waterland 		attr = NULL;
1009*5c51f124SMoriah Waterland 	}
1010*5c51f124SMoriah Waterland 	retval = 0;
1011*5c51f124SMoriah Waterland 
1012*5c51f124SMoriah Waterland cleanup:
1013*5c51f124SMoriah Waterland 	if (str != NULL)
1014*5c51f124SMoriah Waterland 		ASN1_STRING_free(str);
1015*5c51f124SMoriah Waterland 	if (keyid != NULL)
1016*5c51f124SMoriah Waterland 		ASN1_TYPE_free(keyid);
1017*5c51f124SMoriah Waterland 	if (attr != NULL)
1018*5c51f124SMoriah Waterland 		X509_ATTRIBUTE_free(attr);
1019*5c51f124SMoriah Waterland 
1020*5c51f124SMoriah Waterland 	return (retval);
1021*5c51f124SMoriah Waterland }
1022*5c51f124SMoriah Waterland 
1023*5c51f124SMoriah Waterland /*
1024*5c51f124SMoriah Waterland  * sunw_get_pkey_localkeyid() gets the localkeyid from a private key.  It can
1025*5c51f124SMoriah Waterland  *     optionally remove the value found.
1026*5c51f124SMoriah Waterland  *
1027*5c51f124SMoriah Waterland  * Arguments:
1028*5c51f124SMoriah Waterland  *   dowhat   - What to do with the attributes (remove them or copy them).
1029*5c51f124SMoriah Waterland  *   pkey     - Points to a private key to set the keyidstr in.
1030*5c51f124SMoriah Waterland  *   keyid_str- Points to a location which will receive the pointer to
1031*5c51f124SMoriah Waterland  *              a byte string containing the binary localkeyid.  Note that
1032*5c51f124SMoriah Waterland  *              this is a copy, and the caller must free it.
1033*5c51f124SMoriah Waterland  *   keyid_len- Length of keyid_str.
1034*5c51f124SMoriah Waterland  *
1035*5c51f124SMoriah Waterland  * Returns:
1036*5c51f124SMoriah Waterland  *   >= 0     - The number of characters in the keyid returned.
1037*5c51f124SMoriah Waterland  *   < 0      - An error occurred.  It was probably an error in allocating
1038*5c51f124SMoriah Waterland  *              memory.  The error will be set in the error stack.  Call
1039*5c51f124SMoriah Waterland  *              ERR_get_error() to get specific information.
1040*5c51f124SMoriah Waterland  */
1041*5c51f124SMoriah Waterland int
1042*5c51f124SMoriah Waterland sunw_get_pkey_localkeyid(getdo_actions_t dowhat, EVP_PKEY *pkey,
1043*5c51f124SMoriah Waterland     char **keyid_str, int *keyid_len)
1044*5c51f124SMoriah Waterland {
1045*5c51f124SMoriah Waterland 	X509_ATTRIBUTE *attr = NULL;
1046*5c51f124SMoriah Waterland 	ASN1_OCTET_STRING *str = NULL;
1047*5c51f124SMoriah Waterland 	ASN1_TYPE *ty = NULL;
1048*5c51f124SMoriah Waterland 	int len = 0;
1049*5c51f124SMoriah Waterland 	int i;
1050*5c51f124SMoriah Waterland 
1051*5c51f124SMoriah Waterland 	if (keyid_str != NULL)
1052*5c51f124SMoriah Waterland 		*keyid_str = NULL;
1053*5c51f124SMoriah Waterland 	if (keyid_len != NULL)
1054*5c51f124SMoriah Waterland 		*keyid_len = 0;
1055*5c51f124SMoriah Waterland 
1056*5c51f124SMoriah Waterland 	if (pkey == NULL || pkey->attributes == NULL) {
1057*5c51f124SMoriah Waterland 		return (0);
1058*5c51f124SMoriah Waterland 	}
1059*5c51f124SMoriah Waterland 
1060*5c51f124SMoriah Waterland 	if ((i = find_attr_by_nid(pkey->attributes, NID_localKeyID)) < 0) {
1061*5c51f124SMoriah Waterland 		return (0);
1062*5c51f124SMoriah Waterland 	}
1063*5c51f124SMoriah Waterland 	attr = sk_X509_ATTRIBUTE_value(pkey->attributes, i);
1064*5c51f124SMoriah Waterland 
1065*5c51f124SMoriah Waterland 	if ((ty = attrib2type(attr)) == NULL ||
1066*5c51f124SMoriah Waterland 	    ty->type != V_ASN1_OCTET_STRING) {
1067*5c51f124SMoriah Waterland 		return (0);
1068*5c51f124SMoriah Waterland 	}
1069*5c51f124SMoriah Waterland 
1070*5c51f124SMoriah Waterland 	if (dowhat == GETDO_DEL) {
1071*5c51f124SMoriah Waterland 		attr = sk_X509_ATTRIBUTE_delete(pkey->attributes, i);
1072*5c51f124SMoriah Waterland 		if (attr != NULL)
1073*5c51f124SMoriah Waterland 			X509_ATTRIBUTE_free(attr);
1074*5c51f124SMoriah Waterland 		return (0);
1075*5c51f124SMoriah Waterland 	}
1076*5c51f124SMoriah Waterland 
1077*5c51f124SMoriah Waterland 	str = ty->value.octet_string;
1078*5c51f124SMoriah Waterland 	len = str->length;
1079*5c51f124SMoriah Waterland 	if ((*keyid_str = malloc(len)) == NULL) {
1080*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_GET_LOCALKEYID, SUNW_R_MEMORY_FAILURE);
1081*5c51f124SMoriah Waterland 		return (-1);
1082*5c51f124SMoriah Waterland 	}
1083*5c51f124SMoriah Waterland 
1084*5c51f124SMoriah Waterland 	(void) memcpy(*keyid_str, str->data, len);
1085*5c51f124SMoriah Waterland 	*keyid_len = len;
1086*5c51f124SMoriah Waterland 
1087*5c51f124SMoriah Waterland 	return (len);
1088*5c51f124SMoriah Waterland }
1089*5c51f124SMoriah Waterland 
1090*5c51f124SMoriah Waterland /*
1091*5c51f124SMoriah Waterland  * sunw_get_pkey_fname() gets the friendlyName from a private key.  It can
1092*5c51f124SMoriah Waterland  *     optionally remove the value found.
1093*5c51f124SMoriah Waterland  *
1094*5c51f124SMoriah Waterland  * Arguments:
1095*5c51f124SMoriah Waterland  *   dowhat   - What to do with the attributes (remove them or copy them).
1096*5c51f124SMoriah Waterland  *   pkey     - Points to a private key to get the frientlyname from
1097*5c51f124SMoriah Waterland  *   fname    - Points to a location which will receive the pointer to a
1098*5c51f124SMoriah Waterland  *              byte string with the ASCII friendlyname
1099*5c51f124SMoriah Waterland  *
1100*5c51f124SMoriah Waterland  * Returns:
1101*5c51f124SMoriah Waterland  *   >= 0     - The number of characters in the frienlyname returned.
1102*5c51f124SMoriah Waterland  *   < 0      - An error occurred.  It was probably an error in allocating
1103*5c51f124SMoriah Waterland  *              memory.  The error will be set in the error stack.  Call
1104*5c51f124SMoriah Waterland  *              ERR_get_error() to get specific information.
1105*5c51f124SMoriah Waterland  */
1106*5c51f124SMoriah Waterland int
1107*5c51f124SMoriah Waterland sunw_get_pkey_fname(getdo_actions_t dowhat, EVP_PKEY *pkey, char **fname)
1108*5c51f124SMoriah Waterland {
1109*5c51f124SMoriah Waterland 	X509_ATTRIBUTE *attr = NULL;
1110*5c51f124SMoriah Waterland 	ASN1_BMPSTRING *str = NULL;
1111*5c51f124SMoriah Waterland 	ASN1_TYPE *ty = NULL;
1112*5c51f124SMoriah Waterland 	int len = 0;
1113*5c51f124SMoriah Waterland 	int i;
1114*5c51f124SMoriah Waterland 
1115*5c51f124SMoriah Waterland 	if (fname != NULL)
1116*5c51f124SMoriah Waterland 		*fname = NULL;
1117*5c51f124SMoriah Waterland 
1118*5c51f124SMoriah Waterland 	if (pkey == NULL || pkey->attributes == NULL) {
1119*5c51f124SMoriah Waterland 		return (0);
1120*5c51f124SMoriah Waterland 	}
1121*5c51f124SMoriah Waterland 
1122*5c51f124SMoriah Waterland 	if ((i = find_attr_by_nid(pkey->attributes, NID_friendlyName)) < 0) {
1123*5c51f124SMoriah Waterland 		return (0);
1124*5c51f124SMoriah Waterland 	}
1125*5c51f124SMoriah Waterland 	attr = sk_X509_ATTRIBUTE_value(pkey->attributes, i);
1126*5c51f124SMoriah Waterland 
1127*5c51f124SMoriah Waterland 	if ((ty = attrib2type(attr)) == NULL ||
1128*5c51f124SMoriah Waterland 	    ty->type != V_ASN1_BMPSTRING) {
1129*5c51f124SMoriah Waterland 		return (0);
1130*5c51f124SMoriah Waterland 	}
1131*5c51f124SMoriah Waterland 
1132*5c51f124SMoriah Waterland 	if (dowhat == GETDO_DEL) {
1133*5c51f124SMoriah Waterland 		attr = sk_X509_ATTRIBUTE_delete(pkey->attributes, i);
1134*5c51f124SMoriah Waterland 		if (attr != NULL)
1135*5c51f124SMoriah Waterland 			X509_ATTRIBUTE_free(attr);
1136*5c51f124SMoriah Waterland 		return (0);
1137*5c51f124SMoriah Waterland 	}
1138*5c51f124SMoriah Waterland 
1139*5c51f124SMoriah Waterland 	str = ty->value.bmpstring;
1140*5c51f124SMoriah Waterland 	*fname = uni2asc(str->data, str->length);
1141*5c51f124SMoriah Waterland 	if (*fname == NULL) {
1142*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_GET_PKEY_FNAME, SUNW_R_MEMORY_FAILURE);
1143*5c51f124SMoriah Waterland 		return (-1);
1144*5c51f124SMoriah Waterland 	}
1145*5c51f124SMoriah Waterland 
1146*5c51f124SMoriah Waterland 	len = strlen(*fname);
1147*5c51f124SMoriah Waterland 
1148*5c51f124SMoriah Waterland 	return (len);
1149*5c51f124SMoriah Waterland }
1150*5c51f124SMoriah Waterland 
1151*5c51f124SMoriah Waterland /*
1152*5c51f124SMoriah Waterland  * sunw_find_localkeyid() searches stacks of certs and private keys,
1153*5c51f124SMoriah Waterland  *     and returns  the first matching cert/private key found.
1154*5c51f124SMoriah Waterland  *
1155*5c51f124SMoriah Waterland  * Look for a keyid in a stack of certs.  if 'certs' is NULL and 'pkeys' is
1156*5c51f124SMoriah Waterland  * not NULL, search the list of private keys.  Move the matching cert to
1157*5c51f124SMoriah Waterland  * 'matching_cert' and its matching private key to 'matching_pkey'.  If no
1158*5c51f124SMoriah Waterland  * cert or keys match, no match occurred.
1159*5c51f124SMoriah Waterland  *
1160*5c51f124SMoriah Waterland  * Arguments:
1161*5c51f124SMoriah Waterland  *   keyid_str- A byte string with the localkeyid to match
1162*5c51f124SMoriah Waterland  *   keyid_len- Length of the keyid byte string.
1163*5c51f124SMoriah Waterland  *   pkeys    - Points to a stack of private keys which match the certs.
1164*5c51f124SMoriah Waterland  *              This may be NULL, in which case no keys are returned.
1165*5c51f124SMoriah Waterland  *   certs    - Points to a stack of certs to search.  If NULL, search the
1166*5c51f124SMoriah Waterland  *              stack of keys instead.
1167*5c51f124SMoriah Waterland  *   matching_pkey
1168*5c51f124SMoriah Waterland  *            - Pointer to receive address of first matching pkey found.
1169*5c51f124SMoriah Waterland  *              'matching_pkey' must not be NULL; '*matching_pkey' will be
1170*5c51f124SMoriah Waterland  *              reset.
1171*5c51f124SMoriah Waterland  *   matching_cert
1172*5c51f124SMoriah Waterland  *            - Pointer to receive address of first matching cert found.
1173*5c51f124SMoriah Waterland  *              'matching_cert' must not be NULL; '*matching_cert' will be
1174*5c51f124SMoriah Waterland  *              reset.
1175*5c51f124SMoriah Waterland  *
1176*5c51f124SMoriah Waterland  * Returns:
1177*5c51f124SMoriah Waterland  *  <  0 - An error returned.  Call ERR_get_error() to get errors information.
1178*5c51f124SMoriah Waterland  *         Where possible, memory has been freed.
1179*5c51f124SMoriah Waterland  *  >= 0 - Objects were found and returned.  Which objects are indicated by
1180*5c51f124SMoriah Waterland  *         which bits are set (FOUND_PKEY and/or FOUND_CERT).
1181*5c51f124SMoriah Waterland  */
1182*5c51f124SMoriah Waterland int
1183*5c51f124SMoriah Waterland sunw_find_localkeyid(char *keyid_str, int len, STACK_OF(EVP_PKEY) *pkeys,
1184*5c51f124SMoriah Waterland STACK_OF(X509) *certs, EVP_PKEY **matching_pkey, X509 **matching_cert)
1185*5c51f124SMoriah Waterland {
1186*5c51f124SMoriah Waterland 	ASN1_STRING *cmpstr = NULL;
1187*5c51f124SMoriah Waterland 	EVP_PKEY *tmp_pkey = NULL;
1188*5c51f124SMoriah Waterland 	X509 *tmp_cert = NULL;
1189*5c51f124SMoriah Waterland 	int retval = 0;
1190*5c51f124SMoriah Waterland 
1191*5c51f124SMoriah Waterland 	/* If NULL arguments, this is an error */
1192*5c51f124SMoriah Waterland 	if (keyid_str == NULL ||
1193*5c51f124SMoriah Waterland 	    (pkeys == NULL || certs == NULL) ||
1194*5c51f124SMoriah Waterland 	    (pkeys != NULL && matching_pkey == NULL) ||
1195*5c51f124SMoriah Waterland 	    (certs != NULL && matching_cert == NULL)) {
1196*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_FIND_LOCALKEYID, SUNW_R_INVALID_ARG);
1197*5c51f124SMoriah Waterland 		return (-1);
1198*5c51f124SMoriah Waterland 	}
1199*5c51f124SMoriah Waterland 
1200*5c51f124SMoriah Waterland 	if (matching_pkey != NULL)
1201*5c51f124SMoriah Waterland 		*matching_pkey = NULL;
1202*5c51f124SMoriah Waterland 	if (matching_cert != NULL)
1203*5c51f124SMoriah Waterland 		*matching_cert = NULL;
1204*5c51f124SMoriah Waterland 
1205*5c51f124SMoriah Waterland 	cmpstr = (ASN1_STRING *)M_ASN1_OCTET_STRING_new();
1206*5c51f124SMoriah Waterland 	if (cmpstr == NULL ||
1207*5c51f124SMoriah Waterland 	    M_ASN1_OCTET_STRING_set(cmpstr, keyid_str, len) == 0) {
1208*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_FIND_LOCALKEYID, SUNW_R_MEMORY_FAILURE);
1209*5c51f124SMoriah Waterland 		return (-1);
1210*5c51f124SMoriah Waterland 	}
1211*5c51f124SMoriah Waterland 
1212*5c51f124SMoriah Waterland 	retval = find_attr(NID_localKeyID, cmpstr, pkeys, &tmp_pkey, certs,
1213*5c51f124SMoriah Waterland 	    &tmp_cert);
1214*5c51f124SMoriah Waterland 	if (retval == 0) {
1215*5c51f124SMoriah Waterland 		ASN1_STRING_free(cmpstr);
1216*5c51f124SMoriah Waterland 		return (retval);
1217*5c51f124SMoriah Waterland 	}
1218*5c51f124SMoriah Waterland 
1219*5c51f124SMoriah Waterland 	if (matching_pkey != NULL)
1220*5c51f124SMoriah Waterland 		*matching_pkey = tmp_pkey;
1221*5c51f124SMoriah Waterland 	if (matching_cert != NULL)
1222*5c51f124SMoriah Waterland 		*matching_cert = tmp_cert;
1223*5c51f124SMoriah Waterland 
1224*5c51f124SMoriah Waterland 	return (retval);
1225*5c51f124SMoriah Waterland }
1226*5c51f124SMoriah Waterland 
1227*5c51f124SMoriah Waterland /*
1228*5c51f124SMoriah Waterland  * sunw_find_fname() searches stacks of certs and private keys for one with
1229*5c51f124SMoriah Waterland  *     a matching friendlyname and returns the first matching cert/private
1230*5c51f124SMoriah Waterland  *     key found.
1231*5c51f124SMoriah Waterland  *
1232*5c51f124SMoriah Waterland  * Look for a friendlyname in a stack of certs.  if 'certs' is NULL and 'pkeys'
1233*5c51f124SMoriah Waterland  * is not NULL, search the list of private keys.  Move the matching cert to
1234*5c51f124SMoriah Waterland  * 'matching_cert' and its matching private key to 'matching_pkey'.  If no
1235*5c51f124SMoriah Waterland  * cert or keys match, no match occurred.
1236*5c51f124SMoriah Waterland  *
1237*5c51f124SMoriah Waterland  * Arguments:
1238*5c51f124SMoriah Waterland  *   fname    - Friendlyname to find (NULL-terminated ASCII string).
1239*5c51f124SMoriah Waterland  *   pkeys    - Points to a stack of private keys which match the certs.
1240*5c51f124SMoriah Waterland  *              This may be NULL, in which case no keys are returned.
1241*5c51f124SMoriah Waterland  *   certs    - Points to a stack of certs to search.  If NULL, search the
1242*5c51f124SMoriah Waterland  *              stack of keys instead.
1243*5c51f124SMoriah Waterland  *   matching_pkey
1244*5c51f124SMoriah Waterland  *            - Pointer to receive address of first matching pkey found.
1245*5c51f124SMoriah Waterland  *   matching_cert
1246*5c51f124SMoriah Waterland  *            - Pointer to receive address of first matching cert found.
1247*5c51f124SMoriah Waterland  *
1248*5c51f124SMoriah Waterland  * Returns:
1249*5c51f124SMoriah Waterland  *  <  0 - An error returned.  Call ERR_get_error() to get errors information.
1250*5c51f124SMoriah Waterland  *         Where possible, memory has been freed.
1251*5c51f124SMoriah Waterland  *  >= 0 - Objects were found and returned.  Which objects are indicated by
1252*5c51f124SMoriah Waterland  *         which bits are set (FOUND_PKEY and/or FOUND_CERT).
1253*5c51f124SMoriah Waterland  */
1254*5c51f124SMoriah Waterland int
1255*5c51f124SMoriah Waterland sunw_find_fname(char *fname, STACK_OF(EVP_PKEY) *pkeys, STACK_OF(X509) *certs,
1256*5c51f124SMoriah Waterland     EVP_PKEY **matching_pkey, X509 ** matching_cert)
1257*5c51f124SMoriah Waterland {
1258*5c51f124SMoriah Waterland 	ASN1_STRING *cmpstr = NULL;
1259*5c51f124SMoriah Waterland 	EVP_PKEY *tmp_pkey = NULL;
1260*5c51f124SMoriah Waterland 	X509 *tmp_cert = NULL;
1261*5c51f124SMoriah Waterland 	int retval = 0;
1262*5c51f124SMoriah Waterland 
1263*5c51f124SMoriah Waterland 	/* If NULL arguments, this is an error */
1264*5c51f124SMoriah Waterland 	if (fname == NULL ||
1265*5c51f124SMoriah Waterland 	    (pkeys == NULL && certs == NULL) ||
1266*5c51f124SMoriah Waterland 	    (pkeys != NULL && matching_pkey == NULL) ||
1267*5c51f124SMoriah Waterland 	    (certs != NULL && matching_cert == NULL)) {
1268*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_FIND_FNAME, SUNW_R_INVALID_ARG);
1269*5c51f124SMoriah Waterland 		return (-1);
1270*5c51f124SMoriah Waterland 	}
1271*5c51f124SMoriah Waterland 
1272*5c51f124SMoriah Waterland 	if (matching_pkey != NULL)
1273*5c51f124SMoriah Waterland 		*matching_pkey = NULL;
1274*5c51f124SMoriah Waterland 	if (matching_cert != NULL)
1275*5c51f124SMoriah Waterland 		*matching_cert = NULL;
1276*5c51f124SMoriah Waterland 
1277*5c51f124SMoriah Waterland 	cmpstr = (ASN1_STRING *)asc2bmpstring(fname, strlen(fname));
1278*5c51f124SMoriah Waterland 	if (cmpstr == NULL) {
1279*5c51f124SMoriah Waterland 		/*
1280*5c51f124SMoriah Waterland 		 * Error already on stack
1281*5c51f124SMoriah Waterland 		 */
1282*5c51f124SMoriah Waterland 		return (-1);
1283*5c51f124SMoriah Waterland 	}
1284*5c51f124SMoriah Waterland 
1285*5c51f124SMoriah Waterland 	retval = find_attr(NID_friendlyName, cmpstr, pkeys, &tmp_pkey, certs,
1286*5c51f124SMoriah Waterland 	    &tmp_cert);
1287*5c51f124SMoriah Waterland 	if (retval == 0) {
1288*5c51f124SMoriah Waterland 		ASN1_STRING_free(cmpstr);
1289*5c51f124SMoriah Waterland 		return (retval);
1290*5c51f124SMoriah Waterland 	}
1291*5c51f124SMoriah Waterland 
1292*5c51f124SMoriah Waterland 	if (matching_pkey != NULL)
1293*5c51f124SMoriah Waterland 		*matching_pkey = tmp_pkey;
1294*5c51f124SMoriah Waterland 	if (matching_cert != NULL)
1295*5c51f124SMoriah Waterland 		*matching_cert = tmp_cert;
1296*5c51f124SMoriah Waterland 
1297*5c51f124SMoriah Waterland 	return (retval);
1298*5c51f124SMoriah Waterland }
1299*5c51f124SMoriah Waterland 
1300*5c51f124SMoriah Waterland /*
1301*5c51f124SMoriah Waterland  * sunw_get_cert_fname() gets the fiendlyname from a cert.  It can
1302*5c51f124SMoriah Waterland  *     optionally remove the value found.
1303*5c51f124SMoriah Waterland  *
1304*5c51f124SMoriah Waterland  * Arguments:
1305*5c51f124SMoriah Waterland  *   dowhat   - What to do with the attributes (remove them or copy them).
1306*5c51f124SMoriah Waterland  *   cert     - Points to a cert to get the friendlyName from.
1307*5c51f124SMoriah Waterland  *   fname    - Points to a location which will receive the pointer to a
1308*5c51f124SMoriah Waterland  *              byte string with the ASCII friendlyname
1309*5c51f124SMoriah Waterland  *
1310*5c51f124SMoriah Waterland  * Returns:
1311*5c51f124SMoriah Waterland  *   >= 0     - The number of characters in the friendlyname returned.
1312*5c51f124SMoriah Waterland  *   < 0      - An error occurred.  It was probably an error in allocating
1313*5c51f124SMoriah Waterland  *              memory.  The error will be set in the error stack.  Call
1314*5c51f124SMoriah Waterland  *              ERR_get_error() to get specific information.
1315*5c51f124SMoriah Waterland  */
1316*5c51f124SMoriah Waterland int
1317*5c51f124SMoriah Waterland sunw_get_cert_fname(getdo_actions_t dowhat, X509 *cert, char **fname)
1318*5c51f124SMoriah Waterland {
1319*5c51f124SMoriah Waterland 	int len;
1320*5c51f124SMoriah Waterland 
1321*5c51f124SMoriah Waterland 	if (fname != NULL)
1322*5c51f124SMoriah Waterland 		*fname = NULL;
1323*5c51f124SMoriah Waterland 
1324*5c51f124SMoriah Waterland 	if (cert == NULL || cert->aux == NULL || cert->aux->alias == NULL) {
1325*5c51f124SMoriah Waterland 		return (0);
1326*5c51f124SMoriah Waterland 	}
1327*5c51f124SMoriah Waterland 
1328*5c51f124SMoriah Waterland 	if (dowhat == GETDO_DEL) {
1329*5c51f124SMoriah Waterland 		/* Delete the entry */
1330*5c51f124SMoriah Waterland 		ASN1_UTF8STRING_free(cert->aux->alias);
1331*5c51f124SMoriah Waterland 		cert->aux->alias = NULL;
1332*5c51f124SMoriah Waterland 		return (0);
1333*5c51f124SMoriah Waterland 	}
1334*5c51f124SMoriah Waterland 
1335*5c51f124SMoriah Waterland 	*((uchar_t **)fname) = utf82ascstr(cert->aux->alias);
1336*5c51f124SMoriah Waterland 	if (*fname == NULL) {
1337*5c51f124SMoriah Waterland 		/*
1338*5c51f124SMoriah Waterland 		 * Error already on stack
1339*5c51f124SMoriah Waterland 		 */
1340*5c51f124SMoriah Waterland 		return (-1);
1341*5c51f124SMoriah Waterland 	}
1342*5c51f124SMoriah Waterland 
1343*5c51f124SMoriah Waterland 	len = strlen(*fname);
1344*5c51f124SMoriah Waterland 
1345*5c51f124SMoriah Waterland 	return (len);
1346*5c51f124SMoriah Waterland }
1347*5c51f124SMoriah Waterland 
1348*5c51f124SMoriah Waterland /*
1349*5c51f124SMoriah Waterland  * sunw_set_fname() sets the friendlyName in a cert, a private key or
1350*5c51f124SMoriah Waterland  *     both.  Any existing friendlyname will be discarded.
1351*5c51f124SMoriah Waterland  *
1352*5c51f124SMoriah Waterland  * Arguments:
1353*5c51f124SMoriah Waterland  *   ascname  - An ASCII string with the friendlyName to set
1354*5c51f124SMoriah Waterland  *   pkey     - Points to a private key to set the fname in.
1355*5c51f124SMoriah Waterland  *   cert     - Points to a cert to set the fname in.
1356*5c51f124SMoriah Waterland  *
1357*5c51f124SMoriah Waterland  * Note that setting a friendlyName into a cert which will not be written out
1358*5c51f124SMoriah Waterland  * as a PKCS12 cert is pointless since it will be lost.
1359*5c51f124SMoriah Waterland  *
1360*5c51f124SMoriah Waterland  * Returns:
1361*5c51f124SMoriah Waterland  *   0        - Success.
1362*5c51f124SMoriah Waterland  *   <0       - An error occurred.  It was probably an error in allocating
1363*5c51f124SMoriah Waterland  *              memory.  The error will be set in the error stack.  Call
1364*5c51f124SMoriah Waterland  *              ERR_get_error() to get specific information.
1365*5c51f124SMoriah Waterland  */
1366*5c51f124SMoriah Waterland int
1367*5c51f124SMoriah Waterland sunw_set_fname(const char *ascname, EVP_PKEY *pkey, X509 *cert)
1368*5c51f124SMoriah Waterland {
1369*5c51f124SMoriah Waterland 	X509_ATTRIBUTE *attr = NULL;
1370*5c51f124SMoriah Waterland 	ASN1_BMPSTRING *str = NULL;
1371*5c51f124SMoriah Waterland 	ASN1_TYPE *fname = NULL;
1372*5c51f124SMoriah Waterland 	unsigned char *data = NULL;
1373*5c51f124SMoriah Waterland 	int retval = -1;
1374*5c51f124SMoriah Waterland 	int len;
1375*5c51f124SMoriah Waterland 	int i;
1376*5c51f124SMoriah Waterland 
1377*5c51f124SMoriah Waterland 	str = asc2bmpstring(ascname, strlen(ascname));
1378*5c51f124SMoriah Waterland 	if (str == NULL) {
1379*5c51f124SMoriah Waterland 		/*
1380*5c51f124SMoriah Waterland 		 * Error already on stack
1381*5c51f124SMoriah Waterland 		 */
1382*5c51f124SMoriah Waterland 		return (-1);
1383*5c51f124SMoriah Waterland 	}
1384*5c51f124SMoriah Waterland 
1385*5c51f124SMoriah Waterland 	if (cert != NULL) {
1386*5c51f124SMoriah Waterland 		if (cert->aux != NULL && cert->aux->alias != NULL) {
1387*5c51f124SMoriah Waterland 			ASN1_UTF8STRING_free(cert->aux->alias);
1388*5c51f124SMoriah Waterland 		}
1389*5c51f124SMoriah Waterland 
1390*5c51f124SMoriah Waterland 		len = ASN1_STRING_to_UTF8(&data, str);
1391*5c51f124SMoriah Waterland 		i = -23;
1392*5c51f124SMoriah Waterland 		if (len <= 0 || (i = X509_alias_set1(cert, data, len)) == 0) {
1393*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_SET_FNAME, SUNW_R_SET_FNAME_ERR);
1394*5c51f124SMoriah Waterland 			goto cleanup;
1395*5c51f124SMoriah Waterland 		}
1396*5c51f124SMoriah Waterland 	}
1397*5c51f124SMoriah Waterland 	if (pkey != NULL) {
1398*5c51f124SMoriah Waterland 		if ((fname = ASN1_TYPE_new()) == NULL) {
1399*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_SET_FNAME, SUNW_R_MEMORY_FAILURE);
1400*5c51f124SMoriah Waterland 			goto cleanup;
1401*5c51f124SMoriah Waterland 		}
1402*5c51f124SMoriah Waterland 
1403*5c51f124SMoriah Waterland 		ASN1_TYPE_set(fname, V_ASN1_BMPSTRING, str);
1404*5c51f124SMoriah Waterland 		str = NULL;
1405*5c51f124SMoriah Waterland 
1406*5c51f124SMoriah Waterland 		attr = type2attrib(fname, NID_friendlyName);
1407*5c51f124SMoriah Waterland 		if (attr == NULL) {
1408*5c51f124SMoriah Waterland 			/*
1409*5c51f124SMoriah Waterland 			 * Error already on stack
1410*5c51f124SMoriah Waterland 			 */
1411*5c51f124SMoriah Waterland 			goto cleanup;
1412*5c51f124SMoriah Waterland 		}
1413*5c51f124SMoriah Waterland 		fname = NULL;
1414*5c51f124SMoriah Waterland 
1415*5c51f124SMoriah Waterland 		if (pkey->attributes == NULL) {
1416*5c51f124SMoriah Waterland 			pkey->attributes = sk_X509_ATTRIBUTE_new_null();
1417*5c51f124SMoriah Waterland 			if (pkey->attributes == NULL) {
1418*5c51f124SMoriah Waterland 				SUNWerr(SUNW_F_SET_FNAME,
1419*5c51f124SMoriah Waterland 				    SUNW_R_MEMORY_FAILURE);
1420*5c51f124SMoriah Waterland 				goto cleanup;
1421*5c51f124SMoriah Waterland 			}
1422*5c51f124SMoriah Waterland 		} else if ((i = find_attr_by_nid(pkey->attributes,
1423*5c51f124SMoriah Waterland 		    NID_friendlyName)) >= 0) {
1424*5c51f124SMoriah Waterland 			(void) sk_X509_ATTRIBUTE_delete(pkey->attributes, i);
1425*5c51f124SMoriah Waterland 		}
1426*5c51f124SMoriah Waterland 
1427*5c51f124SMoriah Waterland 		if (sk_X509_ATTRIBUTE_push(pkey->attributes, attr) == 0) {
1428*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_SET_FNAME, SUNW_R_MEMORY_FAILURE);
1429*5c51f124SMoriah Waterland 			goto cleanup;
1430*5c51f124SMoriah Waterland 		}
1431*5c51f124SMoriah Waterland 
1432*5c51f124SMoriah Waterland 		attr = NULL;
1433*5c51f124SMoriah Waterland 	}
1434*5c51f124SMoriah Waterland 	retval = 0;
1435*5c51f124SMoriah Waterland 
1436*5c51f124SMoriah Waterland cleanup:
1437*5c51f124SMoriah Waterland 	if (data != NULL)
1438*5c51f124SMoriah Waterland 		OPENSSL_free(data);
1439*5c51f124SMoriah Waterland 	if (str != NULL)
1440*5c51f124SMoriah Waterland 		ASN1_BMPSTRING_free(str);
1441*5c51f124SMoriah Waterland 	if (fname != NULL)
1442*5c51f124SMoriah Waterland 		ASN1_TYPE_free(fname);
1443*5c51f124SMoriah Waterland 	if (attr != NULL)
1444*5c51f124SMoriah Waterland 		X509_ATTRIBUTE_free(attr);
1445*5c51f124SMoriah Waterland 
1446*5c51f124SMoriah Waterland 	return (retval);
1447*5c51f124SMoriah Waterland }
1448*5c51f124SMoriah Waterland 
1449*5c51f124SMoriah Waterland /*
1450*5c51f124SMoriah Waterland  * sunw_check_keys() compares the public key in the certificate and a
1451*5c51f124SMoriah Waterland  *     private key to ensure that they match.
1452*5c51f124SMoriah Waterland  *
1453*5c51f124SMoriah Waterland  * Arguments:
1454*5c51f124SMoriah Waterland  *   cert     - Points to a certificate.
1455*5c51f124SMoriah Waterland  *   pkey     - Points to a private key.
1456*5c51f124SMoriah Waterland  *
1457*5c51f124SMoriah Waterland  * Returns:
1458*5c51f124SMoriah Waterland  *  == 0 - These do not match.
1459*5c51f124SMoriah Waterland  *  != 0 - The cert's public key and the private key match.
1460*5c51f124SMoriah Waterland  */
1461*5c51f124SMoriah Waterland int
1462*5c51f124SMoriah Waterland sunw_check_keys(X509 *cert, EVP_PKEY *pkey)
1463*5c51f124SMoriah Waterland {
1464*5c51f124SMoriah Waterland 	int retval = 0;
1465*5c51f124SMoriah Waterland 
1466*5c51f124SMoriah Waterland 	if (pkey != NULL && cert != NULL)
1467*5c51f124SMoriah Waterland 		retval = X509_check_private_key(cert, pkey);
1468*5c51f124SMoriah Waterland 
1469*5c51f124SMoriah Waterland 	return (retval);
1470*5c51f124SMoriah Waterland }
1471*5c51f124SMoriah Waterland 
1472*5c51f124SMoriah Waterland /*
1473*5c51f124SMoriah Waterland  * sunw_check_cert_times() compares the time fields in a certificate
1474*5c51f124SMoriah Waterland  *
1475*5c51f124SMoriah Waterland  * Compare the 'not before' and the 'not after' times in the cert
1476*5c51f124SMoriah Waterland  * to the current time.  Return the results of the comparison (bad time formats,
1477*5c51f124SMoriah Waterland  * cert not yet in force, cert expired or in range)
1478*5c51f124SMoriah Waterland  *
1479*5c51f124SMoriah Waterland  * Arguments:
1480*5c51f124SMoriah Waterland  *   dowhat   - what field(s) to check.
1481*5c51f124SMoriah Waterland  *   cert     - Points to a cert to check
1482*5c51f124SMoriah Waterland  *
1483*5c51f124SMoriah Waterland  * Returns:
1484*5c51f124SMoriah Waterland  *   Results of the comparison.
1485*5c51f124SMoriah Waterland  */
1486*5c51f124SMoriah Waterland chk_errs_t
1487*5c51f124SMoriah Waterland sunw_check_cert_times(chk_actions_t chkwhat, X509 *cert)
1488*5c51f124SMoriah Waterland {
1489*5c51f124SMoriah Waterland 	return (check_time(chkwhat, cert));
1490*5c51f124SMoriah Waterland }
1491*5c51f124SMoriah Waterland 
1492*5c51f124SMoriah Waterland /*
1493*5c51f124SMoriah Waterland  * ----------------------------------------------------------------------------
1494*5c51f124SMoriah Waterland  * Local routines
1495*5c51f124SMoriah Waterland  * ----------------------------------------------------------------------------
1496*5c51f124SMoriah Waterland  */
1497*5c51f124SMoriah Waterland 
1498*5c51f124SMoriah Waterland 
1499*5c51f124SMoriah Waterland /*
1500*5c51f124SMoriah Waterland  * parse_pkcs12 - Oversee parsing of the pkcs12 structure.  Get it
1501*5c51f124SMoriah Waterland  *         parsed.  After that either return what's found directly, or
1502*5c51f124SMoriah Waterland  *         do any required matching.
1503*5c51f124SMoriah Waterland  *
1504*5c51f124SMoriah Waterland  * Arguments:
1505*5c51f124SMoriah Waterland  *   p12      - Structure with pkcs12 info to be parsed
1506*5c51f124SMoriah Waterland  *   pass     - Pass phrase for the private key (possibly empty) or NULL if
1507*5c51f124SMoriah Waterland  *              there is none.
1508*5c51f124SMoriah Waterland  *   matchty  - Info about which certs/keys to return if many are in the file.
1509*5c51f124SMoriah Waterland  *   keyid    - If private key localkeyids friendlynames are to match a
1510*5c51f124SMoriah Waterland  *              predetermined value, the value to match. This value should
1511*5c51f124SMoriah Waterland  *		be an octet string.
1512*5c51f124SMoriah Waterland  *   keyid_len- Length of the keyid byte string.
1513*5c51f124SMoriah Waterland  *   name_str - If friendlynames are to match a predetermined value, the value
1514*5c51f124SMoriah Waterland  *		 to match. This value should be a NULL terminated string.
1515*5c51f124SMoriah Waterland  *   pkey     - Points to location pointing to the private key returned.
1516*5c51f124SMoriah Waterland  *   cert     - Points to locaiton which points to the client cert returned
1517*5c51f124SMoriah Waterland  *   ca       - Points to location that points to a stack of 'certificate
1518*5c51f124SMoriah Waterland  *              authority' certs/trust anchors.
1519*5c51f124SMoriah Waterland  *
1520*5c51f124SMoriah Waterland  *   Note about error codes:  This function is an internal function, and the
1521*5c51f124SMoriah Waterland  *   place where it is called sets error codes.  Therefore only set an error
1522*5c51f124SMoriah Waterland  *   code if it is something that is unique or if the function which detected
1523*5c51f124SMoriah Waterland  *   the error doesn't set one.
1524*5c51f124SMoriah Waterland  *
1525*5c51f124SMoriah Waterland  * Returns:
1526*5c51f124SMoriah Waterland  *   == -1 - An error occurred.  Call ERR_get_error() to get error information.
1527*5c51f124SMoriah Waterland  *           Where possible, memory has been freed.
1528*5c51f124SMoriah Waterland  *   == 0  - No matching returns were found.
1529*5c51f124SMoriah Waterland  *    > 0  - This is the aithmetic 'or' of the FOUND_* bits that indicate which
1530*5c51f124SMoriah Waterland  *           of the requested entries were found.
1531*5c51f124SMoriah Waterland  */
1532*5c51f124SMoriah Waterland static int
1533*5c51f124SMoriah Waterland parse_pkcs12(PKCS12 *p12, const char *pass, int matchty, char *keyid,
1534*5c51f124SMoriah Waterland     int kstr_len, char *name_str, EVP_PKEY **pkey, X509 **cert,
1535*5c51f124SMoriah Waterland     STACK_OF(X509) **ca)
1536*5c51f124SMoriah Waterland {
1537*5c51f124SMoriah Waterland 	STACK_OF(EVP_PKEY) *work_kl = NULL;	/* Head for private key list */
1538*5c51f124SMoriah Waterland 	STACK_OF(EVP_PKEY) *nocerts = NULL;	/* Head for alt. key list */
1539*5c51f124SMoriah Waterland 	STACK_OF(X509) *work_ca = NULL;		/* Head for cert list */
1540*5c51f124SMoriah Waterland 	STACK_OF(X509) *work_cl = NULL;
1541*5c51f124SMoriah Waterland 	int retval = 0;
1542*5c51f124SMoriah Waterland 	int n;
1543*5c51f124SMoriah Waterland 
1544*5c51f124SMoriah Waterland 	retval = sunw_PKCS12_contents(p12, pass, &work_kl, &work_ca);
1545*5c51f124SMoriah Waterland 	if (retval < 0) {
1546*5c51f124SMoriah Waterland 		goto cleanup;
1547*5c51f124SMoriah Waterland 	} else if (retval == 0) {
1548*5c51f124SMoriah Waterland 		/*
1549*5c51f124SMoriah Waterland 		 * Not really an error here - its just that nothing was found.
1550*5c51f124SMoriah Waterland 		 */
1551*5c51f124SMoriah Waterland 		goto cleanup;
1552*5c51f124SMoriah Waterland 	}
1553*5c51f124SMoriah Waterland 
1554*5c51f124SMoriah Waterland 	if (sk_EVP_PKEY_num(work_kl) > 0) {
1555*5c51f124SMoriah Waterland 
1556*5c51f124SMoriah Waterland 		if (sunw_split_certs(work_kl, work_ca, &work_cl, &nocerts)
1557*5c51f124SMoriah Waterland 		    < 0) {
1558*5c51f124SMoriah Waterland 			goto cleanup;
1559*5c51f124SMoriah Waterland 		}
1560*5c51f124SMoriah Waterland 	}
1561*5c51f124SMoriah Waterland 
1562*5c51f124SMoriah Waterland 	/*
1563*5c51f124SMoriah Waterland 	 * Go through the lists of certs and private keys which were
1564*5c51f124SMoriah Waterland 	 * returned, looking for matches of the appropriate type.  Do these
1565*5c51f124SMoriah Waterland 	 * in the order described above.
1566*5c51f124SMoriah Waterland 	 */
1567*5c51f124SMoriah Waterland 	if ((matchty & DO_FIND_KEYID) != 0) {
1568*5c51f124SMoriah Waterland 
1569*5c51f124SMoriah Waterland 		if (keyid == NULL) {
1570*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PKCS12_PARSE, SUNW_R_INVALID_ARG);
1571*5c51f124SMoriah Waterland 			retval = -1;
1572*5c51f124SMoriah Waterland 			goto cleanup;
1573*5c51f124SMoriah Waterland 		}
1574*5c51f124SMoriah Waterland 
1575*5c51f124SMoriah Waterland 		/* See if string matches localkeyid's */
1576*5c51f124SMoriah Waterland 		retval = sunw_find_localkeyid(keyid, kstr_len,
1577*5c51f124SMoriah Waterland 		    work_kl, work_cl, pkey, cert);
1578*5c51f124SMoriah Waterland 		if (retval != 0) {
1579*5c51f124SMoriah Waterland 			if (retval == -1)
1580*5c51f124SMoriah Waterland 				goto cleanup;
1581*5c51f124SMoriah Waterland 			else
1582*5c51f124SMoriah Waterland 				goto last_part;
1583*5c51f124SMoriah Waterland 		}
1584*5c51f124SMoriah Waterland 	}
1585*5c51f124SMoriah Waterland 	if ((matchty & DO_FIND_FN) != 0) {
1586*5c51f124SMoriah Waterland 
1587*5c51f124SMoriah Waterland 		if (name_str == NULL) {
1588*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PKCS12_PARSE, SUNW_R_INVALID_ARG);
1589*5c51f124SMoriah Waterland 			retval = -1;
1590*5c51f124SMoriah Waterland 			goto cleanup;
1591*5c51f124SMoriah Waterland 		}
1592*5c51f124SMoriah Waterland 
1593*5c51f124SMoriah Waterland 		/* See if string matches friendly names */
1594*5c51f124SMoriah Waterland 		retval = sunw_find_fname(name_str, work_kl, work_cl,
1595*5c51f124SMoriah Waterland 		    pkey, cert);
1596*5c51f124SMoriah Waterland 		if (retval != 0) {
1597*5c51f124SMoriah Waterland 			if (retval == -1)
1598*5c51f124SMoriah Waterland 				goto cleanup;
1599*5c51f124SMoriah Waterland 			else
1600*5c51f124SMoriah Waterland 				goto last_part;
1601*5c51f124SMoriah Waterland 		}
1602*5c51f124SMoriah Waterland 	}
1603*5c51f124SMoriah Waterland 
1604*5c51f124SMoriah Waterland 	if (matchty & DO_FIRST_PAIR) {
1605*5c51f124SMoriah Waterland 
1606*5c51f124SMoriah Waterland 		/* Find the first cert and private key and return them */
1607*5c51f124SMoriah Waterland 		retval = get_key_cert(0, work_kl, pkey, work_cl, cert);
1608*5c51f124SMoriah Waterland 		if (retval != 0) {
1609*5c51f124SMoriah Waterland 			if (retval == -1)
1610*5c51f124SMoriah Waterland 				goto cleanup;
1611*5c51f124SMoriah Waterland 			else
1612*5c51f124SMoriah Waterland 				goto last_part;
1613*5c51f124SMoriah Waterland 		}
1614*5c51f124SMoriah Waterland 	}
1615*5c51f124SMoriah Waterland 
1616*5c51f124SMoriah Waterland 	if (matchty & DO_LAST_PAIR) {
1617*5c51f124SMoriah Waterland 
1618*5c51f124SMoriah Waterland 		/*
1619*5c51f124SMoriah Waterland 		 * Find the last matching cert and private key and return
1620*5c51f124SMoriah Waterland 		 * them.  Since keys which don't have matching client certs
1621*5c51f124SMoriah Waterland 		 * are at the end of the list of keys, use the number of
1622*5c51f124SMoriah Waterland 		 * client certs to compute the position of the last private
1623*5c51f124SMoriah Waterland 		 * key which matches a client cert.
1624*5c51f124SMoriah Waterland 		 */
1625*5c51f124SMoriah Waterland 		n = sk_X509_num(work_cl) - 1;
1626*5c51f124SMoriah Waterland 		retval = get_key_cert(n, work_kl, pkey, work_cl, cert);
1627*5c51f124SMoriah Waterland 		if (retval != 0) {
1628*5c51f124SMoriah Waterland 			if (retval == -1)
1629*5c51f124SMoriah Waterland 				goto cleanup;
1630*5c51f124SMoriah Waterland 			else
1631*5c51f124SMoriah Waterland 				goto last_part;
1632*5c51f124SMoriah Waterland 		}
1633*5c51f124SMoriah Waterland 	}
1634*5c51f124SMoriah Waterland 
1635*5c51f124SMoriah Waterland 	if (matchty & DO_UNMATCHING) {
1636*5c51f124SMoriah Waterland 		STACK_OF(EVP_PKEY) *tmpk;
1637*5c51f124SMoriah Waterland 		STACK_OF(X509) *tmpc;
1638*5c51f124SMoriah Waterland 
1639*5c51f124SMoriah Waterland 		/* Find the first cert and private key and return them */
1640*5c51f124SMoriah Waterland 		tmpc = work_cl;
1641*5c51f124SMoriah Waterland 		if (work_cl == NULL || sk_X509_num(work_cl) == 0)
1642*5c51f124SMoriah Waterland 			tmpc = work_ca;
1643*5c51f124SMoriah Waterland 		tmpk = work_kl;
1644*5c51f124SMoriah Waterland 		if (work_kl == NULL || sk_EVP_PKEY_num(work_kl) == 0)
1645*5c51f124SMoriah Waterland 			tmpk = nocerts;
1646*5c51f124SMoriah Waterland 		retval = get_key_cert(0, tmpk, pkey, tmpc, cert);
1647*5c51f124SMoriah Waterland 		if (retval != 0) {
1648*5c51f124SMoriah Waterland 			if (retval == -1)
1649*5c51f124SMoriah Waterland 				goto cleanup;
1650*5c51f124SMoriah Waterland 			else
1651*5c51f124SMoriah Waterland 				goto last_part;
1652*5c51f124SMoriah Waterland 		}
1653*5c51f124SMoriah Waterland 	}
1654*5c51f124SMoriah Waterland 
1655*5c51f124SMoriah Waterland last_part:
1656*5c51f124SMoriah Waterland 	/* If no errors, terminate normally */
1657*5c51f124SMoriah Waterland 	if (retval != -1)
1658*5c51f124SMoriah Waterland 		retval |= set_results(NULL, NULL, NULL, NULL, ca, &work_ca,
1659*5c51f124SMoriah Waterland 		    NULL, NULL);
1660*5c51f124SMoriah Waterland 	if (retval >= 0) {
1661*5c51f124SMoriah Waterland 		goto clean_part;
1662*5c51f124SMoriah Waterland 	}
1663*5c51f124SMoriah Waterland 
1664*5c51f124SMoriah Waterland 	/* Fallthrough is intentional in error cases. */
1665*5c51f124SMoriah Waterland cleanup:
1666*5c51f124SMoriah Waterland 	if (pkey != NULL && *pkey != NULL) {
1667*5c51f124SMoriah Waterland 		sunw_evp_pkey_free(*pkey);
1668*5c51f124SMoriah Waterland 		*pkey = NULL;
1669*5c51f124SMoriah Waterland 	}
1670*5c51f124SMoriah Waterland 	if (cert != NULL && *cert != NULL) {
1671*5c51f124SMoriah Waterland 		X509_free(*cert);
1672*5c51f124SMoriah Waterland 		*cert = NULL;
1673*5c51f124SMoriah Waterland 	}
1674*5c51f124SMoriah Waterland 
1675*5c51f124SMoriah Waterland clean_part:
1676*5c51f124SMoriah Waterland 
1677*5c51f124SMoriah Waterland 	if (work_kl != NULL) {
1678*5c51f124SMoriah Waterland 		sk_EVP_PKEY_pop_free(work_kl, sunw_evp_pkey_free);
1679*5c51f124SMoriah Waterland 	}
1680*5c51f124SMoriah Waterland 	if (work_ca != NULL)
1681*5c51f124SMoriah Waterland 		sk_X509_pop_free(work_ca, X509_free);
1682*5c51f124SMoriah Waterland 	if (work_cl != NULL)
1683*5c51f124SMoriah Waterland 		sk_X509_pop_free(work_cl, X509_free);
1684*5c51f124SMoriah Waterland 
1685*5c51f124SMoriah Waterland 	return (retval);
1686*5c51f124SMoriah Waterland }
1687*5c51f124SMoriah Waterland 
1688*5c51f124SMoriah Waterland /*
1689*5c51f124SMoriah Waterland  * parse_outer - Unpack the outer PKCS#12 structure and go through the
1690*5c51f124SMoriah Waterland  *         individual bags.  Return stacks of certs, private keys found and
1691*5c51f124SMoriah Waterland  *         CA certs found.
1692*5c51f124SMoriah Waterland  *
1693*5c51f124SMoriah Waterland  *   Note about error codes:  This function is an internal function, and the
1694*5c51f124SMoriah Waterland  *   place where it is called sets error codes.
1695*5c51f124SMoriah Waterland  *
1696*5c51f124SMoriah Waterland  * Returns:
1697*5c51f124SMoriah Waterland  *    0 - An error returned.  Call ERR_get_error() to get errors information.
1698*5c51f124SMoriah Waterland  *        Where possible, memory has been freed.
1699*5c51f124SMoriah Waterland  *    1 - PKCS12 data object was parsed and lists of certs and private keys
1700*5c51f124SMoriah Waterland  *        were returned.
1701*5c51f124SMoriah Waterland  */
1702*5c51f124SMoriah Waterland static int
1703*5c51f124SMoriah Waterland parse_outer(PKCS12 *p12, const char *pass, STACK_OF(EVP_PKEY) *kl,
1704*5c51f124SMoriah Waterland     STACK_OF(X509) *cl)
1705*5c51f124SMoriah Waterland {
1706*5c51f124SMoriah Waterland 	STACK_OF(PKCS12_SAFEBAG) *bags;
1707*5c51f124SMoriah Waterland 	STACK_OF(PKCS7) *asafes;
1708*5c51f124SMoriah Waterland 	int i, bagnid;
1709*5c51f124SMoriah Waterland 	PKCS7 *p7;
1710*5c51f124SMoriah Waterland 
1711*5c51f124SMoriah Waterland 	if ((asafes = M_PKCS12_unpack_authsafes(p12)) == NULL)
1712*5c51f124SMoriah Waterland 		return (0);
1713*5c51f124SMoriah Waterland 
1714*5c51f124SMoriah Waterland 	for (i = 0; i < sk_PKCS7_num(asafes); i++) {
1715*5c51f124SMoriah Waterland 		p7 = sk_PKCS7_value(asafes, i);
1716*5c51f124SMoriah Waterland 		bagnid = OBJ_obj2nid(p7->type);
1717*5c51f124SMoriah Waterland 		if (bagnid == NID_pkcs7_data) {
1718*5c51f124SMoriah Waterland 			bags = M_PKCS12_unpack_p7data(p7);
1719*5c51f124SMoriah Waterland 		} else if (bagnid == NID_pkcs7_encrypted) {
1720*5c51f124SMoriah Waterland 			/*
1721*5c51f124SMoriah Waterland 			 * A length of '-1' means strlen() can be used
1722*5c51f124SMoriah Waterland 			 * to determine the password length.
1723*5c51f124SMoriah Waterland 			 */
1724*5c51f124SMoriah Waterland 			bags = M_PKCS12_unpack_p7encdata(p7, pass, -1);
1725*5c51f124SMoriah Waterland 		} else {
1726*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PARSE_OUTER, SUNW_R_BAD_BAGTYPE);
1727*5c51f124SMoriah Waterland 			return (0);
1728*5c51f124SMoriah Waterland 		}
1729*5c51f124SMoriah Waterland 
1730*5c51f124SMoriah Waterland 		if (bags == NULL) {
1731*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PARSE_OUTER, SUNW_R_PARSE_BAG_ERR);
1732*5c51f124SMoriah Waterland 			sk_PKCS7_pop_free(asafes, PKCS7_free);
1733*5c51f124SMoriah Waterland 			return (0);
1734*5c51f124SMoriah Waterland 		}
1735*5c51f124SMoriah Waterland 		if (parse_all_bags(bags, pass, kl, cl) == 0) {
1736*5c51f124SMoriah Waterland 			sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free);
1737*5c51f124SMoriah Waterland 			sk_PKCS7_pop_free(asafes, PKCS7_free);
1738*5c51f124SMoriah Waterland 			return (0);
1739*5c51f124SMoriah Waterland 		}
1740*5c51f124SMoriah Waterland 	}
1741*5c51f124SMoriah Waterland 
1742*5c51f124SMoriah Waterland 	return (1);
1743*5c51f124SMoriah Waterland }
1744*5c51f124SMoriah Waterland 
1745*5c51f124SMoriah Waterland /*
1746*5c51f124SMoriah Waterland  * parse_all_bags - go through the stack of bags, parsing each.
1747*5c51f124SMoriah Waterland  *
1748*5c51f124SMoriah Waterland  *   Note about error codes:  This function is an internal function, and the
1749*5c51f124SMoriah Waterland  *   place where it is called sets error codes.
1750*5c51f124SMoriah Waterland  *
1751*5c51f124SMoriah Waterland  * Returns:
1752*5c51f124SMoriah Waterland  *    0 - An error returned.  Call ERR_get_error() to get errors information.
1753*5c51f124SMoriah Waterland  *        Where possible, memory has been freed.
1754*5c51f124SMoriah Waterland  *    1 - Stack of safebags was parsed and lists of certs and private keys
1755*5c51f124SMoriah Waterland  *        were returned.
1756*5c51f124SMoriah Waterland  */
1757*5c51f124SMoriah Waterland static int
1758*5c51f124SMoriah Waterland parse_all_bags(STACK_OF(PKCS12_SAFEBAG) *bags, const char *pass,
1759*5c51f124SMoriah Waterland     STACK_OF(EVP_PKEY) *kl, STACK_OF(X509) *cl)
1760*5c51f124SMoriah Waterland {
1761*5c51f124SMoriah Waterland 	int i;
1762*5c51f124SMoriah Waterland 	for (i = 0; i < sk_PKCS12_SAFEBAG_num(bags); i++) {
1763*5c51f124SMoriah Waterland 		if (parse_one_bag(sk_PKCS12_SAFEBAG_value(bags, i),
1764*5c51f124SMoriah Waterland 		    pass, kl, cl) == 0)
1765*5c51f124SMoriah Waterland 			return (0);
1766*5c51f124SMoriah Waterland 	}
1767*5c51f124SMoriah Waterland 	return (1);
1768*5c51f124SMoriah Waterland }
1769*5c51f124SMoriah Waterland 
1770*5c51f124SMoriah Waterland /*
1771*5c51f124SMoriah Waterland  * parse_one_bag - Parse an individual bag
1772*5c51f124SMoriah Waterland  *
1773*5c51f124SMoriah Waterland  *   i = parse_one_bag(bag, pass, kl, cl);
1774*5c51f124SMoriah Waterland  *
1775*5c51f124SMoriah Waterland  * Arguments:
1776*5c51f124SMoriah Waterland  *   bag	- pkcs12 safebag to parse.
1777*5c51f124SMoriah Waterland  *   pass 	- password for use in decryption of shrouded keybag
1778*5c51f124SMoriah Waterland  *   kl         - Stack of private keys found so far.  New private keys will
1779*5c51f124SMoriah Waterland  *                be added here if found.
1780*5c51f124SMoriah Waterland  *   cl         - Stack of certs found so far.  New certificates will be
1781*5c51f124SMoriah Waterland  *                added here if found.
1782*5c51f124SMoriah Waterland  *
1783*5c51f124SMoriah Waterland  * Returns:
1784*5c51f124SMoriah Waterland  *    0 - An error returned.  Call ERR_get_error() to get errors information.
1785*5c51f124SMoriah Waterland  *        Where possible, memory has been freed.
1786*5c51f124SMoriah Waterland  *    1 - one safebag was parsed. If it contained a cert or private key, it
1787*5c51f124SMoriah Waterland  *        was added to the stack of certs or private keys found, respectively.
1788*5c51f124SMoriah Waterland  *        localKeyId or friendlyName attributes are returned with the
1789*5c51f124SMoriah Waterland  *        private key or certificate.
1790*5c51f124SMoriah Waterland  */
1791*5c51f124SMoriah Waterland static int
1792*5c51f124SMoriah Waterland parse_one_bag(PKCS12_SAFEBAG *bag, const char *pass, STACK_OF(EVP_PKEY) *kl,
1793*5c51f124SMoriah Waterland     STACK_OF(X509) *cl)
1794*5c51f124SMoriah Waterland {
1795*5c51f124SMoriah Waterland 	X509_ATTRIBUTE *attr = NULL;
1796*5c51f124SMoriah Waterland 	ASN1_TYPE *keyid = NULL;
1797*5c51f124SMoriah Waterland 	ASN1_TYPE *fname = NULL;
1798*5c51f124SMoriah Waterland 	PKCS8_PRIV_KEY_INFO *p8;
1799*5c51f124SMoriah Waterland 	EVP_PKEY *pkey = NULL;
1800*5c51f124SMoriah Waterland 	X509 *x509 = NULL;
1801*5c51f124SMoriah Waterland 	uchar_t *data = NULL;
1802*5c51f124SMoriah Waterland 	char *str = NULL;
1803*5c51f124SMoriah Waterland 	int retval = 1;
1804*5c51f124SMoriah Waterland 
1805*5c51f124SMoriah Waterland 	keyid = PKCS12_get_attr(bag, NID_localKeyID);
1806*5c51f124SMoriah Waterland 	fname = PKCS12_get_attr(bag, NID_friendlyName);
1807*5c51f124SMoriah Waterland 
1808*5c51f124SMoriah Waterland 	switch (M_PKCS12_bag_type(bag)) {
1809*5c51f124SMoriah Waterland 	case NID_keyBag:
1810*5c51f124SMoriah Waterland 		if ((pkey = EVP_PKCS82PKEY(bag->value.keybag)) == NULL) {
1811*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PARSE_ONE_BAG, SUNW_R_PARSE_BAG_ERR);
1812*5c51f124SMoriah Waterland 			retval = 0;
1813*5c51f124SMoriah Waterland 			break;
1814*5c51f124SMoriah Waterland 		}
1815*5c51f124SMoriah Waterland 		break;
1816*5c51f124SMoriah Waterland 
1817*5c51f124SMoriah Waterland 	case NID_pkcs8ShroudedKeyBag:
1818*5c51f124SMoriah Waterland 		/*
1819*5c51f124SMoriah Waterland 		 * A length of '-1' means strlen() can be used
1820*5c51f124SMoriah Waterland 		 * to determine the password length.
1821*5c51f124SMoriah Waterland 		 */
1822*5c51f124SMoriah Waterland 		if ((p8 = M_PKCS12_decrypt_skey(bag, pass, -1)) == NULL) {
1823*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PARSE_ONE_BAG, SUNW_R_PARSE_BAG_ERR);
1824*5c51f124SMoriah Waterland 			retval = 0;
1825*5c51f124SMoriah Waterland 			break;
1826*5c51f124SMoriah Waterland 		}
1827*5c51f124SMoriah Waterland 		pkey = EVP_PKCS82PKEY(p8);
1828*5c51f124SMoriah Waterland 		PKCS8_PRIV_KEY_INFO_free(p8);
1829*5c51f124SMoriah Waterland 		if (pkey == NULL) {
1830*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PARSE_ONE_BAG, SUNW_R_PARSE_BAG_ERR);
1831*5c51f124SMoriah Waterland 			retval = 0;
1832*5c51f124SMoriah Waterland 		}
1833*5c51f124SMoriah Waterland 		break;
1834*5c51f124SMoriah Waterland 
1835*5c51f124SMoriah Waterland 	case NID_certBag:
1836*5c51f124SMoriah Waterland 		if (M_PKCS12_cert_bag_type(bag) != NID_x509Certificate) {
1837*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PARSE_ONE_BAG, SUNW_R_BAD_CERTTYPE);
1838*5c51f124SMoriah Waterland 			break;
1839*5c51f124SMoriah Waterland 		}
1840*5c51f124SMoriah Waterland 		if ((x509 = M_PKCS12_certbag2x509(bag)) == NULL) {
1841*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PARSE_ONE_BAG,
1842*5c51f124SMoriah Waterland 			    SUNW_R_PARSE_CERT_ERR);
1843*5c51f124SMoriah Waterland 			retval = 0;
1844*5c51f124SMoriah Waterland 			break;
1845*5c51f124SMoriah Waterland 		}
1846*5c51f124SMoriah Waterland 
1847*5c51f124SMoriah Waterland 		if (keyid != NULL) {
1848*5c51f124SMoriah Waterland 			if (keyid->type != V_ASN1_OCTET_STRING) {
1849*5c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PARSE_ONE_BAG,
1850*5c51f124SMoriah Waterland 				    SUNW_R_BAD_LKID);
1851*5c51f124SMoriah Waterland 				retval = 0;
1852*5c51f124SMoriah Waterland 				break;
1853*5c51f124SMoriah Waterland 			}
1854*5c51f124SMoriah Waterland 			if (X509_keyid_set1(x509,
1855*5c51f124SMoriah Waterland 			    keyid->value.octet_string->data,
1856*5c51f124SMoriah Waterland 			    keyid->value.octet_string->length) == 0) {
1857*5c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PARSE_ONE_BAG,
1858*5c51f124SMoriah Waterland 				    SUNW_R_SET_LKID_ERR);
1859*5c51f124SMoriah Waterland 				retval = 0;
1860*5c51f124SMoriah Waterland 				break;
1861*5c51f124SMoriah Waterland 			}
1862*5c51f124SMoriah Waterland 		}
1863*5c51f124SMoriah Waterland 
1864*5c51f124SMoriah Waterland 		if (fname != NULL) {
1865*5c51f124SMoriah Waterland 			ASN1_STRING *tmpstr = NULL;
1866*5c51f124SMoriah Waterland 			int len;
1867*5c51f124SMoriah Waterland 
1868*5c51f124SMoriah Waterland 			if (fname->type != V_ASN1_BMPSTRING) {
1869*5c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PARSE_ONE_BAG,
1870*5c51f124SMoriah Waterland 				    SUNW_R_BAD_FNAME);
1871*5c51f124SMoriah Waterland 				retval = 0;
1872*5c51f124SMoriah Waterland 				break;
1873*5c51f124SMoriah Waterland 			}
1874*5c51f124SMoriah Waterland 
1875*5c51f124SMoriah Waterland 			tmpstr = fname->value.asn1_string;
1876*5c51f124SMoriah Waterland 			len = ASN1_STRING_to_UTF8(&data, tmpstr);
1877*5c51f124SMoriah Waterland 			if (len < 0) {
1878*5c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PARSE_ONE_BAG,
1879*5c51f124SMoriah Waterland 				    SUNW_R_SET_FNAME_ERR);
1880*5c51f124SMoriah Waterland 				retval = 0;
1881*5c51f124SMoriah Waterland 				break;
1882*5c51f124SMoriah Waterland 			}
1883*5c51f124SMoriah Waterland 
1884*5c51f124SMoriah Waterland 			if (X509_alias_set1(x509, data, len) == 0) {
1885*5c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PARSE_ONE_BAG,
1886*5c51f124SMoriah Waterland 				    SUNW_R_SET_FNAME_ERR);
1887*5c51f124SMoriah Waterland 				retval = 0;
1888*5c51f124SMoriah Waterland 				break;
1889*5c51f124SMoriah Waterland 			}
1890*5c51f124SMoriah Waterland 		}
1891*5c51f124SMoriah Waterland 
1892*5c51f124SMoriah Waterland 		if (sk_X509_push(cl, x509) == 0) {
1893*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PARSE_ONE_BAG, SUNW_R_MEMORY_FAILURE);
1894*5c51f124SMoriah Waterland 			retval = 0;
1895*5c51f124SMoriah Waterland 			break;
1896*5c51f124SMoriah Waterland 		}
1897*5c51f124SMoriah Waterland 		x509 = NULL;
1898*5c51f124SMoriah Waterland 		break;
1899*5c51f124SMoriah Waterland 
1900*5c51f124SMoriah Waterland 	case NID_safeContentsBag:
1901*5c51f124SMoriah Waterland 		if (keyid != NULL)
1902*5c51f124SMoriah Waterland 			ASN1_TYPE_free(keyid);
1903*5c51f124SMoriah Waterland 		if (fname != NULL)
1904*5c51f124SMoriah Waterland 			ASN1_TYPE_free(fname);
1905*5c51f124SMoriah Waterland 		if (parse_all_bags(bag->value.safes, pass, kl, cl) == 0) {
1906*5c51f124SMoriah Waterland 			/*
1907*5c51f124SMoriah Waterland 			 * Error already on stack
1908*5c51f124SMoriah Waterland 			 */
1909*5c51f124SMoriah Waterland 			return (0);
1910*5c51f124SMoriah Waterland 		}
1911*5c51f124SMoriah Waterland 		return (1);
1912*5c51f124SMoriah Waterland 
1913*5c51f124SMoriah Waterland 	default:
1914*5c51f124SMoriah Waterland 		if (keyid != NULL)
1915*5c51f124SMoriah Waterland 			ASN1_TYPE_free(keyid);
1916*5c51f124SMoriah Waterland 		if (fname != NULL)
1917*5c51f124SMoriah Waterland 			ASN1_TYPE_free(fname);
1918*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PARSE_ONE_BAG, SUNW_R_BAD_BAGTYPE);
1919*5c51f124SMoriah Waterland 		return (0);
1920*5c51f124SMoriah Waterland 	}
1921*5c51f124SMoriah Waterland 
1922*5c51f124SMoriah Waterland 
1923*5c51f124SMoriah Waterland 	if (pkey != NULL) {
1924*5c51f124SMoriah Waterland 		if (retval != 0 && (keyid != NULL || fname != NULL) &&
1925*5c51f124SMoriah Waterland 		    pkey->attributes == NULL) {
1926*5c51f124SMoriah Waterland 			pkey->attributes = sk_X509_ATTRIBUTE_new_null();
1927*5c51f124SMoriah Waterland 			if (pkey->attributes == NULL) {
1928*5c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PARSE_ONE_BAG,
1929*5c51f124SMoriah Waterland 				    SUNW_R_MEMORY_FAILURE);
1930*5c51f124SMoriah Waterland 				retval = 0;
1931*5c51f124SMoriah Waterland 			}
1932*5c51f124SMoriah Waterland 		}
1933*5c51f124SMoriah Waterland 
1934*5c51f124SMoriah Waterland 		if (retval != 0 && keyid != NULL) {
1935*5c51f124SMoriah Waterland 			attr = type2attrib(keyid, NID_localKeyID);
1936*5c51f124SMoriah Waterland 			if (attr == NULL)
1937*5c51f124SMoriah Waterland 				/*
1938*5c51f124SMoriah Waterland 				 * Error already on stack
1939*5c51f124SMoriah Waterland 				 */
1940*5c51f124SMoriah Waterland 				retval = 0;
1941*5c51f124SMoriah Waterland 			else {
1942*5c51f124SMoriah Waterland 				keyid = NULL;
1943*5c51f124SMoriah Waterland 				if (sk_X509_ATTRIBUTE_push(pkey->attributes,
1944*5c51f124SMoriah Waterland 				    attr) == 0) {
1945*5c51f124SMoriah Waterland 					SUNWerr(SUNW_F_PARSE_ONE_BAG,
1946*5c51f124SMoriah Waterland 					    SUNW_R_MEMORY_FAILURE);
1947*5c51f124SMoriah Waterland 					retval = 0;
1948*5c51f124SMoriah Waterland 				} else {
1949*5c51f124SMoriah Waterland 					attr = NULL;
1950*5c51f124SMoriah Waterland 				}
1951*5c51f124SMoriah Waterland 			}
1952*5c51f124SMoriah Waterland 		}
1953*5c51f124SMoriah Waterland 
1954*5c51f124SMoriah Waterland 		if (retval != 0 && fname != NULL) {
1955*5c51f124SMoriah Waterland 			attr = type2attrib(fname, NID_friendlyName);
1956*5c51f124SMoriah Waterland 			if (attr == NULL) {
1957*5c51f124SMoriah Waterland 				/*
1958*5c51f124SMoriah Waterland 				 * Error already on stack
1959*5c51f124SMoriah Waterland 				 */
1960*5c51f124SMoriah Waterland 				retval = 0;
1961*5c51f124SMoriah Waterland 			} else {
1962*5c51f124SMoriah Waterland 				fname = NULL;
1963*5c51f124SMoriah Waterland 				if (sk_X509_ATTRIBUTE_push(pkey->attributes,
1964*5c51f124SMoriah Waterland 				    attr) == 0) {
1965*5c51f124SMoriah Waterland 					SUNWerr(SUNW_F_PARSE_ONE_BAG,
1966*5c51f124SMoriah Waterland 					    SUNW_R_MEMORY_FAILURE);
1967*5c51f124SMoriah Waterland 					retval = 0;
1968*5c51f124SMoriah Waterland 				} else {
1969*5c51f124SMoriah Waterland 					attr = NULL;
1970*5c51f124SMoriah Waterland 				}
1971*5c51f124SMoriah Waterland 			}
1972*5c51f124SMoriah Waterland 		}
1973*5c51f124SMoriah Waterland 
1974*5c51f124SMoriah Waterland 		/* Save the private key */
1975*5c51f124SMoriah Waterland 		if (retval != 0) {
1976*5c51f124SMoriah Waterland 			if (sk_EVP_PKEY_push(kl, pkey) == 0) {
1977*5c51f124SMoriah Waterland 				SUNWerr(SUNW_F_PARSE_ONE_BAG,
1978*5c51f124SMoriah Waterland 				    SUNW_R_MEMORY_FAILURE);
1979*5c51f124SMoriah Waterland 				retval = 0;
1980*5c51f124SMoriah Waterland 			} else {
1981*5c51f124SMoriah Waterland 				pkey = NULL;
1982*5c51f124SMoriah Waterland 			}
1983*5c51f124SMoriah Waterland 		}
1984*5c51f124SMoriah Waterland 	}
1985*5c51f124SMoriah Waterland 
1986*5c51f124SMoriah Waterland 	if (pkey != NULL) {
1987*5c51f124SMoriah Waterland 		sunw_evp_pkey_free(pkey);
1988*5c51f124SMoriah Waterland 	}
1989*5c51f124SMoriah Waterland 
1990*5c51f124SMoriah Waterland 	if (x509 != NULL)
1991*5c51f124SMoriah Waterland 		X509_free(x509);
1992*5c51f124SMoriah Waterland 
1993*5c51f124SMoriah Waterland 	if (keyid != NULL)
1994*5c51f124SMoriah Waterland 		ASN1_TYPE_free(keyid);
1995*5c51f124SMoriah Waterland 
1996*5c51f124SMoriah Waterland 	if (fname != NULL)
1997*5c51f124SMoriah Waterland 		ASN1_TYPE_free(fname);
1998*5c51f124SMoriah Waterland 
1999*5c51f124SMoriah Waterland 	if (attr != NULL)
2000*5c51f124SMoriah Waterland 		X509_ATTRIBUTE_free(attr);
2001*5c51f124SMoriah Waterland 
2002*5c51f124SMoriah Waterland 	if (data != NULL)
2003*5c51f124SMoriah Waterland 		OPENSSL_free(data);
2004*5c51f124SMoriah Waterland 
2005*5c51f124SMoriah Waterland 	if (str != NULL)
2006*5c51f124SMoriah Waterland 		OPENSSL_free(str);
2007*5c51f124SMoriah Waterland 
2008*5c51f124SMoriah Waterland 	return (retval);
2009*5c51f124SMoriah Waterland }
2010*5c51f124SMoriah Waterland 
2011*5c51f124SMoriah Waterland /*
2012*5c51f124SMoriah Waterland  * This function uses the only function that reads PEM files, regardless of
2013*5c51f124SMoriah Waterland  * the kinds of information included (private keys, public keys, cert requests,
2014*5c51f124SMoriah Waterland  * certs).  Other interfaces that read files require that the application
2015*5c51f124SMoriah Waterland  * specifically know what kinds of things to read next, and call different
2016*5c51f124SMoriah Waterland  * interfaces for the different kinds of entities.
2017*5c51f124SMoriah Waterland  *
2018*5c51f124SMoriah Waterland  * There is only one aspect of this function that's a bit problematic.
2019*5c51f124SMoriah Waterland  * If it finds an encrypted private key, it does not decrypt it.  It returns
2020*5c51f124SMoriah Waterland  * the encrypted data and other information needed to decrypt it.  The caller
2021*5c51f124SMoriah Waterland  * must do the decryption.  This function does the decoding.
2022*5c51f124SMoriah Waterland  */
2023*5c51f124SMoriah Waterland static int
2024*5c51f124SMoriah Waterland pem_info(FILE *fp, pem_password_cb cb, void *userdata,
2025*5c51f124SMoriah Waterland     STACK_OF(EVP_PKEY) **pkeys, STACK_OF(X509) **certs)
2026*5c51f124SMoriah Waterland {
2027*5c51f124SMoriah Waterland 	STACK_OF(X509_INFO) *info;
2028*5c51f124SMoriah Waterland 	STACK_OF(EVP_PKEY) *work_kl;
2029*5c51f124SMoriah Waterland 	STACK_OF(X509) *work_cl;
2030*5c51f124SMoriah Waterland 	X509_INFO *x;
2031*5c51f124SMoriah Waterland 	int retval = 0;
2032*5c51f124SMoriah Waterland 	int i;
2033*5c51f124SMoriah Waterland 
2034*5c51f124SMoriah Waterland 	info = PEM_X509_INFO_read(fp, NULL, cb, userdata);
2035*5c51f124SMoriah Waterland 	if (info == NULL) {
2036*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PEM_INFO, SUNW_R_READ_ERR);
2037*5c51f124SMoriah Waterland 		return (-1);
2038*5c51f124SMoriah Waterland 	}
2039*5c51f124SMoriah Waterland 
2040*5c51f124SMoriah Waterland 	/*
2041*5c51f124SMoriah Waterland 	 * Allocate the working stacks for private key(s) and for the cert(s).
2042*5c51f124SMoriah Waterland 	 */
2043*5c51f124SMoriah Waterland 	if ((work_kl = sk_EVP_PKEY_new_null()) == NULL) {
2044*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PEM_INFO, SUNW_R_MEMORY_FAILURE);
2045*5c51f124SMoriah Waterland 		retval = -1;
2046*5c51f124SMoriah Waterland 		goto cleanup;
2047*5c51f124SMoriah Waterland 	}
2048*5c51f124SMoriah Waterland 
2049*5c51f124SMoriah Waterland 	if ((work_cl = sk_X509_new_null()) == NULL) {
2050*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_PEM_INFO, SUNW_R_MEMORY_FAILURE);
2051*5c51f124SMoriah Waterland 		retval = -1;
2052*5c51f124SMoriah Waterland 		goto cleanup;
2053*5c51f124SMoriah Waterland 	}
2054*5c51f124SMoriah Waterland 
2055*5c51f124SMoriah Waterland 	/*
2056*5c51f124SMoriah Waterland 	 * Go through the entries in the info structure.
2057*5c51f124SMoriah Waterland 	 */
2058*5c51f124SMoriah Waterland 	for (i = 0; i < sk_X509_INFO_num(info); i++) {
2059*5c51f124SMoriah Waterland 		x = sk_X509_INFO_value(info, i);
2060*5c51f124SMoriah Waterland 		if (x->x509) {
2061*5c51f124SMoriah Waterland 			if (sk_X509_push(work_cl, x->x509) == 0) {
2062*5c51f124SMoriah Waterland 				retval = -1;
2063*5c51f124SMoriah Waterland 				break;
2064*5c51f124SMoriah Waterland 			}
2065*5c51f124SMoriah Waterland 			x->x509 = NULL;
2066*5c51f124SMoriah Waterland 		}
2067*5c51f124SMoriah Waterland 		if (x->x_pkey != NULL && x->x_pkey->dec_pkey != NULL &&
2068*5c51f124SMoriah Waterland 		    (x->x_pkey->dec_pkey->type == EVP_PKEY_RSA ||
2069*5c51f124SMoriah Waterland 		    x->x_pkey->dec_pkey->type == EVP_PKEY_DSA)) {
2070*5c51f124SMoriah Waterland 			const uchar_t *p;
2071*5c51f124SMoriah Waterland 
2072*5c51f124SMoriah Waterland 			/*
2073*5c51f124SMoriah Waterland 			 * If the key was encrypted, PEM_X509_INFO_read does
2074*5c51f124SMoriah Waterland 			 * not decrypt it.  If that is the case, the 'enc_pkey'
2075*5c51f124SMoriah Waterland 			 * field is set to point to the unencrypted key data.
2076*5c51f124SMoriah Waterland 			 * Go through the additional steps to decode it before
2077*5c51f124SMoriah Waterland 			 * going on.
2078*5c51f124SMoriah Waterland 			 */
2079*5c51f124SMoriah Waterland 			if (x->x_pkey->enc_pkey != NULL) {
2080*5c51f124SMoriah Waterland 
2081*5c51f124SMoriah Waterland 				if (PEM_do_header(&x->enc_cipher,
2082*5c51f124SMoriah Waterland 				    (uchar_t *)x->enc_data,
2083*5c51f124SMoriah Waterland 				    (long *)&x->enc_len,
2084*5c51f124SMoriah Waterland 				    cb, userdata) == 0) {
2085*5c51f124SMoriah Waterland 					if (ERR_GET_REASON(ERR_peek_error()) ==
2086*5c51f124SMoriah Waterland 					    PEM_R_BAD_PASSWORD_READ) {
2087*5c51f124SMoriah Waterland 						SUNWerr(SUNW_F_PEM_INFO,
2088*5c51f124SMoriah Waterland 						    SUNW_R_PASSWORD_ERR);
2089*5c51f124SMoriah Waterland 					} else {
2090*5c51f124SMoriah Waterland 						SUNWerr(SUNW_F_PEM_INFO,
2091*5c51f124SMoriah Waterland 						    SUNW_R_PKEY_READ_ERR);
2092*5c51f124SMoriah Waterland 					}
2093*5c51f124SMoriah Waterland 					retval = -1;
2094*5c51f124SMoriah Waterland 					break;
2095*5c51f124SMoriah Waterland 				}
2096*5c51f124SMoriah Waterland 				if (x->x_pkey->dec_pkey->type == EVP_PKEY_RSA) {
2097*5c51f124SMoriah Waterland 					RSA **pp;
2098*5c51f124SMoriah Waterland 
2099*5c51f124SMoriah Waterland 					pp = &(x->x_pkey->dec_pkey->pkey.rsa);
2100*5c51f124SMoriah Waterland 					p = (uchar_t *)x->enc_data;
2101*5c51f124SMoriah Waterland 					if (d2i_RSAPrivateKey(pp, &p,
2102*5c51f124SMoriah Waterland 					    x->enc_len) == NULL) {
2103*5c51f124SMoriah Waterland 						SUNWerr(SUNW_F_PEM_INFO,
2104*5c51f124SMoriah Waterland 						    SUNW_R_PKEY_READ_ERR);
2105*5c51f124SMoriah Waterland 						retval = -1;
2106*5c51f124SMoriah Waterland 						break;
2107*5c51f124SMoriah Waterland 					}
2108*5c51f124SMoriah Waterland 				} else {
2109*5c51f124SMoriah Waterland 					DSA **pp;
2110*5c51f124SMoriah Waterland 
2111*5c51f124SMoriah Waterland 					pp = &(x->x_pkey->dec_pkey->pkey.dsa);
2112*5c51f124SMoriah Waterland 					p = (uchar_t *)x->enc_data;
2113*5c51f124SMoriah Waterland 					if (d2i_DSAPrivateKey(pp, &p,
2114*5c51f124SMoriah Waterland 					    x->enc_len) == NULL) {
2115*5c51f124SMoriah Waterland 						SUNWerr(SUNW_F_PEM_INFO,
2116*5c51f124SMoriah Waterland 						    SUNW_R_PKEY_READ_ERR);
2117*5c51f124SMoriah Waterland 						retval = -1;
2118*5c51f124SMoriah Waterland 						break;
2119*5c51f124SMoriah Waterland 					}
2120*5c51f124SMoriah Waterland 				}
2121*5c51f124SMoriah Waterland 			}
2122*5c51f124SMoriah Waterland 
2123*5c51f124SMoriah Waterland 			/* Save the key. */
2124*5c51f124SMoriah Waterland 			retval = sk_EVP_PKEY_push(work_kl, x->x_pkey->dec_pkey);
2125*5c51f124SMoriah Waterland 			if (retval == 0) {
2126*5c51f124SMoriah Waterland 				retval = -1;
2127*5c51f124SMoriah Waterland 				break;
2128*5c51f124SMoriah Waterland 			}
2129*5c51f124SMoriah Waterland 			x->x_pkey->dec_pkey = NULL;
2130*5c51f124SMoriah Waterland 		} else if (x->x_pkey != NULL) {
2131*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_PEM_INFO, SUNW_R_BAD_PKEYTYPE);
2132*5c51f124SMoriah Waterland 			retval = -1;
2133*5c51f124SMoriah Waterland 			break;
2134*5c51f124SMoriah Waterland 		}
2135*5c51f124SMoriah Waterland 	}
2136*5c51f124SMoriah Waterland 	if (retval == -1)
2137*5c51f124SMoriah Waterland 		goto cleanup;
2138*5c51f124SMoriah Waterland 
2139*5c51f124SMoriah Waterland 	/* If error occurs, then error already on stack */
2140*5c51f124SMoriah Waterland 	retval = set_results(pkeys, &work_kl, certs, &work_cl, NULL, NULL,
2141*5c51f124SMoriah Waterland 	    NULL, NULL);
2142*5c51f124SMoriah Waterland 
2143*5c51f124SMoriah Waterland cleanup:
2144*5c51f124SMoriah Waterland 	if (work_kl != NULL) {
2145*5c51f124SMoriah Waterland 		sk_EVP_PKEY_pop_free(work_kl, sunw_evp_pkey_free);
2146*5c51f124SMoriah Waterland 	}
2147*5c51f124SMoriah Waterland 	if (work_cl != NULL)
2148*5c51f124SMoriah Waterland 		sk_X509_pop_free(work_cl, X509_free);
2149*5c51f124SMoriah Waterland 
2150*5c51f124SMoriah Waterland 	sk_X509_INFO_pop_free(info, X509_INFO_free);
2151*5c51f124SMoriah Waterland 
2152*5c51f124SMoriah Waterland 	return (retval);
2153*5c51f124SMoriah Waterland }
2154*5c51f124SMoriah Waterland 
2155*5c51f124SMoriah Waterland /*
2156*5c51f124SMoriah Waterland  * sunw_append_keys - Given two stacks of private keys, remove the keys from
2157*5c51f124SMoriah Waterland  *      the second stack and append them to the first.  Both stacks must exist
2158*5c51f124SMoriah Waterland  *      at time of call.
2159*5c51f124SMoriah Waterland  *
2160*5c51f124SMoriah Waterland  * Arguments:
2161*5c51f124SMoriah Waterland  *   dst 	- the stack to receive the keys from 'src'
2162*5c51f124SMoriah Waterland  *   src	- the stack whose keys are to be moved.
2163*5c51f124SMoriah Waterland  *
2164*5c51f124SMoriah Waterland  * Returns:
2165*5c51f124SMoriah Waterland  *   -1  	- An error occurred.  The error status is set.
2166*5c51f124SMoriah Waterland  *   >= 0       - The number of keys that were copied.
2167*5c51f124SMoriah Waterland  */
2168*5c51f124SMoriah Waterland static int
2169*5c51f124SMoriah Waterland sunw_append_keys(STACK_OF(EVP_PKEY) *dst, STACK_OF(EVP_PKEY) *src)
2170*5c51f124SMoriah Waterland {
2171*5c51f124SMoriah Waterland 	EVP_PKEY *tmpk;
2172*5c51f124SMoriah Waterland 	int count = 0;
2173*5c51f124SMoriah Waterland 
2174*5c51f124SMoriah Waterland 	while (sk_EVP_PKEY_num(src) > 0) {
2175*5c51f124SMoriah Waterland 		tmpk = sk_EVP_PKEY_delete(src, 0);
2176*5c51f124SMoriah Waterland 		if (sk_EVP_PKEY_push(dst, tmpk) == 0) {
2177*5c51f124SMoriah Waterland 			sunw_evp_pkey_free(tmpk);
2178*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_APPEND_KEYS, SUNW_R_MEMORY_FAILURE);
2179*5c51f124SMoriah Waterland 			return (-1);
2180*5c51f124SMoriah Waterland 		}
2181*5c51f124SMoriah Waterland 		count ++;
2182*5c51f124SMoriah Waterland 	}
2183*5c51f124SMoriah Waterland 
2184*5c51f124SMoriah Waterland 	return (count);
2185*5c51f124SMoriah Waterland }
2186*5c51f124SMoriah Waterland 
2187*5c51f124SMoriah Waterland /*
2188*5c51f124SMoriah Waterland  * move_certs - Given two stacks of certs, remove the certs from
2189*5c51f124SMoriah Waterland  *      the second stack and append them to the first.
2190*5c51f124SMoriah Waterland  *
2191*5c51f124SMoriah Waterland  * Arguments:
2192*5c51f124SMoriah Waterland  *   dst 	- the stack to receive the certs from 'src'
2193*5c51f124SMoriah Waterland  *   src	- the stack whose certs are to be moved.
2194*5c51f124SMoriah Waterland  *
2195*5c51f124SMoriah Waterland  * Returns:
2196*5c51f124SMoriah Waterland  *   -1  	- An error occurred.  The error status is set.
2197*5c51f124SMoriah Waterland  *   >= 0       - The number of certs that were copied.
2198*5c51f124SMoriah Waterland  */
2199*5c51f124SMoriah Waterland static int
2200*5c51f124SMoriah Waterland move_certs(STACK_OF(X509) *dst, STACK_OF(X509) *src)
2201*5c51f124SMoriah Waterland {
2202*5c51f124SMoriah Waterland 	X509 *tmpc;
2203*5c51f124SMoriah Waterland 	int count = 0;
2204*5c51f124SMoriah Waterland 
2205*5c51f124SMoriah Waterland 	while (sk_X509_num(src) > 0) {
2206*5c51f124SMoriah Waterland 		tmpc = sk_X509_delete(src, 0);
2207*5c51f124SMoriah Waterland 		if (sk_X509_push(dst, tmpc) == 0) {
2208*5c51f124SMoriah Waterland 			X509_free(tmpc);
2209*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_MOVE_CERTS, SUNW_R_MEMORY_FAILURE);
2210*5c51f124SMoriah Waterland 			return (-1);
2211*5c51f124SMoriah Waterland 		}
2212*5c51f124SMoriah Waterland 		count++;
2213*5c51f124SMoriah Waterland 	}
2214*5c51f124SMoriah Waterland 
2215*5c51f124SMoriah Waterland 	return (count);
2216*5c51f124SMoriah Waterland }
2217*5c51f124SMoriah Waterland 
2218*5c51f124SMoriah Waterland /*
2219*5c51f124SMoriah Waterland  * get_key_cert - Get a cert and its matching key from the stacks of certs
2220*5c51f124SMoriah Waterland  *      and keys.  They are removed from the stacks.
2221*5c51f124SMoriah Waterland  *
2222*5c51f124SMoriah Waterland  * Arguments:
2223*5c51f124SMoriah Waterland  *   n        - Offset of the entries to return.
2224*5c51f124SMoriah Waterland  *   kl       - Points to a stack of private keys that matches the list of
2225*5c51f124SMoriah Waterland  *              certs below.
2226*5c51f124SMoriah Waterland  *   pkey     - Points at location where the address of the matching private
2227*5c51f124SMoriah Waterland  *              key will be stored.
2228*5c51f124SMoriah Waterland  *   cl       - Points to a stack of client certs with matching private keys.
2229*5c51f124SMoriah Waterland  *   cert     - Points to locaiton where the address of the matching client cert
2230*5c51f124SMoriah Waterland  *              will be returned
2231*5c51f124SMoriah Waterland  *
2232*5c51f124SMoriah Waterland  * The assumption is that the stacks of keys and certs contain key/cert pairs,
2233*5c51f124SMoriah Waterland  * with entries in the same order and hence at the same offset.  Provided
2234*5c51f124SMoriah Waterland  * the key and cert selected match, each will be removed from its stack and
2235*5c51f124SMoriah Waterland  * returned.
2236*5c51f124SMoriah Waterland  *
2237*5c51f124SMoriah Waterland  * A stack of certs can be passed in without a stack of private keys, and vise
2238*5c51f124SMoriah Waterland  * versa.  In that case, the indicated key/cert will be returned.
2239*5c51f124SMoriah Waterland  *
2240*5c51f124SMoriah Waterland  * Returns:
2241*5c51f124SMoriah Waterland  *     0 - No matches were found.
2242*5c51f124SMoriah Waterland  *   > 0 - Bits set based on FOUND_* definitions, indicating what is returned.
2243*5c51f124SMoriah Waterland  *         This can be FOUND_PKEY, FOUND_CERT or (FOUND_PKEY | FOUND_CERT).
2244*5c51f124SMoriah Waterland  */
2245*5c51f124SMoriah Waterland static int
2246*5c51f124SMoriah Waterland get_key_cert(int n, STACK_OF(EVP_PKEY) *kl, EVP_PKEY **pkey, STACK_OF(X509) *cl,
2247*5c51f124SMoriah Waterland     X509 **cert)
2248*5c51f124SMoriah Waterland {
2249*5c51f124SMoriah Waterland 	int retval = 0;
2250*5c51f124SMoriah Waterland 	int nk;
2251*5c51f124SMoriah Waterland 	int nc;
2252*5c51f124SMoriah Waterland 
2253*5c51f124SMoriah Waterland 	nk = (kl != NULL) ? sk_EVP_PKEY_num(kl) : 0;
2254*5c51f124SMoriah Waterland 	nc = (cl != NULL) ? sk_X509_num(cl) : 0;
2255*5c51f124SMoriah Waterland 
2256*5c51f124SMoriah Waterland 	if (pkey != NULL && *pkey == NULL) {
2257*5c51f124SMoriah Waterland 		if (nk > 0 && n >= 0 || n < nk) {
2258*5c51f124SMoriah Waterland 			*pkey = sk_EVP_PKEY_delete(kl, n);
2259*5c51f124SMoriah Waterland 			if (*pkey != NULL)
2260*5c51f124SMoriah Waterland 				retval |= FOUND_PKEY;
2261*5c51f124SMoriah Waterland 		}
2262*5c51f124SMoriah Waterland 	}
2263*5c51f124SMoriah Waterland 
2264*5c51f124SMoriah Waterland 	if (cert != NULL && *cert == NULL) {
2265*5c51f124SMoriah Waterland 		if (nc > 0 && n >= 0 && n < nc) {
2266*5c51f124SMoriah Waterland 			*cert = sk_X509_delete(cl, n);
2267*5c51f124SMoriah Waterland 			if (*cert != NULL)
2268*5c51f124SMoriah Waterland 				retval |= FOUND_CERT;
2269*5c51f124SMoriah Waterland 		}
2270*5c51f124SMoriah Waterland 	}
2271*5c51f124SMoriah Waterland 
2272*5c51f124SMoriah Waterland 	return (retval);
2273*5c51f124SMoriah Waterland }
2274*5c51f124SMoriah Waterland 
2275*5c51f124SMoriah Waterland 
2276*5c51f124SMoriah Waterland /*
2277*5c51f124SMoriah Waterland  * asc2bmpstring - Convert a regular C ASCII string to an ASn1_STRING in
2278*5c51f124SMoriah Waterland  *         ASN1_BMPSTRING format.
2279*5c51f124SMoriah Waterland  *
2280*5c51f124SMoriah Waterland  * Arguments:
2281*5c51f124SMoriah Waterland  *   str      - String to be convered.
2282*5c51f124SMoriah Waterland  *   len      - Length of the string.
2283*5c51f124SMoriah Waterland  *
2284*5c51f124SMoriah Waterland  * Returns:
2285*5c51f124SMoriah Waterland  *   == NULL  - An error occurred.  Error information (accessible by
2286*5c51f124SMoriah Waterland  *              ERR_get_error()) is set.
2287*5c51f124SMoriah Waterland  *   != NULL  - Points to an ASN1_BMPSTRING structure with the converted
2288*5c51f124SMoriah Waterland  *              string as a value.
2289*5c51f124SMoriah Waterland  */
2290*5c51f124SMoriah Waterland static ASN1_BMPSTRING *
2291*5c51f124SMoriah Waterland asc2bmpstring(const char *str, int len)
2292*5c51f124SMoriah Waterland {
2293*5c51f124SMoriah Waterland 	ASN1_BMPSTRING *bmp = NULL;
2294*5c51f124SMoriah Waterland 	uchar_t *uni = NULL;
2295*5c51f124SMoriah Waterland 	int unilen;
2296*5c51f124SMoriah Waterland 
2297*5c51f124SMoriah Waterland 	/* Convert the character to the bmp format. */
2298*5c51f124SMoriah Waterland 	if (asc2uni(str, len, &uni, &unilen) == 0) {
2299*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_ASC2BMPSTRING, SUNW_R_MEMORY_FAILURE);
2300*5c51f124SMoriah Waterland 		return (NULL);
2301*5c51f124SMoriah Waterland 	}
2302*5c51f124SMoriah Waterland 
2303*5c51f124SMoriah Waterland 	/*
2304*5c51f124SMoriah Waterland 	 * Adjust for possible pair of NULL bytes at the end because
2305*5c51f124SMoriah Waterland 	 * asc2uni() returns a doubly null terminated string.
2306*5c51f124SMoriah Waterland 	 */
2307*5c51f124SMoriah Waterland 	if (uni[unilen - 1] == '\0' && uni[unilen - 2] == '\0')
2308*5c51f124SMoriah Waterland 		unilen -= 2;
2309*5c51f124SMoriah Waterland 
2310*5c51f124SMoriah Waterland 	/* Construct comparison string with correct format */
2311*5c51f124SMoriah Waterland 	bmp = M_ASN1_BMPSTRING_new();
2312*5c51f124SMoriah Waterland 	if (bmp == NULL) {
2313*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_ASC2BMPSTRING, SUNW_R_MEMORY_FAILURE);
2314*5c51f124SMoriah Waterland 		OPENSSL_free(uni);
2315*5c51f124SMoriah Waterland 		return (NULL);
2316*5c51f124SMoriah Waterland 	}
2317*5c51f124SMoriah Waterland 
2318*5c51f124SMoriah Waterland 	bmp->data = uni;
2319*5c51f124SMoriah Waterland 	bmp->length = unilen;
2320*5c51f124SMoriah Waterland 
2321*5c51f124SMoriah Waterland 	return (bmp);
2322*5c51f124SMoriah Waterland }
2323*5c51f124SMoriah Waterland 
2324*5c51f124SMoriah Waterland /*
2325*5c51f124SMoriah Waterland  * utf82ascstr - Convert a UTF8STRING string to a regular C ASCII string.
2326*5c51f124SMoriah Waterland  *         This goes through an intermediate step with a ASN1_STRING type of
2327*5c51f124SMoriah Waterland  *         IA5STRING (International Alphabet 5, which is the same as ASCII).
2328*5c51f124SMoriah Waterland  *
2329*5c51f124SMoriah Waterland  * Arguments:
2330*5c51f124SMoriah Waterland  *   str      - UTF8STRING to be converted.
2331*5c51f124SMoriah Waterland  *
2332*5c51f124SMoriah Waterland  * Returns:
2333*5c51f124SMoriah Waterland  *   == NULL  - An error occurred.  Error information (accessible by
2334*5c51f124SMoriah Waterland  *              ERR_get_error()) is set.
2335*5c51f124SMoriah Waterland  *   != NULL  - Points to a NULL-termianted ASCII string.  The caller must
2336*5c51f124SMoriah Waterland  *              free it.
2337*5c51f124SMoriah Waterland  */
2338*5c51f124SMoriah Waterland static uchar_t *
2339*5c51f124SMoriah Waterland utf82ascstr(ASN1_UTF8STRING *ustr)
2340*5c51f124SMoriah Waterland {
2341*5c51f124SMoriah Waterland 	ASN1_STRING tmpstr;
2342*5c51f124SMoriah Waterland 	ASN1_STRING *astr = &tmpstr;
2343*5c51f124SMoriah Waterland 	uchar_t *retstr = NULL;
2344*5c51f124SMoriah Waterland 	int mbflag;
2345*5c51f124SMoriah Waterland 	int ret;
2346*5c51f124SMoriah Waterland 
2347*5c51f124SMoriah Waterland 	if (ustr == NULL || ustr->type != V_ASN1_UTF8STRING) {
2348*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_UTF82ASCSTR, SUNW_R_INVALID_ARG);
2349*5c51f124SMoriah Waterland 		return (NULL);
2350*5c51f124SMoriah Waterland 	}
2351*5c51f124SMoriah Waterland 
2352*5c51f124SMoriah Waterland 	mbflag = MBSTRING_ASC;
2353*5c51f124SMoriah Waterland 	tmpstr.data = NULL;
2354*5c51f124SMoriah Waterland 	tmpstr.length = 0;
2355*5c51f124SMoriah Waterland 
2356*5c51f124SMoriah Waterland 	ret = ASN1_mbstring_copy(&astr, ustr->data, ustr->length, mbflag,
2357*5c51f124SMoriah Waterland 	    B_ASN1_IA5STRING);
2358*5c51f124SMoriah Waterland 	if (ret < 0) {
2359*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_UTF82ASCSTR, SUNW_R_STR_CONVERT_ERR);
2360*5c51f124SMoriah Waterland 		return (NULL);
2361*5c51f124SMoriah Waterland 	}
2362*5c51f124SMoriah Waterland 
2363*5c51f124SMoriah Waterland 	retstr = OPENSSL_malloc(astr->length + 1);
2364*5c51f124SMoriah Waterland 	if (retstr == NULL) {
2365*5c51f124SMoriah Waterland 		SUNWerr(SUNW_F_UTF82ASCSTR, SUNW_R_MEMORY_FAILURE);
2366*5c51f124SMoriah Waterland 		return (NULL);
2367*5c51f124SMoriah Waterland 	}
2368*5c51f124SMoriah Waterland 
2369*5c51f124SMoriah Waterland 	(void) memcpy(retstr, astr->data, astr->length);
2370*5c51f124SMoriah Waterland 	retstr[astr->length] = '\0';
2371*5c51f124SMoriah Waterland 	OPENSSL_free(astr->data);
2372*5c51f124SMoriah Waterland 
2373*5c51f124SMoriah Waterland 	return (retstr);
2374*5c51f124SMoriah Waterland }
2375*5c51f124SMoriah Waterland 
2376*5c51f124SMoriah Waterland 
2377*5c51f124SMoriah Waterland /*
2378*5c51f124SMoriah Waterland  * type2attrib - Given a ASN1_TYPE, return a X509_ATTRIBUTE of the type
2379*5c51f124SMoriah Waterland  *     specified by the given NID.
2380*5c51f124SMoriah Waterland  *
2381*5c51f124SMoriah Waterland  * Arguments:
2382*5c51f124SMoriah Waterland  *   ty       - Type structure to be made into an attribute
2383*5c51f124SMoriah Waterland  *   nid      - NID of the attribute
2384*5c51f124SMoriah Waterland  *
2385*5c51f124SMoriah Waterland  * Returns:
2386*5c51f124SMoriah Waterland  *   NULL	An error occurred.
2387*5c51f124SMoriah Waterland  *   != NULL	An X509_ATTRIBUTE structure.
2388*5c51f124SMoriah Waterland  */
2389*5c51f124SMoriah Waterland X509_ATTRIBUTE *
2390*5c51f124SMoriah Waterland type2attrib(ASN1_TYPE *ty, int nid)
2391*5c51f124SMoriah Waterland {
2392*5c51f124SMoriah Waterland 	X509_ATTRIBUTE *a;
2393*5c51f124SMoriah Waterland 
2394*5c51f124SMoriah Waterland 	if ((a = X509_ATTRIBUTE_new()) == NULL ||
2395*5c51f124SMoriah Waterland 	    (a->value.set = sk_ASN1_TYPE_new_null()) == NULL ||
2396*5c51f124SMoriah Waterland 	    sk_ASN1_TYPE_push(a->value.set, ty) == 0) {
2397*5c51f124SMoriah Waterland 		if (a != NULL)
2398*5c51f124SMoriah Waterland 			X509_ATTRIBUTE_free(a);
2399*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_TYPE2ATTRIB, SUNW_R_MEMORY_FAILURE);
2400*5c51f124SMoriah Waterland 		return (NULL);
2401*5c51f124SMoriah Waterland 	}
2402*5c51f124SMoriah Waterland 	a->single = 0;
2403*5c51f124SMoriah Waterland 	a->object = OBJ_nid2obj(nid);
2404*5c51f124SMoriah Waterland 
2405*5c51f124SMoriah Waterland 	return (a);
2406*5c51f124SMoriah Waterland }
2407*5c51f124SMoriah Waterland 
2408*5c51f124SMoriah Waterland /*
2409*5c51f124SMoriah Waterland  * attrib2type - Given a X509_ATTRIBUTE, return pointer to the ASN1_TYPE
2410*5c51f124SMoriah Waterland  *     component
2411*5c51f124SMoriah Waterland  *
2412*5c51f124SMoriah Waterland  * Arguments:
2413*5c51f124SMoriah Waterland  *   attr     - Attribute structure containing a type.
2414*5c51f124SMoriah Waterland  *
2415*5c51f124SMoriah Waterland  * Returns:
2416*5c51f124SMoriah Waterland  *   NULL	An error occurred.
2417*5c51f124SMoriah Waterland  *   != NULL	An ASN1_TYPE structure.
2418*5c51f124SMoriah Waterland  */
2419*5c51f124SMoriah Waterland static ASN1_TYPE *
2420*5c51f124SMoriah Waterland attrib2type(X509_ATTRIBUTE *attr)
2421*5c51f124SMoriah Waterland {
2422*5c51f124SMoriah Waterland 	ASN1_TYPE *ty = NULL;
2423*5c51f124SMoriah Waterland 
2424*5c51f124SMoriah Waterland 	if (attr == NULL || attr->single == 1)
2425*5c51f124SMoriah Waterland 		return (NULL);
2426*5c51f124SMoriah Waterland 
2427*5c51f124SMoriah Waterland 	if (sk_ASN1_TYPE_num(attr->value.set) > 0)
2428*5c51f124SMoriah Waterland 		ty = sk_ASN1_TYPE_value(attr->value.set, 0);
2429*5c51f124SMoriah Waterland 
2430*5c51f124SMoriah Waterland 	return (ty);
2431*5c51f124SMoriah Waterland }
2432*5c51f124SMoriah Waterland 
2433*5c51f124SMoriah Waterland /*
2434*5c51f124SMoriah Waterland  * find_attr_by_nid - Given a ASN1_TYPE, return the offset of a X509_ATTRIBUTE
2435*5c51f124SMoriah Waterland  *     of the type specified by the given NID.
2436*5c51f124SMoriah Waterland  *
2437*5c51f124SMoriah Waterland  * Arguments:
2438*5c51f124SMoriah Waterland  *   attrs    - Stack of attributes to search
2439*5c51f124SMoriah Waterland  *   nid      - NID of the attribute being searched for
2440*5c51f124SMoriah Waterland  *
2441*5c51f124SMoriah Waterland  * Returns:
2442*5c51f124SMoriah Waterland  *   -1 	None found
2443*5c51f124SMoriah Waterland  *   != -1	Offset of the matching attribute.
2444*5c51f124SMoriah Waterland  */
2445*5c51f124SMoriah Waterland static int
2446*5c51f124SMoriah Waterland find_attr_by_nid(STACK_OF(X509_ATTRIBUTE) *attrs, int nid)
2447*5c51f124SMoriah Waterland {
2448*5c51f124SMoriah Waterland 	X509_ATTRIBUTE *a;
2449*5c51f124SMoriah Waterland 	int i;
2450*5c51f124SMoriah Waterland 
2451*5c51f124SMoriah Waterland 	if (attrs == NULL)
2452*5c51f124SMoriah Waterland 		return (-1);
2453*5c51f124SMoriah Waterland 
2454*5c51f124SMoriah Waterland 	for (i = 0; i < sk_X509_ATTRIBUTE_num(attrs); i++) {
2455*5c51f124SMoriah Waterland 		a = sk_X509_ATTRIBUTE_value(attrs, i);
2456*5c51f124SMoriah Waterland 		if (OBJ_obj2nid(a->object) == nid)
2457*5c51f124SMoriah Waterland 			return (i);
2458*5c51f124SMoriah Waterland 	}
2459*5c51f124SMoriah Waterland 	return (-1);
2460*5c51f124SMoriah Waterland }
2461*5c51f124SMoriah Waterland 
2462*5c51f124SMoriah Waterland /*
2463*5c51f124SMoriah Waterland  * Called by our PKCS12 code to read our function and error codes
2464*5c51f124SMoriah Waterland  * into memory so that the OpenSSL framework can retrieve them.
2465*5c51f124SMoriah Waterland  */
2466*5c51f124SMoriah Waterland void
2467*5c51f124SMoriah Waterland ERR_load_SUNW_strings(void)
2468*5c51f124SMoriah Waterland {
2469*5c51f124SMoriah Waterland 	assert(SUNW_lib_error_code == 0);
2470*5c51f124SMoriah Waterland #ifndef OPENSSL_NO_ERR
2471*5c51f124SMoriah Waterland 	/*
2472*5c51f124SMoriah Waterland 	 * Have OpenSSL provide us with a unique ID.
2473*5c51f124SMoriah Waterland 	 */
2474*5c51f124SMoriah Waterland 	SUNW_lib_error_code = ERR_get_next_error_library();
2475*5c51f124SMoriah Waterland 
2476*5c51f124SMoriah Waterland 	ERR_load_strings(SUNW_lib_error_code, SUNW_str_functs);
2477*5c51f124SMoriah Waterland 	ERR_load_strings(SUNW_lib_error_code, SUNW_str_reasons);
2478*5c51f124SMoriah Waterland 
2479*5c51f124SMoriah Waterland 	SUNW_lib_name->error = ERR_PACK(SUNW_lib_error_code, 0, 0);
2480*5c51f124SMoriah Waterland 	ERR_load_strings(0, SUNW_lib_name);
2481*5c51f124SMoriah Waterland #endif
2482*5c51f124SMoriah Waterland }
2483*5c51f124SMoriah Waterland 
2484*5c51f124SMoriah Waterland /*
2485*5c51f124SMoriah Waterland  * The SUNWerr macro resolves to this routine. So when we need
2486*5c51f124SMoriah Waterland  * to push an error, this routine does it for us. Notice that
2487*5c51f124SMoriah Waterland  * the SUNWerr macro provides a filename and line #.
2488*5c51f124SMoriah Waterland  */
2489*5c51f124SMoriah Waterland void
2490*5c51f124SMoriah Waterland ERR_SUNW_error(int function, int reason, char *file, int line)
2491*5c51f124SMoriah Waterland {
2492*5c51f124SMoriah Waterland 	assert(SUNW_lib_error_code != 0);
2493*5c51f124SMoriah Waterland #ifndef OPENSSL_NO_ERR
2494*5c51f124SMoriah Waterland 	ERR_PUT_error(SUNW_lib_error_code, function, reason, file, line);
2495*5c51f124SMoriah Waterland #endif
2496*5c51f124SMoriah Waterland }
2497*5c51f124SMoriah Waterland 
2498*5c51f124SMoriah Waterland /*
2499*5c51f124SMoriah Waterland  * check_time - Given an indication of the which time(s) to check, check
2500*5c51f124SMoriah Waterland  *      that time or those times against the current time and return the
2501*5c51f124SMoriah Waterland  *      relationship.
2502*5c51f124SMoriah Waterland  *
2503*5c51f124SMoriah Waterland  * Arguments:
2504*5c51f124SMoriah Waterland  *   chkwhat    - What kind of check to do.
2505*5c51f124SMoriah Waterland  *   cert	- The cert to check.
2506*5c51f124SMoriah Waterland  *
2507*5c51f124SMoriah Waterland  * Returns:
2508*5c51f124SMoriah Waterland  *   CHKERR_* values.
2509*5c51f124SMoriah Waterland  */
2510*5c51f124SMoriah Waterland static chk_errs_t
2511*5c51f124SMoriah Waterland check_time(chk_actions_t chkwhat, X509 *cert)
2512*5c51f124SMoriah Waterland {
2513*5c51f124SMoriah Waterland 	int i;
2514*5c51f124SMoriah Waterland 
2515*5c51f124SMoriah Waterland 	if (chkwhat == CHK_NOT_BEFORE || chkwhat == CHK_BOTH) {
2516*5c51f124SMoriah Waterland 		i = X509_cmp_time(X509_get_notBefore(cert), NULL);
2517*5c51f124SMoriah Waterland 		if (i == 0)
2518*5c51f124SMoriah Waterland 			return (CHKERR_TIME_BEFORE_BAD);
2519*5c51f124SMoriah Waterland 		if (i > 0)
2520*5c51f124SMoriah Waterland 			return (CHKERR_TIME_IS_BEFORE);
2521*5c51f124SMoriah Waterland 
2522*5c51f124SMoriah Waterland 		/* The current time is after the 'not before' time */
2523*5c51f124SMoriah Waterland 	}
2524*5c51f124SMoriah Waterland 
2525*5c51f124SMoriah Waterland 	if (chkwhat == CHK_NOT_AFTER || chkwhat == CHK_BOTH) {
2526*5c51f124SMoriah Waterland 		i = X509_cmp_time(X509_get_notAfter(cert), NULL);
2527*5c51f124SMoriah Waterland 		if (i == 0)
2528*5c51f124SMoriah Waterland 			return (CHKERR_TIME_AFTER_BAD);
2529*5c51f124SMoriah Waterland 		if (i < 0)
2530*5c51f124SMoriah Waterland 			return (CHKERR_TIME_HAS_EXPIRED);
2531*5c51f124SMoriah Waterland 	}
2532*5c51f124SMoriah Waterland 
2533*5c51f124SMoriah Waterland 	return (CHKERR_TIME_OK);
2534*5c51f124SMoriah Waterland }
2535*5c51f124SMoriah Waterland 
2536*5c51f124SMoriah Waterland /*
2537*5c51f124SMoriah Waterland  * find_attr - Look for a given attribute of the type associated with the NID.
2538*5c51f124SMoriah Waterland  *
2539*5c51f124SMoriah Waterland  * Arguments:
2540*5c51f124SMoriah Waterland  *   nid      - NID for the attribute to be found (either NID_friendlyName or
2541*5c51f124SMoriah Waterland  *              NID_locakKeyId)
2542*5c51f124SMoriah Waterland  *   str      - ASN1_STRING-type structure containing the value to be found,
2543*5c51f124SMoriah Waterland  *              FriendlyName expects a ASN1_BMPSTRING and localKeyID uses a
2544*5c51f124SMoriah Waterland  *              ASN1_STRING.
2545*5c51f124SMoriah Waterland  *   kl       - Points to a stack of private keys.
2546*5c51f124SMoriah Waterland  *   pkey     - Points at a location where the address of the matching private
2547*5c51f124SMoriah Waterland  *              key will be stored.
2548*5c51f124SMoriah Waterland  *   cl       - Points to a stack of client certs with matching private keys.
2549*5c51f124SMoriah Waterland  *   cert     - Points to locaiton where the address of the matching client cert
2550*5c51f124SMoriah Waterland  *              will be returned
2551*5c51f124SMoriah Waterland  *
2552*5c51f124SMoriah Waterland  * This function is designed to process lists of certs and private keys.
2553*5c51f124SMoriah Waterland  * This is made complex because these the attributes are stored differently
2554*5c51f124SMoriah Waterland  * for certs and for keys.  For certs, only a few attributes are retained.
2555*5c51f124SMoriah Waterland  * FriendlyName is stored in the aux structure, under the name 'alias'.
2556*5c51f124SMoriah Waterland  * LocalKeyId is also stored in the aux structure, under the name 'keyid'.
2557*5c51f124SMoriah Waterland  * A pkey structure has a stack of attributes.
2558*5c51f124SMoriah Waterland  *
2559*5c51f124SMoriah Waterland  * The basic approach is:
2560*5c51f124SMoriah Waterland  *   - If there there is no stack of certs but a stack of private keys exists,
2561*5c51f124SMoriah Waterland  *     search the stack of keys for a match. Alternately, if there is a stack
2562*5c51f124SMoriah Waterland  *     of certs and no private keys, search the certs.
2563*5c51f124SMoriah Waterland  *
2564*5c51f124SMoriah Waterland  *   - If there are both certs and keys, assume that the matching certs and
2565*5c51f124SMoriah Waterland  *     keys are in their respective stacks, with matching entries in the same
2566*5c51f124SMoriah Waterland  *     order.  Search for the name or keyid in the stack of certs.  If it is
2567*5c51f124SMoriah Waterland  *     not found, then this function returns 0 (nothing found).
2568*5c51f124SMoriah Waterland  *
2569*5c51f124SMoriah Waterland  *   - Once a cert is found, verify that the key actually matches by
2570*5c51f124SMoriah Waterland  *     comparing the private key with the public key (in the cert).
2571*5c51f124SMoriah Waterland  *     If they don't match, return an error.
2572*5c51f124SMoriah Waterland  *
2573*5c51f124SMoriah Waterland  *   A pointer to cert and/or pkey which matches the name or keyid is stored
2574*5c51f124SMoriah Waterland  *   in the return arguments.
2575*5c51f124SMoriah Waterland  *
2576*5c51f124SMoriah Waterland  * Returns:
2577*5c51f124SMoriah Waterland  *     0 - No matches were found.
2578*5c51f124SMoriah Waterland  *   > 0 - Bits set based on FOUND_* definitions, indicating what was found.
2579*5c51f124SMoriah Waterland  *         This can be FOUND_PKEY, FOUND_CERT or (FOUND_PKEY | FOUND_CERT).
2580*5c51f124SMoriah Waterland  */
2581*5c51f124SMoriah Waterland static int
2582*5c51f124SMoriah Waterland find_attr(int nid, ASN1_STRING *str, STACK_OF(EVP_PKEY) *kl, EVP_PKEY **pkey,
2583*5c51f124SMoriah Waterland     STACK_OF(X509) *cl, X509 **cert)
2584*5c51f124SMoriah Waterland {
2585*5c51f124SMoriah Waterland 	ASN1_UTF8STRING *ustr = NULL;
2586*5c51f124SMoriah Waterland 	ASN1_STRING *s;
2587*5c51f124SMoriah Waterland 	ASN1_TYPE *t;
2588*5c51f124SMoriah Waterland 	EVP_PKEY *p;
2589*5c51f124SMoriah Waterland 	uchar_t *fname = NULL;
2590*5c51f124SMoriah Waterland 	X509 *x;
2591*5c51f124SMoriah Waterland 	int found = 0;
2592*5c51f124SMoriah Waterland 	int chkcerts;
2593*5c51f124SMoriah Waterland 	int len;
2594*5c51f124SMoriah Waterland 	int res;
2595*5c51f124SMoriah Waterland 	int c = -1;
2596*5c51f124SMoriah Waterland 	int k = -1;
2597*5c51f124SMoriah Waterland 
2598*5c51f124SMoriah Waterland 	chkcerts = (cert != NULL || pkey != NULL) && cl != NULL;
2599*5c51f124SMoriah Waterland 	if (chkcerts && nid == NID_friendlyName &&
2600*5c51f124SMoriah Waterland 	    str->type == V_ASN1_BMPSTRING) {
2601*5c51f124SMoriah Waterland 		ustr = ASN1_UTF8STRING_new();
2602*5c51f124SMoriah Waterland 		if (ustr == NULL) {
2603*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_FINDATTR, SUNW_R_MEMORY_FAILURE);
2604*5c51f124SMoriah Waterland 			return (0);
2605*5c51f124SMoriah Waterland 		}
2606*5c51f124SMoriah Waterland 		len = ASN1_STRING_to_UTF8(&fname, str);
2607*5c51f124SMoriah Waterland 		if (fname == NULL) {
2608*5c51f124SMoriah Waterland 			ASN1_UTF8STRING_free(ustr);
2609*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_FINDATTR, SUNW_R_STR_CONVERT_ERR);
2610*5c51f124SMoriah Waterland 			return (0);
2611*5c51f124SMoriah Waterland 		}
2612*5c51f124SMoriah Waterland 
2613*5c51f124SMoriah Waterland 		if (ASN1_STRING_set(ustr, fname, len) == 0) {
2614*5c51f124SMoriah Waterland 			ASN1_UTF8STRING_free(ustr);
2615*5c51f124SMoriah Waterland 			OPENSSL_free(fname);
2616*5c51f124SMoriah Waterland 			SUNWerr(SUNW_F_FINDATTR, SUNW_R_MEMORY_FAILURE);
2617*5c51f124SMoriah Waterland 			return (0);
2618*5c51f124SMoriah Waterland 		}
2619*5c51f124SMoriah Waterland 	}
2620*5c51f124SMoriah Waterland 
2621*5c51f124SMoriah Waterland 	if (chkcerts) {
2622*5c51f124SMoriah Waterland 		for (c = 0; c < sk_X509_num(cl); c++) {
2623*5c51f124SMoriah Waterland 			res = -1;
2624*5c51f124SMoriah Waterland 			x = sk_X509_value(cl, c);
2625*5c51f124SMoriah Waterland 			if (nid == NID_friendlyName && ustr != NULL) {
2626*5c51f124SMoriah Waterland 				if (x->aux == NULL || x->aux->alias == NULL)
2627*5c51f124SMoriah Waterland 					continue;
2628*5c51f124SMoriah Waterland 				s = x->aux->alias;
2629*5c51f124SMoriah Waterland 				if (s != NULL && s->type == ustr->type &&
2630*5c51f124SMoriah Waterland 				    s->data != NULL) {
2631*5c51f124SMoriah Waterland 					res = ASN1_STRING_cmp(s, ustr);
2632*5c51f124SMoriah Waterland 				}
2633*5c51f124SMoriah Waterland 			} else {
2634*5c51f124SMoriah Waterland 				if (x->aux == NULL || x->aux->keyid == NULL)
2635*5c51f124SMoriah Waterland 					continue;
2636*5c51f124SMoriah Waterland 				s = x->aux->keyid;
2637*5c51f124SMoriah Waterland 				if (s != NULL && s->type == str->type &&
2638*5c51f124SMoriah Waterland 				    s->data != NULL) {
2639*5c51f124SMoriah Waterland 					res = ASN1_STRING_cmp(s, str);
2640*5c51f124SMoriah Waterland 				}
2641*5c51f124SMoriah Waterland 			}
2642*5c51f124SMoriah Waterland 			if (res == 0) {
2643*5c51f124SMoriah Waterland 				if (cert != NULL)
2644*5c51f124SMoriah Waterland 					*cert = sk_X509_delete(cl, c);
2645*5c51f124SMoriah Waterland 				found = FOUND_CERT;
2646*5c51f124SMoriah Waterland 				break;
2647*5c51f124SMoriah Waterland 			}
2648*5c51f124SMoriah Waterland 		}
2649*5c51f124SMoriah Waterland 		if (ustr != NULL) {
2650*5c51f124SMoriah Waterland 			ASN1_UTF8STRING_free(ustr);
2651*5c51f124SMoriah Waterland 			OPENSSL_free(fname);
2652*5c51f124SMoriah Waterland 		}
2653*5c51f124SMoriah Waterland 	}
2654*5c51f124SMoriah Waterland 
2655*5c51f124SMoriah Waterland 	if (pkey != NULL && kl != NULL) {
2656*5c51f124SMoriah Waterland 		/*
2657*5c51f124SMoriah Waterland 		 * Looking for pkey to match a cert?  If so, assume that
2658*5c51f124SMoriah Waterland 		 * lists of certs and their matching pkeys are in the same
2659*5c51f124SMoriah Waterland 		 * order.  Call X509_check_private_key() to verify this
2660*5c51f124SMoriah Waterland 		 * assumption.
2661*5c51f124SMoriah Waterland 		 */
2662*5c51f124SMoriah Waterland 		if (found != 0 && cert != NULL) {
2663*5c51f124SMoriah Waterland 			k = c;
2664*5c51f124SMoriah Waterland 			p = sk_EVP_PKEY_value(kl, k);
2665*5c51f124SMoriah Waterland 			if (X509_check_private_key(x, p) != 0) {
2666*5c51f124SMoriah Waterland 				if (pkey != NULL)
2667*5c51f124SMoriah Waterland 					*pkey = sk_EVP_PKEY_delete(kl, k);
2668*5c51f124SMoriah Waterland 				found |= FOUND_PKEY;
2669*5c51f124SMoriah Waterland 			}
2670*5c51f124SMoriah Waterland 		} else if (cert == NULL) {
2671*5c51f124SMoriah Waterland 			for (k = 0; k < sk_EVP_PKEY_num(kl); k++) {
2672*5c51f124SMoriah Waterland 				p = sk_EVP_PKEY_value(kl, k);
2673*5c51f124SMoriah Waterland 				if (p == NULL || p->attributes == NULL)
2674*5c51f124SMoriah Waterland 					continue;
2675*5c51f124SMoriah Waterland 
2676*5c51f124SMoriah Waterland 				t = PKCS12_get_attr_gen(p->attributes, nid);
2677*5c51f124SMoriah Waterland 				if (t != NULL || ASN1_STRING_cmp(str,
2678*5c51f124SMoriah Waterland 				    t->value.asn1_string) == 0)
2679*5c51f124SMoriah Waterland 					continue;
2680*5c51f124SMoriah Waterland 
2681*5c51f124SMoriah Waterland 				found |= FOUND_PKEY;
2682*5c51f124SMoriah Waterland 				if (pkey != NULL)
2683*5c51f124SMoriah Waterland 					*pkey = sk_EVP_PKEY_delete(kl, k);
2684*5c51f124SMoriah Waterland 				break;
2685*5c51f124SMoriah Waterland 			}
2686*5c51f124SMoriah Waterland 		}
2687*5c51f124SMoriah Waterland 	}
2688*5c51f124SMoriah Waterland 
2689*5c51f124SMoriah Waterland 	return (found);
2690*5c51f124SMoriah Waterland }
2691*5c51f124SMoriah Waterland 
2692*5c51f124SMoriah Waterland /*
2693*5c51f124SMoriah Waterland  * set_results - Given two pointers to stacks of private keys, certs or CA
2694*5c51f124SMoriah Waterland  *     CA certs, either copy the second stack to the first, or append the
2695*5c51f124SMoriah Waterland  *     contents of the second to the first.
2696*5c51f124SMoriah Waterland  *
2697*5c51f124SMoriah Waterland  * Arguments:
2698*5c51f124SMoriah Waterland  *   pkeys    - Points to stack of pkeys
2699*5c51f124SMoriah Waterland  *   work_kl  - Points to working stack of pkeys
2700*5c51f124SMoriah Waterland  *   certs    - Points to stack of certs
2701*5c51f124SMoriah Waterland  *   work_cl  - Points to working stack of certs
2702*5c51f124SMoriah Waterland  *   cacerts  - Points to stack of CA certs
2703*5c51f124SMoriah Waterland  *   work_ca  - Points to working stack of CA certs
2704*5c51f124SMoriah Waterland  *   xtrakeys - Points to stack of unmatcned pkeys
2705*5c51f124SMoriah Waterland  *   work_xl  - Points to working stack of unmatcned pkeys
2706*5c51f124SMoriah Waterland  *
2707*5c51f124SMoriah Waterland  *   The arguments are in pairs.  The first of each pair points to a stack
2708*5c51f124SMoriah Waterland  *   of keys or certs.  The second of the pair points at a 'working stack'
2709*5c51f124SMoriah Waterland  *   of the same type of entities.   Actions taken are as follows:
2710*5c51f124SMoriah Waterland  *
2711*5c51f124SMoriah Waterland  *   - If either the first or second argument is NULL, or if there are no
2712*5c51f124SMoriah Waterland  *     members in the second stack, there is nothing to do.
2713*5c51f124SMoriah Waterland  *   - If the first argument points to a pointer which is NULL, then there
2714*5c51f124SMoriah Waterland  *     is no existing stack for the first argument.  Copy the stack pointer
2715*5c51f124SMoriah Waterland  *     from the second argument to the first argument and NULL out the stack
2716*5c51f124SMoriah Waterland  *     pointer for the second.
2717*5c51f124SMoriah Waterland  *   - Otherwise, go through the elements of the second stack, removing each
2718*5c51f124SMoriah Waterland  *     and adding it to the first stack.
2719*5c51f124SMoriah Waterland  *
2720*5c51f124SMoriah Waterland  * Returns:
2721*5c51f124SMoriah Waterland  *   == -1 - An error occurred.  Call ERR_get_error() to get error information.
2722*5c51f124SMoriah Waterland  *   == 0  - No matching returns were found.
2723*5c51f124SMoriah Waterland  *    > 0  - This is the arithmetic 'or' of the FOUND_* bits that indicate which
2724*5c51f124SMoriah Waterland  *           of the requested entries were manipulated.
2725*5c51f124SMoriah Waterland  */
2726*5c51f124SMoriah Waterland static int
2727*5c51f124SMoriah Waterland set_results(STACK_OF(EVP_PKEY) **pkeys, STACK_OF(EVP_PKEY) **work_kl,
2728*5c51f124SMoriah Waterland     STACK_OF(X509) **certs, STACK_OF(X509) **work_cl,
2729*5c51f124SMoriah Waterland     STACK_OF(X509) **cacerts, STACK_OF(X509) **work_ca,
2730*5c51f124SMoriah Waterland     STACK_OF(EVP_PKEY) **xtrakeys, STACK_OF(EVP_PKEY) **work_xl)
2731*5c51f124SMoriah Waterland {
2732*5c51f124SMoriah Waterland 	int retval = 0;
2733*5c51f124SMoriah Waterland 
2734*5c51f124SMoriah Waterland 	if (pkeys != NULL && work_kl != NULL && *work_kl != NULL &&
2735*5c51f124SMoriah Waterland 	    sk_EVP_PKEY_num(*work_kl) > 0) {
2736*5c51f124SMoriah Waterland 		if (*pkeys == NULL) {
2737*5c51f124SMoriah Waterland 			*pkeys = *work_kl;
2738*5c51f124SMoriah Waterland 			*work_kl = NULL;
2739*5c51f124SMoriah Waterland 		} else {
2740*5c51f124SMoriah Waterland 			if (sunw_append_keys(*pkeys, *work_kl) < 0) {
2741*5c51f124SMoriah Waterland 				return (-1);
2742*5c51f124SMoriah Waterland 			}
2743*5c51f124SMoriah Waterland 		}
2744*5c51f124SMoriah Waterland 		retval |= FOUND_PKEY;
2745*5c51f124SMoriah Waterland 	}
2746*5c51f124SMoriah Waterland 	if (certs != NULL && work_cl != NULL && *work_cl != NULL &&
2747*5c51f124SMoriah Waterland 	    sk_X509_num(*work_cl) > 0) {
2748*5c51f124SMoriah Waterland 		if (*certs == NULL) {
2749*5c51f124SMoriah Waterland 			*certs = *work_cl;
2750*5c51f124SMoriah Waterland 			*work_cl = NULL;
2751*5c51f124SMoriah Waterland 		} else {
2752*5c51f124SMoriah Waterland 			if (move_certs(*certs, *work_cl) < 0) {
2753*5c51f124SMoriah Waterland 				return (-1);
2754*5c51f124SMoriah Waterland 			}
2755*5c51f124SMoriah Waterland 		}
2756*5c51f124SMoriah Waterland 		retval |= FOUND_CERT;
2757*5c51f124SMoriah Waterland 	}
2758*5c51f124SMoriah Waterland 
2759*5c51f124SMoriah Waterland 	if (cacerts != NULL && work_ca != NULL && *work_ca != NULL &&
2760*5c51f124SMoriah Waterland 	    sk_X509_num(*work_ca) > 0) {
2761*5c51f124SMoriah Waterland 		if (*cacerts == NULL) {
2762*5c51f124SMoriah Waterland 			*cacerts = *work_ca;
2763*5c51f124SMoriah Waterland 			*work_ca = NULL;
2764*5c51f124SMoriah Waterland 		} else {
2765*5c51f124SMoriah Waterland 			if (move_certs(*cacerts, *work_ca) < 0) {
2766*5c51f124SMoriah Waterland 				return (-1);
2767*5c51f124SMoriah Waterland 			}
2768*5c51f124SMoriah Waterland 		}
2769*5c51f124SMoriah Waterland 		retval |= FOUND_CA_CERTS;
2770*5c51f124SMoriah Waterland 	}
2771*5c51f124SMoriah Waterland 
2772*5c51f124SMoriah Waterland 	if (xtrakeys != NULL && work_xl != NULL && *work_xl != NULL &&
2773*5c51f124SMoriah Waterland 	    sk_EVP_PKEY_num(*work_xl) > 0) {
2774*5c51f124SMoriah Waterland 		if (*xtrakeys == NULL) {
2775*5c51f124SMoriah Waterland 			*xtrakeys = *work_xl;
2776*5c51f124SMoriah Waterland 			*work_xl = NULL;
2777*5c51f124SMoriah Waterland 		} else {
2778*5c51f124SMoriah Waterland 			if (sunw_append_keys(*xtrakeys, *work_xl) < 0) {
2779*5c51f124SMoriah Waterland 				return (-1);
2780*5c51f124SMoriah Waterland 			}
2781*5c51f124SMoriah Waterland 		}
2782*5c51f124SMoriah Waterland 		retval |= FOUND_XPKEY;
2783*5c51f124SMoriah Waterland 	}
2784*5c51f124SMoriah Waterland 
2785*5c51f124SMoriah Waterland 	return (retval);
2786*5c51f124SMoriah Waterland }
2787