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