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