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