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