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