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