xref: /illumos-gate/usr/src/lib/krb5/plugins/preauth/pkinit/pkinit_crypto_openssl.c (revision 300fdee27f8b59b381c1a0316bdee52fdfdb9213)
1 /*
2  * COPYRIGHT (C) 2006,2007
3  * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
4  * ALL RIGHTS RESERVED
5  *
6  * Permission is granted to use, copy, create derivative works
7  * and redistribute this software and such derivative works
8  * for any purpose, so long as the name of The University of
9  * Michigan is not used in any advertising or publicity
10  * pertaining to the use of distribution of this software
11  * without specific, written prior authorization.  If the
12  * above copyright notice or any other identification of the
13  * University of Michigan is included in any copy of any
14  * portion of this software, then the disclaimer below must
15  * also be included.
16  *
17  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
18  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
19  * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
20  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
21  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
22  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
23  * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
24  * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
25  * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
26  * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
27  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGES.
29  */
30 
31 /*
32  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
33  * Copyright (c) 2012, OmniTI Computer Consulting, Inc. All rights reserved.
34  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
35  */
36 
37 #include <errno.h>
38 #include <string.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <dlfcn.h>
42 #include <unistd.h>
43 #include <dirent.h>
44 
45 
46 /* Solaris Kerberos */
47 #include <libintl.h>
48 #include <assert.h>
49 #include <security/pam_appl.h>
50 #include <ctype.h>
51 #include "k5-int.h"
52 #include <ctype.h>
53 
54 /*
55  * Q: What is this SILLYDECRYPT stuff about?
56  * A: When using the ActivCard Linux pkcs11 library (v2.0.1),
57  *    the decrypt function fails.  By inserting an extra
58  *    function call, which serves nothing but to change the
59  *    stack, we were able to work around the issue.  If the
60  *    ActivCard library is fixed in the future, this
61  *    definition and related code can be removed.
62  */
63 #define SILLYDECRYPT
64 
65 #include "pkinit_crypto_openssl.h"
66 
67 /*
68  * Solaris Kerberos:
69  * Changed to a switch statement so gettext() can be used
70  * for internationization.
71  * Use defined constants rather than raw numbers for error codes.
72  */
73 static char *
74 pkcs11_error_table(short code) {
75 	switch (code) {
76 	    case CKR_OK:
77 		return (gettext("ok"));
78 	    case CKR_CANCEL:
79 		return (gettext("cancel"));
80 	    case CKR_HOST_MEMORY:
81 		return (gettext("host memory"));
82 	    case CKR_SLOT_ID_INVALID:
83 		return (gettext("slot id invalid"));
84 	    case CKR_GENERAL_ERROR:
85 		return (gettext("general error"));
86 	    case CKR_FUNCTION_FAILED:
87 		return (gettext("function failed"));
88 	    case CKR_ARGUMENTS_BAD:
89 		return (gettext("arguments bad"));
90 	    case CKR_NO_EVENT:
91 		return (gettext("no event"));
92 	    case CKR_NEED_TO_CREATE_THREADS:
93 		return (gettext("need to create threads"));
94 	    case CKR_CANT_LOCK:
95 		return (gettext("cant lock"));
96 	    case CKR_ATTRIBUTE_READ_ONLY:
97 		return (gettext("attribute read only"));
98 	    case CKR_ATTRIBUTE_SENSITIVE:
99 		return (gettext("attribute sensitive"));
100 	    case CKR_ATTRIBUTE_TYPE_INVALID:
101 		return (gettext("attribute type invalid"));
102 	    case CKR_ATTRIBUTE_VALUE_INVALID:
103 		return (gettext("attribute value invalid"));
104 	    case CKR_DATA_INVALID:
105 		return (gettext("data invalid"));
106 	    case CKR_DATA_LEN_RANGE:
107 		return (gettext("data len range"));
108 	    case CKR_DEVICE_ERROR:
109 		return (gettext("device error"));
110 	    case CKR_DEVICE_MEMORY:
111 		return (gettext("device memory"));
112 	    case CKR_DEVICE_REMOVED:
113 		return (gettext("device removed"));
114 	    case CKR_ENCRYPTED_DATA_INVALID:
115 		return (gettext("encrypted data invalid"));
116 	    case CKR_ENCRYPTED_DATA_LEN_RANGE:
117 		return (gettext("encrypted data len range"));
118 	    case CKR_FUNCTION_CANCELED:
119 		return (gettext("function canceled"));
120 	    case CKR_FUNCTION_NOT_PARALLEL:
121 		return (gettext("function not parallel"));
122 	    case CKR_FUNCTION_NOT_SUPPORTED:
123 		return (gettext("function not supported"));
124 	    case CKR_KEY_HANDLE_INVALID:
125 		return (gettext("key handle invalid"));
126 	    case CKR_KEY_SIZE_RANGE:
127 		return (gettext("key size range"));
128 	    case CKR_KEY_TYPE_INCONSISTENT:
129 		return (gettext("key type inconsistent"));
130 	    case CKR_KEY_NOT_NEEDED:
131 		return (gettext("key not needed"));
132 	    case CKR_KEY_CHANGED:
133 		return (gettext("key changed"));
134 	    case CKR_KEY_NEEDED:
135 		return (gettext("key needed"));
136 	    case CKR_KEY_INDIGESTIBLE:
137 		return (gettext("key indigestible"));
138 	    case CKR_KEY_FUNCTION_NOT_PERMITTED:
139 		return (gettext("key function not permitted"));
140 	    case CKR_KEY_NOT_WRAPPABLE:
141 		return (gettext("key not wrappable"));
142 	    case CKR_KEY_UNEXTRACTABLE:
143 		return (gettext("key unextractable"));
144 	    case CKR_MECHANISM_INVALID:
145 		return (gettext("mechanism invalid"));
146 	    case CKR_MECHANISM_PARAM_INVALID:
147 		return (gettext("mechanism param invalid"));
148 	    case CKR_OBJECT_HANDLE_INVALID:
149 		return (gettext("object handle invalid"));
150 	    case CKR_OPERATION_ACTIVE:
151 		return (gettext("operation active"));
152 	    case CKR_OPERATION_NOT_INITIALIZED:
153 		return (gettext("operation not initialized"));
154 	    case CKR_PIN_INCORRECT:
155 		return (gettext("pin incorrect"));
156 	    case CKR_PIN_INVALID:
157 		return (gettext("pin invalid"));
158 	    case CKR_PIN_LEN_RANGE:
159 		return (gettext("pin len range"));
160 	    case CKR_PIN_EXPIRED:
161 		return (gettext("pin expired"));
162 	    case CKR_PIN_LOCKED:
163 		return (gettext("pin locked"));
164 	    case CKR_SESSION_CLOSED:
165 		return (gettext("session closed"));
166 	    case CKR_SESSION_COUNT:
167 		return (gettext("session count"));
168 	    case CKR_SESSION_HANDLE_INVALID:
169 		return (gettext("session handle invalid"));
170 	    case CKR_SESSION_PARALLEL_NOT_SUPPORTED:
171 		return (gettext("session parallel not supported"));
172 	    case CKR_SESSION_READ_ONLY:
173 		return (gettext("session read only"));
174 	    case CKR_SESSION_EXISTS:
175 		return (gettext("session exists"));
176 	    case CKR_SESSION_READ_ONLY_EXISTS:
177 		return (gettext("session read only exists"));
178 	    case CKR_SESSION_READ_WRITE_SO_EXISTS:
179 		return (gettext("session read write so exists"));
180 	    case CKR_SIGNATURE_INVALID:
181 		return (gettext("signature invalid"));
182 	    case CKR_SIGNATURE_LEN_RANGE:
183 		return (gettext("signature len range"));
184 	    case CKR_TEMPLATE_INCOMPLETE:
185 		return (gettext("template incomplete"));
186 	    case CKR_TEMPLATE_INCONSISTENT:
187 		return (gettext("template inconsistent"));
188 	    case CKR_TOKEN_NOT_PRESENT:
189 		return (gettext("token not present"));
190 	    case CKR_TOKEN_NOT_RECOGNIZED:
191 		return (gettext("token not recognized"));
192 	    case CKR_TOKEN_WRITE_PROTECTED:
193 		return (gettext("token write protected"));
194 	    case CKR_UNWRAPPING_KEY_HANDLE_INVALID:
195 		return (gettext("unwrapping key handle invalid"));
196 	    case CKR_UNWRAPPING_KEY_SIZE_RANGE:
197 		return (gettext("unwrapping key size range"));
198 	    case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT:
199 		return (gettext("unwrapping key type inconsistent"));
200 	    case CKR_USER_ALREADY_LOGGED_IN:
201 		return (gettext("user already logged in"));
202 	    case CKR_USER_NOT_LOGGED_IN:
203 		return (gettext("user not logged in"));
204 	    case CKR_USER_PIN_NOT_INITIALIZED:
205 		return (gettext("user pin not initialized"));
206 	    case CKR_USER_TYPE_INVALID:
207 		return (gettext("user type invalid"));
208 	    case CKR_USER_ANOTHER_ALREADY_LOGGED_IN:
209 		return (gettext("user another already logged in"));
210 	    case CKR_USER_TOO_MANY_TYPES:
211 		return (gettext("user too many types"));
212 	    case CKR_WRAPPED_KEY_INVALID:
213 		return (gettext("wrapped key invalid"));
214 	    case CKR_WRAPPED_KEY_LEN_RANGE:
215 		return (gettext("wrapped key len range"));
216 	    case CKR_WRAPPING_KEY_HANDLE_INVALID:
217 		return (gettext("wrapping key handle invalid"));
218 	    case CKR_WRAPPING_KEY_SIZE_RANGE:
219 		return (gettext("wrapping key size range"));
220 	    case CKR_WRAPPING_KEY_TYPE_INCONSISTENT:
221 		return (gettext("wrapping key type inconsistent"));
222 	    case CKR_RANDOM_SEED_NOT_SUPPORTED:
223 		return (gettext("random seed not supported"));
224 	    case CKR_RANDOM_NO_RNG:
225 		return (gettext("random no rng"));
226 	    case CKR_DOMAIN_PARAMS_INVALID:
227 		return (gettext("domain params invalid"));
228 	    case CKR_BUFFER_TOO_SMALL:
229 		return (gettext("buffer too small"));
230 	    case CKR_SAVED_STATE_INVALID:
231 		return (gettext("saved state invalid"));
232 	    case CKR_INFORMATION_SENSITIVE:
233 		return (gettext("information sensitive"));
234 	    case CKR_STATE_UNSAVEABLE:
235 		return (gettext("state unsaveable"));
236 	    case CKR_CRYPTOKI_NOT_INITIALIZED:
237 		return (gettext("cryptoki not initialized"));
238 	    case CKR_CRYPTOKI_ALREADY_INITIALIZED:
239 		return (gettext("cryptoki already initialized"));
240 	    case CKR_MUTEX_BAD:
241 		return (gettext("mutex bad"));
242 	    case CKR_MUTEX_NOT_LOCKED:
243 		return (gettext("mutex not locked"));
244 	    case CKR_FUNCTION_REJECTED:
245 		return (gettext("function rejected"));
246 	    default:
247 		return (gettext("unknown error"));
248 	}
249 }
250 
251 /* DH parameters */
252 unsigned char pkinit_1024_dhprime[128] = {
253     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
254     0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
255     0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
256     0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
257     0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
258     0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
259     0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
260     0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
261     0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
262     0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
263     0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
264     0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
265     0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
266     0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
267     0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
268     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
269 };
270 
271 unsigned char pkinit_2048_dhprime[2048/8] = {
272     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
273     0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
274     0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
275     0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
276     0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
277     0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
278     0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
279     0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
280     0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
281     0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
282     0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
283     0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
284     0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
285     0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
286     0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
287     0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
288     0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
289     0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
290     0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
291     0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
292     0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
293     0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
294     0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
295     0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
296     0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
297     0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
298     0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
299     0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
300     0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
301     0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
302     0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
303     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
304 };
305 
306 unsigned char pkinit_4096_dhprime[4096/8] = {
307     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
308     0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
309     0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
310     0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
311     0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
312     0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
313     0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
314     0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
315     0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
316     0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
317     0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
318     0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
319     0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
320     0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
321     0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
322     0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
323     0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
324     0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
325     0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
326     0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
327     0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
328     0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
329     0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
330     0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
331     0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
332     0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
333     0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
334     0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
335     0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
336     0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
337     0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
338     0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
339     0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
340     0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
341     0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
342     0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
343     0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
344     0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
345     0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
346     0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
347     0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
348     0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
349     0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
350     0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
351     0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
352     0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
353     0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
354     0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
355     0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
356     0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
357     0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
358     0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
359     0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
360     0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
361     0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
362     0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
363     0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
364     0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
365     0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
366     0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
367     0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
368     0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
369     0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
370     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
371 };
372 
373 #if OPENSSL_VERSION_NUMBER < 0x10100000L
374 /*
375  * Many things have changed in OpenSSL 1.1. The code in this file has been
376  * updated to use the v1.1 APIs but some are new and require emulation
377  * for older OpenSSL versions.
378  */
379 
380 /* EVP_MD_CTX construct and destructor names have changed */
381 
382 #define EVP_MD_CTX_new EVP_MD_CTX_create
383 #define EVP_MD_CTX_free EVP_MD_CTX_destroy
384 
385 /* ASN1_STRING_data is deprecated */
386 #define ASN1_STRING_get0_data ASN1_STRING_data
387 
388 /* X509_STORE_CTX_trusted_stack is deprecated */
389 #define X509_STORE_CTX_set0_trusted_stack X509_STORE_CTX_trusted_stack
390 
391 /* get_rfc2409_prime_1024() has been renamed. */
392 #define BN_get_rfc2409_prime_1024 get_rfc2409_prime_1024
393 
394 #define OBJ_get0_data(o) ((o)->data)
395 #define OBJ_length(o) ((o)->length)
396 
397 /* Some new DH functions that aren't in OpenSSL 1.0.x */
398 #define DH_bits(dh) BN_num_bits((dh)->p);
399 
400 #define DH_set0_pqg(dh, p, q, g) __DH_set0_pqg(dh, p, q, g)
401 static int
402 __DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
403 {
404     if ((dh->p == NULL && p == NULL) || (dh->g == NULL && g == NULL))
405         return 0;
406 
407     if (p != NULL) {
408         BN_free(dh->p);
409         dh->p = p;
410     }
411     if (q != NULL) {
412         BN_free(dh->q);
413         dh->q = q;
414     }
415     if (g != NULL) {
416         BN_free(dh->g);
417         dh->g = g;
418     }
419 
420     if (q != NULL) {
421         dh->length = BN_num_bits(q);
422     }
423 
424     return 1;
425 }
426 
427 #define DH_get0_pqg(dh, p, q, g) __DH_get0_pqg(dh, p, q, g)
428 static void
429 __DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q,
430     const BIGNUM **g)
431 {
432     if (p != NULL)
433         *p = dh->p;
434     if (q != NULL)
435         *q = dh->q;
436     if (g != NULL)
437         *g = dh->g;
438 }
439 
440 #define DH_set0_key(dh, pub, priv) __DH_set0_key(dh, pub, priv)
441 static int
442 __DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
443 {
444     if (pub_key != NULL) {
445         BN_free(dh->pub_key);
446         dh->pub_key = pub_key;
447     }
448     if (priv_key != NULL) {
449         BN_free(dh->priv_key);
450         dh->priv_key = priv_key;
451     }
452 
453     return 1;
454 }
455 
456 #define DH_get0_key(dh, pub, priv) __DH_get0_key(dh, pub, priv)
457 static void
458 __DH_get0_key(const DH *dh, const BIGNUM **pub, const BIGNUM **priv)
459 {
460     if (pub != NULL)
461         *pub = dh->pub_key;
462     if (priv != NULL)
463         *priv = dh->priv_key;
464 }
465 
466 #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
467 
468 /* Solaris Kerberos */
469 static k5_mutex_t oids_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
470 static int pkinit_oids_refs = 0;
471 
472 krb5_error_code
473 pkinit_init_plg_crypto(pkinit_plg_crypto_context *cryptoctx) {
474 
475     krb5_error_code retval = ENOMEM;
476     pkinit_plg_crypto_context ctx = NULL;
477 
478     /* initialize openssl routines */
479     /* Solaris Kerberos */
480     retval = openssl_init();
481     if (retval != 0)
482 	goto out;
483 
484     ctx = (pkinit_plg_crypto_context)malloc(sizeof(*ctx));
485     if (ctx == NULL)
486 	goto out;
487     (void) memset(ctx, 0, sizeof(*ctx));
488 
489     pkiDebug("%s: initializing openssl crypto context at %p\n",
490 	     __FUNCTION__, ctx);
491     retval = pkinit_init_pkinit_oids(ctx);
492     if (retval)
493 	goto out;
494 
495     retval = pkinit_init_dh_params(ctx);
496     if (retval)
497 	goto out;
498 
499     *cryptoctx = ctx;
500 
501 out:
502     if (retval && ctx != NULL)
503 	    pkinit_fini_plg_crypto(ctx);
504 
505     return retval;
506 }
507 
508 void
509 pkinit_fini_plg_crypto(pkinit_plg_crypto_context cryptoctx)
510 {
511     pkiDebug("%s: freeing context at %p\n", __FUNCTION__, cryptoctx);
512 
513     if (cryptoctx == NULL)
514 	return;
515     pkinit_fini_pkinit_oids(cryptoctx);
516     pkinit_fini_dh_params(cryptoctx);
517     free(cryptoctx);
518 }
519 
520 krb5_error_code
521 pkinit_init_identity_crypto(pkinit_identity_crypto_context *idctx)
522 {
523     krb5_error_code retval = ENOMEM;
524     pkinit_identity_crypto_context ctx = NULL;
525 
526     ctx = (pkinit_identity_crypto_context)malloc(sizeof(*ctx));
527     if (ctx == NULL)
528 	goto out;
529     (void) memset(ctx, 0, sizeof(*ctx));
530 
531     retval = pkinit_init_certs(ctx);
532     if (retval)
533 	goto out;
534 
535     retval = pkinit_init_pkcs11(ctx);
536     if (retval)
537 	goto out;
538 
539     pkiDebug("%s: returning ctx at %p\n", __FUNCTION__, ctx);
540     *idctx = ctx;
541 
542 out:
543     if (retval) {
544 	if (ctx)
545 	    pkinit_fini_identity_crypto(ctx);
546     }
547 
548     return retval;
549 }
550 
551 void
552 pkinit_fini_identity_crypto(pkinit_identity_crypto_context idctx)
553 {
554     if (idctx == NULL)
555 	return;
556 
557     pkiDebug("%s: freeing   ctx at %p\n", __FUNCTION__, idctx);
558     pkinit_fini_certs(idctx);
559     pkinit_fini_pkcs11(idctx);
560     free(idctx);
561 }
562 
563 krb5_error_code
564 pkinit_init_req_crypto(pkinit_req_crypto_context *cryptoctx)
565 {
566 
567     pkinit_req_crypto_context ctx = NULL;
568 
569     /* Solaris Kerberos */
570     if (cryptoctx == NULL)
571 	return EINVAL;
572 
573     ctx = (pkinit_req_crypto_context)malloc(sizeof(*ctx));
574     if (ctx == NULL)
575 	return ENOMEM;
576     (void) memset(ctx, 0, sizeof(*ctx));
577 
578     ctx->dh = NULL;
579     ctx->received_cert = NULL;
580 
581     *cryptoctx = ctx;
582 
583     pkiDebug("%s: returning ctx at %p\n", __FUNCTION__, ctx);
584 
585     return 0;
586 }
587 
588 void
589 pkinit_fini_req_crypto(pkinit_req_crypto_context req_cryptoctx)
590 {
591     if (req_cryptoctx == NULL)
592 	return;
593 
594     pkiDebug("%s: freeing   ctx at %p\n", __FUNCTION__, req_cryptoctx);
595     if (req_cryptoctx->dh != NULL)
596       DH_free(req_cryptoctx->dh);
597     if (req_cryptoctx->received_cert != NULL)
598       X509_free(req_cryptoctx->received_cert);
599 
600     free(req_cryptoctx);
601 }
602 
603 static krb5_error_code
604 pkinit_init_pkinit_oids(pkinit_plg_crypto_context ctx)
605 {
606     krb5_error_code retval = ENOMEM;
607     int nid = 0;
608 
609     /*
610      * If OpenSSL already knows about the OID, use the
611      * existing definition. Otherwise, create an OID object.
612      */
613     #define CREATE_OBJ_IF_NEEDED(oid, vn, sn, ln) \
614 	nid = OBJ_txt2nid(oid); \
615 	if (nid == NID_undef) { \
616 	    nid = OBJ_create(oid, sn, ln); \
617 	    if (nid == NID_undef) { \
618 		pkiDebug("Error creating oid object for '%s'\n", oid); \
619 		goto out; \
620 	    } \
621 	} \
622 	ctx->vn = OBJ_nid2obj(nid);
623 
624     /* Solaris Kerberos */
625     retval = k5_mutex_lock(&oids_mutex);
626     if (retval != 0)
627 	goto out;
628 
629     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.2", id_pkinit_san,
630 			 "id-pkinit-san", "KRB5PrincipalName");
631 
632     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.1", id_pkinit_authData,
633 			 "id-pkinit-authdata", "PKINIT signedAuthPack");
634 
635     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.2", id_pkinit_DHKeyData,
636 			 "id-pkinit-DHKeyData", "PKINIT dhSignedData");
637 
638     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.3", id_pkinit_rkeyData,
639 			 "id-pkinit-rkeyData", "PKINIT encKeyPack");
640 
641     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.4", id_pkinit_KPClientAuth,
642 			 "id-pkinit-KPClientAuth", "PKINIT Client EKU");
643 
644     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.5", id_pkinit_KPKdc,
645 			 "id-pkinit-KPKdc", "KDC EKU");
646 
647 #if 0
648     CREATE_OBJ_IF_NEEDED("1.2.840.113549.1.7.1", id_pkinit_authData9,
649 			 "id-pkcs7-data", "PKCS7 data");
650 #else
651     /* See note in pkinit_pkcs7type2oid() */
652     ctx->id_pkinit_authData9 = NULL;
653 #endif
654 
655     CREATE_OBJ_IF_NEEDED("1.3.6.1.4.1.311.20.2.2", id_ms_kp_sc_logon,
656 			 "id-ms-kp-sc-logon EKU", "Microsoft SmartCard Login EKU");
657 
658     CREATE_OBJ_IF_NEEDED("1.3.6.1.4.1.311.20.2.3", id_ms_san_upn,
659 			 "id-ms-san-upn", "Microsoft Universal Principal Name");
660 
661     CREATE_OBJ_IF_NEEDED("1.3.6.1.5.5.7.3.1", id_kp_serverAuth,
662 			 "id-kp-serverAuth EKU", "Server Authentication EKU");
663 
664     /* Success */
665     retval = 0;
666 
667     pkinit_oids_refs++;
668     /* Solaris Kerberos */
669     k5_mutex_unlock(&oids_mutex);
670 
671 out:
672     return retval;
673 }
674 
675 static krb5_error_code
676 get_cert(char *filename, X509 **retcert)
677 {
678     X509 *cert = NULL;
679     BIO *tmp = NULL;
680     int code;
681     krb5_error_code retval;
682 
683     if (filename == NULL || retcert == NULL)
684 	return EINVAL;
685 
686     *retcert = NULL;
687 
688     tmp = BIO_new(BIO_s_file());
689     if (tmp == NULL)
690 	return ENOMEM;
691 
692     code = BIO_read_filename(tmp, filename);
693     if (code == 0) {
694 	retval = errno;
695 	goto cleanup;
696     }
697 
698     cert = (X509 *) PEM_read_bio_X509(tmp, NULL, NULL, NULL);
699     if (cert == NULL) {
700 	retval = EIO;
701 	pkiDebug("failed to read certificate from %s\n", filename);
702 	goto cleanup;
703     }
704     *retcert = cert;
705     retval = 0;
706 cleanup:
707     if (tmp != NULL)
708 	BIO_free(tmp);
709     return retval;
710 }
711 
712 static krb5_error_code
713 get_key(char *filename, EVP_PKEY **retkey)
714 {
715     EVP_PKEY *pkey = NULL;
716     BIO *tmp = NULL;
717     int code;
718     krb5_error_code retval;
719 
720     if (filename == NULL || retkey == NULL)
721 	return EINVAL;
722 
723     tmp = BIO_new(BIO_s_file());
724     if (tmp == NULL)
725 	return ENOMEM;
726 
727     code = BIO_read_filename(tmp, filename);
728     if (code == 0) {
729 	retval = errno;
730 	goto cleanup;
731     }
732     pkey = (EVP_PKEY *) PEM_read_bio_PrivateKey(tmp, NULL, NULL, NULL);
733     if (pkey == NULL) {
734 	retval = EIO;
735 	pkiDebug("failed to read private key from %s\n", filename);
736 	goto cleanup;
737     }
738     *retkey = pkey;
739     retval = 0;
740 cleanup:
741     if (tmp != NULL)
742 	BIO_free(tmp);
743     return retval;
744 }
745 
746 static void
747 pkinit_fini_pkinit_oids(pkinit_plg_crypto_context ctx)
748 {
749     if (ctx == NULL)
750 	return;
751 
752     /* Only call OBJ_cleanup once! */
753     /* Solaris Kerberos: locking */
754     k5_mutex_lock(&oids_mutex);
755 #if OPENSSL_VERSION_NUMBER < 0x10100000L
756     /*
757      * In OpenSSL versions prior to 1.1.0, OBJ_cleanup() cleaned up OpenSSL's
758      * internal object table. This function is deprecated in version 1.1.0.
759      * No explicit de-initialisation is now required.
760      */
761     if (--pkinit_oids_refs == 0)
762 	OBJ_cleanup();
763 #else
764     pkinit_oids_refs--;
765 #endif
766     k5_mutex_unlock(&oids_mutex);
767 }
768 
769 static DH *
770 make_dhprime(uint8_t *prime, size_t len)
771 {
772     DH *dh = NULL;
773     BIGNUM *p = NULL, *q = NULL, *g = NULL;
774 
775     if ((p = BN_bin2bn(prime, len, NULL)) == NULL)
776 	goto cleanup;
777     if ((q = BN_new()) == NULL)
778 	goto cleanup;
779     if (!BN_rshift1(q, p))
780 	goto cleanup;
781     if ((g = BN_new()) == NULL)
782 	goto cleanup;
783     if (!BN_set_word(g, DH_GENERATOR_2))
784 	goto cleanup;
785 
786     dh = DH_new();
787     if (dh == NULL)
788 	goto cleanup;
789     DH_set0_pqg(dh, p, q, g);
790     p = g = q = NULL;
791 
792 cleanup:
793     BN_free(p);
794     BN_free(q);
795     BN_free(g);
796     return dh;
797 }
798 
799 static krb5_error_code
800 pkinit_init_dh_params(pkinit_plg_crypto_context plgctx)
801 {
802     krb5_error_code retval = ENOMEM;
803 
804     plgctx->dh_1024 = make_dhprime(pkinit_1024_dhprime,
805         sizeof(pkinit_1024_dhprime));
806     if (plgctx->dh_1024 == NULL)
807 	goto cleanup;
808 
809     plgctx->dh_2048 = make_dhprime(pkinit_2048_dhprime,
810         sizeof(pkinit_2048_dhprime));
811     if (plgctx->dh_2048 == NULL)
812 	goto cleanup;
813 
814     plgctx->dh_4096 = make_dhprime(pkinit_4096_dhprime,
815         sizeof(pkinit_4096_dhprime));
816     if (plgctx->dh_4096 == NULL)
817 	goto cleanup;
818 
819     retval = 0;
820 
821 cleanup:
822     if (retval)
823 	pkinit_fini_dh_params(plgctx);
824 
825     return retval;
826 }
827 
828 static void
829 pkinit_fini_dh_params(pkinit_plg_crypto_context plgctx)
830 {
831     if (plgctx->dh_1024 != NULL)
832 	DH_free(plgctx->dh_1024);
833     if (plgctx->dh_2048 != NULL)
834 	DH_free(plgctx->dh_2048);
835     if (plgctx->dh_4096 != NULL)
836 	DH_free(plgctx->dh_4096);
837 
838     plgctx->dh_1024 = plgctx->dh_2048 = plgctx->dh_4096 = NULL;
839 }
840 
841 static krb5_error_code
842 pkinit_init_certs(pkinit_identity_crypto_context ctx)
843 {
844     /* Solaris Kerberos */
845     int i;
846 
847     for (i = 0; i < MAX_CREDS_ALLOWED; i++)
848 	ctx->creds[i] = NULL;
849     ctx->my_certs = NULL;
850     ctx->cert_index = 0;
851     ctx->my_key = NULL;
852     ctx->trustedCAs = NULL;
853     ctx->intermediateCAs = NULL;
854     ctx->revoked = NULL;
855 
856     return 0;
857 }
858 
859 static void
860 pkinit_fini_certs(pkinit_identity_crypto_context ctx)
861 {
862     if (ctx == NULL)
863 	return;
864 
865     if (ctx->my_certs != NULL)
866 	sk_X509_pop_free(ctx->my_certs, X509_free);
867 
868     if (ctx->my_key != NULL)
869 	EVP_PKEY_free(ctx->my_key);
870 
871     if (ctx->trustedCAs != NULL)
872 	sk_X509_pop_free(ctx->trustedCAs, X509_free);
873 
874     if (ctx->intermediateCAs != NULL)
875 	sk_X509_pop_free(ctx->intermediateCAs, X509_free);
876 
877     if (ctx->revoked != NULL)
878 	sk_X509_CRL_pop_free(ctx->revoked, X509_CRL_free);
879 }
880 
881 static krb5_error_code
882 pkinit_init_pkcs11(pkinit_identity_crypto_context ctx)
883 {
884     /* Solaris Kerberos */
885 
886 #ifndef WITHOUT_PKCS11
887     ctx->p11_module_name = strdup(PKCS11_MODNAME);
888     if (ctx->p11_module_name == NULL)
889 	return ENOMEM;
890     ctx->p11_module = NULL;
891     ctx->slotid = PK_NOSLOT;
892     ctx->token_label = NULL;
893     ctx->cert_label = NULL;
894     ctx->PIN = NULL;
895     ctx->session = CK_INVALID_HANDLE;
896     ctx->p11 = NULL;
897     ctx->p11flags = 0; /* Solaris Kerberos */
898 #endif
899     ctx->pkcs11_method = 0;
900     (void) memset(ctx->creds, 0, sizeof(ctx->creds));
901 
902     return 0;
903 }
904 
905 static void
906 pkinit_fini_pkcs11(pkinit_identity_crypto_context ctx)
907 {
908 #ifndef WITHOUT_PKCS11
909     if (ctx == NULL)
910 	return;
911 
912     if (ctx->p11 != NULL) {
913 	if (ctx->session != CK_INVALID_HANDLE) {
914 	    ctx->p11->C_CloseSession(ctx->session);
915 	    ctx->session = CK_INVALID_HANDLE;
916 	}
917 	/*
918 	 * Solaris Kerberos:
919 	 * Only call C_Finalize if the process was not already using pkcs11.
920 	 */
921 	if (ctx->finalize_pkcs11 == TRUE)
922 	    ctx->p11->C_Finalize(NULL_PTR);
923 
924 	ctx->p11 = NULL;
925     }
926     if (ctx->p11_module != NULL) {
927 	pkinit_C_UnloadModule(ctx->p11_module);
928 	ctx->p11_module = NULL;
929     }
930     if (ctx->p11_module_name != NULL)
931 	free(ctx->p11_module_name);
932     if (ctx->token_label != NULL)
933 	free(ctx->token_label);
934     if (ctx->cert_id != NULL)
935 	free(ctx->cert_id);
936     if (ctx->cert_label != NULL)
937 	free(ctx->cert_label);
938     if (ctx->PIN != NULL) {
939 	(void) memset(ctx->PIN, 0, strlen(ctx->PIN));
940 	free(ctx->PIN);
941     }
942 #endif
943 }
944 
945 krb5_error_code
946 pkinit_identity_set_prompter(pkinit_identity_crypto_context id_cryptoctx,
947 			     krb5_prompter_fct prompter,
948 			     void *prompter_data)
949 {
950     id_cryptoctx->prompter = prompter;
951     id_cryptoctx->prompter_data = prompter_data;
952 
953     return 0;
954 }
955 
956 /* ARGSUSED */
957 krb5_error_code
958 cms_signeddata_create(krb5_context context,
959 		      pkinit_plg_crypto_context plg_cryptoctx,
960 		      pkinit_req_crypto_context req_cryptoctx,
961 		      pkinit_identity_crypto_context id_cryptoctx,
962 		      int cms_msg_type,
963 		      int include_certchain,
964 		      unsigned char *data,
965 		      unsigned int data_len,
966 		      unsigned char **signed_data,
967 		      unsigned int *signed_data_len)
968 {
969     /* Solaris Kerberos */
970     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
971     PKCS7  *p7 = NULL, *inner_p7 = NULL;
972     PKCS7_SIGNED *p7s = NULL;
973     PKCS7_SIGNER_INFO *p7si = NULL;
974     unsigned char *p;
975     ASN1_TYPE *pkinit_data = NULL;
976     STACK_OF(X509) * cert_stack = NULL;
977     ASN1_OCTET_STRING *digest_attr = NULL;
978     EVP_MD_CTX *ctx = NULL, *ctx2 = NULL;
979     const EVP_MD *md_tmp = NULL;
980     unsigned char md_data[EVP_MAX_MD_SIZE], md_data2[EVP_MAX_MD_SIZE];
981     unsigned char *digestInfo_buf = NULL, *abuf = NULL;
982     unsigned int md_len, md_len2, alen, digestInfo_len;
983     STACK_OF(X509_ATTRIBUTE) * sk;
984     unsigned char *sig = NULL;
985     unsigned int sig_len = 0;
986     X509_ALGOR *alg = NULL;
987     ASN1_OCTET_STRING *digest = NULL;
988     unsigned int alg_len = 0, digest_len = 0;
989     unsigned char *y = NULL, *alg_buf = NULL, *digest_buf = NULL;
990     X509 *cert = NULL;
991     ASN1_OBJECT *oid = NULL;
992 
993     /* Solaris Kerberos */
994     if (signed_data == NULL)
995 	return EINVAL;
996 
997     if (signed_data_len == NULL)
998 	return EINVAL;
999 
1000     /* start creating PKCS7 data */
1001     if ((p7 = PKCS7_new()) == NULL)
1002 	goto cleanup;
1003     p7->type = OBJ_nid2obj(NID_pkcs7_signed);
1004 
1005     if ((p7s = PKCS7_SIGNED_new()) == NULL)
1006 	goto cleanup;
1007     p7->d.sign = p7s;
1008     if (!ASN1_INTEGER_set(p7s->version, 3))
1009 	goto cleanup;
1010 
1011     /* create a cert chain that has at least the signer's certificate */
1012     if ((cert_stack = sk_X509_new_null()) == NULL)
1013 	goto cleanup;
1014 
1015     cert = sk_X509_value(id_cryptoctx->my_certs, id_cryptoctx->cert_index);
1016     if (!include_certchain) {
1017 	pkiDebug("only including signer's certificate\n");
1018 	sk_X509_push(cert_stack, X509_dup(cert));
1019     } else {
1020 	/* create a cert chain */
1021 	X509_STORE *certstore = NULL;
1022 	X509_STORE_CTX *certctx;
1023 	STACK_OF(X509) *certstack = NULL;
1024 	char buf[DN_BUF_LEN];
1025 	int i = 0, size = 0;
1026 
1027 	if ((certstore = X509_STORE_new()) == NULL)
1028 	    goto cleanup;
1029 	if ((certctx = X509_STORE_CTX_new()) == NULL)
1030 	    goto cleanup;
1031 	pkiDebug("building certificate chain\n");
1032 	X509_STORE_set_verify_cb(certstore, openssl_callback);
1033 	X509_STORE_CTX_init(certctx, certstore, cert,
1034 			    id_cryptoctx->intermediateCAs);
1035 	X509_STORE_CTX_set0_trusted_stack(certctx, id_cryptoctx->trustedCAs);
1036 	/* Solaris Kerberos */
1037 	if (X509_verify_cert(certctx) <= 0) {
1038 	    pkiDebug("failed to create a certificate chain: %s\n",
1039 	    X509_verify_cert_error_string(X509_STORE_CTX_get_error(certctx)));
1040 	    if (!sk_X509_num(id_cryptoctx->trustedCAs))
1041 		pkiDebug("No trusted CAs found. Check your X509_anchors\n");
1042 	    goto cleanup;
1043 	}
1044 	certstack = X509_STORE_CTX_get1_chain(certctx);
1045 	size = sk_X509_num(certstack);
1046 	pkiDebug("size of certificate chain = %d\n", size);
1047 	for(i = 0; i < size - 1; i++) {
1048 	    X509 *x = sk_X509_value(certstack, i);
1049 	    X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
1050 	    pkiDebug("cert #%d: %s\n", i, buf);
1051 	    sk_X509_push(cert_stack, X509_dup(x));
1052 	}
1053 	X509_STORE_CTX_free(certctx);
1054 	X509_STORE_free(certstore);
1055 	sk_X509_pop_free(certstack, X509_free);
1056     }
1057     p7s->cert = cert_stack;
1058 
1059     /* fill-in PKCS7_SIGNER_INFO */
1060     if ((p7si = PKCS7_SIGNER_INFO_new()) == NULL)
1061 	goto cleanup;
1062     if (!ASN1_INTEGER_set(p7si->version, 1))
1063 	goto cleanup;
1064     if (!X509_NAME_set(&p7si->issuer_and_serial->issuer,
1065 		       X509_get_issuer_name(cert)))
1066 	goto cleanup;
1067     /* because ASN1_INTEGER_set is used to set a 'long' we will do
1068      * things the ugly way. */
1069     ASN1_INTEGER_free(p7si->issuer_and_serial->serial);
1070     if (!(p7si->issuer_and_serial->serial =
1071 	  ASN1_INTEGER_dup(X509_get_serialNumber(cert))))
1072 	goto cleanup;
1073 
1074     /* will not fill-out EVP_PKEY because it's on the smartcard */
1075 
1076     /* Set digest algs */
1077     p7si->digest_alg->algorithm = OBJ_nid2obj(NID_sha1);
1078 
1079     if (p7si->digest_alg->parameter != NULL)
1080 	ASN1_TYPE_free(p7si->digest_alg->parameter);
1081     if ((p7si->digest_alg->parameter = ASN1_TYPE_new()) == NULL)
1082 	goto cleanup;
1083     p7si->digest_alg->parameter->type = V_ASN1_NULL;
1084 
1085     /* Set sig algs */
1086     if (p7si->digest_enc_alg->parameter != NULL)
1087 	ASN1_TYPE_free(p7si->digest_enc_alg->parameter);
1088     p7si->digest_enc_alg->algorithm = OBJ_nid2obj(NID_sha1WithRSAEncryption);
1089     if (!(p7si->digest_enc_alg->parameter = ASN1_TYPE_new()))
1090 	goto cleanup;
1091     p7si->digest_enc_alg->parameter->type = V_ASN1_NULL;
1092 
1093     /* pick the correct oid for the eContentInfo */
1094     oid = pkinit_pkcs7type2oid(plg_cryptoctx, cms_msg_type);
1095     if (oid == NULL)
1096 	goto cleanup;
1097 
1098     if (cms_msg_type == CMS_SIGN_DRAFT9) {
1099 	/* don't include signed attributes for pa-type 15 request */
1100 	abuf = data;
1101 	alen = data_len;
1102     } else {
1103 	/* add signed attributes */
1104 	/* compute sha1 digest over the EncapsulatedContentInfo */
1105 	ctx = EVP_MD_CTX_new();
1106 	if (ctx == NULL)
1107 	    goto cleanup2;
1108 	EVP_MD_CTX_init(ctx);
1109 	EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
1110 	EVP_DigestUpdate(ctx, data, data_len);
1111 	md_tmp = EVP_MD_CTX_md(ctx);
1112 	EVP_DigestFinal_ex(ctx, md_data, &md_len);
1113 	EVP_MD_CTX_free(ctx);
1114 	ctx = NULL;
1115 
1116 	/* create a message digest attr */
1117 	digest_attr = ASN1_OCTET_STRING_new();
1118 	ASN1_OCTET_STRING_set(digest_attr, md_data, (int)md_len);
1119 	PKCS7_add_signed_attribute(p7si, NID_pkcs9_messageDigest,
1120 				   V_ASN1_OCTET_STRING, (char *) digest_attr);
1121 
1122 	/* create a content-type attr */
1123 	PKCS7_add_signed_attribute(p7si, NID_pkcs9_contentType,
1124 				   V_ASN1_OBJECT, oid);
1125 
1126 	/* create the signature over signed attributes. get DER encoded value */
1127 	/* This is the place where smartcard signature needs to be calculated */
1128 	sk = p7si->auth_attr;
1129 	alen = ASN1_item_i2d((ASN1_VALUE *) sk, &abuf,
1130 			     ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
1131 	if (abuf == NULL)
1132 	    goto cleanup2;
1133     }
1134 
1135 #ifndef WITHOUT_PKCS11
1136     /* Some tokens can only do RSAEncryption without sha1 hash */
1137     /* to compute sha1WithRSAEncryption, encode the algorithm ID for the hash
1138      * function and the hash value into an ASN.1 value of type DigestInfo
1139      * DigestInfo::=SEQUENCE {
1140      *	digestAlgorithm  AlgorithmIdentifier,
1141      *	digest OCTET STRING }
1142      */
1143     if (id_cryptoctx->pkcs11_method == 1 &&
1144 	    id_cryptoctx->mech == CKM_RSA_PKCS) {
1145 	pkiDebug("mech = CKM_RSA_PKCS\n");
1146 	ctx2 = EVP_MD_CTX_new();
1147 	if (ctx2 == NULL)
1148 	    goto cleanup2;
1149 	EVP_MD_CTX_init(ctx2);
1150 	/* if this is not draft9 request, include digest signed attribute */
1151 	if (cms_msg_type != CMS_SIGN_DRAFT9)
1152 	    EVP_DigestInit_ex(ctx2, md_tmp, NULL);
1153 	else
1154 	    EVP_DigestInit_ex(ctx2, EVP_sha1(), NULL);
1155 	EVP_DigestUpdate(ctx2, abuf, alen);
1156 	EVP_DigestFinal_ex(ctx2, md_data2, &md_len2);
1157 	EVP_MD_CTX_free(ctx2);
1158 	ctx2 = NULL;
1159 
1160 	alg = X509_ALGOR_new();
1161 	if (alg == NULL)
1162 	    goto cleanup2;
1163 	alg->algorithm = OBJ_nid2obj(NID_sha1);
1164 	alg->parameter = NULL;
1165 	alg_len = i2d_X509_ALGOR(alg, NULL);
1166 	alg_buf = (unsigned char *)malloc(alg_len);
1167 	if (alg_buf == NULL)
1168 	    goto cleanup2;
1169 
1170 	digest = ASN1_OCTET_STRING_new();
1171 	if (digest == NULL)
1172 	    goto cleanup2;
1173 	ASN1_OCTET_STRING_set(digest, md_data2, (int)md_len2);
1174 	digest_len = i2d_ASN1_OCTET_STRING(digest, NULL);
1175 	digest_buf = (unsigned char *)malloc(digest_len);
1176 	if (digest_buf == NULL)
1177 	    goto cleanup2;
1178 
1179 	digestInfo_len = ASN1_object_size(1, (int)(alg_len + digest_len),
1180 					  V_ASN1_SEQUENCE);
1181 	y = digestInfo_buf = (unsigned char *)malloc(digestInfo_len);
1182 	if (digestInfo_buf == NULL)
1183 	    goto cleanup2;
1184 	ASN1_put_object(&y, 1, (int)(alg_len + digest_len), V_ASN1_SEQUENCE,
1185 			V_ASN1_UNIVERSAL);
1186 	i2d_X509_ALGOR(alg, &y);
1187 	i2d_ASN1_OCTET_STRING(digest, &y);
1188 #ifdef DEBUG_SIG
1189 	pkiDebug("signing buffer\n");
1190 	print_buffer(digestInfo_buf, digestInfo_len);
1191 	print_buffer_bin(digestInfo_buf, digestInfo_len, "/tmp/pkcs7_tosign");
1192 #endif
1193 	retval = pkinit_sign_data(context, id_cryptoctx, digestInfo_buf,
1194 				  digestInfo_len, &sig, &sig_len);
1195     } else
1196 #endif
1197     {
1198 	pkiDebug("mech = %s\n",
1199 	    id_cryptoctx->pkcs11_method == 1 ? "CKM_SHA1_RSA_PKCS" : "FS");
1200 	retval = pkinit_sign_data(context, id_cryptoctx, abuf, alen,
1201 				  &sig, &sig_len);
1202     }
1203 #ifdef DEBUG_SIG
1204     print_buffer(sig, sig_len);
1205 #endif
1206     if (cms_msg_type != CMS_SIGN_DRAFT9)
1207 	free(abuf);
1208     if (retval)
1209 	goto cleanup2;
1210 
1211     /* Add signature */
1212     if (!ASN1_STRING_set(p7si->enc_digest, (unsigned char *) sig,
1213 			 (int)sig_len)) {
1214 	unsigned long err = ERR_peek_error();
1215 	retval = KRB5KDC_ERR_PREAUTH_FAILED;
1216 	krb5_set_error_message(context, retval, "%s\n",
1217 			       ERR_error_string(err, NULL));
1218 	pkiDebug("failed to add a signed digest attribute\n");
1219 	goto cleanup2;
1220     }
1221     /* adder signer_info to pkcs7 signed */
1222     if (!PKCS7_add_signer(p7, p7si))
1223 	goto cleanup2;
1224 
1225     /* start on adding data to the pkcs7 signed */
1226     if ((inner_p7 = PKCS7_new()) == NULL)
1227 	goto cleanup2;
1228     if ((pkinit_data = ASN1_TYPE_new()) == NULL)
1229 	goto cleanup2;
1230     pkinit_data->type = V_ASN1_OCTET_STRING;
1231     if ((pkinit_data->value.octet_string = ASN1_OCTET_STRING_new()) == NULL)
1232 	goto cleanup2;
1233     if (!ASN1_OCTET_STRING_set(pkinit_data->value.octet_string, data,
1234 			       (int)data_len)) {
1235 	unsigned long err = ERR_peek_error();
1236 	retval = KRB5KDC_ERR_PREAUTH_FAILED;
1237 	krb5_set_error_message(context, retval, "%s\n",
1238 			       ERR_error_string(err, NULL));
1239 	pkiDebug("failed to add pkcs7 data\n");
1240 	goto cleanup2;
1241     }
1242 
1243     if (!PKCS7_set0_type_other(inner_p7, OBJ_obj2nid(oid), pkinit_data))
1244 	goto cleanup2;
1245 
1246     if (p7s->contents != NULL)
1247 	PKCS7_free(p7s->contents);
1248     p7s->contents = inner_p7;
1249 
1250     *signed_data_len = i2d_PKCS7(p7, NULL);
1251     if (!(*signed_data_len)) {
1252 	unsigned long err = ERR_peek_error();
1253 	retval = KRB5KDC_ERR_PREAUTH_FAILED;
1254 	krb5_set_error_message(context, retval, "%s\n",
1255 			       ERR_error_string(err, NULL));
1256 	pkiDebug("failed to der encode pkcs7\n");
1257 	goto cleanup2;
1258     }
1259     if ((p = *signed_data =
1260 	 (unsigned char *) malloc((size_t)*signed_data_len)) == NULL)
1261 	goto cleanup2;
1262 
1263     /* DER encode PKCS7 data */
1264     retval = i2d_PKCS7(p7, &p);
1265     if (!retval) {
1266 	unsigned long err = ERR_peek_error();
1267 	retval = KRB5KDC_ERR_PREAUTH_FAILED;
1268 	krb5_set_error_message(context, retval, "%s\n",
1269 			       ERR_error_string(err, NULL));
1270 	pkiDebug("failed to der encode pkcs7\n");
1271 	goto cleanup2;
1272     }
1273     retval = 0;
1274 
1275 #ifdef DEBUG_ASN1
1276     if (cms_msg_type == CMS_SIGN_CLIENT) {
1277 	print_buffer_bin(*signed_data, *signed_data_len,
1278 			 "/tmp/client_pkcs7_signeddata");
1279     } else {
1280 	if (cms_msg_type == CMS_SIGN_SERVER) {
1281 	    print_buffer_bin(*signed_data, *signed_data_len,
1282 			     "/tmp/kdc_pkcs7_signeddata");
1283 	} else {
1284 	    print_buffer_bin(*signed_data, *signed_data_len,
1285 			     "/tmp/draft9_pkcs7_signeddata");
1286 	}
1287     }
1288 #endif
1289 
1290   cleanup2:
1291     if (cms_msg_type != CMS_SIGN_DRAFT9)
1292 	if (ctx != NULL)
1293 		EVP_MD_CTX_free(ctx);
1294 #ifndef WITHOUT_PKCS11
1295     if (id_cryptoctx->pkcs11_method == 1 &&
1296 	    id_cryptoctx->mech == CKM_RSA_PKCS) {
1297 	if (ctx2 != NULL)
1298 		EVP_MD_CTX_free(ctx2);
1299 	if (digest_buf != NULL)
1300 	    free(digest_buf);
1301 	if (digestInfo_buf != NULL)
1302 	    free(digestInfo_buf);
1303 	if (alg_buf != NULL)
1304 	    free(alg_buf);
1305 	if (digest != NULL)
1306 	    ASN1_OCTET_STRING_free(digest);
1307     }
1308 #endif
1309     if (alg != NULL)
1310 	X509_ALGOR_free(alg);
1311   cleanup:
1312     if (p7 != NULL)
1313 	PKCS7_free(p7);
1314     if (sig != NULL)
1315 	free(sig);
1316 
1317     return retval;
1318 }
1319 
1320 krb5_error_code
1321 cms_signeddata_verify(krb5_context context,
1322 		      pkinit_plg_crypto_context plgctx,
1323 		      pkinit_req_crypto_context reqctx,
1324 		      pkinit_identity_crypto_context idctx,
1325 		      int cms_msg_type,
1326 		      int require_crl_checking,
1327 		      unsigned char *signed_data,
1328 		      unsigned int signed_data_len,
1329 		      unsigned char **data,
1330 		      unsigned int *data_len,
1331 		      unsigned char **authz_data,
1332 		      unsigned int *authz_data_len)
1333 {
1334     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
1335     PKCS7 *p7 = NULL;
1336     BIO *out = NULL;
1337     int flags = PKCS7_NOVERIFY, i = 0;
1338     unsigned int vflags = 0, size = 0;
1339     const unsigned char *p = signed_data;
1340     STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL;
1341     PKCS7_SIGNER_INFO *si = NULL;
1342     X509 *x = NULL;
1343     X509_STORE *store = NULL;
1344     X509_STORE_CTX *cert_ctx;
1345     STACK_OF(X509) *intermediateCAs = NULL;
1346     STACK_OF(X509_CRL) *revoked = NULL;
1347     STACK_OF(X509) *verified_chain = NULL;
1348     ASN1_OBJECT *oid = NULL;
1349     krb5_external_principal_identifier **krb5_verified_chain = NULL;
1350     krb5_data *authz = NULL;
1351     char buf[DN_BUF_LEN];
1352 
1353 #ifdef DEBUG_ASN1
1354     print_buffer_bin(signed_data, signed_data_len,
1355 		     "/tmp/client_received_pkcs7_signeddata");
1356 #endif
1357 
1358     /* Do this early enough to create the shadow OID for pkcs7-data if needed */
1359     oid = pkinit_pkcs7type2oid(plgctx, cms_msg_type);
1360     if (oid == NULL)
1361 	goto cleanup;
1362 
1363     /* decode received PKCS7 message */
1364     if ((p7 = d2i_PKCS7(NULL, &p, (int)signed_data_len)) == NULL) {
1365 	unsigned long err = ERR_peek_error();
1366 	krb5_set_error_message(context, retval, "%s\n",
1367 			       ERR_error_string(err, NULL));
1368 	pkiDebug("%s: failed to decode message: %s\n",
1369 		 __FUNCTION__, ERR_error_string(err, NULL));
1370 	goto cleanup;
1371     }
1372 
1373     /* verify that the received message is PKCS7 SignedData message */
1374     if (OBJ_obj2nid(p7->type) != NID_pkcs7_signed) {
1375 	pkiDebug("Expected id-signedData PKCS7 msg (received type = %d)\n",
1376 		 OBJ_obj2nid(p7->type));
1377 	krb5_set_error_message(context, retval, "wrong oid\n");
1378 	goto cleanup;
1379     }
1380 
1381     /* setup to verify X509 certificate used to sign PKCS7 message */
1382     if (!(store = X509_STORE_new()))
1383 	goto cleanup;
1384 
1385     /* check if we are inforcing CRL checking */
1386     vflags = X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL;
1387     if (require_crl_checking)
1388 	X509_STORE_set_verify_cb(store, openssl_callback);
1389     else
1390 	X509_STORE_set_verify_cb(store, openssl_callback_ignore_crls);
1391     X509_STORE_set_flags(store, vflags);
1392 
1393     /* get the signer's information from the PKCS7 message */
1394     if ((si_sk = PKCS7_get_signer_info(p7)) == NULL)
1395 	goto cleanup;
1396     if ((si = sk_PKCS7_SIGNER_INFO_value(si_sk, 0)) == NULL)
1397 	goto cleanup;
1398     if ((x = PKCS7_cert_from_signer_info(p7, si)) == NULL)
1399 	goto cleanup;
1400 
1401     /* create available CRL information (get local CRLs and include CRLs
1402      * received in the PKCS7 message
1403      */
1404     if (idctx->revoked == NULL)
1405 	revoked = p7->d.sign->crl;
1406     else if (p7->d.sign->crl == NULL)
1407 	revoked = idctx->revoked;
1408     else {
1409 	size = sk_X509_CRL_num(idctx->revoked);
1410 	revoked = sk_X509_CRL_new_null();
1411 	for (i = 0; i < size; i++)
1412 	    sk_X509_CRL_push(revoked, sk_X509_CRL_value(idctx->revoked, i));
1413 	size = sk_X509_CRL_num(p7->d.sign->crl);
1414 	for (i = 0; i < size; i++)
1415 	    sk_X509_CRL_push(revoked, sk_X509_CRL_value(p7->d.sign->crl, i));
1416     }
1417 
1418     /* create available intermediate CAs chains (get local intermediateCAs and
1419      * include the CA chain received in the PKCS7 message
1420      */
1421     if (idctx->intermediateCAs == NULL)
1422 	intermediateCAs = p7->d.sign->cert;
1423     else if (p7->d.sign->cert == NULL)
1424 	intermediateCAs = idctx->intermediateCAs;
1425     else {
1426 	size = sk_X509_num(idctx->intermediateCAs);
1427 	intermediateCAs = sk_X509_new_null();
1428 	for (i = 0; i < size; i++) {
1429 	    sk_X509_push(intermediateCAs,
1430 		sk_X509_value(idctx->intermediateCAs, i));
1431 	}
1432 	size = sk_X509_num(p7->d.sign->cert);
1433 	for (i = 0; i < size; i++) {
1434 	    sk_X509_push(intermediateCAs, sk_X509_value(p7->d.sign->cert, i));
1435 	}
1436     }
1437 
1438     /* initialize x509 context with the received certificate and
1439      * trusted and intermediate CA chains and CRLs
1440      */
1441     if ((cert_ctx = X509_STORE_CTX_new()) == NULL)
1442 	goto cleanup;
1443     if (!X509_STORE_CTX_init(cert_ctx, store, x, intermediateCAs))
1444 	goto cleanup;
1445 
1446     X509_STORE_CTX_set0_crls(cert_ctx, revoked);
1447 
1448     /* add trusted CAs certificates for cert verification */
1449     if (idctx->trustedCAs != NULL)
1450 	X509_STORE_CTX_set0_trusted_stack(cert_ctx, idctx->trustedCAs);
1451     else {
1452 	pkiDebug("unable to find any trusted CAs\n");
1453 	goto cleanup;
1454     }
1455 #ifdef DEBUG_CERTCHAIN
1456     if (intermediateCAs != NULL) {
1457 	size = sk_X509_num(intermediateCAs);
1458 	pkiDebug("untrusted cert chain of size %d\n", size);
1459 	for (i = 0; i < size; i++) {
1460 	    X509_NAME_oneline(X509_get_subject_name(
1461 		sk_X509_value(intermediateCAs, i)), buf, sizeof(buf));
1462 	    pkiDebug("cert #%d: %s\n", i, buf);
1463 	}
1464     }
1465     if (idctx->trustedCAs != NULL) {
1466 	size = sk_X509_num(idctx->trustedCAs);
1467 	pkiDebug("trusted cert chain of size %d\n", size);
1468 	for (i = 0; i < size; i++) {
1469 	    X509_NAME_oneline(X509_get_subject_name(
1470 		sk_X509_value(idctx->trustedCAs, i)), buf, sizeof(buf));
1471 	    pkiDebug("cert #%d: %s\n", i, buf);
1472 	}
1473     }
1474     if (revoked != NULL) {
1475 	size = sk_X509_CRL_num(revoked);
1476 	pkiDebug("CRL chain of size %d\n", size);
1477 	for (i = 0; i < size; i++) {
1478 	    X509_CRL *crl = sk_X509_CRL_value(revoked, i);
1479 	    X509_NAME_oneline(X509_CRL_get_issuer(crl), buf, sizeof(buf));
1480 	    pkiDebug("crls by CA #%d: %s\n", i , buf);
1481 	}
1482     }
1483 #endif
1484 
1485     i = X509_verify_cert(cert_ctx);
1486     if (i <= 0) {
1487 	int j = X509_STORE_CTX_get_error(cert_ctx);
1488 
1489 	reqctx->received_cert = X509_dup(
1490 	    X509_STORE_CTX_get_current_cert(cert_ctx));
1491 	switch(j) {
1492 	    case X509_V_ERR_CERT_REVOKED:
1493 		retval = KRB5KDC_ERR_REVOKED_CERTIFICATE;
1494 		break;
1495 	    case X509_V_ERR_UNABLE_TO_GET_CRL:
1496 		retval = KRB5KDC_ERR_REVOCATION_STATUS_UNKNOWN;
1497 		break;
1498 	    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
1499 	    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
1500 		retval = KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE;
1501 		break;
1502 	    default:
1503 		retval = KRB5KDC_ERR_INVALID_CERTIFICATE;
1504 	}
1505 	X509_NAME_oneline(X509_get_subject_name(
1506 	    reqctx->received_cert), buf, sizeof(buf));
1507 	pkiDebug("problem with cert DN = %s (error=%d) %s\n", buf, j,
1508 		 X509_verify_cert_error_string(j));
1509 	krb5_set_error_message(context, retval, "%s\n",
1510 	    X509_verify_cert_error_string(j));
1511 #ifdef DEBUG_CERTCHAIN
1512 	size = sk_X509_num(p7->d.sign->cert);
1513 	pkiDebug("received cert chain of size %d\n", size);
1514 	for (j = 0; j < size; j++) {
1515 	    X509 *tmp_cert = sk_X509_value(p7->d.sign->cert, j);
1516 	    X509_NAME_oneline(X509_get_subject_name(tmp_cert), buf, sizeof(buf));
1517 	    pkiDebug("cert #%d: %s\n", j, buf);
1518 	}
1519 #endif
1520     } else {
1521 	/* retrieve verified certificate chain */
1522 	if (cms_msg_type == CMS_SIGN_CLIENT || cms_msg_type == CMS_SIGN_DRAFT9)
1523 	    verified_chain = X509_STORE_CTX_get1_chain(cert_ctx);
1524     }
1525     X509_STORE_CTX_free(cert_ctx);
1526     if (i <= 0)
1527 	goto cleanup;
1528 
1529     out = BIO_new(BIO_s_mem());
1530     if (cms_msg_type == CMS_SIGN_DRAFT9)
1531 	flags |= PKCS7_NOATTR;
1532     if (PKCS7_verify(p7, NULL, store, NULL, out, flags)) {
1533 	int valid_oid = 0;
1534 
1535 	if (!OBJ_cmp(p7->d.sign->contents->type, oid))
1536 	    valid_oid = 1;
1537 	else if (cms_msg_type == CMS_SIGN_DRAFT9) {
1538 	    /*
1539 	     * Various implementations of the pa-type 15 request use
1540 	     * different OIDS.  We check that the returned object
1541 	     * has any of the acceptable OIDs
1542 	     */
1543 	    ASN1_OBJECT *client_oid = NULL, *server_oid = NULL, *rsa_oid = NULL;
1544 	    client_oid = pkinit_pkcs7type2oid(plgctx, CMS_SIGN_CLIENT);
1545 	    server_oid = pkinit_pkcs7type2oid(plgctx, CMS_SIGN_SERVER);
1546 	    rsa_oid = pkinit_pkcs7type2oid(plgctx, CMS_ENVEL_SERVER);
1547 	    if (!OBJ_cmp(p7->d.sign->contents->type, client_oid) ||
1548 		!OBJ_cmp(p7->d.sign->contents->type, server_oid) ||
1549 		!OBJ_cmp(p7->d.sign->contents->type, rsa_oid))
1550 		valid_oid = 1;
1551 	}
1552 
1553 	if (valid_oid)
1554 	    pkiDebug("PKCS7 Verification successful\n");
1555 	else {
1556 	    const ASN1_OBJECT *etype = p7->d.sign->contents->type;
1557 	    pkiDebug("wrong oid in eContentType\n");
1558 	    print_buffer((unsigned char *)OBJ_get0_data(etype),
1559 		OBJ_length(etype));
1560 	    retval = KRB5KDC_ERR_PREAUTH_FAILED;
1561 	    krb5_set_error_message(context, retval, "wrong oid\n");
1562 	    goto cleanup;
1563 	}
1564     }
1565     else {
1566 	unsigned long err = ERR_peek_error();
1567 	switch(ERR_GET_REASON(err)) {
1568 	    case PKCS7_R_DIGEST_FAILURE:
1569 		retval = KRB5KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED;
1570 		break;
1571 	    case PKCS7_R_SIGNATURE_FAILURE:
1572 	    default:
1573 		retval = KRB5KDC_ERR_INVALID_SIG;
1574 	}
1575 	pkiDebug("PKCS7 Verification failure\n");
1576 	krb5_set_error_message(context, retval, "%s\n",
1577 			       ERR_error_string(err, NULL));
1578 	goto cleanup;
1579     }
1580 
1581     /* transfer the data from PKCS7 message into return buffer */
1582     for (size = 0;;) {
1583 	if ((*data = realloc(*data, size + 1024 * 10)) == NULL)
1584 	    goto cleanup;
1585 	i = BIO_read(out, &((*data)[size]), 1024 * 10);
1586 	if (i <= 0)
1587 	    break;
1588 	else
1589 	    size += i;
1590     }
1591     *data_len = size;
1592 
1593     reqctx->received_cert = X509_dup(x);
1594 
1595     /* generate authorization data */
1596     if (cms_msg_type == CMS_SIGN_CLIENT || cms_msg_type == CMS_SIGN_DRAFT9) {
1597 
1598 	if (authz_data == NULL || authz_data_len == NULL)
1599 	    goto out;
1600 
1601 	*authz_data = NULL;
1602 	retval = create_identifiers_from_stack(verified_chain,
1603 					       &krb5_verified_chain);
1604 	if (retval) {
1605 	    pkiDebug("create_identifiers_from_stack failed\n");
1606 	    goto cleanup;
1607 	}
1608 
1609 	retval = k5int_encode_krb5_td_trusted_certifiers((const krb5_external_principal_identifier **)krb5_verified_chain, &authz);
1610 	if (retval) {
1611 	    pkiDebug("encode_krb5_td_trusted_certifiers failed\n");
1612 	    goto cleanup;
1613 	}
1614 #ifdef DEBUG_ASN1
1615 	print_buffer_bin((unsigned char *)authz->data, authz->length,
1616 			 "/tmp/kdc_ad_initial_verified_cas");
1617 #endif
1618 	*authz_data = (unsigned char *)malloc(authz->length);
1619 	if (*authz_data == NULL) {
1620 	    retval = ENOMEM;
1621 	    goto cleanup;
1622 	}
1623 	(void) memcpy(*authz_data, authz->data, authz->length);
1624 	*authz_data_len = authz->length;
1625     }
1626   out:
1627     retval = 0;
1628 
1629   cleanup:
1630     if (out != NULL)
1631 	BIO_free(out);
1632     if (store != NULL)
1633 	X509_STORE_free(store);
1634     if (p7 != NULL) {
1635 	if (idctx->intermediateCAs != NULL && p7->d.sign->cert)
1636 	    sk_X509_free(intermediateCAs);
1637 	if (idctx->revoked != NULL && p7->d.sign->crl)
1638 	    sk_X509_CRL_free(revoked);
1639 	PKCS7_free(p7);
1640     }
1641     if (verified_chain != NULL)
1642 	sk_X509_pop_free(verified_chain, X509_free);
1643     if (krb5_verified_chain != NULL)
1644 	free_krb5_external_principal_identifier(&krb5_verified_chain);
1645     if (authz != NULL)
1646 	krb5_free_data(context, authz);
1647 
1648     return retval;
1649 }
1650 
1651 krb5_error_code
1652 cms_envelopeddata_create(krb5_context context,
1653 			 pkinit_plg_crypto_context plgctx,
1654 			 pkinit_req_crypto_context reqctx,
1655 			 pkinit_identity_crypto_context idctx,
1656 			 krb5_preauthtype pa_type,
1657 			 int include_certchain,
1658 			 unsigned char *key_pack,
1659 			 unsigned int key_pack_len,
1660 			 unsigned char **out,
1661 			 unsigned int *out_len)
1662 {
1663 
1664     /* Solaris Kerberos */
1665     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
1666     PKCS7 *p7 = NULL;
1667     BIO *in = NULL;
1668     unsigned char *p = NULL, *signed_data = NULL, *enc_data = NULL;
1669     int signed_data_len = 0, enc_data_len = 0, flags = PKCS7_BINARY;
1670     STACK_OF(X509) *encerts = NULL;
1671     const EVP_CIPHER *cipher = NULL;
1672     int cms_msg_type;
1673 
1674     /* create the PKCS7 SignedData portion of the PKCS7 EnvelopedData */
1675     switch ((int)pa_type) {
1676 	case KRB5_PADATA_PK_AS_REQ_OLD:
1677 	case KRB5_PADATA_PK_AS_REP_OLD:
1678 	    cms_msg_type = CMS_SIGN_DRAFT9;
1679 	    break;
1680 	case KRB5_PADATA_PK_AS_REQ:
1681 	    cms_msg_type = CMS_ENVEL_SERVER;
1682 	    break;
1683 	default:
1684 	    /* Solaris Kerberos */
1685 	    retval = EINVAL;
1686 	    goto cleanup;
1687     }
1688 
1689     retval = cms_signeddata_create(context, plgctx, reqctx, idctx,
1690 	cms_msg_type, include_certchain, key_pack, key_pack_len,
1691 	&signed_data, (unsigned int *)&signed_data_len);
1692     if (retval) {
1693 	pkiDebug("failed to create pkcs7 signed data\n");
1694 	goto cleanup;
1695     }
1696 
1697     /* check we have client's certificate */
1698     if (reqctx->received_cert == NULL) {
1699 	retval = KRB5KDC_ERR_PREAUTH_FAILED;
1700 	goto cleanup;
1701     }
1702     encerts = sk_X509_new_null();
1703     sk_X509_push(encerts, reqctx->received_cert);
1704 
1705     cipher = EVP_des_ede3_cbc();
1706     in = BIO_new(BIO_s_mem());
1707     switch (pa_type) {
1708 	case KRB5_PADATA_PK_AS_REQ:
1709 	    prepare_enc_data(signed_data, signed_data_len, &enc_data,
1710 			     &enc_data_len);
1711 	    retval = BIO_write(in, enc_data, enc_data_len);
1712 	    if (retval != enc_data_len) {
1713 		pkiDebug("BIO_write only wrote %d\n", retval);
1714 		goto cleanup;
1715 	    }
1716 	    break;
1717 	case KRB5_PADATA_PK_AS_REP_OLD:
1718 	case KRB5_PADATA_PK_AS_REQ_OLD:
1719 	    retval = BIO_write(in, signed_data, signed_data_len);
1720 		if (retval != signed_data_len) {
1721 		    pkiDebug("BIO_write only wrote %d\n", retval);
1722 		    /* Solaris Kerberos */
1723 		    retval = KRB5KRB_ERR_GENERIC;
1724 		    goto cleanup;
1725 	    }
1726 	    break;
1727 	default:
1728 	    retval = -1;
1729 	    goto cleanup;
1730     }
1731 
1732     p7 = PKCS7_encrypt(encerts, in, cipher, flags);
1733     if (p7 == NULL) {
1734 	pkiDebug("failed to encrypt PKCS7 object\n");
1735 	retval = -1;
1736 	goto cleanup;
1737     }
1738     switch (pa_type) {
1739 	case KRB5_PADATA_PK_AS_REQ:
1740 	    p7->d.enveloped->enc_data->content_type =
1741 		OBJ_nid2obj(NID_pkcs7_signed);
1742 	    break;
1743 	case KRB5_PADATA_PK_AS_REP_OLD:
1744 	case KRB5_PADATA_PK_AS_REQ_OLD:
1745 	    p7->d.enveloped->enc_data->content_type =
1746 		OBJ_nid2obj(NID_pkcs7_data);
1747 	    break;
1748     }
1749 
1750     *out_len = i2d_PKCS7(p7, NULL);
1751     if (!*out_len || (p = *out = (unsigned char *)malloc(*out_len)) == NULL) {
1752 	retval = ENOMEM;
1753 	goto cleanup;
1754     }
1755     retval = i2d_PKCS7(p7, &p);
1756     if (!retval) {
1757 	pkiDebug("unable to write pkcs7 object\n");
1758 	goto cleanup;
1759     }
1760     retval = 0;
1761 
1762 #ifdef DEBUG_ASN1
1763     print_buffer_bin(*out, *out_len, "/tmp/kdc_enveloped_data");
1764 #endif
1765 
1766 cleanup:
1767     if (p7 != NULL)
1768 	PKCS7_free(p7);
1769     if (in != NULL)
1770 	BIO_free(in);
1771     if (signed_data != NULL)
1772 	free(signed_data);
1773     if (enc_data != NULL)
1774 	free(enc_data);
1775     if (encerts != NULL)
1776 	sk_X509_free(encerts);
1777 
1778     return retval;
1779 }
1780 
1781 krb5_error_code
1782 cms_envelopeddata_verify(krb5_context context,
1783 			 pkinit_plg_crypto_context plg_cryptoctx,
1784 			 pkinit_req_crypto_context req_cryptoctx,
1785 			 pkinit_identity_crypto_context id_cryptoctx,
1786 			 krb5_preauthtype pa_type,
1787 			 int require_crl_checking,
1788 			 unsigned char *enveloped_data,
1789 			 unsigned int enveloped_data_len,
1790 			 unsigned char **data,
1791 			 unsigned int *data_len)
1792 {
1793     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
1794     PKCS7 *p7 = NULL;
1795     BIO *out = NULL;
1796     int i = 0;
1797     unsigned int size = 0;
1798     const unsigned char *p = enveloped_data;
1799     unsigned int tmp_buf_len = 0, tmp_buf2_len = 0, vfy_buf_len = 0;
1800     unsigned char *tmp_buf = NULL, *tmp_buf2 = NULL, *vfy_buf = NULL;
1801     int msg_type = 0;
1802 
1803 #ifdef DEBUG_ASN1
1804     print_buffer_bin(enveloped_data, enveloped_data_len,
1805 		     "/tmp/client_envelopeddata");
1806 #endif
1807     /* decode received PKCS7 message */
1808     if ((p7 = d2i_PKCS7(NULL, &p, (int)enveloped_data_len)) == NULL) {
1809 	unsigned long err = ERR_peek_error();
1810 	pkiDebug("failed to decode pkcs7\n");
1811 	krb5_set_error_message(context, retval, "%s\n",
1812 			       ERR_error_string(err, NULL));
1813 	goto cleanup;
1814     }
1815 
1816     /* verify that the received message is PKCS7 EnvelopedData message */
1817     if (OBJ_obj2nid(p7->type) != NID_pkcs7_enveloped) {
1818 	pkiDebug("Expected id-enveloped PKCS7 msg (received type = %d)\n",
1819 		 OBJ_obj2nid(p7->type));
1820 	krb5_set_error_message(context, retval, "wrong oid\n");
1821 	goto cleanup;
1822     }
1823 
1824     /* decrypt received PKCS7 message */
1825     out = BIO_new(BIO_s_mem());
1826     if (pkcs7_decrypt(context, id_cryptoctx, p7, out)) {
1827 	pkiDebug("PKCS7 decryption successful\n");
1828     } else {
1829 	unsigned long err = ERR_peek_error();
1830 	if (err != 0)
1831 	    krb5_set_error_message(context, retval, "%s\n",
1832 				   ERR_error_string(err, NULL));
1833 	pkiDebug("PKCS7 decryption failed\n");
1834 	goto cleanup;
1835     }
1836 
1837     /* transfer the decoded PKCS7 SignedData message into a separate buffer */
1838     for (;;) {
1839 	if ((tmp_buf = realloc(tmp_buf, size + 1024 * 10)) == NULL)
1840 	    goto cleanup;
1841 	i = BIO_read(out, &(tmp_buf[size]), 1024 * 10);
1842 	if (i <= 0)
1843 	    break;
1844 	else
1845 	    size += i;
1846     }
1847     tmp_buf_len = size;
1848 
1849 #ifdef DEBUG_ASN1
1850     print_buffer_bin(tmp_buf, tmp_buf_len, "/tmp/client_enc_keypack");
1851 #endif
1852     /* verify PKCS7 SignedData message */
1853     switch (pa_type) {
1854 	case KRB5_PADATA_PK_AS_REP:
1855 	    msg_type = CMS_ENVEL_SERVER;
1856 
1857 	    break;
1858 	case KRB5_PADATA_PK_AS_REP_OLD:
1859 	    msg_type = CMS_SIGN_DRAFT9;
1860 	    break;
1861 	default:
1862 	    pkiDebug("%s: unrecognized pa_type = %d\n", __FUNCTION__, pa_type);
1863 	    retval = KRB5KDC_ERR_PREAUTH_FAILED;
1864 	    goto cleanup;
1865     }
1866     /*
1867      * If this is the RFC style, wrap the signed data to make
1868      * decoding easier in the verify routine.
1869      * For draft9-compatible, we don't do anything because it
1870      * is already wrapped.
1871      */
1872 #ifdef LONGHORN_BETA_COMPAT
1873     /*
1874      * The Longhorn server returns the expected RFC-style data, but
1875      * it is missing the sequence tag and length, so it requires
1876      * special processing when wrapping.
1877      * This will hopefully be fixed before the final release and
1878      * this can all be removed.
1879      */
1880     if (msg_type == CMS_ENVEL_SERVER || longhorn == 1) {
1881 	retval = wrap_signeddata(tmp_buf, tmp_buf_len,
1882 				 &tmp_buf2, &tmp_buf2_len, longhorn);
1883 	if (retval) {
1884 	    pkiDebug("failed to encode signeddata\n");
1885 	    goto cleanup;
1886 	}
1887 	vfy_buf = tmp_buf2;
1888 	vfy_buf_len = tmp_buf2_len;
1889 
1890     } else {
1891 	vfy_buf = tmp_buf;
1892 	vfy_buf_len = tmp_buf_len;
1893     }
1894 #else
1895     if (msg_type == CMS_ENVEL_SERVER) {
1896 	retval = wrap_signeddata(tmp_buf, tmp_buf_len,
1897 				 &tmp_buf2, &tmp_buf2_len);
1898 	if (retval) {
1899 	    pkiDebug("failed to encode signeddata\n");
1900 	    goto cleanup;
1901 	}
1902 	vfy_buf = tmp_buf2;
1903 	vfy_buf_len = tmp_buf2_len;
1904 
1905     } else {
1906 	vfy_buf = tmp_buf;
1907 	vfy_buf_len = tmp_buf_len;
1908     }
1909 #endif
1910 
1911 #ifdef DEBUG_ASN1
1912     print_buffer_bin(vfy_buf, vfy_buf_len, "/tmp/client_enc_keypack2");
1913 #endif
1914 
1915     retval = cms_signeddata_verify(context, plg_cryptoctx, req_cryptoctx,
1916 				   id_cryptoctx, msg_type,
1917 				   require_crl_checking,
1918 				   vfy_buf, vfy_buf_len,
1919 				   data, data_len, NULL, NULL);
1920 
1921     if (!retval)
1922 	pkiDebug("PKCS7 Verification Success\n");
1923     else {
1924 	pkiDebug("PKCS7 Verification Failure\n");
1925 	goto cleanup;
1926     }
1927 
1928     retval = 0;
1929 
1930   cleanup:
1931 
1932     if (p7 != NULL)
1933 	PKCS7_free(p7);
1934     if (out != NULL)
1935 	BIO_free(out);
1936     if (tmp_buf != NULL)
1937 	free(tmp_buf);
1938     if (tmp_buf2 != NULL)
1939 	free(tmp_buf2);
1940 
1941     return retval;
1942 }
1943 
1944 /* ARGSUSED */
1945 static krb5_error_code
1946 crypto_retrieve_X509_sans(krb5_context context,
1947 			  pkinit_plg_crypto_context plgctx,
1948 			  pkinit_req_crypto_context reqctx,
1949 			  X509 *cert,
1950 			  krb5_principal **princs_ret,
1951 			  krb5_principal **upn_ret,
1952 			  unsigned char ***dns_ret)
1953 {
1954     krb5_error_code retval = EINVAL;
1955     char buf[DN_BUF_LEN];
1956     int p = 0, u = 0, d = 0;
1957     krb5_principal *princs = NULL;
1958     krb5_principal *upns = NULL;
1959     unsigned char **dnss = NULL;
1960     int i, num_found = 0;
1961 
1962     if (princs_ret == NULL && upn_ret == NULL && dns_ret == NULL) {
1963 	pkiDebug("%s: nowhere to return any values!\n", __FUNCTION__);
1964 	return retval;
1965     }
1966 
1967     if (cert == NULL) {
1968 	pkiDebug("%s: no certificate!\n", __FUNCTION__);
1969 	return retval;
1970     }
1971 
1972     X509_NAME_oneline(X509_get_subject_name(cert),
1973 		      buf, sizeof(buf));
1974     pkiDebug("%s: looking for SANs in cert = %s\n", __FUNCTION__, buf);
1975 
1976     if ((i = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1)) >= 0) {
1977 	X509_EXTENSION *ext = NULL;
1978 	GENERAL_NAMES *ialt = NULL;
1979 	GENERAL_NAME *gen = NULL;
1980 	int ret = 0;
1981 	unsigned int num_sans = 0;
1982 
1983 	if (!(ext = X509_get_ext(cert, i)) || !(ialt = X509V3_EXT_d2i(ext))) {
1984 	    pkiDebug("%s: found no subject alt name extensions\n",
1985 		     __FUNCTION__);
1986 	    goto cleanup;
1987 	}
1988 	num_sans = sk_GENERAL_NAME_num(ialt);
1989 
1990 	pkiDebug("%s: found %d subject alt name extension(s)\n",
1991 		 __FUNCTION__, num_sans);
1992 
1993 	/* OK, we're likely returning something. Allocate return values */
1994 	if (princs_ret != NULL) {
1995 	    princs = calloc(num_sans + 1, sizeof(krb5_principal));
1996 	    if (princs == NULL) {
1997 		retval = ENOMEM;
1998 		goto cleanup;
1999 	    }
2000 	}
2001 	if (upn_ret != NULL) {
2002 	    upns = calloc(num_sans + 1, sizeof(krb5_principal));
2003 	    if (upns == NULL) {
2004 		retval = ENOMEM;
2005 		goto cleanup;
2006 	    }
2007 	}
2008 	if (dns_ret != NULL) {
2009 	    dnss = calloc(num_sans + 1, sizeof(*dnss));
2010 	    if (dnss == NULL) {
2011 		retval = ENOMEM;
2012 		goto cleanup;
2013 	    }
2014 	}
2015 
2016 	for (i = 0; i < num_sans; i++) {
2017 	    krb5_data name = { 0, 0, NULL };
2018 
2019 	    gen = sk_GENERAL_NAME_value(ialt, i);
2020 	    switch (gen->type) {
2021 	    case GEN_OTHERNAME:
2022 		name.length = gen->d.otherName->value->value.sequence->length;
2023 		name.data = (char *)gen->d.otherName->value->value.sequence->data;
2024 		if (princs != NULL
2025 		    && OBJ_cmp(plgctx->id_pkinit_san,
2026 			       gen->d.otherName->type_id) == 0) {
2027 #ifdef DEBUG_ASN1
2028 		    print_buffer_bin((unsigned char *)name.data, name.length,
2029 				     "/tmp/pkinit_san");
2030 #endif
2031 		    ret = k5int_decode_krb5_principal_name(&name, &princs[p]);
2032 		    if (ret) {
2033 			pkiDebug("%s: failed decoding pkinit san value\n",
2034 				 __FUNCTION__);
2035 		    } else {
2036 			p++;
2037 			num_found++;
2038 		    }
2039 		} else if (upns != NULL
2040 			   && OBJ_cmp(plgctx->id_ms_san_upn,
2041 				      gen->d.otherName->type_id) == 0) {
2042 		    ret = krb5_parse_name(context, name.data, &upns[u]);
2043 		    if (ret) {
2044 			pkiDebug("%s: failed parsing ms-upn san value\n",
2045 				 __FUNCTION__);
2046 		    } else {
2047 			u++;
2048 			num_found++;
2049 		    }
2050 		} else {
2051 		    pkiDebug("%s: unrecognized othername oid in SAN\n",
2052 			     __FUNCTION__);
2053 		    continue;
2054 		}
2055 
2056 		break;
2057 	    case GEN_DNS:
2058 		if (dnss != NULL) {
2059 		    pkiDebug("%s: found dns name = %s\n",
2060 			     __FUNCTION__, gen->d.dNSName->data);
2061 		    dnss[d] = (unsigned char *)
2062 				    strdup((char *)gen->d.dNSName->data);
2063 		    if (dnss[d] == NULL) {
2064 			pkiDebug("%s: failed to duplicate dns name\n",
2065 				 __FUNCTION__);
2066 		    } else {
2067 			d++;
2068 			num_found++;
2069 		    }
2070 		}
2071 		break;
2072 	    default:
2073 		pkiDebug("%s: SAN type = %d expecting %d\n",
2074 			 __FUNCTION__, gen->type, GEN_OTHERNAME);
2075 	    }
2076 	}
2077 	sk_GENERAL_NAME_pop_free(ialt, GENERAL_NAME_free);
2078     }
2079 
2080     retval = 0;
2081     if (princs)
2082 	*princs_ret = princs;
2083     if (upns)
2084 	*upn_ret = upns;
2085     if (dnss)
2086 	*dns_ret = dnss;
2087 
2088   cleanup:
2089     if (retval) {
2090 	if (princs != NULL) {
2091 	    for (i = 0; princs[i] != NULL; i++)
2092 		krb5_free_principal(context, princs[i]);
2093 	    free(princs);
2094 	}
2095 	if (upns != NULL) {
2096 	    for (i = 0; upns[i] != NULL; i++)
2097 		krb5_free_principal(context, upns[i]);
2098 	    free(upns);
2099 	}
2100 	if (dnss != NULL) {
2101 	    for (i = 0; dnss[i] != NULL; i++)
2102 		free(dnss[i]);
2103 	    free(dnss);
2104 	}
2105     }
2106     return retval;
2107 }
2108 
2109 /* ARGSUSED */
2110 krb5_error_code
2111 crypto_retrieve_cert_sans(krb5_context context,
2112 			  pkinit_plg_crypto_context plgctx,
2113 			  pkinit_req_crypto_context reqctx,
2114 			  pkinit_identity_crypto_context idctx,
2115 			  krb5_principal **princs_ret,
2116 			  krb5_principal **upn_ret,
2117 			  unsigned char ***dns_ret)
2118 {
2119     krb5_error_code retval = EINVAL;
2120 
2121     if (reqctx->received_cert == NULL) {
2122 	pkiDebug("%s: No certificate!\n", __FUNCTION__);
2123 	return retval;
2124     }
2125 
2126     return crypto_retrieve_X509_sans(context, plgctx, reqctx,
2127 				     reqctx->received_cert, princs_ret,
2128 				     upn_ret, dns_ret);
2129 }
2130 
2131 /* ARGSUSED */
2132 krb5_error_code
2133 crypto_check_cert_eku(krb5_context context,
2134 		      pkinit_plg_crypto_context plgctx,
2135 		      pkinit_req_crypto_context reqctx,
2136 		      pkinit_identity_crypto_context idctx,
2137 		      int checking_kdc_cert,
2138 		      int allow_secondary_usage,
2139 		      int *valid_eku)
2140 {
2141     char buf[DN_BUF_LEN];
2142     int found_eku = 0;
2143     krb5_error_code retval = EINVAL;
2144     int i;
2145 
2146     /* Solaris Kerberos */
2147     if (valid_eku == NULL)
2148 	return retval;
2149 
2150     *valid_eku = 0;
2151     if (reqctx->received_cert == NULL)
2152 	goto cleanup;
2153 
2154     X509_NAME_oneline(X509_get_subject_name(reqctx->received_cert),
2155 		      buf, sizeof(buf));
2156     pkiDebug("%s: looking for EKUs in cert = %s\n", __FUNCTION__, buf);
2157 
2158     if ((i = X509_get_ext_by_NID(reqctx->received_cert,
2159 				 NID_ext_key_usage, -1)) >= 0) {
2160 	EXTENDED_KEY_USAGE *extusage;
2161 
2162 	extusage = X509_get_ext_d2i(reqctx->received_cert, NID_ext_key_usage,
2163 				    NULL, NULL);
2164 	if (extusage) {
2165 	    pkiDebug("%s: found eku info in the cert\n", __FUNCTION__);
2166 	    for (i = 0; found_eku == 0 && i < sk_ASN1_OBJECT_num(extusage); i++) {
2167 		ASN1_OBJECT *tmp_oid;
2168 
2169 		tmp_oid = sk_ASN1_OBJECT_value(extusage, i);
2170 		pkiDebug("%s: checking eku %d of %d, allow_secondary = %d\n",
2171 			 __FUNCTION__, i+1, sk_ASN1_OBJECT_num(extusage),
2172 			 allow_secondary_usage);
2173 		if (checking_kdc_cert) {
2174 		    if ((OBJ_cmp(tmp_oid, plgctx->id_pkinit_KPKdc) == 0)
2175 			 || (allow_secondary_usage
2176 			 && OBJ_cmp(tmp_oid, plgctx->id_kp_serverAuth) == 0))
2177 			found_eku = 1;
2178 		} else {
2179 		    if ((OBJ_cmp(tmp_oid, plgctx->id_pkinit_KPClientAuth) == 0)
2180 			 || (allow_secondary_usage
2181 			 && OBJ_cmp(tmp_oid, plgctx->id_ms_kp_sc_logon) == 0))
2182 			found_eku = 1;
2183 		}
2184 	    }
2185 	}
2186 	EXTENDED_KEY_USAGE_free(extusage);
2187 
2188 	if (found_eku) {
2189 	    ASN1_BIT_STRING *usage = NULL;
2190 	    pkiDebug("%s: found acceptable EKU, checking for digitalSignature\n", __FUNCTION__);
2191 
2192 	    /* check that digitalSignature KeyUsage is present */
2193 	    if ((usage = X509_get_ext_d2i(reqctx->received_cert,
2194 					  NID_key_usage, NULL, NULL))) {
2195 
2196 		if (!ku_reject(reqctx->received_cert,
2197 			       X509v3_KU_DIGITAL_SIGNATURE)) {
2198 		    pkiDebug("%s: found digitalSignature KU\n",
2199 			     __FUNCTION__);
2200 		    *valid_eku = 1;
2201 		} else
2202 		    pkiDebug("%s: didn't find digitalSignature KU\n",
2203 			     __FUNCTION__);
2204 	    }
2205 	    ASN1_BIT_STRING_free(usage);
2206 	}
2207     }
2208     retval = 0;
2209 cleanup:
2210     pkiDebug("%s: returning retval %d, valid_eku %d\n",
2211 	     __FUNCTION__, retval, *valid_eku);
2212     return retval;
2213 }
2214 
2215 krb5_error_code
2216 pkinit_octetstring2key(krb5_context context,
2217 		       krb5_enctype etype,
2218 		       unsigned char *key,
2219 		       unsigned int dh_key_len,
2220 		       krb5_keyblock * key_block)
2221 {
2222     krb5_error_code retval;
2223     unsigned char *buf = NULL;
2224     unsigned char md[SHA_DIGEST_LENGTH];
2225     unsigned char counter;
2226     size_t keybytes, keylength, offset;
2227     krb5_data random_data;
2228 
2229 
2230     if ((buf = (unsigned char *) malloc(dh_key_len)) == NULL) {
2231 	retval = ENOMEM;
2232 	goto cleanup;
2233     }
2234     (void) memset(buf, 0, dh_key_len);
2235 
2236     counter = 0;
2237     offset = 0;
2238     do {
2239 	SHA_CTX c;
2240 
2241 	SHA1_Init(&c);
2242 	SHA1_Update(&c, &counter, 1);
2243 	SHA1_Update(&c, key, dh_key_len);
2244 	SHA1_Final(md, &c);
2245 
2246 	if (dh_key_len - offset < sizeof(md))
2247 	    (void) memcpy(buf + offset, md, dh_key_len - offset);
2248 	else
2249 	    (void) memcpy(buf + offset, md, sizeof(md));
2250 
2251 	offset += sizeof(md);
2252 	counter++;
2253     } while (offset < dh_key_len);
2254 
2255     /* Solaris Kerberos */
2256     key_block->magic = KV5M_KEYBLOCK;
2257     key_block->enctype = etype;
2258 
2259     retval = krb5_c_keylengths(context, etype, &keybytes, &keylength);
2260     if (retval)
2261 	goto cleanup;
2262 
2263     key_block->length = keylength;
2264     key_block->contents = calloc(keylength, sizeof(unsigned char *));
2265     if (key_block->contents == NULL) {
2266 	retval = ENOMEM;
2267 	goto cleanup;
2268     }
2269 
2270     random_data.length = keybytes;
2271     random_data.data = (char *)buf;
2272 
2273     retval = krb5_c_random_to_key(context, etype, &random_data, key_block);
2274 
2275   cleanup:
2276     if (buf != NULL)
2277 	free(buf);
2278     if (retval && key_block->contents != NULL && key_block->length != 0) {
2279 	(void) memset(key_block->contents, 0, key_block->length);
2280 	key_block->length = 0;
2281     }
2282 
2283     return retval;
2284 }
2285 
2286 /* ARGSUSED */
2287 krb5_error_code
2288 client_create_dh(krb5_context context,
2289 		 pkinit_plg_crypto_context plg_cryptoctx,
2290 		 pkinit_req_crypto_context cryptoctx,
2291 		 pkinit_identity_crypto_context id_cryptoctx,
2292 		 int dh_size,
2293 		 unsigned char **dh_params,
2294 		 unsigned int *dh_params_len,
2295 		 unsigned char **dh_pubkey,
2296 		 unsigned int *dh_pubkey_len)
2297 {
2298     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2299     unsigned char *buf = NULL;
2300     int dh_err = 0;
2301     ASN1_INTEGER *asn_pub_key = NULL;
2302     BIGNUM *p, *g, *q;
2303     const BIGNUM *pub_key;
2304 
2305     if (cryptoctx->dh == NULL) {
2306 	if ((cryptoctx->dh = DH_new()) == NULL)
2307 	    goto cleanup;
2308 	if ((g = BN_new()) == NULL || (q = BN_new()) == NULL)
2309 	    goto cleanup;
2310 
2311 	switch(dh_size) {
2312 	    case 1024:
2313 		pkiDebug("client uses 1024 DH keys\n");
2314 		cryptoctx->dh = make_dhprime(pkinit_1024_dhprime,
2315 		    sizeof(pkinit_1024_dhprime));
2316 		break;
2317 	    case 2048:
2318 		pkiDebug("client uses 2048 DH keys\n");
2319 		cryptoctx->dh = make_dhprime(pkinit_2048_dhprime,
2320 		    sizeof(pkinit_2048_dhprime));
2321 		break;
2322 	    case 4096:
2323 		pkiDebug("client uses 4096 DH keys\n");
2324 		cryptoctx->dh = make_dhprime(pkinit_4096_dhprime,
2325 		    sizeof(pkinit_4096_dhprime));
2326 		break;
2327 	}
2328 	if (cryptoctx->dh == NULL)
2329 		goto cleanup;
2330     }
2331 
2332     DH_generate_key(cryptoctx->dh);
2333     DH_get0_key(cryptoctx->dh, &pub_key, NULL);
2334 
2335 /* Solaris Kerberos */
2336 #ifdef DEBUG
2337     DH_check(cryptoctx->dh, &dh_err);
2338     if (dh_err != 0) {
2339 	pkiDebug("Warning: dh_check failed with %d\n", dh_err);
2340 	if (dh_err & DH_CHECK_P_NOT_PRIME)
2341 	    pkiDebug("p value is not prime\n");
2342 	if (dh_err & DH_CHECK_P_NOT_SAFE_PRIME)
2343 	    pkiDebug("p value is not a safe prime\n");
2344 	if (dh_err & DH_UNABLE_TO_CHECK_GENERATOR)
2345 	    pkiDebug("unable to check the generator value\n");
2346 	if (dh_err & DH_NOT_SUITABLE_GENERATOR)
2347 	    pkiDebug("the g value is not a generator\n");
2348     }
2349 #endif
2350 #ifdef DEBUG_DH
2351     print_dh(cryptoctx->dh, "client's DH params\n");
2352     print_pubkey(pub_key, "client's pub_key=");
2353 #endif
2354 
2355     DH_check_pub_key(cryptoctx->dh, pub_key, &dh_err);
2356     if (dh_err != 0) {
2357 	pkiDebug("dh_check_pub_key failed with %d\n", dh_err);
2358 	goto cleanup;
2359     }
2360 
2361     /* pack DHparams */
2362     /* aglo: usually we could just call i2d_DHparams to encode DH params
2363      * however, PKINIT requires RFC3279 encoding and openssl does pkcs#3.
2364      */
2365     DH_get0_pqg(cryptoctx->dh, (const BIGNUM **)&p, (const BIGNUM **)&q,
2366 	(const BIGNUM **)&g);
2367     retval = pkinit_encode_dh_params(p, g, q, dh_params, dh_params_len);
2368     if (retval)
2369 	goto cleanup;
2370 
2371     /* pack DH public key */
2372     /* Diffie-Hellman public key must be ASN1 encoded as an INTEGER; this
2373      * encoding shall be used as the contents (the value) of the
2374      * subjectPublicKey component (a BIT STRING) of the SubjectPublicKeyInfo
2375      * data element
2376      */
2377     if ((asn_pub_key = BN_to_ASN1_INTEGER(pub_key, NULL)) == NULL)
2378 	goto cleanup;
2379     *dh_pubkey_len = i2d_ASN1_INTEGER(asn_pub_key, NULL);
2380     if ((buf = *dh_pubkey = (unsigned char *)
2381         malloc((size_t) *dh_pubkey_len)) == NULL) {
2382 	    retval = ENOMEM;
2383 	    goto cleanup;
2384     }
2385     i2d_ASN1_INTEGER(asn_pub_key, &buf);
2386 
2387     if (asn_pub_key != NULL)
2388 	ASN1_INTEGER_free(asn_pub_key);
2389 
2390     retval = 0;
2391     return retval;
2392 
2393   cleanup:
2394     if (cryptoctx->dh != NULL)
2395 	DH_free(cryptoctx->dh);
2396     cryptoctx->dh = NULL;
2397     if (*dh_params != NULL)
2398 	free(*dh_params);
2399     *dh_params = NULL;
2400     if (*dh_pubkey != NULL)
2401 	free(*dh_pubkey);
2402     *dh_pubkey = NULL;
2403     if (asn_pub_key != NULL)
2404 	ASN1_INTEGER_free(asn_pub_key);
2405 
2406     return retval;
2407 }
2408 
2409 /* ARGSUSED */
2410 krb5_error_code
2411 client_process_dh(krb5_context context,
2412 		  pkinit_plg_crypto_context plg_cryptoctx,
2413 		  pkinit_req_crypto_context cryptoctx,
2414 		  pkinit_identity_crypto_context id_cryptoctx,
2415 		  unsigned char *subjectPublicKey_data,
2416 		  unsigned int subjectPublicKey_length,
2417 		  unsigned char **client_key,
2418 		  unsigned int *client_key_len)
2419 {
2420     /* Solaris Kerberos */
2421     krb5_error_code retval = KRB5_PREAUTH_FAILED;
2422     BIGNUM *server_pub_key = NULL;
2423     ASN1_INTEGER *pub_key = NULL;
2424     const unsigned char *p = NULL;
2425     unsigned char *data = NULL;
2426     long data_len;
2427 
2428     /* decode subjectPublicKey (retrieve INTEGER from OCTET_STRING) */
2429 
2430     if (der_decode_data(subjectPublicKey_data, (long)subjectPublicKey_length,
2431 			&data, &data_len) != 0) {
2432 	pkiDebug("failed to decode subjectPublicKey\n");
2433 	/* Solaris Kerberos */
2434 	retval = KRB5_PREAUTH_FAILED;
2435 	goto cleanup;
2436     }
2437 
2438     *client_key_len = DH_size(cryptoctx->dh);
2439     if ((*client_key = (unsigned char *)
2440 	    malloc((size_t) *client_key_len)) == NULL) {
2441 	retval = ENOMEM;
2442 	goto cleanup;
2443     }
2444     p = data;
2445     if ((pub_key = d2i_ASN1_INTEGER(NULL, &p, data_len)) == NULL)
2446 	goto cleanup;
2447     if ((server_pub_key = ASN1_INTEGER_to_BN(pub_key, NULL)) == NULL)
2448 	goto cleanup;
2449 
2450     DH_compute_key(*client_key, server_pub_key, cryptoctx->dh);
2451 #ifdef DEBUG_DH
2452     print_pubkey(server_pub_key, "server's pub_key=");
2453     pkiDebug("client secret key (%d)= ", *client_key_len);
2454     print_buffer(*client_key, *client_key_len);
2455 #endif
2456 
2457     retval = 0;
2458     if (server_pub_key != NULL)
2459 	BN_free(server_pub_key);
2460     if (pub_key != NULL)
2461 	ASN1_INTEGER_free(pub_key);
2462     if (data != NULL)
2463 	free (data);
2464 
2465     return retval;
2466 
2467   cleanup:
2468     if (*client_key != NULL)
2469 	free(*client_key);
2470     *client_key = NULL;
2471     if (pub_key != NULL)
2472 	ASN1_INTEGER_free(pub_key);
2473     if (data != NULL)
2474 	free (data);
2475 
2476     return retval;
2477 }
2478 
2479 /* ARGSUSED */
2480 krb5_error_code
2481 server_check_dh(krb5_context context,
2482 		pkinit_plg_crypto_context cryptoctx,
2483 		pkinit_req_crypto_context req_cryptoctx,
2484 		pkinit_identity_crypto_context id_cryptoctx,
2485 		krb5_octet_data *dh_params,
2486 		int minbits)
2487 {
2488     DH *dh = NULL;
2489     unsigned char *tmp = NULL;
2490     int dh_prime_bits;
2491     krb5_error_code retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
2492     const BIGNUM *p, *g, *q, *p2;
2493 
2494     tmp = dh_params->data;
2495     dh = DH_new();
2496     dh = pkinit_decode_dh_params(&dh, &tmp, dh_params->length);
2497     if (dh == NULL) {
2498 	pkiDebug("failed to decode dhparams\n");
2499 	goto cleanup;
2500     }
2501 
2502     DH_get0_pqg(dh, &p, &q, &g);
2503 
2504     /* KDC SHOULD check to see if the key parameters satisfy its policy */
2505     dh_prime_bits = BN_num_bits(p);
2506     if (minbits && dh_prime_bits < minbits) {
2507 	pkiDebug("client sent dh params with %d bits, we require %d\n",
2508 		 dh_prime_bits, minbits);
2509 	goto cleanup;
2510     }
2511 
2512     /* check dhparams is group 2 */
2513     DH_get0_pqg(cryptoctx->dh_1024, &p2, NULL, NULL);
2514     if (pkinit_check_dh_params(p2, p, g, q) == 0) {
2515 	retval = 0;
2516 	goto cleanup;
2517     }
2518 
2519     /* check dhparams is group 14 */
2520     DH_get0_pqg(cryptoctx->dh_2048, &p2, NULL, NULL);
2521     if (pkinit_check_dh_params(p2, p, g, q) == 0) {
2522 	retval = 0;
2523 	goto cleanup;
2524     }
2525 
2526     /* check dhparams is group 16 */
2527     DH_get0_pqg(cryptoctx->dh_4096, &p2, NULL, NULL);
2528     if (pkinit_check_dh_params(p2, p, g, q) == 0) {
2529 	retval = 0;
2530 	goto cleanup;
2531     }
2532 
2533   cleanup:
2534     if (retval == 0)
2535 	req_cryptoctx->dh = dh;
2536     else
2537 	DH_free(dh);
2538 
2539     return retval;
2540 }
2541 
2542 /* kdc's dh function */
2543 /* ARGSUSED */
2544 krb5_error_code
2545 server_process_dh(krb5_context context,
2546 		  pkinit_plg_crypto_context plg_cryptoctx,
2547 		  pkinit_req_crypto_context cryptoctx,
2548 		  pkinit_identity_crypto_context id_cryptoctx,
2549 		  unsigned char *data,
2550 		  unsigned int data_len,
2551 		  unsigned char **dh_pubkey,
2552 		  unsigned int *dh_pubkey_len,
2553 		  unsigned char **server_key,
2554 		  unsigned int *server_key_len)
2555 {
2556     /* Solaris Kerberos */
2557     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2558     DH *dh = NULL, *dh_server = NULL;
2559     const BIGNUM *p, *g, *q, *s_pub_key;
2560     BIGNUM *pub_key;
2561     unsigned char *s = NULL;
2562     ASN1_INTEGER *asn_pub_key = NULL;
2563 
2564     /* get client's received DH parameters that we saved in server_check_dh */
2565     dh = cryptoctx->dh;
2566 
2567     dh_server = DH_new();
2568     if (dh_server == NULL)
2569 	goto cleanup;
2570     DH_get0_pqg(dh, &p, &g, &q);
2571     DH_set0_pqg(dh_server, BN_dup(p), BN_dup(g), BN_dup(q));
2572 
2573     /* decode client's public key */
2574     s = data;
2575     asn_pub_key = d2i_ASN1_INTEGER(NULL,
2576 	(const unsigned char **)&s, (int)data_len);
2577     if (asn_pub_key == NULL)
2578 	goto cleanup;
2579     pub_key = ASN1_INTEGER_to_BN(asn_pub_key, NULL);
2580     if (pub_key == NULL)
2581 	goto cleanup;
2582     DH_set0_key(dh, pub_key, NULL);
2583     ASN1_INTEGER_free(asn_pub_key);
2584 
2585     if (!DH_generate_key(dh_server))
2586 	goto cleanup;
2587 
2588     /* generate DH session key */
2589     *server_key_len = DH_size(dh_server);
2590     if ((*server_key = (unsigned char *) malloc((size_t)*server_key_len))
2591 	== NULL)
2592 	    goto cleanup;
2593     DH_compute_key(*server_key, pub_key, dh_server);
2594     DH_get0_key(dh_server, &s_pub_key, NULL);
2595 
2596 #ifdef DEBUG_DH
2597     print_dh(dh_server, "client&server's DH params\n");
2598     print_pubkey(pub_key, "client's pub_key=");
2599     print_pubkey(s_pub_key, "server's pub_key=");
2600     pkiDebug("server secret key=");
2601     print_buffer(*server_key, *server_key_len);
2602 #endif
2603 
2604     /* KDC reply */
2605     /* pack DH public key */
2606     /* Diffie-Hellman public key must be ASN1 encoded as an INTEGER; this
2607      * encoding shall be used as the contents (the value) of the
2608      * subjectPublicKey component (a BIT STRING) of the SubjectPublicKeyInfo
2609      * data element
2610      */
2611     if ((asn_pub_key = BN_to_ASN1_INTEGER(s_pub_key, NULL)) == NULL)
2612 	goto cleanup;
2613     *dh_pubkey_len = i2d_ASN1_INTEGER(asn_pub_key, NULL);
2614     if ((s = *dh_pubkey = (unsigned char *) malloc((size_t)*dh_pubkey_len))
2615 	== NULL)
2616 	    goto cleanup;
2617     i2d_ASN1_INTEGER(asn_pub_key, &s);
2618     if (asn_pub_key != NULL)
2619 	ASN1_INTEGER_free(asn_pub_key);
2620 
2621     retval = 0;
2622 
2623     if (dh_server != NULL)
2624 	DH_free(dh_server);
2625     return retval;
2626 
2627   cleanup:
2628     if (dh_server != NULL)
2629 	DH_free(dh_server);
2630     if (*dh_pubkey != NULL)
2631 	free(*dh_pubkey);
2632     if (*server_key != NULL)
2633 	free(*server_key);
2634 
2635     return retval;
2636 }
2637 
2638 /*
2639  * Solaris Kerberos:
2640  * Add locking around did_init to make it MT-safe.
2641  */
2642 static krb5_error_code
2643 openssl_init()
2644 {
2645     krb5_error_code ret = 0;
2646     static int did_init = 0;
2647     static k5_mutex_t init_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
2648 
2649     ret = k5_mutex_lock(&init_mutex);
2650     if (ret == 0) {
2651 	if (!did_init) {
2652 	    /* initialize openssl routines */
2653 #if OPENSSL_VERSION_NUMBER < 0x10100000L
2654 	    /*
2655 	     * As of version 1.1.0, OpenSSL will automatically allocate
2656 	     * resources as-needed.
2657 	     */
2658 	    CRYPTO_malloc_init();
2659 	    ERR_load_crypto_strings();
2660 	    OpenSSL_add_all_algorithms();
2661 #endif
2662 	    did_init++;
2663 	}
2664 	k5_mutex_unlock(&init_mutex);
2665     }
2666     return (ret);
2667 }
2668 
2669 static krb5_error_code
2670 pkinit_encode_dh_params(const BIGNUM *p, const BIGNUM *g, const BIGNUM *q,
2671 			unsigned char **buf, unsigned int *buf_len)
2672 {
2673     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2674     int bufsize = 0, r = 0;
2675     unsigned char *tmp = NULL;
2676     ASN1_INTEGER *ap = NULL, *ag = NULL, *aq = NULL;
2677 
2678     if ((ap = BN_to_ASN1_INTEGER(p, NULL)) == NULL)
2679 	goto cleanup;
2680     if ((ag = BN_to_ASN1_INTEGER(g, NULL)) == NULL)
2681 	goto cleanup;
2682     if ((aq = BN_to_ASN1_INTEGER(q, NULL)) == NULL)
2683 	goto cleanup;
2684     bufsize = i2d_ASN1_INTEGER(ap, NULL);
2685     bufsize += i2d_ASN1_INTEGER(ag, NULL);
2686     bufsize += i2d_ASN1_INTEGER(aq, NULL);
2687 
2688     r = ASN1_object_size(1, bufsize, V_ASN1_SEQUENCE);
2689 
2690     tmp = *buf = (unsigned char *)malloc((size_t) r);
2691     if (tmp == NULL)
2692 	goto cleanup;
2693 
2694     ASN1_put_object(&tmp, 1, bufsize, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
2695 
2696     i2d_ASN1_INTEGER(ap, &tmp);
2697     i2d_ASN1_INTEGER(ag, &tmp);
2698     i2d_ASN1_INTEGER(aq, &tmp);
2699 
2700     *buf_len = r;
2701 
2702     retval = 0;
2703 
2704 cleanup:
2705     if (ap != NULL)
2706 	ASN1_INTEGER_free(ap);
2707     if (ag != NULL)
2708 	ASN1_INTEGER_free(ag);
2709     if (aq != NULL)
2710 	ASN1_INTEGER_free(aq);
2711 
2712     return retval;
2713 }
2714 
2715 #if OPENSSL_VERSION_NUMBER < 0x10100000L
2716 
2717 static DH *
2718 pkinit_decode_dh_params(DH ** a, unsigned char **pp, unsigned int len)
2719 {
2720     ASN1_INTEGER ai, *aip = NULL;
2721     long length = (long) len;
2722 
2723     M_ASN1_D2I_vars(a, DH *, DH_new);
2724 
2725     M_ASN1_D2I_Init();
2726     M_ASN1_D2I_start_sequence();
2727     aip = &ai;
2728     ai.data = NULL;
2729     ai.length = 0;
2730     M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER);
2731     if (aip == NULL)
2732 	return NULL;
2733     else {
2734 	(*a)->p = ASN1_INTEGER_to_BN(aip, NULL);
2735 	if ((*a)->p == NULL)
2736 	    return NULL;
2737 	if (ai.data != NULL) {
2738 	    OPENSSL_free(ai.data);
2739 	    ai.data = NULL;
2740 	    ai.length = 0;
2741 	}
2742     }
2743     M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER);
2744     if (aip == NULL)
2745 	return NULL;
2746     else {
2747 	(*a)->g = ASN1_INTEGER_to_BN(aip, NULL);
2748 	if ((*a)->g == NULL)
2749 	    return NULL;
2750 	if (ai.data != NULL) {
2751 	    OPENSSL_free(ai.data);
2752 	    ai.data = NULL;
2753 	    ai.length = 0;
2754 	}
2755 
2756     }
2757     M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER);
2758     if (aip == NULL)
2759 	return NULL;
2760     else {
2761 	(*a)->q = ASN1_INTEGER_to_BN(aip, NULL);
2762 	if ((*a)->q == NULL)
2763 	    return NULL;
2764 	if (ai.data != NULL) {
2765 	    OPENSSL_free(ai.data);
2766 	    ai.data = NULL;
2767 	    ai.length = 0;
2768 	}
2769 
2770     }
2771     M_ASN1_D2I_end_sequence();
2772     M_ASN1_D2I_Finish(a, DH_free, 0);
2773 
2774 }
2775 
2776 #else
2777 
2778 /*
2779  * This is taken from the internal dh_asn1.c file in OpenSSL 1.1, modified to
2780  * make q an optional field.
2781  */
2782 
2783 typedef struct {
2784     ASN1_BIT_STRING *seed;
2785     BIGNUM *counter;
2786 } int_dhvparams;
2787 
2788 typedef struct {
2789     BIGNUM *p;
2790     BIGNUM *q;
2791     BIGNUM *g;
2792     BIGNUM *j;
2793     int_dhvparams *vparams;
2794 } int_dhx942_dh;
2795 
2796 ASN1_SEQUENCE(DHvparams) = {
2797     ASN1_SIMPLE(int_dhvparams, seed, ASN1_BIT_STRING),
2798     ASN1_SIMPLE(int_dhvparams, counter, BIGNUM)
2799 } static_ASN1_SEQUENCE_END_name(int_dhvparams, DHvparams)
2800 
2801 ASN1_SEQUENCE(DHxparams) = {
2802     ASN1_SIMPLE(int_dhx942_dh, p, BIGNUM),
2803     ASN1_SIMPLE(int_dhx942_dh, g, BIGNUM),
2804     ASN1_OPT(int_dhx942_dh, q, BIGNUM),
2805     ASN1_OPT(int_dhx942_dh, j, BIGNUM),
2806     ASN1_OPT(int_dhx942_dh, vparams, DHvparams),
2807 } static_ASN1_SEQUENCE_END_name(int_dhx942_dh, DHxparams)
2808 
2809 static DH *
2810 pkinit_decode_dh_params(DH **a, unsigned char **pp, unsigned int len)
2811 {
2812 	int_dhx942_dh *params;
2813 	DH *dh = *a;
2814 
2815 	if (dh == NULL)
2816 		return NULL;
2817 
2818 	params = (int_dhx942_dh *)ASN1_item_d2i(NULL,
2819 	    (const unsigned char **)pp, len, ASN1_ITEM_rptr(DHxparams));
2820 	if (params == NULL) {
2821 		DH_free(dh);
2822 		return NULL;
2823 	}
2824 
2825 	DH_set0_pqg(dh, params->p, params->q, params->g);
2826 	params->p = params->q = params->g = NULL;
2827 	ASN1_item_free((ASN1_VALUE *)params, ASN1_ITEM_rptr(DHxparams));
2828 	return dh;
2829 }
2830 
2831 #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
2832 
2833 static krb5_error_code
2834 pkinit_create_sequence_of_principal_identifiers(
2835     krb5_context context,
2836     pkinit_plg_crypto_context plg_cryptoctx,
2837     pkinit_req_crypto_context req_cryptoctx,
2838     pkinit_identity_crypto_context id_cryptoctx,
2839     int type,
2840     krb5_data **out_data)
2841 {
2842     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2843     krb5_external_principal_identifier **krb5_trusted_certifiers = NULL;
2844     krb5_data *td_certifiers = NULL, *data = NULL;
2845     krb5_typed_data **typed_data = NULL;
2846 
2847     switch(type) {
2848 	case TD_TRUSTED_CERTIFIERS:
2849 	    retval = create_krb5_trustedCertifiers(context, plg_cryptoctx,
2850 		req_cryptoctx, id_cryptoctx, &krb5_trusted_certifiers);
2851 	    if (retval) {
2852 		pkiDebug("create_krb5_trustedCertifiers failed\n");
2853 		goto cleanup;
2854     	    }
2855 	    break;
2856 	case TD_INVALID_CERTIFICATES:
2857 	    retval = create_krb5_invalidCertificates(context, plg_cryptoctx,
2858 		req_cryptoctx, id_cryptoctx, &krb5_trusted_certifiers);
2859 	    if (retval) {
2860 		pkiDebug("create_krb5_invalidCertificates failed\n");
2861 		goto cleanup;
2862     	    }
2863 	    break;
2864 	default:
2865 	    retval = -1;
2866 	    goto cleanup;
2867     }
2868 
2869     retval = k5int_encode_krb5_td_trusted_certifiers((const krb5_external_principal_identifier **)krb5_trusted_certifiers, &td_certifiers);
2870     if (retval) {
2871 	pkiDebug("encode_krb5_td_trusted_certifiers failed\n");
2872 	goto cleanup;
2873     }
2874 #ifdef DEBUG_ASN1
2875     print_buffer_bin((unsigned char *)td_certifiers->data,
2876 		     td_certifiers->length, "/tmp/kdc_td_certifiers");
2877 #endif
2878     typed_data = malloc (2 * sizeof(krb5_typed_data *));
2879     if (typed_data == NULL) {
2880 	retval = ENOMEM;
2881 	goto cleanup;
2882     }
2883     typed_data[1] = NULL;
2884     init_krb5_typed_data(&typed_data[0]);
2885     if (typed_data[0] == NULL) {
2886 	retval = ENOMEM;
2887 	goto cleanup;
2888     }
2889     typed_data[0]->type = type;
2890     typed_data[0]->length = td_certifiers->length;
2891     typed_data[0]->data = (unsigned char *)td_certifiers->data;
2892     retval = k5int_encode_krb5_typed_data((const krb5_typed_data **)typed_data,
2893 					  &data);
2894     if (retval) {
2895 	pkiDebug("encode_krb5_typed_data failed\n");
2896 	goto cleanup;
2897     }
2898 #ifdef DEBUG_ASN1
2899     print_buffer_bin((unsigned char *)data->data, data->length,
2900 		     "/tmp/kdc_edata");
2901 #endif
2902     *out_data = (krb5_data *)malloc(sizeof(krb5_data));
2903     (*out_data)->length = data->length;
2904     (*out_data)->data = (char *)malloc(data->length);
2905     (void) memcpy((*out_data)->data, data->data, data->length);
2906 
2907     retval = 0;
2908 
2909 cleanup:
2910     if (krb5_trusted_certifiers != NULL)
2911 	free_krb5_external_principal_identifier(&krb5_trusted_certifiers);
2912 
2913     if (data != NULL) {
2914 	if (data->data != NULL)
2915 	    free(data->data);
2916 	free(data);
2917     }
2918 
2919     if (td_certifiers != NULL)
2920 	free(td_certifiers);
2921 
2922     if (typed_data != NULL)
2923 	free_krb5_typed_data(&typed_data);
2924 
2925     return retval;
2926 }
2927 
2928 krb5_error_code
2929 pkinit_create_td_trusted_certifiers(krb5_context context,
2930 				    pkinit_plg_crypto_context plg_cryptoctx,
2931 				    pkinit_req_crypto_context req_cryptoctx,
2932 				    pkinit_identity_crypto_context id_cryptoctx,
2933 				    krb5_data **out_data)
2934 {
2935     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2936 
2937     retval = pkinit_create_sequence_of_principal_identifiers(context,
2938 	plg_cryptoctx, req_cryptoctx, id_cryptoctx,
2939 	TD_TRUSTED_CERTIFIERS, out_data);
2940 
2941     return retval;
2942 }
2943 
2944 krb5_error_code
2945 pkinit_create_td_invalid_certificate(
2946 	krb5_context context,
2947 	pkinit_plg_crypto_context plg_cryptoctx,
2948 	pkinit_req_crypto_context req_cryptoctx,
2949 	pkinit_identity_crypto_context id_cryptoctx,
2950 	krb5_data **out_data)
2951 {
2952     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2953 
2954     retval = pkinit_create_sequence_of_principal_identifiers(context,
2955 	plg_cryptoctx, req_cryptoctx, id_cryptoctx,
2956 	TD_INVALID_CERTIFICATES, out_data);
2957 
2958     return retval;
2959 }
2960 
2961 /* ARGSUSED */
2962 krb5_error_code
2963 pkinit_create_td_dh_parameters(krb5_context context,
2964 			       pkinit_plg_crypto_context plg_cryptoctx,
2965 			       pkinit_req_crypto_context req_cryptoctx,
2966 			       pkinit_identity_crypto_context id_cryptoctx,
2967 			       pkinit_plg_opts *opts,
2968 			       krb5_data **out_data)
2969 {
2970     /* Solaris Kerberos */
2971     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2972     unsigned int buf1_len = 0, buf2_len = 0, buf3_len = 0, i = 0;
2973     unsigned char *buf1 = NULL, *buf2 = NULL, *buf3 = NULL;
2974     krb5_typed_data **typed_data = NULL;
2975     krb5_data *data = NULL, *encoded_algId = NULL;
2976     krb5_algorithm_identifier **algId = NULL;
2977     const BIGNUM *p, *q, *g;
2978 
2979     /* Solaris Kerberos */
2980     if (opts->dh_min_bits > 4096) {
2981 	retval = EINVAL;
2982 	goto cleanup;
2983     }
2984 
2985     if (opts->dh_min_bits <= 1024) {
2986 	DH_get0_pqg(plg_cryptoctx->dh_1024, &p, &q, &g);
2987 	retval = pkinit_encode_dh_params(p, g, q, &buf1, &buf1_len);
2988 	if (retval)
2989 	    goto cleanup;
2990     }
2991     if (opts->dh_min_bits <= 2048) {
2992 	DH_get0_pqg(plg_cryptoctx->dh_2048, &p, &q, &g);
2993 	retval = pkinit_encode_dh_params(p, g, q, &buf2, &buf2_len);
2994 	if (retval)
2995 	    goto cleanup;
2996     }
2997     DH_get0_pqg(plg_cryptoctx->dh_4096, &p, &q, &g);
2998     retval = pkinit_encode_dh_params(p, g, q, &buf3, &buf3_len);
2999     if (retval)
3000 	goto cleanup;
3001 
3002     if (opts->dh_min_bits <= 1024) {
3003 	algId = malloc(4 * sizeof(krb5_algorithm_identifier *));
3004 	if (algId == NULL)
3005 	    goto cleanup;
3006 	algId[3] = NULL;
3007 	algId[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
3008 	if (algId[0] == NULL)
3009 	    goto cleanup;
3010 	algId[0]->parameters.data = (unsigned char *)malloc(buf2_len);
3011 	if (algId[0]->parameters.data == NULL)
3012 	    goto cleanup;
3013 	(void) memcpy(algId[0]->parameters.data, buf2, buf2_len);
3014 	algId[0]->parameters.length = buf2_len;
3015 	algId[0]->algorithm = dh_oid;
3016 
3017 	algId[1] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
3018 	if (algId[1] == NULL)
3019 	    goto cleanup;
3020 	algId[1]->parameters.data = (unsigned char *)malloc(buf3_len);
3021 	if (algId[1]->parameters.data == NULL)
3022 	    goto cleanup;
3023 	(void) memcpy(algId[1]->parameters.data, buf3, buf3_len);
3024 	algId[1]->parameters.length = buf3_len;
3025 	algId[1]->algorithm = dh_oid;
3026 
3027 	algId[2] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
3028 	if (algId[2] == NULL)
3029 	    goto cleanup;
3030 	algId[2]->parameters.data = (unsigned char *)malloc(buf1_len);
3031 	if (algId[2]->parameters.data == NULL)
3032 	    goto cleanup;
3033 	(void) memcpy(algId[2]->parameters.data, buf1, buf1_len);
3034 	algId[2]->parameters.length = buf1_len;
3035 	algId[2]->algorithm = dh_oid;
3036 
3037     } else if (opts->dh_min_bits <= 2048) {
3038 	algId = malloc(3 * sizeof(krb5_algorithm_identifier *));
3039 	if (algId == NULL)
3040 	    goto cleanup;
3041 	algId[2] = NULL;
3042 	algId[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
3043 	if (algId[0] == NULL)
3044 	    goto cleanup;
3045 	algId[0]->parameters.data = (unsigned char *)malloc(buf2_len);
3046 	if (algId[0]->parameters.data == NULL)
3047 	    goto cleanup;
3048 	(void) memcpy(algId[0]->parameters.data, buf2, buf2_len);
3049 	algId[0]->parameters.length = buf2_len;
3050 	algId[0]->algorithm = dh_oid;
3051 
3052 	algId[1] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
3053 	if (algId[1] == NULL)
3054 	    goto cleanup;
3055 	algId[1]->parameters.data = (unsigned char *)malloc(buf3_len);
3056 	if (algId[1]->parameters.data == NULL)
3057 	    goto cleanup;
3058 	(void) memcpy(algId[1]->parameters.data, buf3, buf3_len);
3059 	algId[1]->parameters.length = buf3_len;
3060 	algId[1]->algorithm = dh_oid;
3061 
3062     } else if (opts->dh_min_bits <= 4096) {
3063 	algId = malloc(2 * sizeof(krb5_algorithm_identifier *));
3064 	if (algId == NULL)
3065 	    goto cleanup;
3066 	algId[1] = NULL;
3067 	algId[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
3068 	if (algId[0] == NULL)
3069 	    goto cleanup;
3070 	algId[0]->parameters.data = (unsigned char *)malloc(buf3_len);
3071 	if (algId[0]->parameters.data == NULL)
3072 	    goto cleanup;
3073 	(void) memcpy(algId[0]->parameters.data, buf3, buf3_len);
3074 	algId[0]->parameters.length = buf3_len;
3075 	algId[0]->algorithm = dh_oid;
3076 
3077     }
3078     retval = k5int_encode_krb5_td_dh_parameters((const krb5_algorithm_identifier **)algId, &encoded_algId);
3079     if (retval)
3080 	goto cleanup;
3081 #ifdef DEBUG_ASN1
3082     print_buffer_bin((unsigned char *)encoded_algId->data,
3083 		     encoded_algId->length, "/tmp/kdc_td_dh_params");
3084 #endif
3085     typed_data = malloc (2 * sizeof(krb5_typed_data *));
3086     if (typed_data == NULL) {
3087 	retval = ENOMEM;
3088 	goto cleanup;
3089     }
3090     typed_data[1] = NULL;
3091     init_krb5_typed_data(&typed_data[0]);
3092     if (typed_data == NULL) {
3093 	retval = ENOMEM;
3094 	goto cleanup;
3095     }
3096     typed_data[0]->type = TD_DH_PARAMETERS;
3097     typed_data[0]->length = encoded_algId->length;
3098     typed_data[0]->data = (unsigned char *)encoded_algId->data;
3099     retval = k5int_encode_krb5_typed_data((const krb5_typed_data**)typed_data,
3100 					  &data);
3101     if (retval) {
3102 	pkiDebug("encode_krb5_typed_data failed\n");
3103 	goto cleanup;
3104     }
3105 #ifdef DEBUG_ASN1
3106     print_buffer_bin((unsigned char *)data->data, data->length,
3107 		     "/tmp/kdc_edata");
3108 #endif
3109     *out_data = (krb5_data *)malloc(sizeof(krb5_data));
3110     if (*out_data == NULL)
3111 	goto cleanup;
3112     (*out_data)->length = data->length;
3113     (*out_data)->data = (char *)malloc(data->length);
3114     if ((*out_data)->data == NULL) {
3115 	free(*out_data);
3116 	*out_data = NULL;
3117 	goto cleanup;
3118     }
3119     (void) memcpy((*out_data)->data, data->data, data->length);
3120 
3121     retval = 0;
3122 cleanup:
3123 
3124     if (buf1 != NULL)
3125 	free(buf1);
3126     if (buf2 != NULL)
3127 	free(buf2);
3128     if (buf3 != NULL)
3129 	free(buf3);
3130     if (data != NULL) {
3131 	if (data->data != NULL)
3132 	    free(data->data);
3133 	free(data);
3134     }
3135     if (typed_data != NULL)
3136 	free_krb5_typed_data(&typed_data);
3137     if (encoded_algId != NULL)
3138 	free(encoded_algId);
3139 
3140     if (algId != NULL) {
3141 	while(algId[i] != NULL) {
3142 	    if (algId[i]->parameters.data != NULL)
3143 		free(algId[i]->parameters.data);
3144 	    free(algId[i]);
3145 	    i++;
3146 	}
3147 	free(algId);
3148     }
3149 
3150     return retval;
3151 }
3152 
3153 /* ARGSUSED */
3154 krb5_error_code
3155 pkinit_check_kdc_pkid(krb5_context context,
3156 		      pkinit_plg_crypto_context plg_cryptoctx,
3157 		      pkinit_req_crypto_context req_cryptoctx,
3158 		      pkinit_identity_crypto_context id_cryptoctx,
3159 		      unsigned char *pdid_buf,
3160 		      unsigned int pkid_len,
3161 		      int *valid_kdcPkId)
3162 {
3163     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
3164     PKCS7_ISSUER_AND_SERIAL *is = NULL;
3165     const unsigned char *p = pdid_buf;
3166     int status = 1;
3167     X509 *kdc_cert = sk_X509_value(id_cryptoctx->my_certs, id_cryptoctx->cert_index);
3168 
3169     *valid_kdcPkId = 0;
3170     pkiDebug("found kdcPkId in AS REQ\n");
3171     is = d2i_PKCS7_ISSUER_AND_SERIAL(NULL, &p, (int)pkid_len);
3172     if (is == NULL)
3173 	goto cleanup;
3174 
3175     status = X509_NAME_cmp(X509_get_issuer_name(kdc_cert), is->issuer);
3176     if (!status) {
3177 	status = ASN1_INTEGER_cmp(X509_get_serialNumber(kdc_cert), is->serial);
3178 	if (!status)
3179 	    *valid_kdcPkId = 1;
3180     }
3181 
3182     retval = 0;
3183 cleanup:
3184     X509_NAME_free(is->issuer);
3185     ASN1_INTEGER_free(is->serial);
3186     free(is);
3187 
3188     return retval;
3189 }
3190 
3191 static int
3192 pkinit_check_dh_params(const BIGNUM *p1, const BIGNUM *p2, const BIGNUM *g1,
3193     const BIGNUM *q1)
3194 {
3195     BIGNUM *g2 = NULL, *q2 = NULL;
3196     /* Solaris Kerberos */
3197     int retval = EINVAL;
3198 
3199     if (!BN_cmp(p1, p2)) {
3200 	g2 = BN_new();
3201 	BN_set_word(g2, DH_GENERATOR_2);
3202 	if (!BN_cmp(g1, g2)) {
3203 	    q2 = BN_new();
3204 	    BN_rshift1(q2, p1);
3205 	    if (!BN_cmp(q1, q2)) {
3206 		pkiDebug("good %d dhparams\n", BN_num_bits(p1));
3207 		retval = 0;
3208 	    } else
3209 		pkiDebug("bad group 2 q dhparameter\n");
3210 	    BN_free(q2);
3211 	} else
3212 	    pkiDebug("bad g dhparameter\n");
3213 	BN_free(g2);
3214     } else
3215 	pkiDebug("p is not well-known group 2 dhparameter\n");
3216 
3217     return retval;
3218 }
3219 
3220 /* ARGSUSED */
3221 krb5_error_code
3222 pkinit_process_td_dh_params(krb5_context context,
3223 			    pkinit_plg_crypto_context cryptoctx,
3224 			    pkinit_req_crypto_context req_cryptoctx,
3225 			    pkinit_identity_crypto_context id_cryptoctx,
3226 			    krb5_algorithm_identifier **algId,
3227 			    int *new_dh_size)
3228 {
3229     krb5_error_code retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
3230     int i = 0, use_sent_dh = 0, ok = 0;
3231 
3232     pkiDebug("dh parameters\n");
3233 
3234     while (algId[i] != NULL) {
3235 	DH *dh = NULL;
3236 	unsigned char *tmp = NULL;
3237 	const BIGNUM *p, *g, *q, *p2;
3238 	int dh_prime_bits = 0;
3239 
3240 	if (algId[i]->algorithm.length != dh_oid.length ||
3241 	    memcmp(algId[i]->algorithm.data, dh_oid.data, dh_oid.length))
3242 	    goto cleanup;
3243 
3244 	tmp = algId[i]->parameters.data;
3245 	dh = DH_new();
3246 	dh = pkinit_decode_dh_params(&dh, &tmp, algId[i]->parameters.length);
3247 	dh_prime_bits = DH_bits(dh);
3248 	pkiDebug("client sent %d DH bits server prefers %d DH bits\n",
3249 		 *new_dh_size, dh_prime_bits);
3250 	DH_get0_pqg(dh, &p, &q, &g);
3251 	switch(dh_prime_bits) {
3252 	    case 1024:
3253 		DH_get0_pqg(cryptoctx->dh_1024, &p2, NULL, NULL);
3254 		if (pkinit_check_dh_params(p2, p, g, q) == 0) {
3255 		    *new_dh_size = 1024;
3256 		    ok = 1;
3257 		}
3258 		break;
3259 	    case 2048:
3260 		DH_get0_pqg(cryptoctx->dh_2048, &p2, NULL, NULL);
3261 		if (pkinit_check_dh_params(p2, p, g, q) == 0) {
3262 		    *new_dh_size = 2048;
3263 		    ok = 1;
3264 		}
3265 		break;
3266 	    case 4096:
3267 		DH_get0_pqg(cryptoctx->dh_4096, &p2, NULL, NULL);
3268 		if (pkinit_check_dh_params(p2, p, g, q) == 0) {
3269 		    *new_dh_size = 4096;
3270 		    ok = 1;
3271 		}
3272 		break;
3273 	    default:
3274 		break;
3275 	}
3276 	if (!ok) {
3277 	    DH_check(dh, &retval);
3278 	    if (retval != 0) {
3279 		pkiDebug("DH parameters provided by server are unacceptable\n");
3280 		retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
3281 	    }
3282 	    else {
3283 		use_sent_dh = 1;
3284 		ok = 1;
3285 	    }
3286 	}
3287 	if (!use_sent_dh)
3288 	    DH_free(dh);
3289 	if (ok) {
3290 	    if (req_cryptoctx->dh != NULL) {
3291 		DH_free(req_cryptoctx->dh);
3292 		req_cryptoctx->dh = NULL;
3293 	    }
3294 	    if (use_sent_dh)
3295 		req_cryptoctx->dh = dh;
3296 	    break;
3297 	}
3298 	i++;
3299     }
3300 
3301     if (ok)
3302 	retval = 0;
3303 
3304 cleanup:
3305     return retval;
3306 }
3307 
3308 /* ARGSUSED */
3309 static int
3310 openssl_callback(int ok, X509_STORE_CTX * ctx)
3311 {
3312 #ifdef DEBUG
3313     if (!ok) {
3314 	char buf[DN_BUF_LEN];
3315 
3316 	X509_NAME_oneline(X509_get_subject_name(ctx->current_cert), buf, sizeof(buf));
3317 	pkiDebug("cert = %s\n", buf);
3318 	pkiDebug("callback function: %d (%s)\n", ctx->error,
3319 		X509_verify_cert_error_string(ctx->error));
3320     }
3321 #endif
3322     return ok;
3323 }
3324 
3325 static int
3326 openssl_callback_ignore_crls(int ok, X509_STORE_CTX * ctx)
3327 {
3328     if (!ok)
3329 	return (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_UNABLE_TO_GET_CRL);
3330     return ok;
3331 }
3332 
3333 static ASN1_OBJECT *
3334 pkinit_pkcs7type2oid(pkinit_plg_crypto_context cryptoctx, int pkcs7_type)
3335 {
3336     int nid;
3337 
3338     switch (pkcs7_type) {
3339 	case CMS_SIGN_CLIENT:
3340 	    return cryptoctx->id_pkinit_authData;
3341 	case CMS_SIGN_DRAFT9:
3342 	    /*
3343 	     * Delay creating this OID until we know we need it.
3344 	     * It shadows an existing OpenSSL oid.  If it
3345 	     * is created too early, it breaks things like
3346 	     * the use of pkcs12 (which uses pkcs7 structures).
3347 	     * We need this shadow version because our code
3348 	     * depends on the "other" type to be unknown to the
3349 	     * OpenSSL code.
3350 	     */
3351 	    if (cryptoctx->id_pkinit_authData9 == NULL) {
3352 		pkiDebug("%s: Creating shadow instance of pkcs7-data oid\n",
3353 			 __FUNCTION__);
3354 		nid = OBJ_create("1.2.840.113549.1.7.1", "id-pkcs7-data",
3355 				 "PKCS7 data");
3356 		if (nid == NID_undef)
3357 		    return NULL;
3358 		cryptoctx->id_pkinit_authData9 = OBJ_nid2obj(nid);
3359 	    }
3360 	    return cryptoctx->id_pkinit_authData9;
3361 	case CMS_SIGN_SERVER:
3362 	    return cryptoctx->id_pkinit_DHKeyData;
3363 	case CMS_ENVEL_SERVER:
3364 	    return cryptoctx->id_pkinit_rkeyData;
3365 	default:
3366 	    return NULL;
3367     }
3368 
3369 }
3370 
3371 #ifdef LONGHORN_BETA_COMPAT
3372 #if 0
3373 /*
3374  * This is a version that worked with Longhorn Beta 3.
3375  */
3376 static int
3377 wrap_signeddata(unsigned char *data, unsigned int data_len,
3378 		unsigned char **out, unsigned int *out_len,
3379 		int is_longhorn_server)
3380 {
3381 
3382     unsigned int orig_len = 0, oid_len = 0, tot_len = 0;
3383     ASN1_OBJECT *oid = NULL;
3384     unsigned char *p = NULL;
3385 
3386     pkiDebug("%s: This is the Longhorn version and is_longhorn_server = %d\n",
3387 	     __FUNCTION__, is_longhorn_server);
3388 
3389     /* Get length to wrap the original data with SEQUENCE tag */
3390     tot_len = orig_len = ASN1_object_size(1, (int)data_len, V_ASN1_SEQUENCE);
3391 
3392     if (is_longhorn_server == 0) {
3393 	/* Add the signedData OID and adjust lengths */
3394 	oid = OBJ_nid2obj(NID_pkcs7_signed);
3395 	oid_len = i2d_ASN1_OBJECT(oid, NULL);
3396 
3397 	tot_len = ASN1_object_size(1, (int)(orig_len+oid_len), V_ASN1_SEQUENCE);
3398     }
3399 
3400     p = *out = (unsigned char *)malloc(tot_len);
3401     if (p == NULL) return -1;
3402 
3403     if (is_longhorn_server == 0) {
3404 	ASN1_put_object(&p, 1, (int)(orig_len+oid_len),
3405 			V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3406 
3407 	i2d_ASN1_OBJECT(oid, &p);
3408 
3409 	ASN1_put_object(&p, 1, (int)data_len, 0, V_ASN1_CONTEXT_SPECIFIC);
3410     } else {
3411 	ASN1_put_object(&p, 1, (int)data_len, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3412     }
3413     memcpy(p, data, data_len);
3414 
3415     *out_len = tot_len;
3416 
3417     return 0;
3418 }
3419 #else
3420 /*
3421  * This is a version that works with a patched Longhorn KDC.
3422  * (Which should match SP1 ??).
3423  */
3424 static int
3425 wrap_signeddata(unsigned char *data, unsigned int data_len,
3426 	       unsigned char **out, unsigned int *out_len,
3427 	       int is_longhorn_server)
3428 {
3429 
3430     unsigned int oid_len = 0, tot_len = 0, wrap_len = 0, tag_len = 0;
3431     ASN1_OBJECT *oid = NULL;
3432     unsigned char *p = NULL;
3433 
3434     pkiDebug("%s: This is the Longhorn version and is_longhorn_server = %d\n",
3435 	     __FUNCTION__, is_longhorn_server);
3436 
3437     /* New longhorn is missing another sequence */
3438     if (is_longhorn_server == 1)
3439        wrap_len = ASN1_object_size(1, (int)(data_len), V_ASN1_SEQUENCE);
3440     else
3441        wrap_len = data_len;
3442 
3443     /* Get length to wrap the original data with SEQUENCE tag */
3444     tag_len = ASN1_object_size(1, (int)wrap_len, V_ASN1_SEQUENCE);
3445 
3446     /* Always add oid */
3447     oid = OBJ_nid2obj(NID_pkcs7_signed);
3448     oid_len = i2d_ASN1_OBJECT(oid, NULL);
3449     oid_len += tag_len;
3450 
3451     tot_len = ASN1_object_size(1, (int)(oid_len), V_ASN1_SEQUENCE);
3452 
3453     p = *out = (unsigned char *)malloc(tot_len);
3454     if (p == NULL)
3455        return -1;
3456 
3457     ASN1_put_object(&p, 1, (int)(oid_len),
3458 		    V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3459 
3460     i2d_ASN1_OBJECT(oid, &p);
3461 
3462     ASN1_put_object(&p, 1, (int)wrap_len, 0, V_ASN1_CONTEXT_SPECIFIC);
3463 
3464     /* Wrap in extra seq tag */
3465     if (is_longhorn_server == 1) {
3466        ASN1_put_object(&p, 1, (int)data_len, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3467     }
3468     (void) memcpy(p, data, data_len);
3469 
3470     *out_len = tot_len;
3471 
3472     return 0;
3473 }
3474 
3475 #endif
3476 #else
3477 static int
3478 wrap_signeddata(unsigned char *data, unsigned int data_len,
3479 		unsigned char **out, unsigned int *out_len)
3480 {
3481 
3482     unsigned int orig_len = 0, oid_len = 0, tot_len = 0;
3483     ASN1_OBJECT *oid = NULL;
3484     unsigned char *p = NULL;
3485 
3486     /* Get length to wrap the original data with SEQUENCE tag */
3487     tot_len = orig_len = ASN1_object_size(1, (int)data_len, V_ASN1_SEQUENCE);
3488 
3489     /* Add the signedData OID and adjust lengths */
3490     oid = OBJ_nid2obj(NID_pkcs7_signed);
3491     oid_len = i2d_ASN1_OBJECT(oid, NULL);
3492 
3493     tot_len = ASN1_object_size(1, (int)(orig_len+oid_len), V_ASN1_SEQUENCE);
3494 
3495     p = *out = (unsigned char *)malloc(tot_len);
3496     if (p == NULL) return -1;
3497 
3498     ASN1_put_object(&p, 1, (int)(orig_len+oid_len),
3499 		    V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3500 
3501     i2d_ASN1_OBJECT(oid, &p);
3502 
3503     ASN1_put_object(&p, 1, (int)data_len, 0, V_ASN1_CONTEXT_SPECIFIC);
3504     (void) memcpy(p, data, data_len);
3505 
3506     *out_len = tot_len;
3507 
3508     return 0;
3509 }
3510 #endif
3511 
3512 static int
3513 prepare_enc_data(unsigned char *indata,
3514 		 int indata_len,
3515 		 unsigned char **outdata,
3516 		 int *outdata_len)
3517 {
3518     int tag, class;
3519     long tlen, slen;
3520     const uint8_t *p = indata, *oldp;
3521 
3522     /* Top-bit set means that the conversion failed. */
3523     if (ASN1_get_object(&p, &slen, &tag, &class, indata_len) & 0x80)
3524         return EINVAL;
3525     if (tag != V_ASN1_SEQUENCE)
3526         return EINVAL;
3527 
3528     oldp = p;
3529     if (ASN1_get_object(&p, &tlen, &tag, &class, slen) & 0x80)
3530         return EINVAL;
3531     p += tlen;
3532     slen -= (p - oldp);
3533 
3534     if (ASN1_get_object(&p, &tlen, &tag, &class, slen) & 0x80)
3535         return EINVAL;
3536 
3537     *outdata = malloc(tlen);
3538     if (*outdata == NULL)
3539         return ENOMEM;
3540     memcpy(*outdata, p, tlen);
3541     *outdata_len = tlen;
3542 
3543     return 0;
3544 }
3545 
3546 #ifndef WITHOUT_PKCS11
3547 static void *
3548 pkinit_C_LoadModule(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p)
3549 {
3550     void *handle;
3551     CK_RV (*getflist)(CK_FUNCTION_LIST_PTR_PTR);
3552 
3553     pkiDebug("loading module \"%s\"... ", modname);
3554     /* Solaris Kerberos */
3555     handle = dlopen(modname, RTLD_NOW | RTLD_GROUP);
3556     if (handle == NULL) {
3557 	pkiDebug("not found\n");
3558 	return NULL;
3559     }
3560     getflist = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR)) dlsym(handle, "C_GetFunctionList");
3561     if (getflist == NULL || (*getflist)(p11p) != CKR_OK) {
3562 	(void) dlclose(handle);
3563 	pkiDebug("failed\n");
3564 	return NULL;
3565     }
3566     pkiDebug("ok\n");
3567     return handle;
3568 }
3569 
3570 static CK_RV
3571 pkinit_C_UnloadModule(void *handle)
3572 {
3573     /* Solaris Kerberos */
3574     if (dlclose(handle) != 0)
3575 	return CKR_GENERAL_ERROR;
3576 
3577     return CKR_OK;
3578 }
3579 
3580 /*
3581  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3582  * code.
3583  *
3584  * labelstr will be C string containing token label with trailing white space
3585  * removed.
3586  */
3587 static void
3588 trim_token_label(CK_TOKEN_INFO *tinfo, char *labelstr, unsigned int labelstr_len)
3589 {
3590     int i;
3591 
3592     assert(labelstr_len > sizeof (tinfo->label));
3593     /*
3594      * \0 terminate labelstr in case the last char in the token label is
3595      * non-whitespace
3596      */
3597     labelstr[sizeof (tinfo->label)] = '\0';
3598     (void) memcpy(labelstr, (char *) tinfo->label, sizeof (tinfo->label));
3599 
3600     /* init i so terminating \0 is skipped */
3601     for (i = sizeof (tinfo->label) - 1; i >= 0; i--) {
3602 	if (labelstr[i] == ' ')
3603 	    labelstr[i] = '\0';
3604 	else
3605 	    break;
3606     }
3607 }
3608 
3609 /*
3610  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3611  * code.
3612  */
3613 static krb5_error_code
3614 pkinit_prompt_user(krb5_context context,
3615 		   pkinit_identity_crypto_context cctx,
3616 		   krb5_data *reply,
3617 		   char *prompt,
3618 		   int hidden)
3619 {
3620     krb5_error_code r;
3621     krb5_prompt kprompt;
3622     krb5_prompt_type prompt_type;
3623 
3624     if (cctx->prompter == NULL)
3625 	return (EINVAL);
3626 
3627     kprompt.prompt = prompt;
3628     kprompt.hidden = hidden;
3629     kprompt.reply = reply;
3630     /*
3631      * Note, assuming this type for now, may need to be passed in in the future.
3632      */
3633     prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
3634 
3635     /* PROMPTER_INVOCATION */
3636     k5int_set_prompt_types(context, &prompt_type);
3637     r = (*cctx->prompter)(context, cctx->prompter_data,
3638 			  NULL, NULL, 1, &kprompt);
3639     k5int_set_prompt_types(context, NULL);
3640     return (r);
3641 }
3642 
3643 /*
3644  * Solaris Kerberos: this function was changed to support a PIN being passed
3645  * in.  If that is the case the user will not be prompted for their PIN.
3646  */
3647 static krb5_error_code
3648 pkinit_login(krb5_context context,
3649 	     pkinit_identity_crypto_context id_cryptoctx,
3650 	     CK_TOKEN_INFO *tip)
3651 {
3652     krb5_data rdat;
3653     char *prompt;
3654     int prompt_len;
3655     int r = 0;
3656 
3657     if (tip->flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
3658 	rdat.data = NULL;
3659 	rdat.length = 0;
3660     } else if (id_cryptoctx->PIN != NULL) {
3661 	if ((rdat.data = strdup(id_cryptoctx->PIN)) == NULL)
3662 	    return (ENOMEM);
3663 	/*
3664 	 * Don't include NULL string terminator in length calculation as this
3665 	 * PIN is passed to the C_Login function and only the text chars should
3666 	 * be considered to be the PIN.
3667 	 */
3668 	rdat.length = strlen(id_cryptoctx->PIN);
3669     } else {
3670         /* Solaris Kerberos - trim token label */
3671 	char tmplabel[sizeof (tip->label) + 1];
3672 
3673 	if (!id_cryptoctx->prompter) {
3674 	    pkiDebug("pkinit_login: id_cryptoctx->prompter is NULL\n");
3675 	    /* Solaris Kerberos: Improved error messages */
3676 	    krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
3677 		gettext("Failed to log into token: prompter function is NULL"));
3678 	    return (KRB5KDC_ERR_PREAUTH_FAILED);
3679 	}
3680 	/* Solaris Kerberos - Changes for gettext() */
3681         prompt_len = sizeof (tip->label) + 256;
3682 	if ((prompt = (char *) malloc(prompt_len)) == NULL)
3683 	    return ENOMEM;
3684 
3685 	/* Solaris Kerberos - trim token label which can be padded with space */
3686 	trim_token_label(tip, tmplabel, sizeof (tmplabel));
3687 	(void) snprintf(prompt, prompt_len, gettext("%s PIN"), tmplabel);
3688 
3689 	/* Solaris Kerberos */
3690 	if (tip->flags & CKF_USER_PIN_LOCKED)
3691 	    (void) strlcat(prompt, gettext(" (Warning: PIN locked)"), prompt_len);
3692 	else if (tip->flags & CKF_USER_PIN_FINAL_TRY)
3693 	    (void) strlcat(prompt, gettext(" (Warning: PIN final try)"), prompt_len);
3694 	else if (tip->flags & CKF_USER_PIN_COUNT_LOW)
3695 	    (void) strlcat(prompt, gettext(" (Warning: PIN count low)"), prompt_len);
3696 	rdat.data = malloc(tip->ulMaxPinLen + 2);
3697 	rdat.length = tip->ulMaxPinLen + 1;
3698 	/*
3699 	 * Note that the prompter function will set rdat.length such that the
3700 	 * NULL terminator is not included
3701 	 */
3702 	/* PROMPTER_INVOCATION */
3703 	r = pkinit_prompt_user(context, id_cryptoctx, &rdat, prompt, 1);
3704 	free(prompt);
3705     }
3706 
3707     if (r == 0) {
3708 	r = id_cryptoctx->p11->C_Login(id_cryptoctx->session, CKU_USER,
3709 		(u_char *) rdat.data, rdat.length);
3710 
3711 	if (r != CKR_OK) {
3712 	    pkiDebug("C_Login: %s\n", pkinit_pkcs11_code_to_text(r));
3713 	    /* Solaris Kerberos: Improved error messages */
3714 	    krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
3715 		gettext("Failed to log into token: %s"),
3716 		pkinit_pkcs11_code_to_text(r));
3717 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
3718 	} else {
3719 	    /* Solaris Kerberos: only need to login once */
3720             id_cryptoctx->p11flags |= C_LOGIN_DONE;
3721         }
3722     }
3723     if (rdat.data) {
3724 	(void) memset(rdat.data, 0, rdat.length);
3725 	free(rdat.data);
3726     }
3727 
3728     return (r);
3729 }
3730 
3731 /*
3732  * Solaris Kerberos: added these structs in support of prompting user for
3733  * missing token.
3734  */
3735 struct _token_entry {
3736     CK_SLOT_ID slotID;
3737     CK_SESSION_HANDLE session;
3738     CK_TOKEN_INFO token_info;
3739 };
3740 struct _token_choices {
3741     unsigned int numtokens;
3742     struct _token_entry *token_array;
3743 };
3744 
3745 
3746 /*
3747  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3748  * code.
3749  */
3750 static krb5_error_code
3751 pkinit_prompt_token(krb5_context context,
3752 		    pkinit_identity_crypto_context cctx)
3753 {
3754     char tmpbuf[4];
3755     krb5_data reply;
3756     char *token_prompt = gettext("If you have a smartcard insert it now. "
3757 				 "Press enter to continue");
3758 
3759     reply.data = tmpbuf;
3760     reply.length = sizeof(tmpbuf);
3761 
3762     /* note, don't care about the reply */
3763     return (pkinit_prompt_user(context, cctx, &reply, token_prompt, 0));
3764 }
3765 
3766 /*
3767  * Solaris Kerberos: new defines for prompting support.
3768  */
3769 #define CHOOSE_THIS_TOKEN 0
3770 #define CHOOSE_RESCAN 1
3771 #define CHOOSE_SKIP 2
3772 #define CHOOSE_SEE_NEXT 3
3773 
3774 #define RESCAN_TOKENS -1
3775 #define SKIP_TOKENS -2
3776 
3777 /*
3778  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3779  * code.
3780  *
3781  * This prompts to user for various choices regarding a token to use.  Note
3782  * that if there is no error, choice will be set to one of:
3783  * - the token_choices->token_array entry
3784  * - RESCAN_TOKENS
3785  * - SKIP_TOKENS
3786  */
3787 static int
3788 pkinit_choose_tokens(krb5_context context,
3789 		     pkinit_identity_crypto_context cctx,
3790 		     struct _token_choices *token_choices,
3791 		     int *choice)
3792 {
3793     krb5_error_code r;
3794     /*
3795      * Assuming that PAM_MAX_MSG_SIZE is a reasonable restriction. Note that -
3796      * 2 is to account for the fact that a krb prompter to PAM conv bridge will
3797      * add ": ".
3798      */
3799     char prompt[PAM_MAX_MSG_SIZE - 2];
3800     char tmpbuf[4];
3801     char tmplabel[sizeof (token_choices->token_array->token_info.label) + 1];
3802     krb5_data reply;
3803     int i, num_used, tmpchoice;
3804 
3805     assert(token_choices != NULL);
3806     assert(choice != NULL);
3807 
3808     /* Create the menu prompt */
3809 
3810     /* only need to do this once before the for loop */
3811     reply.data = tmpbuf;
3812 
3813     for (i = 0; i < token_choices->numtokens; i++) {
3814 
3815 	trim_token_label(&token_choices->token_array[i].token_info, tmplabel,
3816 			 sizeof (tmplabel));
3817 
3818 	if (i == (token_choices->numtokens - 1)) {
3819 	    /* no more smartcards/tokens */
3820 	    if ((num_used = snprintf(prompt, sizeof (prompt),
3821 				     "%s\n%d: %s \"%s\" %s %d\n%d: %s\n%d: %s\n",
3822 				     /*
3823 				      * TRANSLATION_NOTE: Translations of the
3824 				      * following 5 strings must not exceed 450
3825 				      * bytes total.
3826 				      */
3827 				     gettext("Select one of the following and press enter:"),
3828 				     CHOOSE_THIS_TOKEN, gettext("Use smartcard"), tmplabel,
3829                                      gettext("in slot"), token_choices->token_array[i].slotID,
3830 				     CHOOSE_RESCAN, gettext("Rescan for newly inserted smartcard"),
3831 				     CHOOSE_SKIP, gettext("Skip smartcard authentication")))
3832 		>= sizeof (prompt)) {
3833 		pkiDebug("pkinit_choose_tokens: buffer overflow num_used: %d,"
3834 			 " sizeof prompt: %d\n", num_used, sizeof (prompt));
3835 		krb5_set_error_message(context, EINVAL,
3836                                gettext("In pkinit_choose_tokens: prompt size"
3837 				      " %d exceeds prompt buffer size %d"),
3838 			       num_used, sizeof(prompt));
3839 		(void) snprintf(prompt, sizeof (prompt), "%s",
3840 			        gettext("Error: PKINIT prompt message is too large for buffer, "
3841 					"please alert the system administrator. Press enter to "
3842 					"continue"));
3843 		reply.length = sizeof(tmpbuf);
3844 		if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
3845 		    return (r);
3846 		return (EINVAL);
3847 	    }
3848 	} else {
3849 	    if ((num_used = snprintf(prompt, sizeof (prompt),
3850 				     "%s\n%d: %s \"%s\" %s %d\n%d: %s\n%d: %s\n%d: %s\n",
3851 				     /*
3852 				      * TRANSLATION_NOTE: Translations of the
3853 				      * following 6 strings must not exceed 445
3854 				      * bytes total.
3855 				      */
3856 				     gettext("Select one of the following and press enter:"),
3857 				     CHOOSE_THIS_TOKEN, gettext("Use smartcard"), tmplabel,
3858                                      gettext("in slot"), token_choices->token_array[i].slotID,
3859 				     CHOOSE_RESCAN, gettext("Rescan for newly inserted smartcard"),
3860 				     CHOOSE_SKIP, gettext("Skip smartcard authentication"),
3861 				     CHOOSE_SEE_NEXT, gettext("See next smartcard")))
3862 		>= sizeof (prompt)) {
3863 
3864 		pkiDebug("pkinit_choose_tokens: buffer overflow num_used: %d,"
3865 			 " sizeof prompt: %d\n", num_used, sizeof (prompt));
3866 		krb5_set_error_message(context, EINVAL,
3867 				       gettext("In pkinit_choose_tokens: prompt size"
3868 					       " %d exceeds prompt buffer size %d"),
3869 				       num_used, sizeof(prompt));
3870 		(void) snprintf(prompt, sizeof (prompt), "%s",
3871 				gettext("Error: PKINIT prompt message is too large for buffer, "
3872 					"please alert the system administrator. Press enter to "
3873 					"continue"));
3874 		reply.length = sizeof(tmpbuf);
3875 		if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
3876 		    return (r);
3877 		return (EINVAL);
3878 	    }
3879 	}
3880 
3881         /*
3882 	 * reply.length needs to be reset to length of tmpbuf before calling
3883 	 * prompter
3884          */
3885         reply.length = sizeof(tmpbuf);
3886 	if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
3887 	    return (r);
3888 
3889 	if (reply.length == 0) {
3890 	    return (EINVAL);
3891 	} else {
3892             char *cp = reply.data;
3893             /* reply better be digits */
3894             while (*cp != NULL) {
3895                 if (!isdigit(*cp++))
3896                     return (EINVAL);
3897             }
3898 	    errno = 0;
3899 	    tmpchoice = (int) strtol(reply.data, (char **)NULL, 10);
3900 	    if (errno != 0)
3901 		return (errno);
3902 	}
3903 
3904 	switch (tmpchoice) {
3905 	case CHOOSE_THIS_TOKEN:
3906 	    *choice = i; /* chosen entry of token_choices->token_array */
3907 	    return (0);
3908 	case CHOOSE_RESCAN:
3909 	    *choice = RESCAN_TOKENS; /* rescan for new smartcard */
3910 	    return (0);
3911 	case CHOOSE_SKIP:
3912 	    *choice = SKIP_TOKENS; /* skip smartcard auth */
3913 	    return (0);
3914 	case CHOOSE_SEE_NEXT: /* see next smartcard */
3915 	    continue;
3916 	default:
3917 	    return (EINVAL);
3918 	}
3919     }
3920 
3921     return (0);
3922 }
3923 
3924 /*
3925  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3926  * code.
3927  *
3928  * Note, this isn't the best solution to providing a function to check the
3929  * certs in a token however I wanted to avoid rewriting a bunch of code so I
3930  * settled for some duplication of processing.
3931  */
3932 static krb5_error_code
3933 check_load_certs(krb5_context context,
3934             CK_SESSION_HANDLE session,
3935 	    pkinit_plg_crypto_context plg_cryptoctx,
3936 	    pkinit_req_crypto_context req_cryptoctx,
3937             pkinit_identity_crypto_context id_cryptoctx,
3938             krb5_principal princ,
3939             int do_matching,
3940             int load_cert)
3941 {
3942     CK_OBJECT_CLASS cls;
3943     CK_OBJECT_HANDLE obj;
3944     CK_ATTRIBUTE attrs[4];
3945     CK_ULONG count;
3946     CK_CERTIFICATE_TYPE certtype;
3947     CK_BYTE_PTR cert = NULL, cert_id = NULL;
3948     const unsigned char *cp;
3949     int i, r;
3950     unsigned int nattrs;
3951     X509 *x = NULL;
3952 
3953     cls = CKO_CERTIFICATE;
3954     attrs[0].type = CKA_CLASS;
3955     attrs[0].pValue = &cls;
3956     attrs[0].ulValueLen = sizeof cls;
3957 
3958     certtype = CKC_X_509;
3959     attrs[1].type = CKA_CERTIFICATE_TYPE;
3960     attrs[1].pValue = &certtype;
3961     attrs[1].ulValueLen = sizeof certtype;
3962 
3963     nattrs = 2;
3964 
3965     /* If a cert id and/or label were given, use them too */
3966     if (id_cryptoctx->cert_id_len > 0) {
3967 	attrs[nattrs].type = CKA_ID;
3968 	attrs[nattrs].pValue = id_cryptoctx->cert_id;
3969 	attrs[nattrs].ulValueLen = id_cryptoctx->cert_id_len;
3970 	nattrs++;
3971     }
3972     if (id_cryptoctx->cert_label != NULL) {
3973 	attrs[nattrs].type = CKA_LABEL;
3974 	attrs[nattrs].pValue = id_cryptoctx->cert_label;
3975 	attrs[nattrs].ulValueLen = strlen(id_cryptoctx->cert_label);
3976 	nattrs++;
3977     }
3978 
3979     r = id_cryptoctx->p11->C_FindObjectsInit(session, attrs, nattrs);
3980     if (r != CKR_OK) {
3981         pkiDebug("C_FindObjectsInit: %s\n", pkinit_pkcs11_code_to_text(r));
3982         krb5_set_error_message(context, EINVAL,
3983                                gettext("PKCS11 error from C_FindObjectsInit: %s"),
3984                                pkinit_pkcs11_code_to_text(r));
3985         r = EINVAL;
3986         goto out;
3987     }
3988 
3989     for (i = 0; ; i++) {
3990 	if (i >= MAX_CREDS_ALLOWED) {
3991             r = EINVAL;
3992             goto out;
3993         }
3994 
3995 	/* Look for x.509 cert */
3996 	/* Solaris Kerberos */
3997 	if ((r = id_cryptoctx->p11->C_FindObjects(session, &obj, 1, &count))
3998             != CKR_OK || count == 0) {
3999 	    id_cryptoctx->creds[i] = NULL;
4000 	    break;
4001 	}
4002 
4003 	/* Get cert and id len */
4004 	attrs[0].type = CKA_VALUE;
4005 	attrs[0].pValue = NULL;
4006 	attrs[0].ulValueLen = 0;
4007 
4008 	attrs[1].type = CKA_ID;
4009 	attrs[1].pValue = NULL;
4010 	attrs[1].ulValueLen = 0;
4011 
4012 	if ((r = id_cryptoctx->p11->C_GetAttributeValue(session,
4013                                                         obj,
4014                                                         attrs,
4015                                                         2)) != CKR_OK &&
4016             r != CKR_BUFFER_TOO_SMALL) {
4017             pkiDebug("C_GetAttributeValue: %s\n", pkinit_pkcs11_code_to_text(r));
4018 	    krb5_set_error_message(context, EINVAL,
4019 				   gettext("Error from PKCS11 C_GetAttributeValue: %s"),
4020 				   pkinit_pkcs11_code_to_text(r));
4021             r = EINVAL;
4022             goto out;
4023         }
4024 	cert = malloc((size_t) attrs[0].ulValueLen + 1);
4025 	if (cert == NULL) {
4026 	    r = ENOMEM;
4027             goto out;
4028         }
4029 	cert_id = malloc((size_t) attrs[1].ulValueLen + 1);
4030 	if (cert_id == NULL) {
4031 	    r = ENOMEM;
4032             goto out;
4033         }
4034 
4035 	/* Read the cert and id off the card */
4036 
4037 	attrs[0].type = CKA_VALUE;
4038 	attrs[0].pValue = cert;
4039 
4040 	attrs[1].type = CKA_ID;
4041 	attrs[1].pValue = cert_id;
4042 
4043 	if ((r = id_cryptoctx->p11->C_GetAttributeValue(session,
4044 		obj, attrs, 2)) != CKR_OK) {
4045 	    pkiDebug("C_GetAttributeValue: %s\n", pkinit_pkcs11_code_to_text(r));
4046 	    krb5_set_error_message(context, EINVAL,
4047 				   gettext("Error from PKCS11 C_GetAttributeValue: %s"),
4048 				   pkinit_pkcs11_code_to_text(r));
4049 	    r = EINVAL;
4050             goto out;
4051 	}
4052 
4053 	pkiDebug("cert %d size %d id %d idlen %d\n", i,
4054 	    (int) attrs[0].ulValueLen, (int) cert_id[0],
4055 	    (int) attrs[1].ulValueLen);
4056 
4057 	cp = (unsigned char *) cert;
4058 	x = d2i_X509(NULL, &cp, (int) attrs[0].ulValueLen);
4059 	if (x == NULL) {
4060 	    r = EINVAL;
4061             goto out;
4062         }
4063 
4064 	id_cryptoctx->creds[i] = malloc(sizeof(struct _pkinit_cred_info));
4065 	if (id_cryptoctx->creds[i] == NULL) {
4066 	    r = ENOMEM;
4067             goto out;
4068         }
4069 	id_cryptoctx->creds[i]->cert = x;
4070 	id_cryptoctx->creds[i]->key = NULL;
4071 	id_cryptoctx->creds[i]->cert_id = cert_id;
4072         cert_id = NULL;
4073 	id_cryptoctx->creds[i]->cert_id_len = attrs[1].ulValueLen;
4074 	free(cert);
4075         cert = NULL;
4076     }
4077     id_cryptoctx->p11->C_FindObjectsFinal(session);
4078 
4079     if (id_cryptoctx->creds[0] == NULL || id_cryptoctx->creds[0]->cert == NULL) {
4080 	r = ENOENT;
4081     } else if (do_matching){
4082         /*
4083          * Do not let pkinit_cert_matching set the primary cert in id_cryptoctx
4084          * as this will be done later.
4085          */
4086         r = pkinit_cert_matching(context, plg_cryptoctx, req_cryptoctx,
4087                                  id_cryptoctx, princ, FALSE);
4088     }
4089 
4090 out:
4091     if ((r != 0 || !load_cert) &&
4092         id_cryptoctx->creds[0] != NULL &&
4093         id_cryptoctx->creds[0]->cert != NULL) {
4094         /*
4095          * If there's an error or load_cert isn't 1 free all the certs loaded
4096          * onto id_cryptoctx.
4097          */
4098         (void) crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
4099                                      id_cryptoctx);
4100     }
4101 
4102     if (cert)
4103         free(cert);
4104 
4105     if (cert_id)
4106         free(cert_id);
4107 
4108     return (r);
4109 }
4110 
4111 /*
4112  * Solaris Kerberos: this function has been significantly modified to prompt
4113  * the user in certain cases so defer to this version when resyncing MIT code.
4114  *
4115  * pkinit_open_session now does several things including prompting the user if
4116  * do_matching is set which indicates the code is executing in a client
4117  * context.  This function fills out a pkinit_identity_crypto_context with a
4118  * set of certs and a open session if a token can be found that matches all
4119  * supplied criteria.  If no token is found then the user is prompted one time
4120  * to insert their token.  If there is more than one token that matches all
4121  * client criteria the user is prompted to make a choice if in client context.
4122  * If do_matching is false (KDC context) then the first token matching all
4123  * server criteria is chosen.
4124  */
4125 static krb5_error_code
4126 pkinit_open_session(krb5_context context,
4127                     pkinit_plg_crypto_context plg_cryptoctx,
4128                     pkinit_req_crypto_context req_cryptoctx,
4129                     pkinit_identity_crypto_context cctx,
4130                     krb5_principal princ,
4131                     int do_matching)
4132 {
4133     int i, r;
4134     CK_ULONG count = 0;
4135     CK_SLOT_ID_PTR slotlist = NULL, tmpslotlist = NULL;
4136     CK_TOKEN_INFO tinfo;
4137     krb5_boolean tokenmatch = FALSE;
4138     CK_SESSION_HANDLE tmpsession = NULL;
4139     struct _token_choices token_choices;
4140     int choice = 0;
4141 
4142     if (cctx->session != CK_INVALID_HANDLE)
4143 	return 0; /* session already open */
4144 
4145     /* Load module */
4146     if (cctx->p11_module == NULL) {
4147         cctx->p11_module =
4148             pkinit_C_LoadModule(cctx->p11_module_name, &cctx->p11);
4149         if (cctx->p11_module == NULL)
4150             return KRB5KDC_ERR_PREAUTH_FAILED;
4151     }
4152 
4153     /* Init */
4154     /* Solaris Kerberos: Don't fail if cryptoki is already initialized */
4155     r = cctx->p11->C_Initialize(NULL);
4156     if (r != CKR_OK && r != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
4157 	pkiDebug("C_Initialize: %s\n", pkinit_pkcs11_code_to_text(r));
4158 	krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4159 			       gettext("Error from PKCS11 C_Initialize: %s"),
4160 			       pkinit_pkcs11_code_to_text(r));
4161 	return KRB5KDC_ERR_PREAUTH_FAILED;
4162     }
4163 
4164     (void) memset(&token_choices, 0, sizeof(token_choices));
4165 
4166     /*
4167      * Solaris Kerberos:
4168      * If C_Initialize was already called by the process before the pkinit
4169      * module was loaded then record that fact.
4170      * "finalize_pkcs11" is used by pkinit_fini_pkcs11 to determine whether
4171      * or not C_Finalize() should be called.
4172      */
4173      cctx->finalize_pkcs11 =
4174 	(r == CKR_CRYPTOKI_ALREADY_INITIALIZED ? FALSE : TRUE);
4175     /*
4176      * First make sure that is an applicable slot otherwise fail.
4177      *
4178      * Start by getting a count of all slots with or without tokens.
4179      */
4180 
4181     if ((r = cctx->p11->C_GetSlotList(FALSE, NULL, &count)) != CKR_OK) {
4182 	pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
4183 	krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4184 	    gettext("Error trying to get PKCS11 slot list: %s"),
4185 	    pkinit_pkcs11_code_to_text(r));
4186 	r = KRB5KDC_ERR_PREAUTH_FAILED;
4187 	goto out;
4188     }
4189 
4190     if (count == 0) {
4191 	/* There are no slots so bail */
4192 	r = KRB5KDC_ERR_PREAUTH_FAILED;
4193 	krb5_set_error_message(context, r,
4194 			       gettext("No PKCS11 slots found"));
4195 	pkiDebug("pkinit_open_session: no slots, count: %d\n", count);
4196 	goto out;
4197     } else if (cctx->slotid != PK_NOSLOT) {
4198 	/* See if any of the slots match the specified slotID */
4199 	tmpslotlist = malloc(count * sizeof (CK_SLOT_ID));
4200 	if (tmpslotlist == NULL) {
4201 	    krb5_set_error_message(context, ENOMEM,
4202 				   gettext("Memory allocation error:"));
4203 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
4204 	    goto out;
4205 	}
4206 	if ((r = cctx->p11->C_GetSlotList(FALSE, tmpslotlist, &count)) != CKR_OK) {
4207 	    krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4208 				   gettext("Error trying to get PKCS11 slot list: %s"),
4209 				   pkinit_pkcs11_code_to_text(r));
4210 	    pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
4211 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
4212 	    goto out;
4213 	}
4214 
4215 	for (i = 0; i < count && cctx->slotid != tmpslotlist[i]; i++)
4216 	    continue;
4217 
4218 	if (i >= count) {
4219 	    /* no slots match */
4220 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
4221 	    krb5_set_error_message(context, r,
4222 				   gettext("Requested PKCS11 slot ID %d not found"),
4223 				   cctx->slotid);
4224 	    pkiDebug("open_session: no matching slot found for slotID %d\n",
4225 		     cctx->slotid);
4226 	    goto out;
4227 	}
4228     }
4229 
4230 tryagain:
4231     /* get count of slots that have tokens */
4232     if ((r = cctx->p11->C_GetSlotList(TRUE, NULL, &count)) != CKR_OK) {
4233 	pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
4234 	krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4235 			       gettext("Error trying to get PKCS11 slot list: %s"),
4236 			       pkinit_pkcs11_code_to_text(r));
4237 	r = KRB5KDC_ERR_PREAUTH_FAILED;
4238 	goto out;
4239     }
4240 
4241     if (count == 0) {
4242 	/*
4243 	 * Note, never prompt if !do_matching as this implies KDC side
4244 	 * processing
4245 	 */
4246 	if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
4247 	    /* found slot(s) but no token so prompt and try again */
4248 	    if ((r = pkinit_prompt_token(context, cctx)) == 0) {
4249 		cctx->p11flags |= C_PROMPTED_USER;
4250 		goto tryagain;
4251 	    } else {
4252 		pkiDebug("open_session: prompt for token/smart card failed\n");
4253 		krb5_set_error_message(context, r,
4254 				       gettext("Prompt for token/smart card failed"));
4255 		r = KRB5KDC_ERR_PREAUTH_FAILED;
4256 		goto out;
4257 	    }
4258 
4259 	} else {
4260 	    /* already prompted once so bailing */
4261 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
4262 	    krb5_set_error_message(context, r,
4263 				   gettext("No smart card tokens found"));
4264 	    pkiDebug("pkinit_open_session: no token, already prompted\n");
4265 	    goto out;
4266 	}
4267     }
4268 
4269     if (slotlist != NULL)
4270 	free(slotlist);
4271 
4272     slotlist = malloc(count * sizeof (CK_SLOT_ID));
4273     if (slotlist == NULL) {
4274 	krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4275 			       gettext("Memory allocation error"));
4276 	r = KRB5KDC_ERR_PREAUTH_FAILED;
4277 	goto out;
4278     }
4279     /*
4280      * Solaris Kerberos: get list of PKCS11 slotid's that have tokens.
4281      */
4282     if (cctx->p11->C_GetSlotList(TRUE, slotlist, &count) != CKR_OK) {
4283 	krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4284 			       gettext("Error trying to get PKCS11 slot list: %s"),
4285 			       pkinit_pkcs11_code_to_text(r));
4286 	pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
4287 	r = KRB5KDC_ERR_PREAUTH_FAILED;
4288 	goto out;
4289     }
4290 
4291     token_choices.numtokens = 0;
4292     token_choices.token_array = malloc(count * sizeof (*token_choices.token_array));
4293     if (token_choices.token_array == NULL) {
4294 	r = KRB5KDC_ERR_PREAUTH_FAILED;
4295 	krb5_set_error_message(context, r,
4296 			       gettext("Memory allocation error"));
4297 	goto out;
4298     }
4299 
4300     /* examine all the tokens */
4301     for (i = 0; i < count; i++) {
4302 	/*
4303 	 * Solaris Kerberos: if a slotid was specified skip slots that don't
4304 	 * match.
4305 	 */
4306 	if (cctx->slotid != PK_NOSLOT && cctx->slotid != slotlist[i])
4307 	    continue;
4308 
4309 	/* Open session */
4310 	if ((r = cctx->p11->C_OpenSession(slotlist[i], CKF_SERIAL_SESSION,
4311 					  NULL, NULL, &tmpsession)) != CKR_OK) {
4312 	    pkiDebug("C_OpenSession: %s\n", pkinit_pkcs11_code_to_text(r));
4313 	    krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4314 				   gettext("Error trying to open PKCS11 session: %s"),
4315 				   pkinit_pkcs11_code_to_text(r));
4316 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
4317 	    goto out;
4318 	}
4319 
4320 	/* Get token info */
4321 	if ((r = cctx->p11->C_GetTokenInfo(slotlist[i], &tinfo)) != CKR_OK) {
4322 	    pkiDebug("C_GetTokenInfo: %s\n", pkinit_pkcs11_code_to_text(r));
4323 	    krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4324 				   gettext("Error trying to read PKCS11 token: %s"),
4325 				   pkinit_pkcs11_code_to_text(r));
4326 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
4327 	    cctx->p11->C_CloseSession(tmpsession);
4328 	    goto out;
4329 	}
4330 
4331 	if (cctx->token_label == NULL) {
4332 	    /*
4333              * If the token doesn't require login to examine the certs then
4334              * let's check the certs out to see if any match the criteria if
4335              * any.
4336              */
4337 	    if (!(tinfo.flags & CKF_LOGIN_REQUIRED)) {
4338 		/*
4339 		 * It's okay to check the certs if we don't have to login but
4340 		 * don't load the certs onto cctx at this point, this will be
4341 		 * done later in this function for the chosen token.
4342 		 */
4343 		if ((r = check_load_certs(context, tmpsession, plg_cryptoctx,
4344 					  req_cryptoctx, cctx, princ,
4345 					  do_matching, 0)) == 0) {
4346 		    tokenmatch = TRUE;
4347 		} else if (r != ENOENT){
4348 		    r = KRB5KDC_ERR_PREAUTH_FAILED;
4349 		    cctx->p11->C_CloseSession(tmpsession);
4350 		    goto out;
4351 		} else {
4352 		    /* ignore ENOENT here */
4353 		    r = 0;
4354 		}
4355 	    } else {
4356                 tokenmatch = TRUE;
4357             }
4358 	} else {
4359 	    /* + 1 so tokenlabelstr can be \0 terminated */
4360 	    char tokenlabelstr[sizeof (tinfo.label) + 1];
4361 
4362 	    /*
4363 	     * Convert token label into C string with trailing white space
4364 	     * trimmed.
4365 	     */
4366 	    trim_token_label(&tinfo, tokenlabelstr, sizeof (tokenlabelstr));
4367 
4368 	    pkiDebug("open_session: slotid %d token found: \"%s\", "
4369 		     "cctx->token_label: \"%s\"\n",
4370 		     slotlist[i], tokenlabelstr, (char *) cctx->token_label);
4371 
4372 	    if (!strcmp(cctx->token_label, tokenlabelstr)) {
4373 		if (!(tinfo.flags & CKF_LOGIN_REQUIRED)) {
4374 		    /*
4375 		     * It's okay to check the certs if we don't have to login but
4376 		     * don't load the certs onto cctx at this point, this will be
4377 		     * done later in this function for the chosen token.
4378 		     */
4379 		    if ((r = check_load_certs(context, tmpsession, plg_cryptoctx,
4380 					      req_cryptoctx, cctx, princ,
4381 					      do_matching, 0)) == 0) {
4382 			tokenmatch = TRUE;
4383 		    } else if (r != ENOENT){
4384 			r = KRB5KDC_ERR_PREAUTH_FAILED;
4385 			cctx->p11->C_CloseSession(tmpsession);
4386 			goto out;
4387 		    } else {
4388 			/* ignore ENOENT here */
4389 			r = 0;
4390 		    }
4391 		} else {
4392 		    tokenmatch = TRUE;
4393 		}
4394 	    }
4395 	}
4396 
4397 	if (tokenmatch == TRUE) {
4398 	    /* add the token to token_choices.token_array */
4399 	    token_choices.token_array[token_choices.numtokens].slotID = slotlist[i];
4400 	    token_choices.token_array[token_choices.numtokens].session = tmpsession;
4401 	    token_choices.token_array[token_choices.numtokens].token_info = tinfo;
4402 	    token_choices.numtokens++;
4403             /* !do_matching implies we take the first matching token */
4404             if (!do_matching)
4405                 break;
4406             else
4407                 tokenmatch = FALSE;
4408 	} else {
4409 	    cctx->p11->C_CloseSession(tmpsession);
4410 	}
4411     }
4412 
4413     if (token_choices.numtokens == 0) {
4414 	/*
4415 	 * Solaris Kerberos: prompt for token one time if there was no token
4416          * and do_matching is 1 (see earlier comment about do_matching).
4417 	 */
4418 	if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
4419 	    if ((r = pkinit_prompt_token(context, cctx)) == 0) {
4420                 cctx->p11flags |= C_PROMPTED_USER;
4421 		goto tryagain;
4422 	    } else {
4423 		pkiDebug("open_session: prompt for token/smart card failed\n");
4424 		krb5_set_error_message(context, r,
4425 				       gettext("Prompt for token/smart card failed"));
4426 		r = KRB5KDC_ERR_PREAUTH_FAILED;
4427 		goto out;
4428 	    }
4429 	} else {
4430 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
4431 	    krb5_set_error_message(context, r,
4432 				   gettext("No smart card tokens found"));
4433 	    pkiDebug("open_session: no matching token found\n");
4434 	    goto out;
4435 	}
4436     } else if (token_choices.numtokens == 1) {
4437         if ((token_choices.token_array[0].token_info.flags & CKF_LOGIN_REQUIRED) &&
4438             !(cctx->p11flags & C_PROMPTED_USER) &&
4439             do_matching) {
4440             if ((r = pkinit_choose_tokens(context, cctx, &token_choices, &choice)) != 0) {
4441                 pkiDebug("pkinit_open_session: pkinit_choose_tokens failed: %d\n", r);
4442                 r = KRB5KDC_ERR_PREAUTH_FAILED;
4443                 krb5_set_error_message(context, r,
4444                                        gettext("Prompt for token/smart card failed"));
4445                 goto out;
4446             }
4447             if (choice == RESCAN_TOKENS) {
4448                 /* rescan for new smartcard/token */
4449                 for (i = 0; i < token_choices.numtokens; i++) {
4450                     /* close all sessions */
4451                     cctx->p11->C_CloseSession(token_choices.token_array[i].session);
4452                 }
4453                 free(token_choices.token_array);
4454                 token_choices.token_array = NULL;
4455                 token_choices.numtokens = 0;
4456                 goto tryagain;
4457             } else if (choice == SKIP_TOKENS) {
4458                 /* do not use smartcard/token for auth */
4459                 cctx->p11flags |= (C_PROMPTED_USER|C_SKIP_PKCS11_AUTH);
4460                 r = KRB5KDC_ERR_PREAUTH_FAILED;
4461                 goto out;
4462             } else {
4463                 cctx->p11flags |= C_PROMPTED_USER;
4464             }
4465         } else {
4466             choice = 0; /* really the only choice is the first token_array entry */
4467         }
4468     } else if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
4469 	/* > 1 token so present menu of token choices, let the user decide. */
4470 	if ((r = pkinit_choose_tokens(context, cctx, &token_choices, &choice)) != 0) {
4471 	    pkiDebug("pkinit_open_session: pkinit_choose_tokens failed: %d\n", r);
4472 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
4473 	    krb5_set_error_message(context, r,
4474 				   gettext("Prompt for token/smart card failed"));
4475 	    goto out;
4476 	}
4477 	if (choice == RESCAN_TOKENS) {
4478 	    /* rescan for new smartcard/token */
4479 	    for (i = 0; i < token_choices.numtokens; i++) {
4480 		/* close all sessions */
4481 		cctx->p11->C_CloseSession(token_choices.token_array[i].session);
4482 	    }
4483 	    free(token_choices.token_array);
4484 	    token_choices.token_array = NULL;
4485 	    token_choices.numtokens = 0;
4486 	    goto tryagain;
4487 	} else if (choice == SKIP_TOKENS) {
4488 	    /* do not use smartcard/token for auth */
4489             cctx->p11flags |= (C_PROMPTED_USER|C_SKIP_PKCS11_AUTH);
4490 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
4491 	    goto out;
4492 	} else {
4493             cctx->p11flags |= C_PROMPTED_USER;
4494         }
4495     } else {
4496         r = KRB5KDC_ERR_PREAUTH_FAILED;
4497         goto out;
4498     }
4499 
4500     cctx->slotid = token_choices.token_array[choice].slotID;
4501     cctx->session = token_choices.token_array[choice].session;
4502 
4503     pkiDebug("open_session: slotid %d (%d of %d)\n", (int) cctx->slotid,
4504 	     i + 1, (int) count);
4505 
4506     /* Login if needed */
4507     /* Solaris Kerberos: added cctx->p11flags check */
4508     if ((token_choices.token_array[choice].token_info.flags & CKF_LOGIN_REQUIRED) &&
4509         !(cctx->p11flags & C_LOGIN_DONE)) {
4510         r = pkinit_login(context, cctx, &token_choices.token_array[choice].token_info);
4511     }
4512 
4513     if (r == 0) {
4514 	/* Doing this again to load the certs into cctx. */
4515 	r = check_load_certs(context, cctx->session, plg_cryptoctx,
4516 			     req_cryptoctx, cctx, princ, do_matching, 1);
4517     }
4518 
4519 out:
4520     if (slotlist != NULL)
4521 	free(slotlist);
4522 
4523     if (tmpslotlist != NULL)
4524 	free(tmpslotlist);
4525 
4526     if (token_choices.token_array != NULL) {
4527 	if (r != 0) {
4528 	    /* close all sessions if there's an error */
4529 	    for (i = 0; i < token_choices.numtokens; i++) {
4530 		cctx->p11->C_CloseSession(token_choices.token_array[i].session);
4531 	    }
4532 	    cctx->session = CK_INVALID_HANDLE;
4533 	} else {
4534 	    /* close sessions not chosen */
4535 	    for (i = 0; i < token_choices.numtokens; i++) {
4536 		if (i != choice) {
4537 		    cctx->p11->C_CloseSession(token_choices.token_array[i].session);
4538 		}
4539 	    }
4540 	}
4541 	free(token_choices.token_array);
4542     }
4543 
4544     return (r);
4545 }
4546 
4547 /*
4548  * Look for a key that's:
4549  * 1. private
4550  * 2. capable of the specified operation (usually signing or decrypting)
4551  * 3. RSA (this may be wrong but it's all we can do for now)
4552  * 4. matches the id of the cert we chose
4553  *
4554  * You must call pkinit_get_certs before calling pkinit_find_private_key
4555  * (that's because we need the ID of the private key)
4556  *
4557  * pkcs11 says the id of the key doesn't have to match that of the cert, but
4558  * I can't figure out any other way to decide which key to use.
4559  *
4560  * We should only find one key that fits all the requirements.
4561  * If there are more than one, we just take the first one.
4562  */
4563 
4564 /* ARGSUSED */
4565 krb5_error_code
4566 pkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx,
4567 			CK_ATTRIBUTE_TYPE usage,
4568 			CK_OBJECT_HANDLE *objp)
4569 {
4570     CK_OBJECT_CLASS cls;
4571     CK_ATTRIBUTE attrs[4];
4572     CK_ULONG count;
4573     CK_KEY_TYPE keytype;
4574     RSA *rsa;
4575     unsigned int nattrs = 0;
4576     int r;
4577 #ifdef PKINIT_USE_KEY_USAGE
4578     CK_BBOOL true_false;
4579 #endif
4580 
4581     cls = CKO_PRIVATE_KEY;
4582     attrs[nattrs].type = CKA_CLASS;
4583     attrs[nattrs].pValue = &cls;
4584     attrs[nattrs].ulValueLen = sizeof cls;
4585     nattrs++;
4586 
4587 #ifdef PKINIT_USE_KEY_USAGE
4588     /*
4589      * Some cards get confused if you try to specify a key usage,
4590      * so don't, and hope for the best. This will fail if you have
4591      * several keys with the same id and different usages but I have
4592      * not seen this on real cards.
4593      */
4594     true_false = TRUE;
4595     attrs[nattrs].type = usage;
4596     attrs[nattrs].pValue = &true_false;
4597     attrs[nattrs].ulValueLen = sizeof true_false;
4598     nattrs++;
4599 #endif
4600 
4601     keytype = CKK_RSA;
4602     attrs[nattrs].type = CKA_KEY_TYPE;
4603     attrs[nattrs].pValue = &keytype;
4604     attrs[nattrs].ulValueLen = sizeof keytype;
4605     nattrs++;
4606 
4607     attrs[nattrs].type = CKA_ID;
4608     attrs[nattrs].pValue = id_cryptoctx->cert_id;
4609     attrs[nattrs].ulValueLen = id_cryptoctx->cert_id_len;
4610     nattrs++;
4611 
4612     r = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs, nattrs);
4613     if (r != CKR_OK) {
4614 	pkiDebug("krb5_pkinit_sign_data: C_FindObjectsInit: %s\n",
4615 		 pkinit_pkcs11_code_to_text(r));
4616 	return KRB5KDC_ERR_PREAUTH_FAILED;
4617     }
4618 
4619     r = id_cryptoctx->p11->C_FindObjects(id_cryptoctx->session, objp, 1, &count);
4620     id_cryptoctx->p11->C_FindObjectsFinal(id_cryptoctx->session);
4621     pkiDebug("found %d private keys (%s)\n", (int) count, pkinit_pkcs11_code_to_text(r));
4622 
4623     /*
4624      * Solaris Kerberos:
4625      * The CKA_ID may not be correctly set for the private key. For e.g. when
4626      * storing a private key in softtoken pktool(1) doesn't generate or store
4627      * a CKA_ID for the private key. Another way to identify the private key is
4628      * to look for a private key with the same RSA modulus as the public key
4629      * in the certificate.
4630      */
4631     if (r == CKR_OK && count != 1) {
4632 
4633 	EVP_PKEY *priv;
4634 	X509 *cert;
4635 	const BIGNUM *rsan;
4636 	unsigned int n_len;
4637 	unsigned char *n_bytes;
4638 
4639 	cert = sk_X509_value(id_cryptoctx->my_certs, 0);
4640 	priv = X509_get_pubkey(cert);
4641 	if (priv == NULL) {
4642     		pkiDebug("Failed to extract pub key from cert\n");
4643 		return KRB5KDC_ERR_PREAUTH_FAILED;
4644 	}
4645 
4646 	nattrs = 0;
4647 	cls = CKO_PRIVATE_KEY;
4648 	attrs[nattrs].type = CKA_CLASS;
4649 	attrs[nattrs].pValue = &cls;
4650 	attrs[nattrs].ulValueLen = sizeof cls;
4651 	nattrs++;
4652 
4653 #ifdef PKINIT_USE_KEY_USAGE
4654 	true_false = TRUE;
4655 	attrs[nattrs].type = usage;
4656 	attrs[nattrs].pValue = &true_false;
4657 	attrs[nattrs].ulValueLen = sizeof true_false;
4658 	nattrs++;
4659 #endif
4660 
4661 	keytype = CKK_RSA;
4662 	attrs[nattrs].type = CKA_KEY_TYPE;
4663 	attrs[nattrs].pValue = &keytype;
4664 	attrs[nattrs].ulValueLen = sizeof keytype;
4665 	nattrs++;
4666 
4667 #if OPENSSL_VERSION_NUMBER < 0x10100000L
4668 	rsa = priv->pkey.rsa;
4669 	rsan = rsa->n;
4670 	n_len = BN_num_bytes(rsan);
4671 #else
4672 	rsa = EVP_PKEY_get0_RSA(priv);
4673 	RSA_get0_key(rsa, &rsan, NULL, NULL);
4674 	n_len = RSA_size(rsa);
4675 #endif
4676 	n_bytes = (unsigned char *) malloc((size_t) n_len);
4677 	if (n_bytes == NULL) {
4678 		return (ENOMEM);
4679 	}
4680 
4681 	if (BN_bn2bin(rsan, n_bytes) == 0) {
4682 		free (n_bytes);
4683 		pkiDebug("zero-byte key modulus\n");
4684 		return KRB5KDC_ERR_PREAUTH_FAILED;
4685 	}
4686 
4687 	attrs[nattrs].type = CKA_MODULUS;
4688 	attrs[nattrs].ulValueLen = n_len;
4689 	attrs[nattrs].pValue = n_bytes;
4690 
4691 	nattrs++;
4692 
4693 	r = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs, nattrs);
4694 	free (n_bytes);
4695 	if (r != CKR_OK) {
4696 		pkiDebug("krb5_pkinit_sign_data: C_FindObjectsInit: %s\n",
4697 			pkinit_pkcs11_code_to_text(r));
4698 		return KRB5KDC_ERR_PREAUTH_FAILED;
4699 	}
4700 
4701 	r = id_cryptoctx->p11->C_FindObjects(id_cryptoctx->session, objp, 1, &count);
4702 	id_cryptoctx->p11->C_FindObjectsFinal(id_cryptoctx->session);
4703 	pkiDebug("found %d private keys (%s)\n", (int) count, pkinit_pkcs11_code_to_text(r));
4704 
4705     }
4706 
4707     if (r != CKR_OK || count < 1)
4708 	return KRB5KDC_ERR_PREAUTH_FAILED;
4709     return 0;
4710 }
4711 #endif
4712 
4713 /* ARGSUSED */
4714 static krb5_error_code
4715 pkinit_decode_data_fs(krb5_context context,
4716 		      pkinit_identity_crypto_context id_cryptoctx,
4717 		      unsigned char *data,
4718 		      unsigned int data_len,
4719 		      unsigned char **decoded_data,
4720 		      unsigned int *decoded_data_len)
4721 {
4722     if (decode_data(decoded_data, decoded_data_len, data, data_len,
4723 		id_cryptoctx->my_key, sk_X509_value(id_cryptoctx->my_certs,
4724 		id_cryptoctx->cert_index)) <= 0) {
4725 	pkiDebug("failed to decode data\n");
4726 	return KRB5KDC_ERR_PREAUTH_FAILED;
4727     }
4728     return 0;
4729 }
4730 
4731 #ifndef WITHOUT_PKCS11
4732 #ifdef SILLYDECRYPT
4733 CK_RV
4734 pkinit_C_Decrypt(pkinit_identity_crypto_context id_cryptoctx,
4735 		 CK_BYTE_PTR pEncryptedData,
4736 		 CK_ULONG  ulEncryptedDataLen,
4737 		 CK_BYTE_PTR pData,
4738 		 CK_ULONG_PTR pulDataLen)
4739 {
4740     CK_RV rv = CKR_OK;
4741 
4742     rv = id_cryptoctx->p11->C_Decrypt(id_cryptoctx->session, pEncryptedData,
4743 	ulEncryptedDataLen, pData, pulDataLen);
4744     if (rv == CKR_OK) {
4745 	pkiDebug("pData %x *pulDataLen %d\n", (int) pData, (int) *pulDataLen);
4746     }
4747     return rv;
4748 }
4749 #endif
4750 
4751 static krb5_error_code
4752 pkinit_decode_data_pkcs11(krb5_context context,
4753 			  pkinit_identity_crypto_context id_cryptoctx,
4754 			  unsigned char *data,
4755 			  unsigned int data_len,
4756 			  unsigned char **decoded_data,
4757 			  unsigned int *decoded_data_len)
4758 {
4759     CK_OBJECT_HANDLE obj;
4760     CK_ULONG len;
4761     CK_MECHANISM mech;
4762     unsigned char *cp;
4763     int r;
4764 
4765     /*
4766      * Solaris Kerberos: assume session is open and libpkcs11 funcs have been
4767      * loaded.
4768      */
4769     assert(id_cryptoctx->p11 != NULL);
4770 
4771     /* Solaris Kerberos: Login, if needed, to access private object */
4772     if (!(id_cryptoctx->p11flags & C_LOGIN_DONE)) {
4773         CK_TOKEN_INFO tinfo;
4774 
4775         r = id_cryptoctx->p11->C_GetTokenInfo(id_cryptoctx->slotid, &tinfo);
4776         if (r != 0)
4777             return r;
4778 
4779         r = pkinit_login(context, id_cryptoctx, &tinfo);
4780         if (r != 0)
4781             return r;
4782     }
4783 
4784     r = pkinit_find_private_key(id_cryptoctx, CKA_DECRYPT, &obj);
4785     if (r != 0)
4786 	return r;
4787 
4788     mech.mechanism = CKM_RSA_PKCS;
4789     mech.pParameter = NULL;
4790     mech.ulParameterLen = 0;
4791 
4792     if ((r = id_cryptoctx->p11->C_DecryptInit(id_cryptoctx->session, &mech,
4793 	    obj)) != CKR_OK) {
4794 	pkiDebug("C_DecryptInit: 0x%x\n", (int) r);
4795 	return KRB5KDC_ERR_PREAUTH_FAILED;
4796     }
4797     pkiDebug("data_len = %d\n", data_len);
4798     cp = (unsigned char *)malloc((size_t) data_len);
4799     if (cp == NULL)
4800 	return ENOMEM;
4801     len = data_len;
4802 #ifdef SILLYDECRYPT
4803     pkiDebug("session %x edata %x edata_len %d data %x datalen @%x %d\n",
4804 	    (int) id_cryptoctx->session, (int) data, (int) data_len, (int) cp,
4805 	    (int) &len, (int) len);
4806     if ((r = pkinit_C_Decrypt(id_cryptoctx, data, (CK_ULONG) data_len,
4807 	    cp, &len)) != CKR_OK) {
4808 #else
4809     if ((r = id_cryptoctx->p11->C_Decrypt(id_cryptoctx->session, data,
4810 	    (CK_ULONG) data_len, cp, &len)) != CKR_OK) {
4811 #endif
4812 	pkiDebug("C_Decrypt: %s\n", pkinit_pkcs11_code_to_text(r));
4813 	if (r == CKR_BUFFER_TOO_SMALL)
4814 	    pkiDebug("decrypt %d needs %d\n", (int) data_len, (int) len);
4815 	return KRB5KDC_ERR_PREAUTH_FAILED;
4816     }
4817     pkiDebug("decrypt %d -> %d\n", (int) data_len, (int) len);
4818     *decoded_data_len = len;
4819     *decoded_data = cp;
4820 
4821     return 0;
4822 }
4823 #endif
4824 
4825 krb5_error_code
4826 pkinit_decode_data(krb5_context context,
4827 		   pkinit_identity_crypto_context id_cryptoctx,
4828 		   unsigned char *data,
4829 		   unsigned int data_len,
4830 		   unsigned char **decoded_data,
4831 		   unsigned int *decoded_data_len)
4832 {
4833     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
4834 
4835     if (id_cryptoctx->pkcs11_method != 1)
4836 	retval = pkinit_decode_data_fs(context, id_cryptoctx, data, data_len,
4837 	    decoded_data, decoded_data_len);
4838 #ifndef WITHOUT_PKCS11
4839     else
4840 	retval = pkinit_decode_data_pkcs11(context, id_cryptoctx, data,
4841 	    data_len, decoded_data, decoded_data_len);
4842 #endif
4843 
4844     return retval;
4845 }
4846 
4847 /* ARGSUSED */
4848 static krb5_error_code
4849 pkinit_sign_data_fs(krb5_context context,
4850 		 pkinit_identity_crypto_context id_cryptoctx,
4851 		 unsigned char *data,
4852 		 unsigned int data_len,
4853 		 unsigned char **sig,
4854 		 unsigned int *sig_len)
4855 {
4856     if (create_signature(sig, sig_len, data, data_len,
4857 	    id_cryptoctx->my_key) != 0) {
4858 	    pkiDebug("failed to create the signature\n");
4859 	    return KRB5KDC_ERR_PREAUTH_FAILED;
4860     }
4861     return 0;
4862 }
4863 
4864 #ifndef WITHOUT_PKCS11
4865 static krb5_error_code
4866 pkinit_sign_data_pkcs11(krb5_context context,
4867 			pkinit_identity_crypto_context id_cryptoctx,
4868 			unsigned char *data,
4869 			unsigned int data_len,
4870 			unsigned char **sig,
4871 			unsigned int *sig_len)
4872 {
4873     CK_OBJECT_HANDLE obj;
4874     CK_ULONG len;
4875     CK_MECHANISM mech;
4876     unsigned char *cp;
4877     int r;
4878 
4879     /*
4880      * Solaris Kerberos: assume session is open and libpkcs11 funcs have been
4881      * loaded.
4882      */
4883     assert(id_cryptoctx->p11 != NULL);
4884 
4885     /* Solaris Kerberos: Login, if needed, to access private object */
4886     if (!(id_cryptoctx->p11flags & C_LOGIN_DONE)) {
4887         CK_TOKEN_INFO tinfo;
4888 
4889         r = id_cryptoctx->p11->C_GetTokenInfo(id_cryptoctx->slotid, &tinfo);
4890         if (r != 0)
4891             return r;
4892 
4893         r = pkinit_login(context, id_cryptoctx, &tinfo);
4894         if (r != 0)
4895             return r;
4896     }
4897 
4898     r = pkinit_find_private_key(id_cryptoctx, CKA_SIGN, &obj);
4899     if (r != 0 )
4900 	return r;
4901 
4902     mech.mechanism = id_cryptoctx->mech;
4903     mech.pParameter = NULL;
4904     mech.ulParameterLen = 0;
4905 
4906     if ((r = id_cryptoctx->p11->C_SignInit(id_cryptoctx->session, &mech,
4907 	    obj)) != CKR_OK) {
4908 	pkiDebug("C_SignInit: %s\n", pkinit_pkcs11_code_to_text(r));
4909 	return KRB5KDC_ERR_PREAUTH_FAILED;
4910     }
4911 
4912     /*
4913      * Key len would give an upper bound on sig size, but there's no way to
4914      * get that. So guess, and if it's too small, re-malloc.
4915      */
4916     len = PK_SIGLEN_GUESS;
4917     cp = (unsigned char *)malloc((size_t) len);
4918     if (cp == NULL)
4919 	return ENOMEM;
4920 
4921     r = id_cryptoctx->p11->C_Sign(id_cryptoctx->session, data,
4922 				 (CK_ULONG) data_len, cp, &len);
4923     if (r == CKR_BUFFER_TOO_SMALL || (r == CKR_OK && len >= PK_SIGLEN_GUESS)) {
4924 	free(cp);
4925 	pkiDebug("C_Sign realloc %d\n", (int) len);
4926 	cp = (unsigned char *)malloc((size_t) len);
4927 	r = id_cryptoctx->p11->C_Sign(id_cryptoctx->session, data,
4928 				     (CK_ULONG) data_len, cp, &len);
4929     }
4930     if (r != CKR_OK) {
4931 	pkiDebug("C_Sign: %s\n", pkinit_pkcs11_code_to_text(r));
4932 	return KRB5KDC_ERR_PREAUTH_FAILED;
4933     }
4934     pkiDebug("sign %d -> %d\n", (int) data_len, (int) len);
4935     *sig_len = len;
4936     *sig = cp;
4937 
4938     return 0;
4939 }
4940 #endif
4941 
4942 krb5_error_code
4943 pkinit_sign_data(krb5_context context,
4944 		 pkinit_identity_crypto_context id_cryptoctx,
4945 		 unsigned char *data,
4946 		 unsigned int data_len,
4947 		 unsigned char **sig,
4948 		 unsigned int *sig_len)
4949 {
4950     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
4951 
4952     if (id_cryptoctx == NULL || id_cryptoctx->pkcs11_method != 1)
4953 	retval = pkinit_sign_data_fs(context, id_cryptoctx, data, data_len,
4954 				     sig, sig_len);
4955 #ifndef WITHOUT_PKCS11
4956     else
4957 	retval = pkinit_sign_data_pkcs11(context, id_cryptoctx, data, data_len,
4958 					 sig, sig_len);
4959 #endif
4960 
4961     return retval;
4962 }
4963 
4964 
4965 static krb5_error_code
4966 decode_data(unsigned char **out_data, unsigned int *out_data_len,
4967 	    unsigned char *data, unsigned int data_len,
4968 	    EVP_PKEY *pkey, X509 *cert)
4969 {
4970     /* Solaris Kerberos */
4971     int len;
4972     unsigned char *buf = NULL;
4973     int buf_len = 0;
4974 
4975     /* Solaris Kerberos */
4976     if (out_data == NULL || out_data_len == NULL)
4977 	return EINVAL;
4978 
4979     if (cert && !X509_check_private_key(cert, pkey)) {
4980 	pkiDebug("private key does not match certificate\n");
4981 	/* Solaris Kerberos */
4982 	return EINVAL;
4983     }
4984 
4985     buf_len = EVP_PKEY_size(pkey);
4986     buf = (unsigned char *)malloc((size_t) buf_len + 10);
4987     if (buf == NULL)
4988 	return ENOMEM;
4989 
4990     len = EVP_PKEY_decrypt_old(buf, data, (int)data_len, pkey);
4991     if (len <= 0) {
4992 	pkiDebug("unable to decrypt received data (len=%d)\n", data_len);
4993 	/* Solaris Kerberos */
4994 	free(buf);
4995 	return KRB5KRB_ERR_GENERIC;
4996     }
4997     *out_data = buf;
4998     *out_data_len = len;
4999 
5000     return 0;
5001 }
5002 
5003 static krb5_error_code
5004 create_signature(unsigned char **sig, unsigned int *sig_len,
5005 		 unsigned char *data, unsigned int data_len, EVP_PKEY *pkey)
5006 {
5007     krb5_error_code retval = ENOMEM;
5008     EVP_MD_CTX *md_ctx;
5009 
5010     if (pkey == NULL)
5011 	/* Solaris Kerberos */
5012 	return EINVAL;
5013 
5014     if ((md_ctx = EVP_MD_CTX_new()) == NULL)
5015 	return EINVAL;
5016 
5017     EVP_VerifyInit(md_ctx, EVP_sha1());
5018     EVP_SignUpdate(md_ctx, data, data_len);
5019     *sig_len = EVP_PKEY_size(pkey);
5020     if ((*sig = (unsigned char *) malloc((size_t) *sig_len)) == NULL)
5021 	goto cleanup;
5022     EVP_SignFinal(md_ctx, *sig, sig_len, pkey);
5023 
5024     retval = 0;
5025 
5026   cleanup:
5027     EVP_MD_CTX_free(md_ctx);
5028 
5029     return retval;
5030 }
5031 
5032 /*
5033  * Note:
5034  * This is not the routine the KDC uses to get its certificate.
5035  * This routine is intended to be called by the client
5036  * to obtain the KDC's certificate from some local storage
5037  * to be sent as a hint in its request to the KDC.
5038  */
5039 /* ARGSUSED */
5040 krb5_error_code
5041 pkinit_get_kdc_cert(krb5_context context,
5042 		    pkinit_plg_crypto_context plg_cryptoctx,
5043 		    pkinit_req_crypto_context req_cryptoctx,
5044 		    pkinit_identity_crypto_context id_cryptoctx,
5045 		    krb5_principal princ)
5046 {
5047    /* Solaris Kerberos */
5048     if (req_cryptoctx == NULL)
5049 	return EINVAL;
5050 
5051     req_cryptoctx->received_cert = NULL;
5052     return 0;
5053 }
5054 
5055 /* ARGSUSED */
5056 static krb5_error_code
5057 pkinit_get_certs_pkcs12(krb5_context context,
5058 			  pkinit_plg_crypto_context plg_cryptoctx,
5059 			  pkinit_req_crypto_context req_cryptoctx,
5060 			  pkinit_identity_opts *idopts,
5061 			  pkinit_identity_crypto_context id_cryptoctx,
5062 			  krb5_principal princ)
5063 {
5064     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
5065     X509 *x = NULL;
5066     PKCS12 *p12 = NULL;
5067     int ret;
5068     FILE *fp;
5069     EVP_PKEY *y = NULL;
5070 
5071     if (idopts->cert_filename == NULL) {
5072 	/* Solaris Kerberos: Improved error messages */
5073 	krb5_set_error_message(context, retval,
5074 	    gettext("Failed to get certificate location"));
5075 	pkiDebug("%s: failed to get user's cert location\n", __FUNCTION__);
5076 	goto cleanup;
5077     }
5078 
5079     if (idopts->key_filename == NULL) {
5080 	/* Solaris Kerberos: Improved error messages */
5081 	krb5_set_error_message(context, retval,
5082 	    gettext("Failed to get private key location"));
5083 	pkiDebug("%s: failed to get user's private key location\n", __FUNCTION__);
5084 	goto cleanup;
5085     }
5086 
5087     fp = fopen(idopts->cert_filename, "rb");
5088     if (fp == NULL) {
5089 	/* Solaris Kerberos: Improved error messages */
5090 	krb5_set_error_message(context, retval,
5091 	    gettext("Failed to open PKCS12 file '%s': %s"),
5092 	    idopts->cert_filename, error_message(errno));
5093 	pkiDebug("Failed to open PKCS12 file '%s', error %d\n",
5094 		 idopts->cert_filename, errno);
5095 	goto cleanup;
5096     }
5097 
5098     p12 = d2i_PKCS12_fp(fp, NULL);
5099     (void) fclose(fp);
5100     if (p12 == NULL) {
5101 	krb5_set_error_message(context, retval,
5102 	    gettext("Failed to decode PKCS12 file '%s' contents"),
5103 	    idopts->cert_filename);
5104 	pkiDebug("Failed to decode PKCS12 file '%s' contents\n",
5105 		 idopts->cert_filename);
5106 	goto cleanup;
5107     }
5108     /*
5109      * Try parsing with no pass phrase first.  If that fails,
5110      * prompt for the pass phrase and try again.
5111      */
5112     ret = PKCS12_parse(p12, NULL, &y, &x, NULL);
5113     if (ret == 0) {
5114 	krb5_data rdat;
5115 	krb5_prompt kprompt;
5116 	krb5_prompt_type prompt_type;
5117 	int r = 0;
5118 	char prompt_string[128];
5119 	char prompt_reply[128];
5120 	/* Solaris Kerberos */
5121 	char *prompt_prefix = gettext("Pass phrase for");
5122 
5123 	pkiDebug("Initial PKCS12_parse with no password failed\n");
5124 
5125 	if (id_cryptoctx->PIN != NULL) {
5126 		/* Solaris Kerberos: use PIN if set */
5127 		rdat.data = id_cryptoctx->PIN;
5128 		/* note rdat.length isn't needed in this case */
5129 	} else {
5130 		(void) memset(prompt_reply, '\0', sizeof(prompt_reply));
5131 		rdat.data = prompt_reply;
5132 		rdat.length = sizeof(prompt_reply);
5133 
5134 		r = snprintf(prompt_string, sizeof(prompt_string), "%s %s",
5135 			     prompt_prefix, idopts->cert_filename);
5136 		if (r >= sizeof(prompt_string)) {
5137 		    pkiDebug("Prompt string, '%s %s', is too long!\n",
5138 			     prompt_prefix, idopts->cert_filename);
5139 		    goto cleanup;
5140 		}
5141 		kprompt.prompt = prompt_string;
5142 		kprompt.hidden = 1;
5143 		kprompt.reply = &rdat;
5144 		prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
5145 
5146 		/* PROMPTER_INVOCATION */
5147 		k5int_set_prompt_types(context, &prompt_type);
5148 		r = (*id_cryptoctx->prompter)(context, id_cryptoctx->prompter_data,
5149 					      NULL, NULL, 1, &kprompt);
5150 		k5int_set_prompt_types(context, NULL);
5151 	}
5152 
5153 	ret = PKCS12_parse(p12, rdat.data, &y, &x, NULL);
5154 	if (ret == 0) {
5155 	    /* Solaris Kerberos: Improved error messages */
5156 	    krb5_set_error_message(context, retval,
5157 	        gettext("Failed to parse PKCS12 file '%s' with password"),
5158 	        idopts->cert_filename);
5159 	    pkiDebug("Seconde PKCS12_parse with password failed\n");
5160 	    goto cleanup;
5161 	}
5162     }
5163     id_cryptoctx->creds[0] = malloc(sizeof(struct _pkinit_cred_info));
5164     if (id_cryptoctx->creds[0] == NULL)
5165 	goto cleanup;
5166     id_cryptoctx->creds[0]->cert = x;
5167 #ifndef WITHOUT_PKCS11
5168     id_cryptoctx->creds[0]->cert_id = NULL;
5169     id_cryptoctx->creds[0]->cert_id_len = 0;
5170 #endif
5171     id_cryptoctx->creds[0]->key = y;
5172     id_cryptoctx->creds[1] = NULL;
5173 
5174     retval = 0;
5175 
5176 cleanup:
5177     if (p12)
5178 	PKCS12_free(p12);
5179     if (retval) {
5180 	if (x != NULL)
5181 	    X509_free(x);
5182 	if (y != NULL)
5183 	    EVP_PKEY_free(y);
5184     }
5185     return retval;
5186 }
5187 
5188 static krb5_error_code
5189 pkinit_load_fs_cert_and_key(krb5_context context,
5190 			    pkinit_identity_crypto_context id_cryptoctx,
5191 			    char *certname,
5192 			    char *keyname,
5193 			    int cindex)
5194 {
5195     krb5_error_code retval;
5196     X509 *x = NULL;
5197     EVP_PKEY *y = NULL;
5198 
5199     /* load the certificate */
5200     retval = get_cert(certname, &x);
5201     if (retval != 0 || x == NULL) {
5202 	/* Solaris Kerberos: Improved error messages */
5203 	krb5_set_error_message(context, retval,
5204 	    gettext("Failed to load user's certificate from %s: %s"),
5205 	        certname, error_message(retval));
5206 	pkiDebug("failed to load user's certificate from '%s'\n", certname);
5207 	goto cleanup;
5208     }
5209     retval = get_key(keyname, &y);
5210     if (retval != 0 || y == NULL) {
5211 	/* Solaris Kerberos: Improved error messages */
5212 	krb5_set_error_message(context, retval,
5213 	    gettext("Failed to load user's private key from %s: %s"),
5214 	        keyname, error_message(retval));
5215 	pkiDebug("failed to load user's private key from '%s'\n", keyname);
5216 	goto cleanup;
5217     }
5218 
5219     id_cryptoctx->creds[cindex] = malloc(sizeof(struct _pkinit_cred_info));
5220     if (id_cryptoctx->creds[cindex] == NULL) {
5221 	retval = ENOMEM;
5222 	goto cleanup;
5223     }
5224     id_cryptoctx->creds[cindex]->cert = x;
5225 #ifndef WITHOUT_PKCS11
5226     id_cryptoctx->creds[cindex]->cert_id = NULL;
5227     id_cryptoctx->creds[cindex]->cert_id_len = 0;
5228 #endif
5229     id_cryptoctx->creds[cindex]->key = y;
5230     id_cryptoctx->creds[cindex+1] = NULL;
5231 
5232     retval = 0;
5233 
5234 cleanup:
5235     if (retval) {
5236 	if (x != NULL)
5237 	    X509_free(x);
5238 	if (y != NULL)
5239 	    EVP_PKEY_free(y);
5240     }
5241     return retval;
5242 }
5243 
5244 /* ARGSUSED */
5245 static krb5_error_code
5246 pkinit_get_certs_fs(krb5_context context,
5247 			  pkinit_plg_crypto_context plg_cryptoctx,
5248 			  pkinit_req_crypto_context req_cryptoctx,
5249 			  pkinit_identity_opts *idopts,
5250 			  pkinit_identity_crypto_context id_cryptoctx,
5251 			  krb5_principal princ)
5252 {
5253     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
5254 
5255     if (idopts->cert_filename == NULL) {
5256 	pkiDebug("%s: failed to get user's cert location\n", __FUNCTION__);
5257 	goto cleanup;
5258     }
5259 
5260     if (idopts->key_filename == NULL) {
5261 	pkiDebug("%s: failed to get user's private key location\n",
5262 		 __FUNCTION__);
5263 	goto cleanup;
5264     }
5265 
5266     retval = pkinit_load_fs_cert_and_key(context, id_cryptoctx,
5267 					 idopts->cert_filename,
5268 					 idopts->key_filename, 0);
5269 cleanup:
5270     return retval;
5271 }
5272 
5273 /* ARGSUSED */
5274 static krb5_error_code
5275 pkinit_get_certs_dir(krb5_context context,
5276 		     pkinit_plg_crypto_context plg_cryptoctx,
5277 		     pkinit_req_crypto_context req_cryptoctx,
5278 		     pkinit_identity_opts *idopts,
5279 		     pkinit_identity_crypto_context id_cryptoctx,
5280 		     krb5_principal princ)
5281 {
5282     /* Solaris Kerberos */
5283     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
5284     DIR *d = NULL;
5285     struct dirent *dentry = NULL;
5286     char certname[1024];
5287     char keyname[1024];
5288     int i = 0, len;
5289     char *dirname, *suf;
5290 
5291     /* Solaris Kerberos */
5292     if (idopts == NULL)
5293 	return EINVAL;
5294 
5295     if (idopts->cert_filename == NULL) {
5296 	pkiDebug("%s: failed to get user's certificate directory location\n",
5297 		 __FUNCTION__);
5298 	return ENOENT;
5299     }
5300 
5301     dirname = idopts->cert_filename;
5302     d = opendir(dirname);
5303     if (d == NULL) {
5304 	/* Solaris Kerberos: Improved error messages */
5305 	krb5_set_error_message(context, errno,
5306 	    gettext("Failed to open directory \"%s\": %s"),
5307 	    dirname, error_message(errno));
5308 	return errno;
5309     }
5310 
5311     /*
5312      * We'll assume that certs are named XXX.crt and the corresponding
5313      * key is named XXX.key
5314      */
5315     while ((i < MAX_CREDS_ALLOWED) &&  (dentry = readdir(d)) != NULL) {
5316 	/* Ignore subdirectories and anything starting with a dot */
5317 #ifdef DT_DIR
5318 	if (dentry->d_type == DT_DIR)
5319 	    continue;
5320 #endif
5321 	if (dentry->d_name[0] == '.')
5322 	    continue;
5323 	len = strlen(dentry->d_name);
5324 	if (len < 5)
5325 	    continue;
5326 	suf = dentry->d_name + (len - 4);
5327 	if (strncmp(suf, ".crt", 4) != 0)
5328 	    continue;
5329 
5330 	/* Checked length */
5331 	if (strlen(dirname) + strlen(dentry->d_name) + 2 > sizeof(certname)) {
5332 	    pkiDebug("%s: Path too long -- directory '%s' and file '%s'\n",
5333 		     __FUNCTION__, dirname, dentry->d_name);
5334 	    continue;
5335 	}
5336 	(void) snprintf(certname, sizeof(certname), "%s/%s", dirname, dentry->d_name);
5337 	(void) snprintf(keyname, sizeof(keyname), "%s/%s", dirname, dentry->d_name);
5338 	len = strlen(keyname);
5339 	keyname[len - 3] = 'k';
5340 	keyname[len - 2] = 'e';
5341 	keyname[len - 1] = 'y';
5342 
5343 	retval = pkinit_load_fs_cert_and_key(context, id_cryptoctx,
5344 					     certname, keyname, i);
5345 	if (retval == 0) {
5346 	    pkiDebug("%s: Successfully loaded cert (and key) for %s\n",
5347 		     __FUNCTION__, dentry->d_name);
5348 	    i++;
5349 	}
5350 	else
5351 	    continue;
5352     }
5353 
5354     if (i == 0) {
5355 	/* Solaris Kerberos: Improved error messages */
5356 	krb5_set_error_message(context, ENOENT,
5357 	    gettext("No suitable cert/key pairs found in directory '%s'"),
5358 	    idopts->cert_filename);
5359 	pkiDebug("%s: No cert/key pairs found in directory '%s'\n",
5360 		 __FUNCTION__, idopts->cert_filename);
5361 	retval = ENOENT;
5362 	goto cleanup;
5363     }
5364 
5365     retval = 0;
5366 
5367   cleanup:
5368     if (d)
5369 	(void) closedir(d);
5370 
5371     return retval;
5372 }
5373 
5374 #ifndef WITHOUT_PKCS11
5375 /* ARGSUSED */
5376 static krb5_error_code
5377 pkinit_get_certs_pkcs11(krb5_context context,
5378 			pkinit_plg_crypto_context plg_cryptoctx,
5379 			pkinit_req_crypto_context req_cryptoctx,
5380 			pkinit_identity_opts *idopts,
5381 			pkinit_identity_crypto_context id_cryptoctx,
5382 			krb5_principal princ,
5383 			int do_matching)
5384 {
5385 #ifdef PKINIT_USE_MECH_LIST
5386     CK_MECHANISM_TYPE_PTR mechp = NULL;
5387     CK_MECHANISM_INFO info;
5388 #endif
5389 
5390     if (id_cryptoctx->p11flags & C_SKIP_PKCS11_AUTH)
5391 	return KRB5KDC_ERR_PREAUTH_FAILED;
5392 
5393     /* Copy stuff from idopts -> id_cryptoctx */
5394     if (idopts->p11_module_name != NULL) {
5395 	id_cryptoctx->p11_module_name = strdup(idopts->p11_module_name);
5396 	if (id_cryptoctx->p11_module_name == NULL)
5397 	    return ENOMEM;
5398     }
5399     if (idopts->token_label != NULL) {
5400 	id_cryptoctx->token_label = strdup(idopts->token_label);
5401 	if (id_cryptoctx->token_label == NULL)
5402 	    return ENOMEM;
5403     }
5404     if (idopts->cert_label != NULL) {
5405 	id_cryptoctx->cert_label = strdup(idopts->cert_label);
5406 	if (id_cryptoctx->cert_label == NULL)
5407 	    return ENOMEM;
5408     }
5409     if (idopts->PIN != NULL) {
5410 	id_cryptoctx->PIN = strdup(idopts->PIN);
5411 	if (id_cryptoctx->PIN == NULL)
5412 	    return ENOMEM;
5413     }
5414     /* Convert the ascii cert_id string into a binary blob */
5415     /*
5416      * Solaris Kerberos:
5417      * If the cert_id_string is empty then behave in a similar way to how
5418      * an empty certlabel is treated - i.e. don't fail now but rather continue
5419      * as though the certid wasn't specified.
5420      */
5421     if (idopts->cert_id_string != NULL && strlen(idopts->cert_id_string) != 0) {
5422 	BIGNUM *bn = NULL;
5423 	BN_hex2bn(&bn, idopts->cert_id_string);
5424 	if (bn == NULL)
5425 	    return ENOMEM;
5426 	id_cryptoctx->cert_id_len = BN_num_bytes(bn);
5427 	id_cryptoctx->cert_id = malloc((size_t) id_cryptoctx->cert_id_len);
5428 	if (id_cryptoctx->cert_id == NULL) {
5429 	    BN_free(bn);
5430 	    return ENOMEM;
5431 	}
5432 	BN_bn2bin(bn, id_cryptoctx->cert_id);
5433 	BN_free(bn);
5434     }
5435     id_cryptoctx->slotid = idopts->slotid;
5436     id_cryptoctx->pkcs11_method = 1;
5437 
5438 #ifndef PKINIT_USE_MECH_LIST
5439     /*
5440      * We'd like to use CKM_SHA1_RSA_PKCS for signing if it's available, but
5441      * many cards seems to be confused about whether they are capable of
5442      * this or not. The safe thing seems to be to ignore the mechanism list,
5443      * always use CKM_RSA_PKCS and calculate the sha1 digest ourselves.
5444      */
5445 
5446     id_cryptoctx->mech = CKM_RSA_PKCS;
5447 #else
5448     if ((r = id_cryptoctx->p11->C_GetMechanismList(id_cryptoctx->slotid, NULL,
5449 	    &count)) != CKR_OK || count <= 0) {
5450 	pkiDebug("C_GetMechanismList: %s\n", pkinit_pkcs11_code_to_text(r));
5451 	return KRB5KDC_ERR_PREAUTH_FAILED;
5452     }
5453     mechp = (CK_MECHANISM_TYPE_PTR) malloc(count * sizeof (CK_MECHANISM_TYPE));
5454     if (mechp == NULL)
5455 	return ENOMEM;
5456     if ((r = id_cryptoctx->p11->C_GetMechanismList(id_cryptoctx->slotid,
5457 	    mechp, &count)) != CKR_OK) {
5458 	free(mechp);
5459 	return KRB5KDC_ERR_PREAUTH_FAILED;
5460     }
5461     for (i = 0; i < count; i++) {
5462 	if ((r = id_cryptoctx->p11->C_GetMechanismInfo(id_cryptoctx->slotid,
5463 		mechp[i], &info)) != CKR_OK) {
5464 	    free(mechp);
5465 	    return KRB5KDC_ERR_PREAUTH_FAILED;
5466 	}
5467 #ifdef DEBUG_MECHINFO
5468 	pkiDebug("mech %x flags %x\n", (int) mechp[i], (int) info.flags);
5469 	if ((info.flags & (CKF_SIGN|CKF_DECRYPT)) == (CKF_SIGN|CKF_DECRYPT))
5470 	    pkiDebug("  this mech is good for sign & decrypt\n");
5471 #endif
5472 	if (mechp[i] == CKM_RSA_PKCS) {
5473 	    /* This seems backwards... */
5474 	    id_cryptoctx->mech =
5475 		(info.flags & CKF_SIGN) ? CKM_SHA1_RSA_PKCS : CKM_RSA_PKCS;
5476 	}
5477     }
5478     free(mechp);
5479 
5480     pkiDebug("got %d mechs from card\n", (int) count);
5481 #endif
5482 
5483     return (pkinit_open_session(context, plg_cryptoctx, req_cryptoctx,
5484                                 id_cryptoctx, princ, do_matching));
5485 }
5486 #endif
5487 
5488 /* ARGSUSED */
5489 static void
5490 free_cred_info(krb5_context context,
5491 	       pkinit_identity_crypto_context id_cryptoctx,
5492 	       struct _pkinit_cred_info *cred)
5493 {
5494     if (cred != NULL) {
5495 	if (cred->cert != NULL)
5496 	    X509_free(cred->cert);
5497 	if (cred->key != NULL)
5498 	    EVP_PKEY_free(cred->key);
5499 #ifndef WITHOUT_PKCS11
5500 	if (cred->cert_id != NULL)
5501 	    free(cred->cert_id);
5502 #endif
5503 	free(cred);
5504     }
5505 }
5506 
5507 /* ARGSUSED */
5508 krb5_error_code
5509 crypto_free_cert_info(krb5_context context,
5510 		      pkinit_plg_crypto_context plg_cryptoctx,
5511 		      pkinit_req_crypto_context req_cryptoctx,
5512 		      pkinit_identity_crypto_context id_cryptoctx)
5513 {
5514     int i;
5515 
5516     if (id_cryptoctx == NULL)
5517 	return EINVAL;
5518 
5519     for (i = 0; i < MAX_CREDS_ALLOWED; i++) {
5520 	if (id_cryptoctx->creds[i] != NULL) {
5521 	    free_cred_info(context, id_cryptoctx, id_cryptoctx->creds[i]);
5522 	    id_cryptoctx->creds[i] = NULL;
5523 	}
5524     }
5525     return 0;
5526 }
5527 
5528 krb5_error_code
5529 crypto_load_certs(krb5_context context,
5530 		  pkinit_plg_crypto_context plg_cryptoctx,
5531 		  pkinit_req_crypto_context req_cryptoctx,
5532 		  pkinit_identity_opts *idopts,
5533 		  pkinit_identity_crypto_context id_cryptoctx,
5534 		  krb5_principal princ,
5535 		  int do_matching)
5536 {
5537     krb5_error_code retval;
5538 
5539     switch(idopts->idtype) {
5540 	case IDTYPE_FILE:
5541 	    retval = pkinit_get_certs_fs(context, plg_cryptoctx,
5542 					 req_cryptoctx, idopts,
5543 					 id_cryptoctx, princ);
5544 	    break;
5545 	case IDTYPE_DIR:
5546 	    retval = pkinit_get_certs_dir(context, plg_cryptoctx,
5547 					  req_cryptoctx, idopts,
5548 					  id_cryptoctx, princ);
5549 	    break;
5550 #ifndef WITHOUT_PKCS11
5551 	case IDTYPE_PKCS11:
5552 	    retval = pkinit_get_certs_pkcs11(context, plg_cryptoctx,
5553 					     req_cryptoctx, idopts,
5554 					     id_cryptoctx, princ, do_matching);
5555 	    break;
5556 #endif
5557 	case IDTYPE_PKCS12:
5558 	    retval = pkinit_get_certs_pkcs12(context, plg_cryptoctx,
5559 					     req_cryptoctx, idopts,
5560 					     id_cryptoctx, princ);
5561 		break;
5562 	default:
5563 	    retval = EINVAL;
5564     }
5565 /* Solaris Kerberos */
5566 
5567     return retval;
5568 }
5569 
5570 /*
5571  * Get number of certificates available after crypto_load_certs()
5572  */
5573 /* ARGSUSED */
5574 krb5_error_code
5575 crypto_cert_get_count(krb5_context context,
5576 		      pkinit_plg_crypto_context plg_cryptoctx,
5577 		      pkinit_req_crypto_context req_cryptoctx,
5578 		      pkinit_identity_crypto_context id_cryptoctx,
5579 		      int *cert_count)
5580 {
5581     int count;
5582 
5583     if (id_cryptoctx == NULL || id_cryptoctx->creds[0] == NULL)
5584 	return EINVAL;
5585 
5586     for (count = 0;
5587 	 count <= MAX_CREDS_ALLOWED && id_cryptoctx->creds[count] != NULL;
5588 	 count++);
5589     *cert_count = count;
5590     return 0;
5591 }
5592 
5593 
5594 /*
5595  * Begin iteration over the certs loaded in crypto_load_certs()
5596  */
5597 /* ARGSUSED */
5598 krb5_error_code
5599 crypto_cert_iteration_begin(krb5_context context,
5600 			    pkinit_plg_crypto_context plg_cryptoctx,
5601 			    pkinit_req_crypto_context req_cryptoctx,
5602 			    pkinit_identity_crypto_context id_cryptoctx,
5603 			    pkinit_cert_iter_handle *ih_ret)
5604 {
5605     struct _pkinit_cert_iter_data *id;
5606 
5607     if (id_cryptoctx == NULL || ih_ret == NULL)
5608 	return EINVAL;
5609     if (id_cryptoctx->creds[0] == NULL)	/* No cred info available */
5610 	return ENOENT;
5611 
5612     id = calloc(1, sizeof(*id));
5613     if (id == NULL)
5614 	return ENOMEM;
5615     id->magic = ITER_MAGIC;
5616     id->plgctx = plg_cryptoctx,
5617     id->reqctx = req_cryptoctx,
5618     id->idctx = id_cryptoctx;
5619     id->index = 0;
5620     *ih_ret = (pkinit_cert_iter_handle) id;
5621     return 0;
5622 }
5623 
5624 /*
5625  * End iteration over the certs loaded in crypto_load_certs()
5626  */
5627 /* ARGSUSED */
5628 krb5_error_code
5629 crypto_cert_iteration_end(krb5_context context,
5630 			  pkinit_cert_iter_handle ih)
5631 {
5632     struct _pkinit_cert_iter_data *id = (struct _pkinit_cert_iter_data *)ih;
5633 
5634     if (id == NULL || id->magic != ITER_MAGIC)
5635 	return EINVAL;
5636     free(ih);
5637     return 0;
5638 }
5639 
5640 /*
5641  * Get next certificate handle
5642  */
5643 /* ARGSUSED */
5644 krb5_error_code
5645 crypto_cert_iteration_next(krb5_context context,
5646 			   pkinit_cert_iter_handle ih,
5647 			   pkinit_cert_handle *ch_ret)
5648 {
5649     struct _pkinit_cert_iter_data *id = (struct _pkinit_cert_iter_data *)ih;
5650     struct _pkinit_cert_data *cd;
5651     pkinit_identity_crypto_context id_cryptoctx;
5652 
5653     if (id == NULL || id->magic != ITER_MAGIC)
5654 	return EINVAL;
5655 
5656     if (ch_ret == NULL)
5657 	return EINVAL;
5658 
5659     id_cryptoctx = id->idctx;
5660     if (id_cryptoctx == NULL)
5661 	return EINVAL;
5662 
5663     if (id_cryptoctx->creds[id->index] == NULL)
5664 	return PKINIT_ITER_NO_MORE;
5665 
5666     cd = calloc(1, sizeof(*cd));
5667     if (cd == NULL)
5668 	return ENOMEM;
5669 
5670     cd->magic = CERT_MAGIC;
5671     cd->plgctx = id->plgctx;
5672     cd->reqctx = id->reqctx;
5673     cd->idctx = id->idctx;
5674     cd->index = id->index;
5675     cd->cred = id_cryptoctx->creds[id->index++];
5676     *ch_ret = (pkinit_cert_handle)cd;
5677     return 0;
5678 }
5679 
5680 /*
5681  * Release cert handle
5682  */
5683 /* ARGSUSED */
5684 krb5_error_code
5685 crypto_cert_release(krb5_context context,
5686 		    pkinit_cert_handle ch)
5687 {
5688     struct _pkinit_cert_data *cd = (struct _pkinit_cert_data *)ch;
5689     if (cd == NULL || cd->magic != CERT_MAGIC)
5690 	return EINVAL;
5691     free(cd);
5692     return 0;
5693 }
5694 
5695 /*
5696  * Get certificate Key Usage and Extended Key Usage
5697  */
5698 /* ARGSUSED */
5699 static krb5_error_code
5700 crypto_retieve_X509_key_usage(krb5_context context,
5701 			      pkinit_plg_crypto_context plgcctx,
5702 			      pkinit_req_crypto_context reqcctx,
5703 			      X509 *x,
5704 			      unsigned int *ret_ku_bits,
5705 			      unsigned int *ret_eku_bits)
5706 {
5707     /* Solaris Kerberos */
5708     int i;
5709     unsigned int eku_bits = 0, ku_bits = 0;
5710     ASN1_BIT_STRING *usage = NULL;
5711 
5712     if (ret_ku_bits == NULL && ret_eku_bits == NULL)
5713 	return EINVAL;
5714 
5715     if (ret_eku_bits)
5716 	*ret_eku_bits = 0;
5717     else {
5718 	pkiDebug("%s: EKUs not requested, not checking\n", __FUNCTION__);
5719 	goto check_kus;
5720     }
5721 
5722     /* Start with Extended Key usage */
5723     i = X509_get_ext_by_NID(x, NID_ext_key_usage, -1);
5724     if (i >= 0) {
5725 	EXTENDED_KEY_USAGE *eku;
5726 
5727 	eku = X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL);
5728 	if (eku) {
5729 	    for (i = 0; i < sk_ASN1_OBJECT_num(eku); i++) {
5730 		ASN1_OBJECT *certoid;
5731 		certoid = sk_ASN1_OBJECT_value(eku, i);
5732 		if ((OBJ_cmp(certoid, plgcctx->id_pkinit_KPClientAuth)) == 0)
5733 		    eku_bits |= PKINIT_EKU_PKINIT;
5734 		else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_ms_smartcard_login))) == 0)
5735 		    eku_bits |= PKINIT_EKU_MSSCLOGIN;
5736 		else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_client_auth))) == 0)
5737 		    eku_bits |= PKINIT_EKU_CLIENTAUTH;
5738 		else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_email_protect))) == 0)
5739 		    eku_bits |= PKINIT_EKU_EMAILPROTECTION;
5740 	    }
5741 	    EXTENDED_KEY_USAGE_free(eku);
5742 	}
5743     }
5744     pkiDebug("%s: returning eku 0x%08x\n", __FUNCTION__, eku_bits);
5745     *ret_eku_bits = eku_bits;
5746 
5747 check_kus:
5748     /* Now the Key Usage bits */
5749     if (ret_ku_bits)
5750 	*ret_ku_bits = 0;
5751     else {
5752 	pkiDebug("%s: KUs not requested, not checking\n", __FUNCTION__);
5753 	goto out;
5754     }
5755 
5756     /* Make sure usage exists before checking bits */
5757     usage = X509_get_ext_d2i(x, NID_key_usage, NULL, NULL);
5758     if (usage) {
5759 	if (!ku_reject(x, X509v3_KU_DIGITAL_SIGNATURE))
5760 	    ku_bits |= PKINIT_KU_DIGITALSIGNATURE;
5761 	if (!ku_reject(x, X509v3_KU_KEY_ENCIPHERMENT))
5762 	    ku_bits |= PKINIT_KU_KEYENCIPHERMENT;
5763 	ASN1_BIT_STRING_free(usage);
5764     }
5765 
5766     pkiDebug("%s: returning ku 0x%08x\n", __FUNCTION__, ku_bits);
5767     *ret_ku_bits = ku_bits;
5768 
5769 out:
5770     return 0;
5771 }
5772 
5773 /*
5774  * Return a string format of an X509_NAME in buf where
5775  * size is an in/out parameter.  On input it is the size
5776  * of the buffer, and on output it is the actual length
5777  * of the name.
5778  * If buf is NULL, returns the length req'd to hold name
5779  */
5780 static char *
5781 X509_NAME_oneline_ex(X509_NAME * a,
5782 		     char *buf,
5783 		     unsigned int *size,
5784 		     unsigned long flag)
5785 {
5786   BIO *out = NULL;
5787 
5788   out = BIO_new(BIO_s_mem ());
5789   if (X509_NAME_print_ex(out, a, 0, flag) > 0) {
5790     if (buf != NULL && *size > (int) BIO_number_written(out)) {
5791       (void) memset(buf, 0, *size);
5792       BIO_read(out, buf, (int) BIO_number_written(out));
5793     }
5794     else {
5795       *size = BIO_number_written(out);
5796     }
5797   }
5798   BIO_free(out);
5799   return (buf);
5800 }
5801 
5802 /*
5803  * Get certificate information
5804  */
5805 krb5_error_code
5806 crypto_cert_get_matching_data(krb5_context context,
5807 			      pkinit_cert_handle ch,
5808 			      pkinit_cert_matching_data **ret_md)
5809 {
5810     krb5_error_code retval;
5811     pkinit_cert_matching_data *md;
5812     krb5_principal *pkinit_sans =NULL, *upn_sans = NULL;
5813     struct _pkinit_cert_data *cd = (struct _pkinit_cert_data *)ch;
5814     int i, j;
5815     char buf[DN_BUF_LEN];
5816     unsigned int bufsize = sizeof(buf);
5817 
5818     if (cd == NULL || cd->magic != CERT_MAGIC)
5819 	return EINVAL;
5820     if (ret_md == NULL)
5821 	return EINVAL;
5822 
5823     md = calloc(1, sizeof(*md));
5824     if (md == NULL)
5825 	return ENOMEM;
5826 
5827     md->ch = ch;
5828 
5829     /* get the subject name (in rfc2253 format) */
5830     X509_NAME_oneline_ex(X509_get_subject_name(cd->cred->cert),
5831 			 buf, &bufsize, XN_FLAG_SEP_COMMA_PLUS);
5832     md->subject_dn = strdup(buf);
5833     if (md->subject_dn == NULL) {
5834 	retval = ENOMEM;
5835 	goto cleanup;
5836     }
5837 
5838     /* get the issuer name (in rfc2253 format) */
5839     X509_NAME_oneline_ex(X509_get_issuer_name(cd->cred->cert),
5840 			 buf, &bufsize, XN_FLAG_SEP_COMMA_PLUS);
5841     md->issuer_dn = strdup(buf);
5842     if (md->issuer_dn == NULL) {
5843 	retval = ENOMEM;
5844 	goto cleanup;
5845     }
5846 
5847     /* get the san data */
5848     retval = crypto_retrieve_X509_sans(context, cd->plgctx, cd->reqctx,
5849 				       cd->cred->cert, &pkinit_sans,
5850 				       &upn_sans, NULL);
5851     if (retval)
5852 	goto cleanup;
5853 
5854     j = 0;
5855     if (pkinit_sans != NULL) {
5856 	for (i = 0; pkinit_sans[i] != NULL; i++)
5857 	    j++;
5858     }
5859     if (upn_sans != NULL) {
5860 	for (i = 0; upn_sans[i] != NULL; i++)
5861 	    j++;
5862     }
5863     if (j != 0) {
5864 	md->sans = calloc((size_t)j+1, sizeof(*md->sans));
5865 	if (md->sans == NULL) {
5866 	    retval = ENOMEM;
5867 	    goto cleanup;
5868 	}
5869 	j = 0;
5870 	if (pkinit_sans != NULL) {
5871 	    for (i = 0; pkinit_sans[i] != NULL; i++)
5872 		md->sans[j++] = pkinit_sans[i];
5873 	    free(pkinit_sans);
5874 	}
5875 	if (upn_sans != NULL) {
5876 	    for (i = 0; upn_sans[i] != NULL; i++)
5877 		md->sans[j++] = upn_sans[i];
5878 	    free(upn_sans);
5879 	}
5880 	md->sans[j] = NULL;
5881     } else
5882 	md->sans = NULL;
5883 
5884     /* get the KU and EKU data */
5885 
5886     retval = crypto_retieve_X509_key_usage(context, cd->plgctx, cd->reqctx,
5887 					   cd->cred->cert,
5888 					   &md->ku_bits, &md->eku_bits);
5889     if (retval)
5890 	goto cleanup;
5891 
5892     *ret_md = md;
5893     retval = 0;
5894 cleanup:
5895     if (retval) {
5896 	if (md)
5897 	    crypto_cert_free_matching_data(context, md);
5898     }
5899     return retval;
5900 }
5901 
5902 /*
5903  * Free certificate information
5904  */
5905 krb5_error_code
5906 crypto_cert_free_matching_data(krb5_context context,
5907 		      pkinit_cert_matching_data *md)
5908 {
5909     krb5_principal p;
5910     int i;
5911 
5912     if (md == NULL)
5913 	return EINVAL;
5914     if (md->subject_dn)
5915 	free(md->subject_dn);
5916     if (md->issuer_dn)
5917 	free(md->issuer_dn);
5918     if (md->sans) {
5919 	for (i = 0, p = md->sans[i]; p != NULL; p = md->sans[++i])
5920 	    krb5_free_principal(context, p);
5921 	free(md->sans);
5922     }
5923     free(md);
5924     return 0;
5925 }
5926 
5927 /*
5928  * Make this matching certificate "the chosen one"
5929  */
5930 /* ARGSUSED */
5931 krb5_error_code
5932 crypto_cert_select(krb5_context context,
5933 		   pkinit_cert_matching_data *md)
5934 {
5935     struct _pkinit_cert_data *cd;
5936     if (md == NULL)
5937 	return EINVAL;
5938 
5939     cd = (struct _pkinit_cert_data *)md->ch;
5940     if (cd == NULL || cd->magic != CERT_MAGIC)
5941 	return EINVAL;
5942 
5943     /* copy the selected cert into our id_cryptoctx */
5944     if (cd->idctx->my_certs != NULL) {
5945 	sk_X509_pop_free(cd->idctx->my_certs, X509_free);
5946     }
5947     cd->idctx->my_certs = sk_X509_new_null();
5948     sk_X509_push(cd->idctx->my_certs, cd->cred->cert);
5949     cd->idctx->creds[cd->index]->cert = NULL;	    /* Don't free it twice */
5950     cd->idctx->cert_index = 0;
5951 
5952     if (cd->idctx->pkcs11_method != 1) {
5953 	cd->idctx->my_key = cd->cred->key;
5954 	cd->idctx->creds[cd->index]->key = NULL;    /* Don't free it twice */
5955     }
5956 #ifndef WITHOUT_PKCS11
5957     else {
5958 	cd->idctx->cert_id = cd->cred->cert_id;
5959 	cd->idctx->creds[cd->index]->cert_id = NULL; /* Don't free it twice */
5960 	cd->idctx->cert_id_len = cd->cred->cert_id_len;
5961     }
5962 #endif
5963     return 0;
5964 }
5965 
5966 /*
5967  * Choose the default certificate as "the chosen one"
5968  */
5969 krb5_error_code
5970 crypto_cert_select_default(krb5_context context,
5971 			   pkinit_plg_crypto_context plg_cryptoctx,
5972 			   pkinit_req_crypto_context req_cryptoctx,
5973 			   pkinit_identity_crypto_context id_cryptoctx)
5974 {
5975     krb5_error_code retval;
5976     int cert_count = 0;
5977 
5978     retval = crypto_cert_get_count(context, plg_cryptoctx, req_cryptoctx,
5979 				   id_cryptoctx, &cert_count);
5980     if (retval) {
5981 	pkiDebug("%s: crypto_cert_get_count error %d, %s\n",
5982 		 __FUNCTION__, retval, error_message(retval));
5983 	goto errout;
5984     }
5985     if (cert_count != 1) {
5986 	/* Solaris Kerberos: Improved error messages */
5987 	retval = EINVAL;
5988 	krb5_set_error_message(context, retval,
5989 	    gettext("Failed to select default certificate: "
5990 	        "found %d certs to choose from but there must be exactly one"),
5991 	    cert_count);
5992 	pkiDebug("%s: ERROR: There are %d certs to choose from, "
5993 		 "but there must be exactly one.\n",
5994 		 __FUNCTION__, cert_count);
5995 	goto errout;
5996     }
5997     /* copy the selected cert into our id_cryptoctx */
5998     if (id_cryptoctx->my_certs != NULL) {
5999 	sk_X509_pop_free(id_cryptoctx->my_certs, X509_free);
6000     }
6001     id_cryptoctx->my_certs = sk_X509_new_null();
6002     sk_X509_push(id_cryptoctx->my_certs, id_cryptoctx->creds[0]->cert);
6003     id_cryptoctx->creds[0]->cert = NULL;	/* Don't free it twice */
6004     id_cryptoctx->cert_index = 0;
6005 
6006     if (id_cryptoctx->pkcs11_method != 1) {
6007 	id_cryptoctx->my_key = id_cryptoctx->creds[0]->key;
6008 	id_cryptoctx->creds[0]->key = NULL;	/* Don't free it twice */
6009     }
6010 #ifndef WITHOUT_PKCS11
6011     else {
6012 	id_cryptoctx->cert_id = id_cryptoctx->creds[0]->cert_id;
6013 	id_cryptoctx->creds[0]->cert_id = NULL; /* Don't free it twice */
6014 	id_cryptoctx->cert_id_len = id_cryptoctx->creds[0]->cert_id_len;
6015     }
6016 #endif
6017     retval = 0;
6018 errout:
6019     return retval;
6020 }
6021 
6022 
6023 /* ARGSUSED */
6024 static krb5_error_code
6025 load_cas_and_crls(krb5_context context,
6026 		  pkinit_plg_crypto_context plg_cryptoctx,
6027 		  pkinit_req_crypto_context req_cryptoctx,
6028 		  pkinit_identity_crypto_context id_cryptoctx,
6029 		  int catype,
6030 		  char *filename)
6031 {
6032     STACK_OF(X509_INFO) *sk = NULL;
6033     STACK_OF(X509) *ca_certs = NULL;
6034     STACK_OF(X509_CRL) *ca_crls = NULL;
6035     BIO *in = NULL;
6036     /* Solaris Kerberos */
6037     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
6038     int i = 0;
6039 
6040     /* If there isn't already a stack in the context,
6041      * create a temporary one now */
6042     switch(catype) {
6043     case CATYPE_ANCHORS:
6044 	if (id_cryptoctx->trustedCAs != NULL)
6045 	    ca_certs = id_cryptoctx->trustedCAs;
6046 	else {
6047 	    ca_certs = sk_X509_new_null();
6048 	    if (ca_certs == NULL)
6049 		return ENOMEM;
6050 	}
6051 	break;
6052     case CATYPE_INTERMEDIATES:
6053 	if (id_cryptoctx->intermediateCAs != NULL)
6054 	    ca_certs = id_cryptoctx->intermediateCAs;
6055 	else {
6056 	    ca_certs = sk_X509_new_null();
6057 	    if (ca_certs == NULL)
6058 		return ENOMEM;
6059 	}
6060 	break;
6061     case CATYPE_CRLS:
6062 	if (id_cryptoctx->revoked != NULL)
6063 	    ca_crls = id_cryptoctx->revoked;
6064 	else {
6065 	    ca_crls = sk_X509_CRL_new_null();
6066 	    if (ca_crls == NULL)
6067 		return ENOMEM;
6068 	}
6069 	break;
6070     default:
6071 	return ENOTSUP;
6072     }
6073 
6074     if (!(in = BIO_new_file(filename, "r"))) {
6075 	retval = errno;
6076 	pkiDebug("%s: error opening file '%s': %s\n", __FUNCTION__,
6077 		 filename, error_message(errno));
6078 	goto cleanup;
6079     }
6080 
6081     /* This loads from a file, a stack of x509/crl/pkey sets */
6082     if ((sk = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL)) == NULL) {
6083 	pkiDebug("%s: error reading file '%s'\n", __FUNCTION__, filename);
6084 	retval = EIO;
6085 	goto cleanup;
6086     }
6087 
6088     /* scan over the stack created from loading the file contents,
6089      * weed out duplicates, and push new ones onto the return stack
6090      */
6091     for (i = 0; i < sk_X509_INFO_num(sk); i++) {
6092 	X509_INFO *xi = sk_X509_INFO_value(sk, i);
6093 	if (xi != NULL && xi->x509 != NULL && catype != CATYPE_CRLS) {
6094 	    int j = 0, size = sk_X509_num(ca_certs), flag = 0;
6095 
6096 	    if (!size) {
6097 		sk_X509_push(ca_certs, xi->x509);
6098 		xi->x509 = NULL;
6099 		continue;
6100 	    }
6101 	    for (j = 0; j < size; j++) {
6102 		X509 *x = sk_X509_value(ca_certs, j);
6103 		flag = X509_cmp(x, xi->x509);
6104 		if (flag == 0)
6105 		    break;
6106 		else
6107 		    continue;
6108 	    }
6109 	    if (flag != 0) {
6110 		sk_X509_push(ca_certs, X509_dup(xi->x509));
6111 	    }
6112 	} else if (xi != NULL && xi->crl != NULL && catype == CATYPE_CRLS) {
6113 	    int j = 0, size = sk_X509_CRL_num(ca_crls), flag = 0;
6114 	    if (!size) {
6115 		sk_X509_CRL_push(ca_crls, xi->crl);
6116 		xi->crl = NULL;
6117 		continue;
6118 	    }
6119 	    for (j = 0; j < size; j++) {
6120 		X509_CRL *x = sk_X509_CRL_value(ca_crls, j);
6121 		flag = X509_CRL_cmp(x, xi->crl);
6122 		if (flag == 0)
6123 		    break;
6124 		else
6125 		    continue;
6126 	    }
6127 	    if (flag != 0) {
6128 		sk_X509_CRL_push(ca_crls, X509_CRL_dup(xi->crl));
6129 	    }
6130 	}
6131     }
6132 
6133     /* If we added something and there wasn't a stack in the
6134      * context before, add the temporary stack to the context.
6135      */
6136     switch(catype) {
6137     case CATYPE_ANCHORS:
6138 	if (sk_X509_num(ca_certs) == 0) {
6139 	    pkiDebug("no anchors in file, %s\n", filename);
6140 	    if (id_cryptoctx->trustedCAs == NULL)
6141 		sk_X509_free(ca_certs);
6142 	} else {
6143 	    if (id_cryptoctx->trustedCAs == NULL)
6144 		id_cryptoctx->trustedCAs = ca_certs;
6145 	}
6146 	break;
6147     case CATYPE_INTERMEDIATES:
6148 	if (sk_X509_num(ca_certs) == 0) {
6149 	    pkiDebug("no intermediates in file, %s\n", filename);
6150 	    if (id_cryptoctx->intermediateCAs == NULL)
6151 		sk_X509_free(ca_certs);
6152 	} else {
6153 	    if (id_cryptoctx->intermediateCAs == NULL)
6154 		id_cryptoctx->intermediateCAs = ca_certs;
6155 	}
6156 	break;
6157     case CATYPE_CRLS:
6158 	if (sk_X509_CRL_num(ca_crls) == 0) {
6159 	    pkiDebug("no crls in file, %s\n", filename);
6160 	    if (id_cryptoctx->revoked == NULL)
6161 		sk_X509_CRL_free(ca_crls);
6162 	} else {
6163 	    if (id_cryptoctx->revoked == NULL)
6164 		id_cryptoctx->revoked = ca_crls;
6165 	}
6166 	break;
6167     default:
6168 	/* Should have been caught above! */
6169 	retval = EINVAL;
6170 	goto cleanup;
6171 	/* Solaris Kerberos: removed "break" as it's never reached */
6172     }
6173 
6174     retval = 0;
6175 
6176   cleanup:
6177     if (in != NULL)
6178 	BIO_free(in);
6179     if (sk != NULL)
6180 	sk_X509_INFO_pop_free(sk, X509_INFO_free);
6181 
6182     return retval;
6183 }
6184 
6185 static krb5_error_code
6186 load_cas_and_crls_dir(krb5_context context,
6187 		      pkinit_plg_crypto_context plg_cryptoctx,
6188 		      pkinit_req_crypto_context req_cryptoctx,
6189 		      pkinit_identity_crypto_context id_cryptoctx,
6190 		      int catype,
6191 		      char *dirname)
6192 {
6193     krb5_error_code retval = EINVAL;
6194     DIR *d = NULL;
6195     struct dirent *dentry = NULL;
6196     char filename[1024];
6197 
6198     if (dirname == NULL)
6199 	return EINVAL;
6200 
6201     d = opendir(dirname);
6202     if (d == NULL)
6203 	return ENOENT;
6204 
6205     while ((dentry = readdir(d))) {
6206 	if (strlen(dirname) + strlen(dentry->d_name) + 2 > sizeof(filename)) {
6207 	    pkiDebug("%s: Path too long -- directory '%s' and file '%s'\n",
6208 		     __FUNCTION__, dirname, dentry->d_name);
6209 	    goto cleanup;
6210 	}
6211 	/* Ignore subdirectories and anything starting with a dot */
6212 #ifdef DT_DIR
6213 	if (dentry->d_type == DT_DIR)
6214 	    continue;
6215 #endif
6216 	if (dentry->d_name[0] == '.')
6217 	    continue;
6218 	(void) snprintf(filename, sizeof(filename), "%s/%s", dirname, dentry->d_name);
6219 
6220 	retval = load_cas_and_crls(context, plg_cryptoctx, req_cryptoctx,
6221 				   id_cryptoctx, catype, filename);
6222 	if (retval)
6223 	    goto cleanup;
6224     }
6225 
6226     retval = 0;
6227 
6228   cleanup:
6229     if (d != NULL)
6230 	(void) closedir(d);
6231 
6232     return retval;
6233 }
6234 
6235 /* ARGSUSED */
6236 krb5_error_code
6237 crypto_load_cas_and_crls(krb5_context context,
6238 			 pkinit_plg_crypto_context plg_cryptoctx,
6239 			 pkinit_req_crypto_context req_cryptoctx,
6240 			 pkinit_identity_opts *idopts,
6241 			 pkinit_identity_crypto_context id_cryptoctx,
6242 			 int idtype,
6243 			 int catype,
6244 			 char *id)
6245 {
6246     pkiDebug("%s: called with idtype %s and catype %s\n",
6247 	     __FUNCTION__, idtype2string(idtype), catype2string(catype));
6248     /* Solaris Kerberos: Removed "break"'s as they are never reached */
6249     switch (idtype) {
6250     case IDTYPE_FILE:
6251 	return load_cas_and_crls(context, plg_cryptoctx, req_cryptoctx,
6252 				 id_cryptoctx, catype, id);
6253     case IDTYPE_DIR:
6254 	return load_cas_and_crls_dir(context, plg_cryptoctx, req_cryptoctx,
6255 				     id_cryptoctx, catype, id);
6256     default:
6257 	return ENOTSUP;
6258     }
6259 }
6260 
6261 static krb5_error_code
6262 create_identifiers_from_stack(STACK_OF(X509) *sk,
6263 			      krb5_external_principal_identifier *** ids)
6264 {
6265     krb5_error_code retval = ENOMEM;
6266     int i = 0, sk_size = sk_X509_num(sk);
6267     krb5_external_principal_identifier **krb5_cas = NULL;
6268     X509 *x = NULL;
6269     X509_NAME *xn = NULL;
6270     unsigned char *p = NULL;
6271     int len = 0;
6272     PKCS7_ISSUER_AND_SERIAL *is = NULL;
6273     char buf[DN_BUF_LEN];
6274 
6275     *ids = NULL;
6276 
6277     krb5_cas =
6278 	malloc((sk_size + 1) * sizeof(krb5_external_principal_identifier *));
6279     if (krb5_cas == NULL)
6280 	return ENOMEM;
6281     krb5_cas[sk_size] = NULL;
6282 
6283     for (i = 0; i < sk_size; i++) {
6284 	krb5_cas[i] = (krb5_external_principal_identifier *)malloc(sizeof(krb5_external_principal_identifier));
6285 
6286 	x = sk_X509_value(sk, i);
6287 
6288 	X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
6289 	pkiDebug("#%d cert= %s\n", i, buf);
6290 
6291 	/* fill-in subjectName */
6292 	krb5_cas[i]->subjectName.magic = 0;
6293 	krb5_cas[i]->subjectName.length = 0;
6294 	krb5_cas[i]->subjectName.data = NULL;
6295 
6296 	xn = X509_get_subject_name(x);
6297 	len = i2d_X509_NAME(xn, NULL);
6298 	if ((p = krb5_cas[i]->subjectName.data = (unsigned char *)malloc((size_t) len)) == NULL)
6299 	    goto cleanup;
6300 	i2d_X509_NAME(xn, &p);
6301 	krb5_cas[i]->subjectName.length = len;
6302 
6303 	/* fill-in issuerAndSerialNumber */
6304 	krb5_cas[i]->issuerAndSerialNumber.length = 0;
6305 	krb5_cas[i]->issuerAndSerialNumber.magic = 0;
6306 	krb5_cas[i]->issuerAndSerialNumber.data = NULL;
6307 
6308 #ifdef LONGHORN_BETA_COMPAT
6309 if (longhorn == 0) { /* XXX Longhorn doesn't like this */
6310 #endif
6311 	is = PKCS7_ISSUER_AND_SERIAL_new();
6312 	X509_NAME_set(&is->issuer, X509_get_issuer_name(x));
6313 	ASN1_INTEGER_free(is->serial);
6314 	is->serial = ASN1_INTEGER_dup(X509_get_serialNumber(x));
6315 	len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
6316 	if ((p = krb5_cas[i]->issuerAndSerialNumber.data =
6317 	     (unsigned char *)malloc((size_t) len)) == NULL)
6318 	    goto cleanup;
6319 	i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
6320 	krb5_cas[i]->issuerAndSerialNumber.length = len;
6321 #ifdef LONGHORN_BETA_COMPAT
6322 }
6323 #endif
6324 
6325 	/* fill-in subjectKeyIdentifier */
6326 	krb5_cas[i]->subjectKeyIdentifier.length = 0;
6327 	krb5_cas[i]->subjectKeyIdentifier.magic = 0;
6328 	krb5_cas[i]->subjectKeyIdentifier.data = NULL;
6329 
6330 
6331 #ifdef LONGHORN_BETA_COMPAT
6332 if (longhorn == 0) {	/* XXX Longhorn doesn't like this */
6333 #endif
6334 	if (X509_get_ext_by_NID(x, NID_subject_key_identifier, -1) >= 0) {
6335 	    ASN1_OCTET_STRING *ikeyid = NULL;
6336 
6337 	    if ((ikeyid = X509_get_ext_d2i(x, NID_subject_key_identifier, NULL,
6338 					   NULL))) {
6339 		len = i2d_ASN1_OCTET_STRING(ikeyid, NULL);
6340 		if ((p = krb5_cas[i]->subjectKeyIdentifier.data =
6341 			(unsigned char *)malloc((size_t) len)) == NULL)
6342 		    goto cleanup;
6343 		i2d_ASN1_OCTET_STRING(ikeyid, &p);
6344 		krb5_cas[i]->subjectKeyIdentifier.length = len;
6345 	    }
6346 	    if (ikeyid != NULL)
6347 		ASN1_OCTET_STRING_free(ikeyid);
6348 	}
6349 #ifdef LONGHORN_BETA_COMPAT
6350 }
6351 #endif
6352 	if (is != NULL) {
6353 	    if (is->issuer != NULL)
6354 		X509_NAME_free(is->issuer);
6355 	    if (is->serial != NULL)
6356 		ASN1_INTEGER_free(is->serial);
6357 	    free(is);
6358 	}
6359     }
6360 
6361     *ids = krb5_cas;
6362 
6363     retval = 0;
6364   cleanup:
6365     if (retval)
6366 	free_krb5_external_principal_identifier(&krb5_cas);
6367 
6368     return retval;
6369 }
6370 
6371 /* ARGSUSED */
6372 static krb5_error_code
6373 create_krb5_invalidCertificates(krb5_context context,
6374 				pkinit_plg_crypto_context plg_cryptoctx,
6375 				pkinit_req_crypto_context req_cryptoctx,
6376 				pkinit_identity_crypto_context id_cryptoctx,
6377 				krb5_external_principal_identifier *** ids)
6378 {
6379 
6380     krb5_error_code retval = ENOMEM;
6381     STACK_OF(X509) *sk = NULL;
6382 
6383     *ids = NULL;
6384     if (req_cryptoctx->received_cert == NULL)
6385 	return KRB5KDC_ERR_PREAUTH_FAILED;
6386 
6387     sk = sk_X509_new_null();
6388     if (sk == NULL)
6389 	goto cleanup;
6390     sk_X509_push(sk, req_cryptoctx->received_cert);
6391 
6392     retval = create_identifiers_from_stack(sk, ids);
6393 
6394     sk_X509_free(sk);
6395 cleanup:
6396 
6397     return retval;
6398 }
6399 
6400 /* ARGSUSED */
6401 krb5_error_code
6402 create_krb5_supportedCMSTypes(krb5_context context,
6403 			      pkinit_plg_crypto_context plg_cryptoctx,
6404 			      pkinit_req_crypto_context req_cryptoctx,
6405 			      pkinit_identity_crypto_context id_cryptoctx,
6406 			      krb5_algorithm_identifier ***oids)
6407 {
6408 
6409     krb5_error_code retval = ENOMEM;
6410     krb5_algorithm_identifier **loids = NULL;
6411     krb5_octet_data des3oid = {0, 8, (unsigned char *)"\x2A\x86\x48\x86\xF7\x0D\x03\x07" };
6412 
6413     *oids = NULL;
6414     loids = malloc(2 * sizeof(krb5_algorithm_identifier *));
6415     if (loids == NULL)
6416 	goto cleanup;
6417     loids[1] = NULL;
6418     loids[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
6419     if (loids[0] == NULL) {
6420 	free(loids);
6421 	goto cleanup;
6422     }
6423     retval = pkinit_copy_krb5_octet_data(&loids[0]->algorithm, &des3oid);
6424     if (retval) {
6425 	free(loids[0]);
6426 	free(loids);
6427 	goto cleanup;
6428     }
6429     loids[0]->parameters.length = 0;
6430     loids[0]->parameters.data = NULL;
6431 
6432     *oids = loids;
6433     retval = 0;
6434 cleanup:
6435 
6436     return retval;
6437 }
6438 
6439 /* ARGSUSED */
6440 krb5_error_code
6441 create_krb5_trustedCertifiers(krb5_context context,
6442 			      pkinit_plg_crypto_context plg_cryptoctx,
6443 			      pkinit_req_crypto_context req_cryptoctx,
6444 			      pkinit_identity_crypto_context id_cryptoctx,
6445 			      krb5_external_principal_identifier *** ids)
6446 {
6447 
6448     /* Solaris Kerberos */
6449     STACK_OF(X509) *sk = id_cryptoctx->trustedCAs;
6450 
6451     *ids = NULL;
6452     if (id_cryptoctx->trustedCAs == NULL)
6453 	return KRB5KDC_ERR_PREAUTH_FAILED;
6454 
6455     return create_identifiers_from_stack(sk, ids);
6456 
6457 }
6458 
6459 /* ARGSUSED */
6460 krb5_error_code
6461 create_krb5_trustedCas(krb5_context context,
6462 		       pkinit_plg_crypto_context plg_cryptoctx,
6463 		       pkinit_req_crypto_context req_cryptoctx,
6464 		       pkinit_identity_crypto_context id_cryptoctx,
6465 		       int flag,
6466 		       krb5_trusted_ca *** ids)
6467 {
6468     krb5_error_code retval = ENOMEM;
6469     STACK_OF(X509) *sk = id_cryptoctx->trustedCAs;
6470     int i = 0, len = 0, sk_size = sk_X509_num(sk);
6471     krb5_trusted_ca **krb5_cas = NULL;
6472     X509 *x = NULL;
6473     char buf[DN_BUF_LEN];
6474     X509_NAME *xn = NULL;
6475     unsigned char *p = NULL;
6476     PKCS7_ISSUER_AND_SERIAL *is = NULL;
6477 
6478     *ids = NULL;
6479     if (id_cryptoctx->trustedCAs == NULL)
6480 	return KRB5KDC_ERR_PREAUTH_FAILED;
6481 
6482     krb5_cas = malloc((sk_size + 1) * sizeof(krb5_trusted_ca *));
6483     if (krb5_cas == NULL)
6484 	return ENOMEM;
6485     krb5_cas[sk_size] = NULL;
6486 
6487     for (i = 0; i < sk_size; i++) {
6488 	krb5_cas[i] = (krb5_trusted_ca *)malloc(sizeof(krb5_trusted_ca));
6489 	if (krb5_cas[i] == NULL)
6490 	    goto cleanup;
6491 	x = sk_X509_value(sk, i);
6492 
6493 	X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
6494 	pkiDebug("#%d cert= %s\n", i, buf);
6495 
6496 	switch (flag) {
6497 	    case choice_trusted_cas_principalName:
6498 		krb5_cas[i]->choice = choice_trusted_cas_principalName;
6499 		break;
6500 	    case choice_trusted_cas_caName:
6501 		krb5_cas[i]->choice = choice_trusted_cas_caName;
6502 		krb5_cas[i]->u.caName.data = NULL;
6503 		krb5_cas[i]->u.caName.length = 0;
6504 		xn = X509_get_subject_name(x);
6505 		len = i2d_X509_NAME(xn, NULL);
6506 		if ((p = krb5_cas[i]->u.caName.data =
6507 		    (unsigned char *)malloc((size_t) len)) == NULL)
6508 		    goto cleanup;
6509 		i2d_X509_NAME(xn, &p);
6510 		krb5_cas[i]->u.caName.length = len;
6511 		break;
6512 	    case choice_trusted_cas_issuerAndSerial:
6513 		krb5_cas[i]->choice = choice_trusted_cas_issuerAndSerial;
6514 		krb5_cas[i]->u.issuerAndSerial.data = NULL;
6515 		krb5_cas[i]->u.issuerAndSerial.length = 0;
6516 		is = PKCS7_ISSUER_AND_SERIAL_new();
6517 		X509_NAME_set(&is->issuer, X509_get_issuer_name(x));
6518 		ASN1_INTEGER_free(is->serial);
6519 		is->serial = ASN1_INTEGER_dup(X509_get_serialNumber(x));
6520 		len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
6521 		if ((p = krb5_cas[i]->u.issuerAndSerial.data =
6522 		    (unsigned char *)malloc((size_t) len)) == NULL)
6523 		    goto cleanup;
6524 		i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
6525 		krb5_cas[i]->u.issuerAndSerial.length = len;
6526 		if (is != NULL) {
6527 		    if (is->issuer != NULL)
6528 			X509_NAME_free(is->issuer);
6529 		    if (is->serial != NULL)
6530 			ASN1_INTEGER_free(is->serial);
6531 		    free(is);
6532 		}
6533 		break;
6534 	    default: break;
6535 	}
6536     }
6537     retval = 0;
6538     *ids = krb5_cas;
6539 cleanup:
6540     if (retval)
6541 	free_krb5_trusted_ca(&krb5_cas);
6542 
6543     return retval;
6544 }
6545 
6546 /* ARGSUSED */
6547 krb5_error_code
6548 create_issuerAndSerial(krb5_context context,
6549 		       pkinit_plg_crypto_context plg_cryptoctx,
6550 		       pkinit_req_crypto_context req_cryptoctx,
6551 		       pkinit_identity_crypto_context id_cryptoctx,
6552 		       unsigned char **out,
6553 		       unsigned int *out_len)
6554 {
6555     unsigned char *p = NULL;
6556     PKCS7_ISSUER_AND_SERIAL *is = NULL;
6557     int len = 0;
6558     krb5_error_code retval = ENOMEM;
6559     X509 *cert = req_cryptoctx->received_cert;
6560 
6561     *out = NULL;
6562     *out_len = 0;
6563     if (req_cryptoctx->received_cert == NULL)
6564 	return 0;
6565 
6566     is = PKCS7_ISSUER_AND_SERIAL_new();
6567     X509_NAME_set(&is->issuer, X509_get_issuer_name(cert));
6568     ASN1_INTEGER_free(is->serial);
6569     is->serial = ASN1_INTEGER_dup(X509_get_serialNumber(cert));
6570     len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
6571     if ((p = *out = (unsigned char *)malloc((size_t) len)) == NULL)
6572 	goto cleanup;
6573     i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
6574     *out_len = len;
6575     retval = 0;
6576 
6577 cleanup:
6578     X509_NAME_free(is->issuer);
6579     ASN1_INTEGER_free(is->serial);
6580     free(is);
6581 
6582     return retval;
6583 }
6584 
6585 static int
6586 pkcs7_decrypt(krb5_context context,
6587 	      pkinit_identity_crypto_context id_cryptoctx,
6588 	      PKCS7 *p7,
6589 	      BIO *data)
6590 {
6591     BIO *tmpmem = NULL;
6592     /* Solaris Kerberos */
6593     int i = 0;
6594     char buf[4096];
6595 
6596     if(p7 == NULL)
6597 	return 0;
6598 
6599     if(!PKCS7_type_is_enveloped(p7)) {
6600 	pkiDebug("wrong pkcs7 content type\n");
6601 	return 0;
6602     }
6603 
6604     if(!(tmpmem = pkcs7_dataDecode(context, id_cryptoctx, p7))) {
6605 	pkiDebug("unable to decrypt pkcs7 object\n");
6606 	return 0;
6607     }
6608 /* Solaris Kerberos: Suppress sun studio compiler warning */
6609 #pragma error_messages (off, E_END_OF_LOOP_CODE_NOT_REACHED)
6610     for(;;) {
6611 	i = BIO_read(tmpmem, buf, sizeof(buf));
6612 	if (i <= 0) break;
6613 	BIO_write(data, buf, i);
6614 	BIO_free_all(tmpmem);
6615 	return 1;
6616     }
6617 #pragma error_messages (default, E_END_OF_LOOP_CODE_NOT_REACHED)
6618 
6619     return 0;
6620 }
6621 
6622 krb5_error_code
6623 pkinit_process_td_trusted_certifiers(
6624     krb5_context context,
6625     pkinit_plg_crypto_context plg_cryptoctx,
6626     pkinit_req_crypto_context req_cryptoctx,
6627     pkinit_identity_crypto_context id_cryptoctx,
6628     krb5_external_principal_identifier **krb5_trusted_certifiers,
6629     int td_type)
6630 {
6631     krb5_error_code retval = ENOMEM;
6632     STACK_OF(X509_NAME) *sk_xn = NULL;
6633     X509_NAME *xn = NULL;
6634     PKCS7_ISSUER_AND_SERIAL *is = NULL;
6635     ASN1_OCTET_STRING *id = NULL;
6636     const unsigned char *p = NULL;
6637     char buf[DN_BUF_LEN];
6638     int i = 0;
6639 
6640     if (td_type == TD_TRUSTED_CERTIFIERS)
6641 	pkiDebug("received trusted certifiers\n");
6642     else
6643 	pkiDebug("received invalid certificate\n");
6644 
6645     sk_xn = sk_X509_NAME_new_null();
6646     while(krb5_trusted_certifiers[i] != NULL) {
6647 	if (krb5_trusted_certifiers[i]->subjectName.data != NULL) {
6648 	    p = krb5_trusted_certifiers[i]->subjectName.data;
6649 	    xn = d2i_X509_NAME(NULL, &p,
6650 		(int)krb5_trusted_certifiers[i]->subjectName.length);
6651 	    if (xn == NULL)
6652 		goto cleanup;
6653 	    X509_NAME_oneline(xn, buf, sizeof(buf));
6654 	    if (td_type == TD_TRUSTED_CERTIFIERS)
6655 		pkiDebug("#%d cert = %s is trusted by kdc\n", i, buf);
6656 	    else
6657 		pkiDebug("#%d cert = %s is invalid\n", i, buf);
6658 		sk_X509_NAME_push(sk_xn, xn);
6659 	}
6660 
6661 	if (krb5_trusted_certifiers[i]->issuerAndSerialNumber.data != NULL) {
6662 	    p = krb5_trusted_certifiers[i]->issuerAndSerialNumber.data;
6663 	    is = d2i_PKCS7_ISSUER_AND_SERIAL(NULL, &p,
6664 		(int)krb5_trusted_certifiers[i]->issuerAndSerialNumber.length);
6665 	    if (is == NULL)
6666 		goto cleanup;
6667 	    X509_NAME_oneline(is->issuer, buf, sizeof(buf));
6668 	    if (td_type == TD_TRUSTED_CERTIFIERS)
6669 		pkiDebug("#%d issuer = %s serial = %ld is trusted bu kdc\n", i,
6670 			 buf, ASN1_INTEGER_get(is->serial));
6671 	    else
6672 		pkiDebug("#%d issuer = %s serial = %ld is invalid\n", i, buf,
6673 			 ASN1_INTEGER_get(is->serial));
6674 	    PKCS7_ISSUER_AND_SERIAL_free(is);
6675 	}
6676 
6677 	if (krb5_trusted_certifiers[i]->subjectKeyIdentifier.data != NULL) {
6678 	    p = krb5_trusted_certifiers[i]->subjectKeyIdentifier.data;
6679 	    id = d2i_ASN1_OCTET_STRING(NULL, &p,
6680 		(int)krb5_trusted_certifiers[i]->subjectKeyIdentifier.length);
6681 	    if (id == NULL)
6682 		goto cleanup;
6683 	    /* XXX */
6684 	    ASN1_OCTET_STRING_free(id);
6685 	}
6686 	i++;
6687     }
6688     /* XXX Since we not doing anything with received trusted certifiers
6689      * return an error. this is the place where we can pick a different
6690      * client certificate based on the information in td_trusted_certifiers
6691      */
6692     retval = KRB5KDC_ERR_PREAUTH_FAILED;
6693 cleanup:
6694     if (sk_xn != NULL)
6695 	sk_X509_NAME_pop_free(sk_xn, X509_NAME_free);
6696 
6697     return retval;
6698 }
6699 
6700 static BIO *
6701 pkcs7_dataDecode(krb5_context context,
6702 		 pkinit_identity_crypto_context id_cryptoctx,
6703 		 PKCS7 *p7)
6704 {
6705     int i = 0;
6706     unsigned int jj = 0, tmp_len = 0;
6707     BIO *out=NULL,*etmp=NULL,*bio=NULL;
6708     unsigned char *tmp=NULL;
6709     ASN1_OCTET_STRING *data_body=NULL;
6710     const EVP_CIPHER *evp_cipher=NULL;
6711     EVP_CIPHER_CTX *evp_ctx=NULL;
6712     X509_ALGOR *enc_alg=NULL;
6713     STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL;
6714 /* Solaris Kerberos: Not used */
6715 #if 0
6716     X509_ALGOR *xalg=NULL;
6717 #endif
6718     PKCS7_RECIP_INFO *ri=NULL;
6719     X509 *cert = sk_X509_value(id_cryptoctx->my_certs,
6720 	id_cryptoctx->cert_index);
6721 
6722     p7->state=PKCS7_S_HEADER;
6723 
6724     rsk=p7->d.enveloped->recipientinfo;
6725     enc_alg=p7->d.enveloped->enc_data->algorithm;
6726     data_body=p7->d.enveloped->enc_data->enc_data;
6727     evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm);
6728     if (evp_cipher == NULL) {
6729 	PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
6730 	goto cleanup;
6731     }
6732 /* Solaris Kerberos: Not used */
6733 #if 0
6734     xalg=p7->d.enveloped->enc_data->algorithm;
6735 #endif
6736 
6737     if ((etmp=BIO_new(BIO_f_cipher())) == NULL) {
6738 	PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB);
6739 	goto cleanup;
6740     }
6741 
6742     /* It was encrypted, we need to decrypt the secret key
6743      * with the private key */
6744 
6745     /* Find the recipientInfo which matches the passed certificate
6746      * (if any)
6747      */
6748 
6749     if (cert) {
6750 	for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) {
6751 	    int tmp_ret = 0;
6752 	    ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
6753 	    tmp_ret = X509_NAME_cmp(ri->issuer_and_serial->issuer,
6754 		X509_get_issuer_name(cert));
6755 	    if (!tmp_ret) {
6756 		tmp_ret = ASN1_INTEGER_cmp(X509_get_serialNumber(cert),
6757 					     ri->issuer_and_serial->serial);
6758 		if (!tmp_ret)
6759 		    break;
6760 	    }
6761 	    ri=NULL;
6762 	}
6763 	if (ri == NULL) {
6764 	    PKCS7err(PKCS7_F_PKCS7_DATADECODE,
6765 		     PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE);
6766 	    goto cleanup;
6767 	}
6768 
6769     }
6770 
6771     /* If we haven't got a certificate try each ri in turn */
6772 
6773     if (cert == NULL) {
6774 	for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) {
6775 	    ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
6776 	    jj = pkinit_decode_data(context, id_cryptoctx,
6777 		(unsigned char *)ASN1_STRING_get0_data(ri->enc_key),
6778 		ASN1_STRING_length(ri->enc_key),
6779 		&tmp, &tmp_len);
6780 	    if (jj) {
6781 		PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_EVP_LIB);
6782 		goto cleanup;
6783 	    }
6784 
6785 	    if (!jj && tmp_len > 0) {
6786 		jj = tmp_len;
6787 		break;
6788 	    }
6789 
6790 	    ERR_clear_error();
6791 	    ri = NULL;
6792 	}
6793 
6794 	if (ri == NULL) {
6795 	    PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE);
6796 	    goto cleanup;
6797 	}
6798     }
6799     else {
6800 	jj = pkinit_decode_data(context, id_cryptoctx,
6801 	    (unsigned char *)ASN1_STRING_get0_data(ri->enc_key),
6802 	    ASN1_STRING_length(ri->enc_key),
6803 	    &tmp, &tmp_len);
6804 	/* Solaris Kerberos: tmp_len is unsigned. Cannot be < 0 */
6805 	if (jj || tmp_len == 0) {
6806 	    PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_EVP_LIB);
6807 	    goto cleanup;
6808 	}
6809 	jj = tmp_len;
6810     }
6811 
6812     evp_ctx=NULL;
6813     BIO_get_cipher_ctx(etmp,&evp_ctx);
6814     if (EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0) <= 0)
6815 	goto cleanup;
6816     if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0)
6817 	goto cleanup;
6818 
6819     if (jj != EVP_CIPHER_CTX_key_length(evp_ctx)) {
6820 	/* Some S/MIME clients don't use the same key
6821 	 * and effective key length. The key length is
6822 	 * determined by the size of the decrypted RSA key.
6823 	 */
6824 	if(!EVP_CIPHER_CTX_set_key_length(evp_ctx, (int)jj)) {
6825 	    PKCS7err(PKCS7_F_PKCS7_DATADECODE,
6826 		     PKCS7_R_DECRYPT_ERROR);
6827 	    goto cleanup;
6828 	}
6829     }
6830     if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,tmp,NULL,0) <= 0)
6831 	goto cleanup;
6832 
6833     OPENSSL_cleanse(tmp,jj);
6834 
6835     if (out == NULL)
6836 	out=etmp;
6837     else
6838 	BIO_push(out,etmp);
6839     etmp=NULL;
6840 
6841     if (data_body->length > 0)
6842 	bio = BIO_new_mem_buf(data_body->data, data_body->length);
6843     else {
6844 	bio=BIO_new(BIO_s_mem());
6845 	BIO_set_mem_eof_return(bio,0);
6846     }
6847     BIO_push(out,bio);
6848     bio=NULL;
6849 
6850     /* Solaris Kerberos */
6851     goto out;
6852 
6853 cleanup:
6854 	if (out != NULL) BIO_free_all(out);
6855 	if (etmp != NULL) BIO_free_all(etmp);
6856 	if (bio != NULL) BIO_free_all(bio);
6857 	out=NULL;
6858 
6859 out:
6860     if (tmp != NULL)
6861 	free(tmp);
6862 
6863     return(out);
6864 }
6865 
6866 static krb5_error_code
6867 der_decode_data(unsigned char *data, long data_len,
6868 		unsigned char **out, long *out_len)
6869 {
6870     /* Solaris Kerberos */
6871     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
6872     ASN1_OCTET_STRING *s = NULL;
6873     const unsigned char *p = data;
6874 
6875     if ((s = d2i_ASN1_BIT_STRING(NULL, &p, data_len)) == NULL)
6876 	goto cleanup;
6877     *out_len = s->length;
6878     if ((*out = (unsigned char *) malloc((size_t) *out_len + 1)) == NULL) {
6879 	retval = ENOMEM;
6880 	goto cleanup;
6881     }
6882     (void) memcpy(*out, s->data, (size_t) s->length);
6883     (*out)[s->length] = '\0';
6884 
6885     retval = 0;
6886   cleanup:
6887     if (s != NULL)
6888 	ASN1_OCTET_STRING_free(s);
6889 
6890     return retval;
6891 }
6892 
6893 
6894 #ifdef DEBUG_DH
6895 static void
6896 print_dh(DH * dh, char *msg)
6897 {
6898     BIO *bio_err = NULL;
6899 
6900     bio_err = BIO_new(BIO_s_file());
6901     BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
6902 
6903     if (msg)
6904 	BIO_puts(bio_err, (const char *)msg);
6905     if (dh)
6906 	DHparams_print(bio_err, dh);
6907 
6908     BN_print(bio_err, dh->q);
6909     BIO_puts(bio_err, (const char *)"\n");
6910     BIO_free(bio_err);
6911 
6912 }
6913 
6914 static void
6915 print_pubkey(BIGNUM * key, char *msg)
6916 {
6917     BIO *bio_err = NULL;
6918 
6919     bio_err = BIO_new(BIO_s_file());
6920     BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
6921 
6922     if (msg)
6923 	BIO_puts(bio_err, (const char *)msg);
6924     if (key)
6925 	BN_print(bio_err, key);
6926     BIO_puts(bio_err, "\n");
6927 
6928     BIO_free(bio_err);
6929 
6930 }
6931 #endif
6932 
6933 /*
6934  * Solaris Kerberos:
6935  * Error message generation has changed so gettext() can be used
6936  */
6937 #if 0
6938 static char *
6939 pkinit_pkcs11_code_to_text(int err)
6940 {
6941     int i;
6942     static char uc[64];
6943 
6944     for (i = 0; pkcs11_errstrings[i].text != NULL; i++)
6945 	if (pkcs11_errstrings[i].code == err)
6946 	    break;
6947     if (pkcs11_errstrings[i].text != NULL)
6948 	return (pkcs11_errstrings[i].text);
6949     snprintf(uc, 64, gettext("unknown code 0x%x"), err);
6950     return (uc);
6951 }
6952 #endif
6953 
6954 static char *
6955 pkinit_pkcs11_code_to_text(int err) {
6956 	return pkcs11_error_table(err);
6957 }
6958