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