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