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