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