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