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