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