Merge commit '3f8dd771c0f9c6553982e4dbcc5c221b5dcf2489'
[unleashed.git] / usr / src / lib / krb5 / plugins / preauth / pkinit / pkinit_crypto_openssl.c
blob24c49f7a220d344677782791dbc0f147ef10fc7b
1 /*
2 * COPYRIGHT (C) 2006,2007
3 * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
4 * ALL RIGHTS RESERVED
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.
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.
32 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
33 * Copyright (c) 2012, OmniTI Computer Consulting, Inc. All rights reserved.
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>
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>
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.
62 #define SILLYDECRYPT
64 #include "pkinit_crypto_openssl.h"
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.
72 static char *
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"));
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
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
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
372 /* Solaris Kerberos */
373 static k5_mutex_t oids_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
374 static int pkinit_oids_refs = 0;
376 krb5_error_code
377 pkinit_init_plg_crypto(pkinit_plg_crypto_context *cryptoctx) {
379 krb5_error_code retval = ENOMEM;
380 pkinit_plg_crypto_context ctx = NULL;
382 /* initialize openssl routines */
383 /* Solaris Kerberos */
384 retval = openssl_init();
385 if (retval != 0)
386 goto out;
388 ctx = (pkinit_plg_crypto_context)malloc(sizeof(*ctx));
389 if (ctx == NULL)
390 goto out;
391 (void) memset(ctx, 0, sizeof(*ctx));
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;
399 retval = pkinit_init_dh_params(ctx);
400 if (retval)
401 goto out;
403 *cryptoctx = ctx;
405 out:
406 if (retval && ctx != NULL)
407 pkinit_fini_plg_crypto(ctx);
409 return retval;
412 void
413 pkinit_fini_plg_crypto(pkinit_plg_crypto_context cryptoctx)
415 pkiDebug("%s: freeing context at %p\n", __FUNCTION__, cryptoctx);
417 if (cryptoctx == NULL)
418 return;
419 pkinit_fini_pkinit_oids(cryptoctx);
420 pkinit_fini_dh_params(cryptoctx);
421 free(cryptoctx);
424 krb5_error_code
425 pkinit_init_identity_crypto(pkinit_identity_crypto_context *idctx)
427 krb5_error_code retval = ENOMEM;
428 pkinit_identity_crypto_context ctx = NULL;
430 ctx = (pkinit_identity_crypto_context)malloc(sizeof(*ctx));
431 if (ctx == NULL)
432 goto out;
433 (void) memset(ctx, 0, sizeof(*ctx));
435 retval = pkinit_init_certs(ctx);
436 if (retval)
437 goto out;
439 retval = pkinit_init_pkcs11(ctx);
440 if (retval)
441 goto out;
443 pkiDebug("%s: returning ctx at %p\n", __FUNCTION__, ctx);
444 *idctx = ctx;
446 out:
447 if (retval) {
448 if (ctx)
449 pkinit_fini_identity_crypto(ctx);
452 return retval;
455 void
456 pkinit_fini_identity_crypto(pkinit_identity_crypto_context idctx)
458 if (idctx == NULL)
459 return;
461 pkiDebug("%s: freeing ctx at %p\n", __FUNCTION__, idctx);
462 pkinit_fini_certs(idctx);
463 pkinit_fini_pkcs11(idctx);
464 free(idctx);
467 krb5_error_code
468 pkinit_init_req_crypto(pkinit_req_crypto_context *cryptoctx)
471 pkinit_req_crypto_context ctx = NULL;
473 /* Solaris Kerberos */
474 if (cryptoctx == NULL)
475 return EINVAL;
477 ctx = (pkinit_req_crypto_context)malloc(sizeof(*ctx));
478 if (ctx == NULL)
479 return ENOMEM;
480 (void) memset(ctx, 0, sizeof(*ctx));
482 ctx->dh = NULL;
483 ctx->received_cert = NULL;
485 *cryptoctx = ctx;
487 pkiDebug("%s: returning ctx at %p\n", __FUNCTION__, ctx);
489 return 0;
492 void
493 pkinit_fini_req_crypto(pkinit_req_crypto_context req_cryptoctx)
495 if (req_cryptoctx == NULL)
496 return;
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);
504 free(req_cryptoctx);
507 static krb5_error_code
508 pkinit_init_pkinit_oids(pkinit_plg_crypto_context ctx)
510 krb5_error_code retval = ENOMEM;
511 int nid = 0;
514 * If OpenSSL already knows about the OID, use the
515 * existing definition. Otherwise, create an OID object.
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; \
526 ctx->vn = OBJ_nid2obj(nid);
528 /* Solaris Kerberos */
529 retval = k5_mutex_lock(&oids_mutex);
530 if (retval != 0)
531 goto out;
533 CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.2", id_pkinit_san,
534 "id-pkinit-san", "KRB5PrincipalName");
536 CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.1", id_pkinit_authData,
537 "id-pkinit-authdata", "PKINIT signedAuthPack");
539 CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.2", id_pkinit_DHKeyData,
540 "id-pkinit-DHKeyData", "PKINIT dhSignedData");
542 CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.3", id_pkinit_rkeyData,
543 "id-pkinit-rkeyData", "PKINIT encKeyPack");
545 CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.4", id_pkinit_KPClientAuth,
546 "id-pkinit-KPClientAuth", "PKINIT Client EKU");
548 CREATE_OBJ_IF_NEEDED("1.3.6.1.5.2.3.5", id_pkinit_KPKdc,
549 "id-pkinit-KPKdc", "KDC EKU");
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
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");
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");
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");
568 /* Success */
569 retval = 0;
571 pkinit_oids_refs++;
572 /* Solaris Kerberos */
573 k5_mutex_unlock(&oids_mutex);
575 out:
576 return retval;
579 static krb5_error_code
580 get_cert(char *filename, X509 **retcert)
582 X509 *cert = NULL;
583 BIO *tmp = NULL;
584 int code;
585 krb5_error_code retval;
587 if (filename == NULL || retcert == NULL)
588 return EINVAL;
590 *retcert = NULL;
592 tmp = BIO_new(BIO_s_file());
593 if (tmp == NULL)
594 return ENOMEM;
596 code = BIO_read_filename(tmp, filename);
597 if (code == 0) {
598 retval = errno;
599 goto cleanup;
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;
608 *retcert = cert;
609 retval = 0;
610 cleanup:
611 if (tmp != NULL)
612 BIO_free(tmp);
613 return retval;
616 static krb5_error_code
617 get_key(char *filename, EVP_PKEY **retkey)
619 EVP_PKEY *pkey = NULL;
620 BIO *tmp = NULL;
621 int code;
622 krb5_error_code retval;
624 if (filename == NULL || retkey == NULL)
625 return EINVAL;
627 tmp = BIO_new(BIO_s_file());
628 if (tmp == NULL)
629 return ENOMEM;
631 code = BIO_read_filename(tmp, filename);
632 if (code == 0) {
633 retval = errno;
634 goto cleanup;
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;
642 *retkey = pkey;
643 retval = 0;
644 cleanup:
645 if (tmp != NULL)
646 BIO_free(tmp);
647 return retval;
650 static void
651 pkinit_fini_pkinit_oids(pkinit_plg_crypto_context ctx)
653 if (ctx == NULL)
654 return;
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);
664 static krb5_error_code
665 pkinit_init_dh_params(pkinit_plg_crypto_context plgctx)
667 krb5_error_code retval = ENOMEM;
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);
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);
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);
702 retval = 0;
704 cleanup:
705 if (retval)
706 pkinit_fini_dh_params(plgctx);
708 return retval;
711 static void
712 pkinit_fini_dh_params(pkinit_plg_crypto_context plgctx)
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);
721 plgctx->dh_1024 = plgctx->dh_2048 = plgctx->dh_4096 = NULL;
724 static krb5_error_code
725 pkinit_init_certs(pkinit_identity_crypto_context ctx)
727 /* Solaris Kerberos */
728 int i;
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;
739 return 0;
742 static void
743 pkinit_fini_certs(pkinit_identity_crypto_context ctx)
745 if (ctx == NULL)
746 return;
748 if (ctx->my_certs != NULL)
749 sk_X509_pop_free(ctx->my_certs, X509_free);
751 if (ctx->my_key != NULL)
752 EVP_PKEY_free(ctx->my_key);
754 if (ctx->trustedCAs != NULL)
755 sk_X509_pop_free(ctx->trustedCAs, X509_free);
757 if (ctx->intermediateCAs != NULL)
758 sk_X509_pop_free(ctx->intermediateCAs, X509_free);
760 if (ctx->revoked != NULL)
761 sk_X509_CRL_pop_free(ctx->revoked, X509_CRL_free);
764 static krb5_error_code
765 pkinit_init_pkcs11(pkinit_identity_crypto_context ctx)
767 /* Solaris Kerberos */
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));
785 return 0;
788 static void
789 pkinit_fini_pkcs11(pkinit_identity_crypto_context ctx)
791 #ifndef WITHOUT_PKCS11
792 if (ctx == NULL)
793 return;
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;
801 * Solaris Kerberos:
802 * Only call C_Finalize if the process was not already using pkcs11.
804 if (ctx->finalize_pkcs11 == TRUE)
805 ctx->p11->C_Finalize(NULL_PTR);
807 ctx->p11 = NULL;
809 if (ctx->p11_module != NULL) {
810 pkinit_C_UnloadModule(ctx->p11_module);
811 ctx->p11_module = NULL;
813 free(ctx->p11_module_name);
814 free(ctx->token_label);
815 free(ctx->cert_id);
816 free(ctx->cert_label);
817 if (ctx->PIN != NULL) {
818 (void) memset(ctx->PIN, 0, strlen(ctx->PIN));
819 free(ctx->PIN);
821 #endif
824 krb5_error_code
825 pkinit_identity_set_prompter(pkinit_identity_crypto_context id_cryptoctx,
826 krb5_prompter_fct prompter,
827 void *prompter_data)
829 id_cryptoctx->prompter = prompter;
830 id_cryptoctx->prompter_data = prompter_data;
832 return 0;
835 /* ARGSUSED */
836 krb5_error_code
837 cms_signeddata_create(krb5_context context,
838 pkinit_plg_crypto_context plg_cryptoctx,
839 pkinit_req_crypto_context req_cryptoctx,
840 pkinit_identity_crypto_context id_cryptoctx,
841 int cms_msg_type,
842 int include_certchain,
843 unsigned char *data,
844 unsigned int data_len,
845 unsigned char **signed_data,
846 unsigned int *signed_data_len)
848 /* Solaris Kerberos */
849 krb5_error_code retval = KRB5KRB_ERR_GENERIC;
850 PKCS7 *p7 = NULL, *inner_p7 = NULL;
851 PKCS7_SIGNED *p7s = NULL;
852 PKCS7_SIGNER_INFO *p7si = NULL;
853 unsigned char *p;
854 ASN1_TYPE *pkinit_data = NULL;
855 STACK_OF(X509) * cert_stack = NULL;
856 ASN1_OCTET_STRING *digest_attr = NULL;
857 EVP_MD_CTX ctx, ctx2;
858 const EVP_MD *md_tmp = NULL;
859 unsigned char md_data[EVP_MAX_MD_SIZE], md_data2[EVP_MAX_MD_SIZE];
860 unsigned char *digestInfo_buf = NULL, *abuf = NULL;
861 unsigned int md_len, md_len2, alen, digestInfo_len;
862 STACK_OF(X509_ATTRIBUTE) * sk;
863 unsigned char *sig = NULL;
864 unsigned int sig_len = 0;
865 X509_ALGOR *alg = NULL;
866 ASN1_OCTET_STRING *digest = NULL;
867 unsigned int alg_len = 0, digest_len = 0;
868 unsigned char *y = NULL, *alg_buf = NULL, *digest_buf = NULL;
869 X509 *cert = NULL;
870 ASN1_OBJECT *oid = NULL;
872 /* Solaris Kerberos */
873 if (signed_data == NULL)
874 return EINVAL;
876 if (signed_data_len == NULL)
877 return EINVAL;
879 /* start creating PKCS7 data */
880 if ((p7 = PKCS7_new()) == NULL)
881 goto cleanup;
882 p7->type = OBJ_nid2obj(NID_pkcs7_signed);
884 if ((p7s = PKCS7_SIGNED_new()) == NULL)
885 goto cleanup;
886 p7->d.sign = p7s;
887 if (!ASN1_INTEGER_set(p7s->version, 3))
888 goto cleanup;
890 /* create a cert chain that has at least the signer's certificate */
891 if ((cert_stack = sk_X509_new_null()) == NULL)
892 goto cleanup;
894 cert = sk_X509_value(id_cryptoctx->my_certs, id_cryptoctx->cert_index);
895 if (!include_certchain) {
896 pkiDebug("only including signer's certificate\n");
897 sk_X509_push(cert_stack, X509_dup(cert));
898 } else {
899 /* create a cert chain */
900 X509_STORE *certstore = NULL;
901 X509_STORE_CTX certctx;
902 STACK_OF(X509) *certstack = NULL;
903 char buf[DN_BUF_LEN];
904 int i = 0, size = 0;
906 if ((certstore = X509_STORE_new()) == NULL)
907 goto cleanup;
908 pkiDebug("building certificate chain\n");
909 X509_STORE_set_verify_cb_func(certstore, openssl_callback);
910 X509_STORE_CTX_init(&certctx, certstore, cert,
911 id_cryptoctx->intermediateCAs);
912 X509_STORE_CTX_trusted_stack(&certctx, id_cryptoctx->trustedCAs);
913 /* Solaris Kerberos */
914 if (X509_verify_cert(&certctx) <= 0) {
915 pkiDebug("failed to create a certificate chain: %s\n",
916 X509_verify_cert_error_string(X509_STORE_CTX_get_error(&certctx)));
917 if (!sk_X509_num(id_cryptoctx->trustedCAs))
918 pkiDebug("No trusted CAs found. Check your X509_anchors\n");
919 goto cleanup;
921 certstack = X509_STORE_CTX_get1_chain(&certctx);
922 size = sk_X509_num(certstack);
923 pkiDebug("size of certificate chain = %d\n", size);
924 for(i = 0; i < size - 1; i++) {
925 X509 *x = sk_X509_value(certstack, i);
926 X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
927 pkiDebug("cert #%d: %s\n", i, buf);
928 sk_X509_push(cert_stack, X509_dup(x));
930 X509_STORE_CTX_cleanup(&certctx);
931 X509_STORE_free(certstore);
932 sk_X509_pop_free(certstack, X509_free);
934 p7s->cert = cert_stack;
936 /* fill-in PKCS7_SIGNER_INFO */
937 if ((p7si = PKCS7_SIGNER_INFO_new()) == NULL)
938 goto cleanup;
939 if (!ASN1_INTEGER_set(p7si->version, 1))
940 goto cleanup;
941 if (!X509_NAME_set(&p7si->issuer_and_serial->issuer,
942 X509_get_issuer_name(cert)))
943 goto cleanup;
944 /* because ASN1_INTEGER_set is used to set a 'long' we will do
945 * things the ugly way. */
946 M_ASN1_INTEGER_free(p7si->issuer_and_serial->serial);
947 if (!(p7si->issuer_and_serial->serial =
948 M_ASN1_INTEGER_dup(X509_get_serialNumber(cert))))
949 goto cleanup;
951 /* will not fill-out EVP_PKEY because it's on the smartcard */
953 /* Set digest algs */
954 p7si->digest_alg->algorithm = OBJ_nid2obj(NID_sha1);
956 if (p7si->digest_alg->parameter != NULL)
957 ASN1_TYPE_free(p7si->digest_alg->parameter);
958 if ((p7si->digest_alg->parameter = ASN1_TYPE_new()) == NULL)
959 goto cleanup;
960 p7si->digest_alg->parameter->type = V_ASN1_NULL;
962 /* Set sig algs */
963 if (p7si->digest_enc_alg->parameter != NULL)
964 ASN1_TYPE_free(p7si->digest_enc_alg->parameter);
965 p7si->digest_enc_alg->algorithm = OBJ_nid2obj(NID_sha1WithRSAEncryption);
966 if (!(p7si->digest_enc_alg->parameter = ASN1_TYPE_new()))
967 goto cleanup;
968 p7si->digest_enc_alg->parameter->type = V_ASN1_NULL;
970 /* pick the correct oid for the eContentInfo */
971 oid = pkinit_pkcs7type2oid(plg_cryptoctx, cms_msg_type);
972 if (oid == NULL)
973 goto cleanup;
975 if (cms_msg_type == CMS_SIGN_DRAFT9) {
976 /* don't include signed attributes for pa-type 15 request */
977 abuf = data;
978 alen = data_len;
979 } else {
980 /* add signed attributes */
981 /* compute sha1 digest over the EncapsulatedContentInfo */
982 EVP_MD_CTX_init(&ctx);
983 EVP_DigestInit_ex(&ctx, EVP_sha1(), NULL);
984 EVP_DigestUpdate(&ctx, data, data_len);
985 md_tmp = EVP_MD_CTX_md(&ctx);
986 EVP_DigestFinal_ex(&ctx, md_data, &md_len);
988 /* create a message digest attr */
989 digest_attr = ASN1_OCTET_STRING_new();
990 ASN1_OCTET_STRING_set(digest_attr, md_data, (int)md_len);
991 PKCS7_add_signed_attribute(p7si, NID_pkcs9_messageDigest,
992 V_ASN1_OCTET_STRING, (char *) digest_attr);
994 /* create a content-type attr */
995 PKCS7_add_signed_attribute(p7si, NID_pkcs9_contentType,
996 V_ASN1_OBJECT, oid);
998 /* create the signature over signed attributes. get DER encoded value */
999 /* This is the place where smartcard signature needs to be calculated */
1000 sk = p7si->auth_attr;
1001 alen = ASN1_item_i2d((ASN1_VALUE *) sk, &abuf,
1002 ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
1003 if (abuf == NULL)
1004 goto cleanup2;
1007 #ifndef WITHOUT_PKCS11
1008 /* Some tokens can only do RSAEncryption without sha1 hash */
1009 /* to compute sha1WithRSAEncryption, encode the algorithm ID for the hash
1010 * function and the hash value into an ASN.1 value of type DigestInfo
1011 * DigestInfo::=SEQUENCE {
1012 * digestAlgorithm AlgorithmIdentifier,
1013 * digest OCTET STRING }
1015 if (id_cryptoctx->pkcs11_method == 1 &&
1016 id_cryptoctx->mech == CKM_RSA_PKCS) {
1017 pkiDebug("mech = CKM_RSA_PKCS\n");
1018 EVP_MD_CTX_init(&ctx2);
1019 /* if this is not draft9 request, include digest signed attribute */
1020 if (cms_msg_type != CMS_SIGN_DRAFT9)
1021 EVP_DigestInit_ex(&ctx2, md_tmp, NULL);
1022 else
1023 EVP_DigestInit_ex(&ctx2, EVP_sha1(), NULL);
1024 EVP_DigestUpdate(&ctx2, abuf, alen);
1025 EVP_DigestFinal_ex(&ctx2, md_data2, &md_len2);
1027 alg = X509_ALGOR_new();
1028 if (alg == NULL)
1029 goto cleanup2;
1030 alg->algorithm = OBJ_nid2obj(NID_sha1);
1031 alg->parameter = NULL;
1032 alg_len = i2d_X509_ALGOR(alg, NULL);
1033 alg_buf = (unsigned char *)malloc(alg_len);
1034 if (alg_buf == NULL)
1035 goto cleanup2;
1037 digest = ASN1_OCTET_STRING_new();
1038 if (digest == NULL)
1039 goto cleanup2;
1040 ASN1_OCTET_STRING_set(digest, md_data2, (int)md_len2);
1041 digest_len = i2d_ASN1_OCTET_STRING(digest, NULL);
1042 digest_buf = (unsigned char *)malloc(digest_len);
1043 if (digest_buf == NULL)
1044 goto cleanup2;
1046 digestInfo_len = ASN1_object_size(1, (int)(alg_len + digest_len),
1047 V_ASN1_SEQUENCE);
1048 y = digestInfo_buf = (unsigned char *)malloc(digestInfo_len);
1049 if (digestInfo_buf == NULL)
1050 goto cleanup2;
1051 ASN1_put_object(&y, 1, (int)(alg_len + digest_len), V_ASN1_SEQUENCE,
1052 V_ASN1_UNIVERSAL);
1053 i2d_X509_ALGOR(alg, &y);
1054 i2d_ASN1_OCTET_STRING(digest, &y);
1055 #ifdef DEBUG_SIG
1056 pkiDebug("signing buffer\n");
1057 print_buffer(digestInfo_buf, digestInfo_len);
1058 print_buffer_bin(digestInfo_buf, digestInfo_len, "/tmp/pkcs7_tosign");
1059 #endif
1060 retval = pkinit_sign_data(context, id_cryptoctx, digestInfo_buf,
1061 digestInfo_len, &sig, &sig_len);
1062 } else
1063 #endif
1065 pkiDebug("mech = %s\n",
1066 id_cryptoctx->pkcs11_method == 1 ? "CKM_SHA1_RSA_PKCS" : "FS");
1067 retval = pkinit_sign_data(context, id_cryptoctx, abuf, alen,
1068 &sig, &sig_len);
1070 #ifdef DEBUG_SIG
1071 print_buffer(sig, sig_len);
1072 #endif
1073 if (cms_msg_type != CMS_SIGN_DRAFT9)
1074 free(abuf);
1075 if (retval)
1076 goto cleanup2;
1078 /* Add signature */
1079 if (!ASN1_STRING_set(p7si->enc_digest, (unsigned char *) sig,
1080 (int)sig_len)) {
1081 unsigned long err = ERR_peek_error();
1082 retval = KRB5KDC_ERR_PREAUTH_FAILED;
1083 krb5_set_error_message(context, retval, "%s\n",
1084 ERR_error_string(err, NULL));
1085 pkiDebug("failed to add a signed digest attribute\n");
1086 goto cleanup2;
1088 /* adder signer_info to pkcs7 signed */
1089 if (!PKCS7_add_signer(p7, p7si))
1090 goto cleanup2;
1092 /* start on adding data to the pkcs7 signed */
1093 if ((inner_p7 = PKCS7_new()) == NULL)
1094 goto cleanup2;
1095 if ((pkinit_data = ASN1_TYPE_new()) == NULL)
1096 goto cleanup2;
1097 pkinit_data->type = V_ASN1_OCTET_STRING;
1098 if ((pkinit_data->value.octet_string = ASN1_OCTET_STRING_new()) == NULL)
1099 goto cleanup2;
1100 if (!ASN1_OCTET_STRING_set(pkinit_data->value.octet_string, data,
1101 (int)data_len)) {
1102 unsigned long err = ERR_peek_error();
1103 retval = KRB5KDC_ERR_PREAUTH_FAILED;
1104 krb5_set_error_message(context, retval, "%s\n",
1105 ERR_error_string(err, NULL));
1106 pkiDebug("failed to add pkcs7 data\n");
1107 goto cleanup2;
1110 if (!PKCS7_set0_type_other(inner_p7, OBJ_obj2nid(oid), pkinit_data))
1111 goto cleanup2;
1113 if (p7s->contents != NULL)
1114 PKCS7_free(p7s->contents);
1115 p7s->contents = inner_p7;
1117 *signed_data_len = i2d_PKCS7(p7, NULL);
1118 if (!(*signed_data_len)) {
1119 unsigned long err = ERR_peek_error();
1120 retval = KRB5KDC_ERR_PREAUTH_FAILED;
1121 krb5_set_error_message(context, retval, "%s\n",
1122 ERR_error_string(err, NULL));
1123 pkiDebug("failed to der encode pkcs7\n");
1124 goto cleanup2;
1126 if ((p = *signed_data =
1127 (unsigned char *) malloc((size_t)*signed_data_len)) == NULL)
1128 goto cleanup2;
1130 /* DER encode PKCS7 data */
1131 retval = i2d_PKCS7(p7, &p);
1132 if (!retval) {
1133 unsigned long err = ERR_peek_error();
1134 retval = KRB5KDC_ERR_PREAUTH_FAILED;
1135 krb5_set_error_message(context, retval, "%s\n",
1136 ERR_error_string(err, NULL));
1137 pkiDebug("failed to der encode pkcs7\n");
1138 goto cleanup2;
1140 retval = 0;
1142 #ifdef DEBUG_ASN1
1143 if (cms_msg_type == CMS_SIGN_CLIENT) {
1144 print_buffer_bin(*signed_data, *signed_data_len,
1145 "/tmp/client_pkcs7_signeddata");
1146 } else {
1147 if (cms_msg_type == CMS_SIGN_SERVER) {
1148 print_buffer_bin(*signed_data, *signed_data_len,
1149 "/tmp/kdc_pkcs7_signeddata");
1150 } else {
1151 print_buffer_bin(*signed_data, *signed_data_len,
1152 "/tmp/draft9_pkcs7_signeddata");
1155 #endif
1157 cleanup2:
1158 if (cms_msg_type != CMS_SIGN_DRAFT9)
1159 EVP_MD_CTX_cleanup(&ctx);
1160 #ifndef WITHOUT_PKCS11
1161 if (id_cryptoctx->pkcs11_method == 1 &&
1162 id_cryptoctx->mech == CKM_RSA_PKCS) {
1163 EVP_MD_CTX_cleanup(&ctx2);
1164 if (digest_buf != NULL)
1165 free(digest_buf);
1166 if (digestInfo_buf != NULL)
1167 free(digestInfo_buf);
1168 if (alg_buf != NULL)
1169 free(alg_buf);
1170 if (digest != NULL)
1171 ASN1_OCTET_STRING_free(digest);
1173 #endif
1174 if (alg != NULL)
1175 X509_ALGOR_free(alg);
1176 cleanup:
1177 if (p7 != NULL)
1178 PKCS7_free(p7);
1179 if (sig != NULL)
1180 free(sig);
1182 return retval;
1185 krb5_error_code
1186 cms_signeddata_verify(krb5_context context,
1187 pkinit_plg_crypto_context plgctx,
1188 pkinit_req_crypto_context reqctx,
1189 pkinit_identity_crypto_context idctx,
1190 int cms_msg_type,
1191 int require_crl_checking,
1192 unsigned char *signed_data,
1193 unsigned int signed_data_len,
1194 unsigned char **data,
1195 unsigned int *data_len,
1196 unsigned char **authz_data,
1197 unsigned int *authz_data_len)
1199 krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
1200 PKCS7 *p7 = NULL;
1201 BIO *out = NULL;
1202 int flags = PKCS7_NOVERIFY, i = 0;
1203 unsigned int vflags = 0, size = 0;
1204 const unsigned char *p = signed_data;
1205 STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL;
1206 PKCS7_SIGNER_INFO *si = NULL;
1207 X509 *x = NULL;
1208 X509_STORE *store = NULL;
1209 X509_STORE_CTX cert_ctx;
1210 STACK_OF(X509) *intermediateCAs = NULL;
1211 STACK_OF(X509_CRL) *revoked = NULL;
1212 STACK_OF(X509) *verified_chain = NULL;
1213 ASN1_OBJECT *oid = NULL;
1214 krb5_external_principal_identifier **krb5_verified_chain = NULL;
1215 krb5_data *authz = NULL;
1216 char buf[DN_BUF_LEN];
1218 #ifdef DEBUG_ASN1
1219 print_buffer_bin(signed_data, signed_data_len,
1220 "/tmp/client_received_pkcs7_signeddata");
1221 #endif
1223 /* Do this early enough to create the shadow OID for pkcs7-data if needed */
1224 oid = pkinit_pkcs7type2oid(plgctx, cms_msg_type);
1225 if (oid == NULL)
1226 goto cleanup;
1228 /* decode received PKCS7 message */
1229 if ((p7 = d2i_PKCS7(NULL, &p, (int)signed_data_len)) == NULL) {
1230 unsigned long err = ERR_peek_error();
1231 krb5_set_error_message(context, retval, "%s\n",
1232 ERR_error_string(err, NULL));
1233 pkiDebug("%s: failed to decode message: %s\n",
1234 __FUNCTION__, ERR_error_string(err, NULL));
1235 goto cleanup;
1238 /* verify that the received message is PKCS7 SignedData message */
1239 if (OBJ_obj2nid(p7->type) != NID_pkcs7_signed) {
1240 pkiDebug("Expected id-signedData PKCS7 msg (received type = %d)\n",
1241 OBJ_obj2nid(p7->type));
1242 krb5_set_error_message(context, retval, "wrong oid\n");
1243 goto cleanup;
1246 /* setup to verify X509 certificate used to sign PKCS7 message */
1247 if (!(store = X509_STORE_new()))
1248 goto cleanup;
1250 /* check if we are inforcing CRL checking */
1251 vflags = X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL;
1252 if (require_crl_checking)
1253 X509_STORE_set_verify_cb_func(store, openssl_callback);
1254 else
1255 X509_STORE_set_verify_cb_func(store, openssl_callback_ignore_crls);
1256 X509_STORE_set_flags(store, vflags);
1258 /* get the signer's information from the PKCS7 message */
1259 if ((si_sk = PKCS7_get_signer_info(p7)) == NULL)
1260 goto cleanup;
1261 if ((si = sk_PKCS7_SIGNER_INFO_value(si_sk, 0)) == NULL)
1262 goto cleanup;
1263 if ((x = PKCS7_cert_from_signer_info(p7, si)) == NULL)
1264 goto cleanup;
1266 /* create available CRL information (get local CRLs and include CRLs
1267 * received in the PKCS7 message
1269 if (idctx->revoked == NULL)
1270 revoked = p7->d.sign->crl;
1271 else if (p7->d.sign->crl == NULL)
1272 revoked = idctx->revoked;
1273 else {
1274 size = sk_X509_CRL_num(idctx->revoked);
1275 revoked = sk_X509_CRL_new_null();
1276 for (i = 0; i < size; i++)
1277 sk_X509_CRL_push(revoked, sk_X509_CRL_value(idctx->revoked, i));
1278 size = sk_X509_CRL_num(p7->d.sign->crl);
1279 for (i = 0; i < size; i++)
1280 sk_X509_CRL_push(revoked, sk_X509_CRL_value(p7->d.sign->crl, i));
1283 /* create available intermediate CAs chains (get local intermediateCAs and
1284 * include the CA chain received in the PKCS7 message
1286 if (idctx->intermediateCAs == NULL)
1287 intermediateCAs = p7->d.sign->cert;
1288 else if (p7->d.sign->cert == NULL)
1289 intermediateCAs = idctx->intermediateCAs;
1290 else {
1291 size = sk_X509_num(idctx->intermediateCAs);
1292 intermediateCAs = sk_X509_new_null();
1293 for (i = 0; i < size; i++) {
1294 sk_X509_push(intermediateCAs,
1295 sk_X509_value(idctx->intermediateCAs, i));
1297 size = sk_X509_num(p7->d.sign->cert);
1298 for (i = 0; i < size; i++) {
1299 sk_X509_push(intermediateCAs, sk_X509_value(p7->d.sign->cert, i));
1303 /* initialize x509 context with the received certificate and
1304 * trusted and intermediate CA chains and CRLs
1306 if (!X509_STORE_CTX_init(&cert_ctx, store, x, intermediateCAs))
1307 goto cleanup;
1309 X509_STORE_CTX_set0_crls(&cert_ctx, revoked);
1311 /* add trusted CAs certificates for cert verification */
1312 if (idctx->trustedCAs != NULL)
1313 X509_STORE_CTX_trusted_stack(&cert_ctx, idctx->trustedCAs);
1314 else {
1315 pkiDebug("unable to find any trusted CAs\n");
1316 goto cleanup;
1318 #ifdef DEBUG_CERTCHAIN
1319 if (intermediateCAs != NULL) {
1320 size = sk_X509_num(intermediateCAs);
1321 pkiDebug("untrusted cert chain of size %d\n", size);
1322 for (i = 0; i < size; i++) {
1323 X509_NAME_oneline(X509_get_subject_name(
1324 sk_X509_value(intermediateCAs, i)), buf, sizeof(buf));
1325 pkiDebug("cert #%d: %s\n", i, buf);
1328 if (idctx->trustedCAs != NULL) {
1329 size = sk_X509_num(idctx->trustedCAs);
1330 pkiDebug("trusted cert chain of size %d\n", size);
1331 for (i = 0; i < size; i++) {
1332 X509_NAME_oneline(X509_get_subject_name(
1333 sk_X509_value(idctx->trustedCAs, i)), buf, sizeof(buf));
1334 pkiDebug("cert #%d: %s\n", i, buf);
1337 if (revoked != NULL) {
1338 size = sk_X509_CRL_num(revoked);
1339 pkiDebug("CRL chain of size %d\n", size);
1340 for (i = 0; i < size; i++) {
1341 X509_CRL *crl = sk_X509_CRL_value(revoked, i);
1342 X509_NAME_oneline(X509_CRL_get_issuer(crl), buf, sizeof(buf));
1343 pkiDebug("crls by CA #%d: %s\n", i , buf);
1346 #endif
1348 i = X509_verify_cert(&cert_ctx);
1349 if (i <= 0) {
1350 int j = X509_STORE_CTX_get_error(&cert_ctx);
1352 reqctx->received_cert = X509_dup(cert_ctx.current_cert);
1353 switch(j) {
1354 case X509_V_ERR_CERT_REVOKED:
1355 retval = KRB5KDC_ERR_REVOKED_CERTIFICATE;
1356 break;
1357 case X509_V_ERR_UNABLE_TO_GET_CRL:
1358 retval = KRB5KDC_ERR_REVOCATION_STATUS_UNKNOWN;
1359 break;
1360 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
1361 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
1362 retval = KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE;
1363 break;
1364 default:
1365 retval = KRB5KDC_ERR_INVALID_CERTIFICATE;
1367 X509_NAME_oneline(X509_get_subject_name(
1368 reqctx->received_cert), buf, sizeof(buf));
1369 pkiDebug("problem with cert DN = %s (error=%d) %s\n", buf, j,
1370 X509_verify_cert_error_string(j));
1371 krb5_set_error_message(context, retval, "%s\n",
1372 X509_verify_cert_error_string(j));
1373 #ifdef DEBUG_CERTCHAIN
1374 size = sk_X509_num(p7->d.sign->cert);
1375 pkiDebug("received cert chain of size %d\n", size);
1376 for (j = 0; j < size; j++) {
1377 X509 *tmp_cert = sk_X509_value(p7->d.sign->cert, j);
1378 X509_NAME_oneline(X509_get_subject_name(tmp_cert), buf, sizeof(buf));
1379 pkiDebug("cert #%d: %s\n", j, buf);
1381 #endif
1382 } else {
1383 /* retrieve verified certificate chain */
1384 if (cms_msg_type == CMS_SIGN_CLIENT || cms_msg_type == CMS_SIGN_DRAFT9)
1385 verified_chain = X509_STORE_CTX_get1_chain(&cert_ctx);
1387 X509_STORE_CTX_cleanup(&cert_ctx);
1388 if (i <= 0)
1389 goto cleanup;
1391 out = BIO_new(BIO_s_mem());
1392 if (cms_msg_type == CMS_SIGN_DRAFT9)
1393 flags |= PKCS7_NOATTR;
1394 if (PKCS7_verify(p7, NULL, store, NULL, out, flags)) {
1395 int valid_oid = 0;
1397 if (!OBJ_cmp(p7->d.sign->contents->type, oid))
1398 valid_oid = 1;
1399 else if (cms_msg_type == CMS_SIGN_DRAFT9) {
1401 * Various implementations of the pa-type 15 request use
1402 * different OIDS. We check that the returned object
1403 * has any of the acceptable OIDs
1405 ASN1_OBJECT *client_oid = NULL, *server_oid = NULL, *rsa_oid = NULL;
1406 client_oid = pkinit_pkcs7type2oid(plgctx, CMS_SIGN_CLIENT);
1407 server_oid = pkinit_pkcs7type2oid(plgctx, CMS_SIGN_SERVER);
1408 rsa_oid = pkinit_pkcs7type2oid(plgctx, CMS_ENVEL_SERVER);
1409 if (!OBJ_cmp(p7->d.sign->contents->type, client_oid) ||
1410 !OBJ_cmp(p7->d.sign->contents->type, server_oid) ||
1411 !OBJ_cmp(p7->d.sign->contents->type, rsa_oid))
1412 valid_oid = 1;
1415 if (valid_oid)
1416 pkiDebug("PKCS7 Verification successful\n");
1417 else {
1418 pkiDebug("wrong oid in eContentType\n");
1419 print_buffer((unsigned char *)p7->d.sign->contents->type->data,
1420 (unsigned int)p7->d.sign->contents->type->length);
1421 retval = KRB5KDC_ERR_PREAUTH_FAILED;
1422 krb5_set_error_message(context, retval, "wrong oid\n");
1423 goto cleanup;
1426 else {
1427 unsigned long err = ERR_peek_error();
1428 switch(ERR_GET_REASON(err)) {
1429 case PKCS7_R_DIGEST_FAILURE:
1430 retval = KRB5KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED;
1431 break;
1432 case PKCS7_R_SIGNATURE_FAILURE:
1433 default:
1434 retval = KRB5KDC_ERR_INVALID_SIG;
1436 pkiDebug("PKCS7 Verification failure\n");
1437 krb5_set_error_message(context, retval, "%s\n",
1438 ERR_error_string(err, NULL));
1439 goto cleanup;
1442 /* transfer the data from PKCS7 message into return buffer */
1443 for (size = 0;;) {
1444 if ((*data = realloc(*data, size + 1024 * 10)) == NULL)
1445 goto cleanup;
1446 i = BIO_read(out, &((*data)[size]), 1024 * 10);
1447 if (i <= 0)
1448 break;
1449 else
1450 size += i;
1452 *data_len = size;
1454 reqctx->received_cert = X509_dup(x);
1456 /* generate authorization data */
1457 if (cms_msg_type == CMS_SIGN_CLIENT || cms_msg_type == CMS_SIGN_DRAFT9) {
1459 if (authz_data == NULL || authz_data_len == NULL)
1460 goto out;
1462 *authz_data = NULL;
1463 retval = create_identifiers_from_stack(verified_chain,
1464 &krb5_verified_chain);
1465 if (retval) {
1466 pkiDebug("create_identifiers_from_stack failed\n");
1467 goto cleanup;
1470 retval = k5int_encode_krb5_td_trusted_certifiers((const krb5_external_principal_identifier **)krb5_verified_chain, &authz);
1471 if (retval) {
1472 pkiDebug("encode_krb5_td_trusted_certifiers failed\n");
1473 goto cleanup;
1475 #ifdef DEBUG_ASN1
1476 print_buffer_bin((unsigned char *)authz->data, authz->length,
1477 "/tmp/kdc_ad_initial_verified_cas");
1478 #endif
1479 *authz_data = (unsigned char *)malloc(authz->length);
1480 if (*authz_data == NULL) {
1481 retval = ENOMEM;
1482 goto cleanup;
1484 (void) memcpy(*authz_data, authz->data, authz->length);
1485 *authz_data_len = authz->length;
1487 out:
1488 retval = 0;
1490 cleanup:
1491 if (out != NULL)
1492 BIO_free(out);
1493 if (store != NULL)
1494 X509_STORE_free(store);
1495 if (p7 != NULL) {
1496 if (idctx->intermediateCAs != NULL && p7->d.sign->cert)
1497 sk_X509_free(intermediateCAs);
1498 if (idctx->revoked != NULL && p7->d.sign->crl)
1499 sk_X509_CRL_free(revoked);
1500 PKCS7_free(p7);
1502 if (verified_chain != NULL)
1503 sk_X509_pop_free(verified_chain, X509_free);
1504 if (krb5_verified_chain != NULL)
1505 free_krb5_external_principal_identifier(&krb5_verified_chain);
1506 if (authz != NULL)
1507 krb5_free_data(context, authz);
1509 return retval;
1512 krb5_error_code
1513 cms_envelopeddata_create(krb5_context context,
1514 pkinit_plg_crypto_context plgctx,
1515 pkinit_req_crypto_context reqctx,
1516 pkinit_identity_crypto_context idctx,
1517 krb5_preauthtype pa_type,
1518 int include_certchain,
1519 unsigned char *key_pack,
1520 unsigned int key_pack_len,
1521 unsigned char **out,
1522 unsigned int *out_len)
1525 /* Solaris Kerberos */
1526 krb5_error_code retval = KRB5KRB_ERR_GENERIC;
1527 PKCS7 *p7 = NULL;
1528 BIO *in = NULL;
1529 unsigned char *p = NULL, *signed_data = NULL, *enc_data = NULL;
1530 int signed_data_len = 0, enc_data_len = 0, flags = PKCS7_BINARY;
1531 STACK_OF(X509) *encerts = NULL;
1532 const EVP_CIPHER *cipher = NULL;
1533 int cms_msg_type;
1535 /* create the PKCS7 SignedData portion of the PKCS7 EnvelopedData */
1536 switch ((int)pa_type) {
1537 case KRB5_PADATA_PK_AS_REQ_OLD:
1538 case KRB5_PADATA_PK_AS_REP_OLD:
1539 cms_msg_type = CMS_SIGN_DRAFT9;
1540 break;
1541 case KRB5_PADATA_PK_AS_REQ:
1542 cms_msg_type = CMS_ENVEL_SERVER;
1543 break;
1544 default:
1545 /* Solaris Kerberos */
1546 retval = EINVAL;
1547 goto cleanup;
1550 retval = cms_signeddata_create(context, plgctx, reqctx, idctx,
1551 cms_msg_type, include_certchain, key_pack, key_pack_len,
1552 &signed_data, (unsigned int *)&signed_data_len);
1553 if (retval) {
1554 pkiDebug("failed to create pkcs7 signed data\n");
1555 goto cleanup;
1558 /* check we have client's certificate */
1559 if (reqctx->received_cert == NULL) {
1560 retval = KRB5KDC_ERR_PREAUTH_FAILED;
1561 goto cleanup;
1563 encerts = sk_X509_new_null();
1564 sk_X509_push(encerts, reqctx->received_cert);
1566 cipher = EVP_des_ede3_cbc();
1567 in = BIO_new(BIO_s_mem());
1568 switch (pa_type) {
1569 case KRB5_PADATA_PK_AS_REQ:
1570 prepare_enc_data(signed_data, signed_data_len, &enc_data,
1571 &enc_data_len);
1572 retval = BIO_write(in, enc_data, enc_data_len);
1573 if (retval != enc_data_len) {
1574 pkiDebug("BIO_write only wrote %d\n", retval);
1575 goto cleanup;
1577 break;
1578 case KRB5_PADATA_PK_AS_REP_OLD:
1579 case KRB5_PADATA_PK_AS_REQ_OLD:
1580 retval = BIO_write(in, signed_data, signed_data_len);
1581 if (retval != signed_data_len) {
1582 pkiDebug("BIO_write only wrote %d\n", retval);
1583 /* Solaris Kerberos */
1584 retval = KRB5KRB_ERR_GENERIC;
1585 goto cleanup;
1587 break;
1588 default:
1589 retval = -1;
1590 goto cleanup;
1593 p7 = PKCS7_encrypt(encerts, in, cipher, flags);
1594 if (p7 == NULL) {
1595 pkiDebug("failed to encrypt PKCS7 object\n");
1596 retval = -1;
1597 goto cleanup;
1599 switch (pa_type) {
1600 case KRB5_PADATA_PK_AS_REQ:
1601 p7->d.enveloped->enc_data->content_type =
1602 OBJ_nid2obj(NID_pkcs7_signed);
1603 break;
1604 case KRB5_PADATA_PK_AS_REP_OLD:
1605 case KRB5_PADATA_PK_AS_REQ_OLD:
1606 p7->d.enveloped->enc_data->content_type =
1607 OBJ_nid2obj(NID_pkcs7_data);
1608 break;
1611 *out_len = i2d_PKCS7(p7, NULL);
1612 if (!*out_len || (p = *out = (unsigned char *)malloc(*out_len)) == NULL) {
1613 retval = ENOMEM;
1614 goto cleanup;
1616 retval = i2d_PKCS7(p7, &p);
1617 if (!retval) {
1618 pkiDebug("unable to write pkcs7 object\n");
1619 goto cleanup;
1621 retval = 0;
1623 #ifdef DEBUG_ASN1
1624 print_buffer_bin(*out, *out_len, "/tmp/kdc_enveloped_data");
1625 #endif
1627 cleanup:
1628 if (p7 != NULL)
1629 PKCS7_free(p7);
1630 if (in != NULL)
1631 BIO_free(in);
1632 if (signed_data != NULL)
1633 free(signed_data);
1634 if (enc_data != NULL)
1635 free(enc_data);
1636 if (encerts != NULL)
1637 sk_X509_free(encerts);
1639 return retval;
1642 krb5_error_code
1643 cms_envelopeddata_verify(krb5_context context,
1644 pkinit_plg_crypto_context plg_cryptoctx,
1645 pkinit_req_crypto_context req_cryptoctx,
1646 pkinit_identity_crypto_context id_cryptoctx,
1647 krb5_preauthtype pa_type,
1648 int require_crl_checking,
1649 unsigned char *enveloped_data,
1650 unsigned int enveloped_data_len,
1651 unsigned char **data,
1652 unsigned int *data_len)
1654 krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
1655 PKCS7 *p7 = NULL;
1656 BIO *out = NULL;
1657 int i = 0;
1658 unsigned int size = 0;
1659 const unsigned char *p = enveloped_data;
1660 unsigned int tmp_buf_len = 0, tmp_buf2_len = 0, vfy_buf_len = 0;
1661 unsigned char *tmp_buf = NULL, *tmp_buf2 = NULL, *vfy_buf = NULL;
1662 int msg_type = 0;
1664 #ifdef DEBUG_ASN1
1665 print_buffer_bin(enveloped_data, enveloped_data_len,
1666 "/tmp/client_envelopeddata");
1667 #endif
1668 /* decode received PKCS7 message */
1669 if ((p7 = d2i_PKCS7(NULL, &p, (int)enveloped_data_len)) == NULL) {
1670 unsigned long err = ERR_peek_error();
1671 pkiDebug("failed to decode pkcs7\n");
1672 krb5_set_error_message(context, retval, "%s\n",
1673 ERR_error_string(err, NULL));
1674 goto cleanup;
1677 /* verify that the received message is PKCS7 EnvelopedData message */
1678 if (OBJ_obj2nid(p7->type) != NID_pkcs7_enveloped) {
1679 pkiDebug("Expected id-enveloped PKCS7 msg (received type = %d)\n",
1680 OBJ_obj2nid(p7->type));
1681 krb5_set_error_message(context, retval, "wrong oid\n");
1682 goto cleanup;
1685 /* decrypt received PKCS7 message */
1686 out = BIO_new(BIO_s_mem());
1687 if (pkcs7_decrypt(context, id_cryptoctx, p7, out)) {
1688 pkiDebug("PKCS7 decryption successful\n");
1689 } else {
1690 unsigned long err = ERR_peek_error();
1691 if (err != 0)
1692 krb5_set_error_message(context, retval, "%s\n",
1693 ERR_error_string(err, NULL));
1694 pkiDebug("PKCS7 decryption failed\n");
1695 goto cleanup;
1698 /* transfer the decoded PKCS7 SignedData message into a separate buffer */
1699 for (;;) {
1700 if ((tmp_buf = realloc(tmp_buf, size + 1024 * 10)) == NULL)
1701 goto cleanup;
1702 i = BIO_read(out, &(tmp_buf[size]), 1024 * 10);
1703 if (i <= 0)
1704 break;
1705 else
1706 size += i;
1708 tmp_buf_len = size;
1710 #ifdef DEBUG_ASN1
1711 print_buffer_bin(tmp_buf, tmp_buf_len, "/tmp/client_enc_keypack");
1712 #endif
1713 /* verify PKCS7 SignedData message */
1714 switch (pa_type) {
1715 case KRB5_PADATA_PK_AS_REP:
1716 msg_type = CMS_ENVEL_SERVER;
1718 break;
1719 case KRB5_PADATA_PK_AS_REP_OLD:
1720 msg_type = CMS_SIGN_DRAFT9;
1721 break;
1722 default:
1723 pkiDebug("%s: unrecognized pa_type = %d\n", __FUNCTION__, pa_type);
1724 retval = KRB5KDC_ERR_PREAUTH_FAILED;
1725 goto cleanup;
1728 * If this is the RFC style, wrap the signed data to make
1729 * decoding easier in the verify routine.
1730 * For draft9-compatible, we don't do anything because it
1731 * is already wrapped.
1733 #ifdef LONGHORN_BETA_COMPAT
1735 * The Longhorn server returns the expected RFC-style data, but
1736 * it is missing the sequence tag and length, so it requires
1737 * special processing when wrapping.
1738 * This will hopefully be fixed before the final release and
1739 * this can all be removed.
1741 if (msg_type == CMS_ENVEL_SERVER || longhorn == 1) {
1742 retval = wrap_signeddata(tmp_buf, tmp_buf_len,
1743 &tmp_buf2, &tmp_buf2_len, longhorn);
1744 if (retval) {
1745 pkiDebug("failed to encode signeddata\n");
1746 goto cleanup;
1748 vfy_buf = tmp_buf2;
1749 vfy_buf_len = tmp_buf2_len;
1751 } else {
1752 vfy_buf = tmp_buf;
1753 vfy_buf_len = tmp_buf_len;
1755 #else
1756 if (msg_type == CMS_ENVEL_SERVER) {
1757 retval = wrap_signeddata(tmp_buf, tmp_buf_len,
1758 &tmp_buf2, &tmp_buf2_len);
1759 if (retval) {
1760 pkiDebug("failed to encode signeddata\n");
1761 goto cleanup;
1763 vfy_buf = tmp_buf2;
1764 vfy_buf_len = tmp_buf2_len;
1766 } else {
1767 vfy_buf = tmp_buf;
1768 vfy_buf_len = tmp_buf_len;
1770 #endif
1772 #ifdef DEBUG_ASN1
1773 print_buffer_bin(vfy_buf, vfy_buf_len, "/tmp/client_enc_keypack2");
1774 #endif
1776 retval = cms_signeddata_verify(context, plg_cryptoctx, req_cryptoctx,
1777 id_cryptoctx, msg_type,
1778 require_crl_checking,
1779 vfy_buf, vfy_buf_len,
1780 data, data_len, NULL, NULL);
1782 if (!retval)
1783 pkiDebug("PKCS7 Verification Success\n");
1784 else {
1785 pkiDebug("PKCS7 Verification Failure\n");
1786 goto cleanup;
1789 retval = 0;
1791 cleanup:
1793 if (p7 != NULL)
1794 PKCS7_free(p7);
1795 if (out != NULL)
1796 BIO_free(out);
1797 free(tmp_buf);
1798 free(tmp_buf2);
1800 return retval;
1803 /* ARGSUSED */
1804 static krb5_error_code
1805 crypto_retrieve_X509_sans(krb5_context context,
1806 pkinit_plg_crypto_context plgctx,
1807 pkinit_req_crypto_context reqctx,
1808 X509 *cert,
1809 krb5_principal **princs_ret,
1810 krb5_principal **upn_ret,
1811 unsigned char ***dns_ret)
1813 krb5_error_code retval = EINVAL;
1814 char buf[DN_BUF_LEN];
1815 int p = 0, u = 0, d = 0;
1816 krb5_principal *princs = NULL;
1817 krb5_principal *upns = NULL;
1818 unsigned char **dnss = NULL;
1819 int i, num_found = 0;
1821 if (princs_ret == NULL && upn_ret == NULL && dns_ret == NULL) {
1822 pkiDebug("%s: nowhere to return any values!\n", __FUNCTION__);
1823 return retval;
1826 if (cert == NULL) {
1827 pkiDebug("%s: no certificate!\n", __FUNCTION__);
1828 return retval;
1831 X509_NAME_oneline(X509_get_subject_name(cert),
1832 buf, sizeof(buf));
1833 pkiDebug("%s: looking for SANs in cert = %s\n", __FUNCTION__, buf);
1835 if ((i = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1)) >= 0) {
1836 X509_EXTENSION *ext = NULL;
1837 GENERAL_NAMES *ialt = NULL;
1838 GENERAL_NAME *gen = NULL;
1839 int ret = 0;
1840 unsigned int num_sans = 0;
1842 if (!(ext = X509_get_ext(cert, i)) || !(ialt = X509V3_EXT_d2i(ext))) {
1843 pkiDebug("%s: found no subject alt name extensions\n",
1844 __FUNCTION__);
1845 goto cleanup;
1847 num_sans = sk_GENERAL_NAME_num(ialt);
1849 pkiDebug("%s: found %d subject alt name extension(s)\n",
1850 __FUNCTION__, num_sans);
1852 /* OK, we're likely returning something. Allocate return values */
1853 if (princs_ret != NULL) {
1854 princs = calloc(num_sans + 1, sizeof(krb5_principal));
1855 if (princs == NULL) {
1856 retval = ENOMEM;
1857 goto cleanup;
1860 if (upn_ret != NULL) {
1861 upns = calloc(num_sans + 1, sizeof(krb5_principal));
1862 if (upns == NULL) {
1863 retval = ENOMEM;
1864 goto cleanup;
1867 if (dns_ret != NULL) {
1868 dnss = calloc(num_sans + 1, sizeof(*dnss));
1869 if (dnss == NULL) {
1870 retval = ENOMEM;
1871 goto cleanup;
1875 for (i = 0; i < num_sans; i++) {
1876 krb5_data name = { 0, 0, NULL };
1878 gen = sk_GENERAL_NAME_value(ialt, i);
1879 switch (gen->type) {
1880 case GEN_OTHERNAME:
1881 name.length = gen->d.otherName->value->value.sequence->length;
1882 name.data = (char *)gen->d.otherName->value->value.sequence->data;
1883 if (princs != NULL
1884 && OBJ_cmp(plgctx->id_pkinit_san,
1885 gen->d.otherName->type_id) == 0) {
1886 #ifdef DEBUG_ASN1
1887 print_buffer_bin((unsigned char *)name.data, name.length,
1888 "/tmp/pkinit_san");
1889 #endif
1890 ret = k5int_decode_krb5_principal_name(&name, &princs[p]);
1891 if (ret) {
1892 pkiDebug("%s: failed decoding pkinit san value\n",
1893 __FUNCTION__);
1894 } else {
1895 p++;
1896 num_found++;
1898 } else if (upns != NULL
1899 && OBJ_cmp(plgctx->id_ms_san_upn,
1900 gen->d.otherName->type_id) == 0) {
1901 ret = krb5_parse_name(context, name.data, &upns[u]);
1902 if (ret) {
1903 pkiDebug("%s: failed parsing ms-upn san value\n",
1904 __FUNCTION__);
1905 } else {
1906 u++;
1907 num_found++;
1909 } else {
1910 pkiDebug("%s: unrecognized othername oid in SAN\n",
1911 __FUNCTION__);
1912 continue;
1915 break;
1916 case GEN_DNS:
1917 if (dnss != NULL) {
1918 pkiDebug("%s: found dns name = %s\n",
1919 __FUNCTION__, gen->d.dNSName->data);
1920 dnss[d] = (unsigned char *)
1921 strdup((char *)gen->d.dNSName->data);
1922 if (dnss[d] == NULL) {
1923 pkiDebug("%s: failed to duplicate dns name\n",
1924 __FUNCTION__);
1925 } else {
1926 d++;
1927 num_found++;
1930 break;
1931 default:
1932 pkiDebug("%s: SAN type = %d expecting %d\n",
1933 __FUNCTION__, gen->type, GEN_OTHERNAME);
1936 sk_GENERAL_NAME_pop_free(ialt, GENERAL_NAME_free);
1939 retval = 0;
1940 if (princs)
1941 *princs_ret = princs;
1942 if (upns)
1943 *upn_ret = upns;
1944 if (dnss)
1945 *dns_ret = dnss;
1947 cleanup:
1948 if (retval) {
1949 if (princs != NULL) {
1950 for (i = 0; princs[i] != NULL; i++)
1951 krb5_free_principal(context, princs[i]);
1952 free(princs);
1954 if (upns != NULL) {
1955 for (i = 0; upns[i] != NULL; i++)
1956 krb5_free_principal(context, upns[i]);
1957 free(upns);
1959 if (dnss != NULL) {
1960 for (i = 0; dnss[i] != NULL; i++)
1961 free(dnss[i]);
1962 free(dnss);
1965 return retval;
1968 /* ARGSUSED */
1969 krb5_error_code
1970 crypto_retrieve_cert_sans(krb5_context context,
1971 pkinit_plg_crypto_context plgctx,
1972 pkinit_req_crypto_context reqctx,
1973 pkinit_identity_crypto_context idctx,
1974 krb5_principal **princs_ret,
1975 krb5_principal **upn_ret,
1976 unsigned char ***dns_ret)
1978 krb5_error_code retval = EINVAL;
1980 if (reqctx->received_cert == NULL) {
1981 pkiDebug("%s: No certificate!\n", __FUNCTION__);
1982 return retval;
1985 return crypto_retrieve_X509_sans(context, plgctx, reqctx,
1986 reqctx->received_cert, princs_ret,
1987 upn_ret, dns_ret);
1990 /* ARGSUSED */
1991 krb5_error_code
1992 crypto_check_cert_eku(krb5_context context,
1993 pkinit_plg_crypto_context plgctx,
1994 pkinit_req_crypto_context reqctx,
1995 pkinit_identity_crypto_context idctx,
1996 int checking_kdc_cert,
1997 int allow_secondary_usage,
1998 int *valid_eku)
2000 char buf[DN_BUF_LEN];
2001 int found_eku = 0;
2002 krb5_error_code retval = EINVAL;
2003 int i;
2005 /* Solaris Kerberos */
2006 if (valid_eku == NULL)
2007 return retval;
2009 *valid_eku = 0;
2010 if (reqctx->received_cert == NULL)
2011 goto cleanup;
2013 X509_NAME_oneline(X509_get_subject_name(reqctx->received_cert),
2014 buf, sizeof(buf));
2015 pkiDebug("%s: looking for EKUs in cert = %s\n", __FUNCTION__, buf);
2017 if ((i = X509_get_ext_by_NID(reqctx->received_cert,
2018 NID_ext_key_usage, -1)) >= 0) {
2019 EXTENDED_KEY_USAGE *extusage;
2021 extusage = X509_get_ext_d2i(reqctx->received_cert, NID_ext_key_usage,
2022 NULL, NULL);
2023 if (extusage) {
2024 pkiDebug("%s: found eku info in the cert\n", __FUNCTION__);
2025 for (i = 0; found_eku == 0 && i < sk_ASN1_OBJECT_num(extusage); i++) {
2026 ASN1_OBJECT *tmp_oid;
2028 tmp_oid = sk_ASN1_OBJECT_value(extusage, i);
2029 pkiDebug("%s: checking eku %d of %d, allow_secondary = %d\n",
2030 __FUNCTION__, i+1, sk_ASN1_OBJECT_num(extusage),
2031 allow_secondary_usage);
2032 if (checking_kdc_cert) {
2033 if ((OBJ_cmp(tmp_oid, plgctx->id_pkinit_KPKdc) == 0)
2034 || (allow_secondary_usage
2035 && OBJ_cmp(tmp_oid, plgctx->id_kp_serverAuth) == 0))
2036 found_eku = 1;
2037 } else {
2038 if ((OBJ_cmp(tmp_oid, plgctx->id_pkinit_KPClientAuth) == 0)
2039 || (allow_secondary_usage
2040 && OBJ_cmp(tmp_oid, plgctx->id_ms_kp_sc_logon) == 0))
2041 found_eku = 1;
2045 EXTENDED_KEY_USAGE_free(extusage);
2047 if (found_eku) {
2048 ASN1_BIT_STRING *usage = NULL;
2049 pkiDebug("%s: found acceptable EKU, checking for digitalSignature\n", __FUNCTION__);
2051 /* check that digitalSignature KeyUsage is present */
2052 if ((usage = X509_get_ext_d2i(reqctx->received_cert,
2053 NID_key_usage, NULL, NULL))) {
2055 if (!ku_reject(reqctx->received_cert,
2056 X509v3_KU_DIGITAL_SIGNATURE)) {
2057 pkiDebug("%s: found digitalSignature KU\n",
2058 __FUNCTION__);
2059 *valid_eku = 1;
2060 } else
2061 pkiDebug("%s: didn't find digitalSignature KU\n",
2062 __FUNCTION__);
2064 ASN1_BIT_STRING_free(usage);
2067 retval = 0;
2068 cleanup:
2069 pkiDebug("%s: returning retval %d, valid_eku %d\n",
2070 __FUNCTION__, retval, *valid_eku);
2071 return retval;
2074 krb5_error_code
2075 pkinit_octetstring2key(krb5_context context,
2076 krb5_enctype etype,
2077 unsigned char *key,
2078 unsigned int dh_key_len,
2079 krb5_keyblock * key_block)
2081 krb5_error_code retval;
2082 unsigned char *buf = NULL;
2083 unsigned char md[SHA_DIGEST_LENGTH];
2084 unsigned char counter;
2085 size_t keybytes, keylength, offset;
2086 krb5_data random_data;
2089 if ((buf = (unsigned char *) malloc(dh_key_len)) == NULL) {
2090 retval = ENOMEM;
2091 goto cleanup;
2093 (void) memset(buf, 0, dh_key_len);
2095 counter = 0;
2096 offset = 0;
2097 do {
2098 SHA_CTX c;
2100 SHA1_Init(&c);
2101 SHA1_Update(&c, &counter, 1);
2102 SHA1_Update(&c, key, dh_key_len);
2103 SHA1_Final(md, &c);
2105 if (dh_key_len - offset < sizeof(md))
2106 (void) memcpy(buf + offset, md, dh_key_len - offset);
2107 else
2108 (void) memcpy(buf + offset, md, sizeof(md));
2110 offset += sizeof(md);
2111 counter++;
2112 } while (offset < dh_key_len);
2114 /* Solaris Kerberos */
2115 key_block->magic = KV5M_KEYBLOCK;
2116 key_block->enctype = etype;
2118 retval = krb5_c_keylengths(context, etype, &keybytes, &keylength);
2119 if (retval)
2120 goto cleanup;
2122 key_block->length = keylength;
2123 key_block->contents = calloc(keylength, sizeof(unsigned char *));
2124 if (key_block->contents == NULL) {
2125 retval = ENOMEM;
2126 goto cleanup;
2129 random_data.length = keybytes;
2130 random_data.data = (char *)buf;
2132 retval = krb5_c_random_to_key(context, etype, &random_data, key_block);
2134 cleanup:
2135 free(buf);
2136 if (retval && key_block->contents != NULL && key_block->length != 0) {
2137 (void) memset(key_block->contents, 0, key_block->length);
2138 key_block->length = 0;
2141 return retval;
2144 /* ARGSUSED */
2145 krb5_error_code
2146 client_create_dh(krb5_context context,
2147 pkinit_plg_crypto_context plg_cryptoctx,
2148 pkinit_req_crypto_context cryptoctx,
2149 pkinit_identity_crypto_context id_cryptoctx,
2150 int dh_size,
2151 unsigned char **dh_params,
2152 unsigned int *dh_params_len,
2153 unsigned char **dh_pubkey,
2154 unsigned int *dh_pubkey_len)
2156 krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2157 unsigned char *buf = NULL;
2158 int dh_err = 0;
2159 ASN1_INTEGER *pub_key = NULL;
2161 if (cryptoctx->dh == NULL) {
2162 if ((cryptoctx->dh = DH_new()) == NULL)
2163 goto cleanup;
2164 if ((cryptoctx->dh->g = BN_new()) == NULL ||
2165 (cryptoctx->dh->q = BN_new()) == NULL)
2166 goto cleanup;
2168 switch(dh_size) {
2169 case 1024:
2170 pkiDebug("client uses 1024 DH keys\n");
2171 cryptoctx->dh->p = get_rfc2409_prime_1024(NULL);
2172 break;
2173 case 2048:
2174 pkiDebug("client uses 2048 DH keys\n");
2175 cryptoctx->dh->p = BN_bin2bn(pkinit_2048_dhprime,
2176 sizeof(pkinit_2048_dhprime), NULL);
2177 break;
2178 case 4096:
2179 pkiDebug("client uses 4096 DH keys\n");
2180 cryptoctx->dh->p = BN_bin2bn(pkinit_4096_dhprime,
2181 sizeof(pkinit_4096_dhprime), NULL);
2182 break;
2183 default:
2184 goto cleanup;
2187 BN_set_word((cryptoctx->dh->g), DH_GENERATOR_2);
2188 BN_rshift1(cryptoctx->dh->q, cryptoctx->dh->p);
2191 DH_generate_key(cryptoctx->dh);
2192 /* Solaris Kerberos */
2193 #ifdef DEBUG
2194 DH_check(cryptoctx->dh, &dh_err);
2195 if (dh_err != 0) {
2196 pkiDebug("Warning: dh_check failed with %d\n", dh_err);
2197 if (dh_err & DH_CHECK_P_NOT_PRIME)
2198 pkiDebug("p value is not prime\n");
2199 if (dh_err & DH_CHECK_P_NOT_SAFE_PRIME)
2200 pkiDebug("p value is not a safe prime\n");
2201 if (dh_err & DH_UNABLE_TO_CHECK_GENERATOR)
2202 pkiDebug("unable to check the generator value\n");
2203 if (dh_err & DH_NOT_SUITABLE_GENERATOR)
2204 pkiDebug("the g value is not a generator\n");
2206 #endif
2207 #ifdef DEBUG_DH
2208 print_dh(cryptoctx->dh, "client's DH params\n");
2209 print_pubkey(cryptoctx->dh->pub_key, "client's pub_key=");
2210 #endif
2212 DH_check_pub_key(cryptoctx->dh, cryptoctx->dh->pub_key, &dh_err);
2213 if (dh_err != 0) {
2214 pkiDebug("dh_check_pub_key failed with %d\n", dh_err);
2215 goto cleanup;
2218 /* pack DHparams */
2219 /* aglo: usually we could just call i2d_DHparams to encode DH params
2220 * however, PKINIT requires RFC3279 encoding and openssl does pkcs#3.
2222 retval = pkinit_encode_dh_params(cryptoctx->dh->p, cryptoctx->dh->g,
2223 cryptoctx->dh->q, dh_params, dh_params_len);
2224 if (retval)
2225 goto cleanup;
2227 /* pack DH public key */
2228 /* Diffie-Hellman public key must be ASN1 encoded as an INTEGER; this
2229 * encoding shall be used as the contents (the value) of the
2230 * subjectPublicKey component (a BIT STRING) of the SubjectPublicKeyInfo
2231 * data element
2233 if ((pub_key = BN_to_ASN1_INTEGER(cryptoctx->dh->pub_key, NULL)) == NULL)
2234 goto cleanup;
2235 *dh_pubkey_len = i2d_ASN1_INTEGER(pub_key, NULL);
2236 if ((buf = *dh_pubkey = (unsigned char *)
2237 malloc((size_t) *dh_pubkey_len)) == NULL) {
2238 retval = ENOMEM;
2239 goto cleanup;
2241 i2d_ASN1_INTEGER(pub_key, &buf);
2243 if (pub_key != NULL)
2244 ASN1_INTEGER_free(pub_key);
2246 retval = 0;
2247 return retval;
2249 cleanup:
2250 if (cryptoctx->dh != NULL)
2251 DH_free(cryptoctx->dh);
2252 cryptoctx->dh = NULL;
2253 free(*dh_params);
2254 *dh_params = NULL;
2255 free(*dh_pubkey);
2256 *dh_pubkey = NULL;
2257 if (pub_key != NULL)
2258 ASN1_INTEGER_free(pub_key);
2260 return retval;
2263 /* ARGSUSED */
2264 krb5_error_code
2265 client_process_dh(krb5_context context,
2266 pkinit_plg_crypto_context plg_cryptoctx,
2267 pkinit_req_crypto_context cryptoctx,
2268 pkinit_identity_crypto_context id_cryptoctx,
2269 unsigned char *subjectPublicKey_data,
2270 unsigned int subjectPublicKey_length,
2271 unsigned char **client_key,
2272 unsigned int *client_key_len)
2274 /* Solaris Kerberos */
2275 krb5_error_code retval = KRB5_PREAUTH_FAILED;
2276 BIGNUM *server_pub_key = NULL;
2277 ASN1_INTEGER *pub_key = NULL;
2278 const unsigned char *p = NULL;
2279 unsigned char *data = NULL;
2280 long data_len;
2282 /* decode subjectPublicKey (retrieve INTEGER from OCTET_STRING) */
2284 if (der_decode_data(subjectPublicKey_data, (long)subjectPublicKey_length,
2285 &data, &data_len) != 0) {
2286 pkiDebug("failed to decode subjectPublicKey\n");
2287 /* Solaris Kerberos */
2288 retval = KRB5_PREAUTH_FAILED;
2289 goto cleanup;
2292 *client_key_len = DH_size(cryptoctx->dh);
2293 if ((*client_key = (unsigned char *)
2294 malloc((size_t) *client_key_len)) == NULL) {
2295 retval = ENOMEM;
2296 goto cleanup;
2298 p = data;
2299 if ((pub_key = d2i_ASN1_INTEGER(NULL, &p, data_len)) == NULL)
2300 goto cleanup;
2301 if ((server_pub_key = ASN1_INTEGER_to_BN(pub_key, NULL)) == NULL)
2302 goto cleanup;
2304 DH_compute_key(*client_key, server_pub_key, cryptoctx->dh);
2305 #ifdef DEBUG_DH
2306 print_pubkey(server_pub_key, "server's pub_key=");
2307 pkiDebug("client secret key (%d)= ", *client_key_len);
2308 print_buffer(*client_key, *client_key_len);
2309 #endif
2311 retval = 0;
2312 if (server_pub_key != NULL)
2313 BN_free(server_pub_key);
2314 if (pub_key != NULL)
2315 ASN1_INTEGER_free(pub_key);
2316 free(data);
2318 return retval;
2320 cleanup:
2321 free(*client_key);
2322 *client_key = NULL;
2323 if (pub_key != NULL)
2324 ASN1_INTEGER_free(pub_key);
2325 free(data);
2327 return retval;
2330 /* ARGSUSED */
2331 krb5_error_code
2332 server_check_dh(krb5_context context,
2333 pkinit_plg_crypto_context cryptoctx,
2334 pkinit_req_crypto_context req_cryptoctx,
2335 pkinit_identity_crypto_context id_cryptoctx,
2336 krb5_octet_data *dh_params,
2337 int minbits)
2339 DH *dh = NULL;
2340 unsigned char *tmp = NULL;
2341 int dh_prime_bits;
2342 krb5_error_code retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
2344 tmp = dh_params->data;
2345 dh = DH_new();
2346 dh = pkinit_decode_dh_params(&dh, &tmp, dh_params->length);
2347 if (dh == NULL) {
2348 pkiDebug("failed to decode dhparams\n");
2349 goto cleanup;
2352 /* KDC SHOULD check to see if the key parameters satisfy its policy */
2353 dh_prime_bits = BN_num_bits(dh->p);
2354 if (minbits && dh_prime_bits < minbits) {
2355 pkiDebug("client sent dh params with %d bits, we require %d\n",
2356 dh_prime_bits, minbits);
2357 goto cleanup;
2360 /* check dhparams is group 2 */
2361 if (pkinit_check_dh_params(cryptoctx->dh_1024->p,
2362 dh->p, dh->g, dh->q) == 0) {
2363 retval = 0;
2364 goto cleanup;
2367 /* check dhparams is group 14 */
2368 if (pkinit_check_dh_params(cryptoctx->dh_2048->p,
2369 dh->p, dh->g, dh->q) == 0) {
2370 retval = 0;
2371 goto cleanup;
2374 /* check dhparams is group 16 */
2375 if (pkinit_check_dh_params(cryptoctx->dh_4096->p,
2376 dh->p, dh->g, dh->q) == 0) {
2377 retval = 0;
2378 goto cleanup;
2381 cleanup:
2382 if (retval == 0)
2383 req_cryptoctx->dh = dh;
2384 else
2385 DH_free(dh);
2387 return retval;
2390 /* kdc's dh function */
2391 /* ARGSUSED */
2392 krb5_error_code
2393 server_process_dh(krb5_context context,
2394 pkinit_plg_crypto_context plg_cryptoctx,
2395 pkinit_req_crypto_context cryptoctx,
2396 pkinit_identity_crypto_context id_cryptoctx,
2397 unsigned char *data,
2398 unsigned int data_len,
2399 unsigned char **dh_pubkey,
2400 unsigned int *dh_pubkey_len,
2401 unsigned char **server_key,
2402 unsigned int *server_key_len)
2404 /* Solaris Kerberos */
2405 krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2406 DH *dh = NULL, *dh_server = NULL;
2407 unsigned char *p = NULL;
2408 ASN1_INTEGER *pub_key = NULL;
2410 /* get client's received DH parameters that we saved in server_check_dh */
2411 dh = cryptoctx->dh;
2413 dh_server = DH_new();
2414 if (dh_server == NULL)
2415 goto cleanup;
2416 dh_server->p = BN_dup(dh->p);
2417 dh_server->g = BN_dup(dh->g);
2418 dh_server->q = BN_dup(dh->q);
2420 /* decode client's public key */
2421 p = data;
2422 pub_key = d2i_ASN1_INTEGER(NULL, (const unsigned char **)&p, (int)data_len);
2423 if (pub_key == NULL)
2424 goto cleanup;
2425 dh->pub_key = ASN1_INTEGER_to_BN(pub_key, NULL);
2426 if (dh->pub_key == NULL)
2427 goto cleanup;
2428 ASN1_INTEGER_free(pub_key);
2430 if (!DH_generate_key(dh_server))
2431 goto cleanup;
2433 /* generate DH session key */
2434 *server_key_len = DH_size(dh_server);
2435 if ((*server_key = (unsigned char *) malloc((size_t)*server_key_len)) == NULL)
2436 goto cleanup;
2437 DH_compute_key(*server_key, dh->pub_key, dh_server);
2439 #ifdef DEBUG_DH
2440 print_dh(dh_server, "client&server's DH params\n");
2441 print_pubkey(dh->pub_key, "client's pub_key=");
2442 print_pubkey(dh_server->pub_key, "server's pub_key=");
2443 pkiDebug("server secret key=");
2444 print_buffer(*server_key, *server_key_len);
2445 #endif
2447 /* KDC reply */
2448 /* pack DH public key */
2449 /* Diffie-Hellman public key must be ASN1 encoded as an INTEGER; this
2450 * encoding shall be used as the contents (the value) of the
2451 * subjectPublicKey component (a BIT STRING) of the SubjectPublicKeyInfo
2452 * data element
2454 if ((pub_key = BN_to_ASN1_INTEGER(dh_server->pub_key, NULL)) == NULL)
2455 goto cleanup;
2456 *dh_pubkey_len = i2d_ASN1_INTEGER(pub_key, NULL);
2457 if ((p = *dh_pubkey = (unsigned char *) malloc((size_t)*dh_pubkey_len)) == NULL)
2458 goto cleanup;
2459 i2d_ASN1_INTEGER(pub_key, &p);
2460 if (pub_key != NULL)
2461 ASN1_INTEGER_free(pub_key);
2463 retval = 0;
2465 if (dh_server != NULL)
2466 DH_free(dh_server);
2467 return retval;
2469 cleanup:
2470 if (dh_server != NULL)
2471 DH_free(dh_server);
2472 free(*dh_pubkey);
2473 free(*server_key);
2475 return retval;
2479 * Solaris Kerberos:
2480 * Add locking around did_init to make it MT-safe.
2482 static krb5_error_code
2483 openssl_init()
2485 krb5_error_code ret = 0;
2486 static int did_init = 0;
2487 static k5_mutex_t init_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
2489 ret = k5_mutex_lock(&init_mutex);
2490 if (ret == 0) {
2491 if (!did_init) {
2492 /* initialize openssl routines */
2493 CRYPTO_malloc_init();
2494 ERR_load_crypto_strings();
2495 OpenSSL_add_all_algorithms();
2496 did_init++;
2498 k5_mutex_unlock(&init_mutex);
2500 return (ret);
2503 static krb5_error_code
2504 pkinit_encode_dh_params(BIGNUM *p, BIGNUM *g, BIGNUM *q,
2505 unsigned char **buf, unsigned int *buf_len)
2507 krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2508 int bufsize = 0, r = 0;
2509 unsigned char *tmp = NULL;
2510 ASN1_INTEGER *ap = NULL, *ag = NULL, *aq = NULL;
2512 if ((ap = BN_to_ASN1_INTEGER(p, NULL)) == NULL)
2513 goto cleanup;
2514 if ((ag = BN_to_ASN1_INTEGER(g, NULL)) == NULL)
2515 goto cleanup;
2516 if ((aq = BN_to_ASN1_INTEGER(q, NULL)) == NULL)
2517 goto cleanup;
2518 bufsize = i2d_ASN1_INTEGER(ap, NULL);
2519 bufsize += i2d_ASN1_INTEGER(ag, NULL);
2520 bufsize += i2d_ASN1_INTEGER(aq, NULL);
2522 r = ASN1_object_size(1, bufsize, V_ASN1_SEQUENCE);
2524 tmp = *buf = (unsigned char *)malloc((size_t) r);
2525 if (tmp == NULL)
2526 goto cleanup;
2528 ASN1_put_object(&tmp, 1, bufsize, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
2530 i2d_ASN1_INTEGER(ap, &tmp);
2531 i2d_ASN1_INTEGER(ag, &tmp);
2532 i2d_ASN1_INTEGER(aq, &tmp);
2534 *buf_len = r;
2536 retval = 0;
2538 cleanup:
2539 if (ap != NULL)
2540 ASN1_INTEGER_free(ap);
2541 if (ag != NULL)
2542 ASN1_INTEGER_free(ag);
2543 if (aq != NULL)
2544 ASN1_INTEGER_free(aq);
2546 return retval;
2549 static DH *
2550 pkinit_decode_dh_params(DH ** a, unsigned char **pp, unsigned int len)
2552 ASN1_INTEGER ai, *aip = NULL;
2553 long length = (long) len;
2555 M_ASN1_D2I_vars(a, DH *, DH_new);
2557 M_ASN1_D2I_Init();
2558 M_ASN1_D2I_start_sequence();
2559 aip = &ai;
2560 ai.data = NULL;
2561 ai.length = 0;
2562 M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER);
2563 if (aip == NULL)
2564 return NULL;
2565 else {
2566 (*a)->p = ASN1_INTEGER_to_BN(aip, NULL);
2567 if ((*a)->p == NULL)
2568 return NULL;
2569 if (ai.data != NULL) {
2570 OPENSSL_free(ai.data);
2571 ai.data = NULL;
2572 ai.length = 0;
2575 M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER);
2576 if (aip == NULL)
2577 return NULL;
2578 else {
2579 (*a)->g = ASN1_INTEGER_to_BN(aip, NULL);
2580 if ((*a)->g == NULL)
2581 return NULL;
2582 if (ai.data != NULL) {
2583 OPENSSL_free(ai.data);
2584 ai.data = NULL;
2585 ai.length = 0;
2589 M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER);
2590 if (aip == NULL)
2591 return NULL;
2592 else {
2593 (*a)->q = ASN1_INTEGER_to_BN(aip, NULL);
2594 if ((*a)->q == NULL)
2595 return NULL;
2596 if (ai.data != NULL) {
2597 OPENSSL_free(ai.data);
2598 ai.data = NULL;
2599 ai.length = 0;
2603 M_ASN1_D2I_end_sequence();
2604 M_ASN1_D2I_Finish(a, DH_free, 0);
2608 static krb5_error_code
2609 pkinit_create_sequence_of_principal_identifiers(
2610 krb5_context context,
2611 pkinit_plg_crypto_context plg_cryptoctx,
2612 pkinit_req_crypto_context req_cryptoctx,
2613 pkinit_identity_crypto_context id_cryptoctx,
2614 int type,
2615 krb5_data **out_data)
2617 krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2618 krb5_external_principal_identifier **krb5_trusted_certifiers = NULL;
2619 krb5_data *td_certifiers = NULL, *data = NULL;
2620 krb5_typed_data **typed_data = NULL;
2622 switch(type) {
2623 case TD_TRUSTED_CERTIFIERS:
2624 retval = create_krb5_trustedCertifiers(context, plg_cryptoctx,
2625 req_cryptoctx, id_cryptoctx, &krb5_trusted_certifiers);
2626 if (retval) {
2627 pkiDebug("create_krb5_trustedCertifiers failed\n");
2628 goto cleanup;
2630 break;
2631 case TD_INVALID_CERTIFICATES:
2632 retval = create_krb5_invalidCertificates(context, plg_cryptoctx,
2633 req_cryptoctx, id_cryptoctx, &krb5_trusted_certifiers);
2634 if (retval) {
2635 pkiDebug("create_krb5_invalidCertificates failed\n");
2636 goto cleanup;
2638 break;
2639 default:
2640 retval = -1;
2641 goto cleanup;
2644 retval = k5int_encode_krb5_td_trusted_certifiers((const krb5_external_principal_identifier **)krb5_trusted_certifiers, &td_certifiers);
2645 if (retval) {
2646 pkiDebug("encode_krb5_td_trusted_certifiers failed\n");
2647 goto cleanup;
2649 #ifdef DEBUG_ASN1
2650 print_buffer_bin((unsigned char *)td_certifiers->data,
2651 td_certifiers->length, "/tmp/kdc_td_certifiers");
2652 #endif
2653 typed_data = malloc (2 * sizeof(krb5_typed_data *));
2654 if (typed_data == NULL) {
2655 retval = ENOMEM;
2656 goto cleanup;
2658 typed_data[1] = NULL;
2659 init_krb5_typed_data(&typed_data[0]);
2660 if (typed_data[0] == NULL) {
2661 retval = ENOMEM;
2662 goto cleanup;
2664 typed_data[0]->type = type;
2665 typed_data[0]->length = td_certifiers->length;
2666 typed_data[0]->data = (unsigned char *)td_certifiers->data;
2667 retval = k5int_encode_krb5_typed_data((const krb5_typed_data **)typed_data,
2668 &data);
2669 if (retval) {
2670 pkiDebug("encode_krb5_typed_data failed\n");
2671 goto cleanup;
2673 #ifdef DEBUG_ASN1
2674 print_buffer_bin((unsigned char *)data->data, data->length,
2675 "/tmp/kdc_edata");
2676 #endif
2677 *out_data = (krb5_data *)malloc(sizeof(krb5_data));
2678 (*out_data)->length = data->length;
2679 (*out_data)->data = (char *)malloc(data->length);
2680 (void) memcpy((*out_data)->data, data->data, data->length);
2682 retval = 0;
2684 cleanup:
2685 if (krb5_trusted_certifiers != NULL)
2686 free_krb5_external_principal_identifier(&krb5_trusted_certifiers);
2688 if (data != NULL) {
2689 free(data->data);
2690 free(data);
2693 free(td_certifiers);
2695 if (typed_data != NULL)
2696 free_krb5_typed_data(&typed_data);
2698 return retval;
2701 krb5_error_code
2702 pkinit_create_td_trusted_certifiers(krb5_context context,
2703 pkinit_plg_crypto_context plg_cryptoctx,
2704 pkinit_req_crypto_context req_cryptoctx,
2705 pkinit_identity_crypto_context id_cryptoctx,
2706 krb5_data **out_data)
2708 krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2710 retval = pkinit_create_sequence_of_principal_identifiers(context,
2711 plg_cryptoctx, req_cryptoctx, id_cryptoctx,
2712 TD_TRUSTED_CERTIFIERS, out_data);
2714 return retval;
2717 krb5_error_code
2718 pkinit_create_td_invalid_certificate(
2719 krb5_context context,
2720 pkinit_plg_crypto_context plg_cryptoctx,
2721 pkinit_req_crypto_context req_cryptoctx,
2722 pkinit_identity_crypto_context id_cryptoctx,
2723 krb5_data **out_data)
2725 krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2727 retval = pkinit_create_sequence_of_principal_identifiers(context,
2728 plg_cryptoctx, req_cryptoctx, id_cryptoctx,
2729 TD_INVALID_CERTIFICATES, out_data);
2731 return retval;
2734 /* ARGSUSED */
2735 krb5_error_code
2736 pkinit_create_td_dh_parameters(krb5_context context,
2737 pkinit_plg_crypto_context plg_cryptoctx,
2738 pkinit_req_crypto_context req_cryptoctx,
2739 pkinit_identity_crypto_context id_cryptoctx,
2740 pkinit_plg_opts *opts,
2741 krb5_data **out_data)
2743 /* Solaris Kerberos */
2744 krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2745 unsigned int buf1_len = 0, buf2_len = 0, buf3_len = 0, i = 0;
2746 unsigned char *buf1 = NULL, *buf2 = NULL, *buf3 = NULL;
2747 krb5_typed_data **typed_data = NULL;
2748 krb5_data *data = NULL, *encoded_algId = NULL;
2749 krb5_algorithm_identifier **algId = NULL;
2751 /* Solaris Kerberos */
2752 if (opts->dh_min_bits > 4096) {
2753 retval = EINVAL;
2754 goto cleanup;
2757 if (opts->dh_min_bits <= 1024) {
2758 retval = pkinit_encode_dh_params(plg_cryptoctx->dh_1024->p,
2759 plg_cryptoctx->dh_1024->g, plg_cryptoctx->dh_1024->q,
2760 &buf1, &buf1_len);
2761 if (retval)
2762 goto cleanup;
2764 if (opts->dh_min_bits <= 2048) {
2765 retval = pkinit_encode_dh_params(plg_cryptoctx->dh_2048->p,
2766 plg_cryptoctx->dh_2048->g, plg_cryptoctx->dh_2048->q,
2767 &buf2, &buf2_len);
2768 if (retval)
2769 goto cleanup;
2771 retval = pkinit_encode_dh_params(plg_cryptoctx->dh_4096->p,
2772 plg_cryptoctx->dh_4096->g, plg_cryptoctx->dh_4096->q,
2773 &buf3, &buf3_len);
2774 if (retval)
2775 goto cleanup;
2777 if (opts->dh_min_bits <= 1024) {
2778 algId = malloc(4 * sizeof(krb5_algorithm_identifier *));
2779 if (algId == NULL)
2780 goto cleanup;
2781 algId[3] = NULL;
2782 algId[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
2783 if (algId[0] == NULL)
2784 goto cleanup;
2785 algId[0]->parameters.data = (unsigned char *)malloc(buf2_len);
2786 if (algId[0]->parameters.data == NULL)
2787 goto cleanup;
2788 (void) memcpy(algId[0]->parameters.data, buf2, buf2_len);
2789 algId[0]->parameters.length = buf2_len;
2790 algId[0]->algorithm = dh_oid;
2792 algId[1] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
2793 if (algId[1] == NULL)
2794 goto cleanup;
2795 algId[1]->parameters.data = (unsigned char *)malloc(buf3_len);
2796 if (algId[1]->parameters.data == NULL)
2797 goto cleanup;
2798 (void) memcpy(algId[1]->parameters.data, buf3, buf3_len);
2799 algId[1]->parameters.length = buf3_len;
2800 algId[1]->algorithm = dh_oid;
2802 algId[2] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
2803 if (algId[2] == NULL)
2804 goto cleanup;
2805 algId[2]->parameters.data = (unsigned char *)malloc(buf1_len);
2806 if (algId[2]->parameters.data == NULL)
2807 goto cleanup;
2808 (void) memcpy(algId[2]->parameters.data, buf1, buf1_len);
2809 algId[2]->parameters.length = buf1_len;
2810 algId[2]->algorithm = dh_oid;
2812 } else if (opts->dh_min_bits <= 2048) {
2813 algId = malloc(3 * sizeof(krb5_algorithm_identifier *));
2814 if (algId == NULL)
2815 goto cleanup;
2816 algId[2] = NULL;
2817 algId[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
2818 if (algId[0] == NULL)
2819 goto cleanup;
2820 algId[0]->parameters.data = (unsigned char *)malloc(buf2_len);
2821 if (algId[0]->parameters.data == NULL)
2822 goto cleanup;
2823 (void) memcpy(algId[0]->parameters.data, buf2, buf2_len);
2824 algId[0]->parameters.length = buf2_len;
2825 algId[0]->algorithm = dh_oid;
2827 algId[1] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
2828 if (algId[1] == NULL)
2829 goto cleanup;
2830 algId[1]->parameters.data = (unsigned char *)malloc(buf3_len);
2831 if (algId[1]->parameters.data == NULL)
2832 goto cleanup;
2833 (void) memcpy(algId[1]->parameters.data, buf3, buf3_len);
2834 algId[1]->parameters.length = buf3_len;
2835 algId[1]->algorithm = dh_oid;
2837 } else if (opts->dh_min_bits <= 4096) {
2838 algId = malloc(2 * sizeof(krb5_algorithm_identifier *));
2839 if (algId == NULL)
2840 goto cleanup;
2841 algId[1] = NULL;
2842 algId[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
2843 if (algId[0] == NULL)
2844 goto cleanup;
2845 algId[0]->parameters.data = (unsigned char *)malloc(buf3_len);
2846 if (algId[0]->parameters.data == NULL)
2847 goto cleanup;
2848 (void) memcpy(algId[0]->parameters.data, buf3, buf3_len);
2849 algId[0]->parameters.length = buf3_len;
2850 algId[0]->algorithm = dh_oid;
2853 retval = k5int_encode_krb5_td_dh_parameters((const krb5_algorithm_identifier **)algId, &encoded_algId);
2854 if (retval)
2855 goto cleanup;
2856 #ifdef DEBUG_ASN1
2857 print_buffer_bin((unsigned char *)encoded_algId->data,
2858 encoded_algId->length, "/tmp/kdc_td_dh_params");
2859 #endif
2860 typed_data = malloc (2 * sizeof(krb5_typed_data *));
2861 if (typed_data == NULL) {
2862 retval = ENOMEM;
2863 goto cleanup;
2865 typed_data[1] = NULL;
2866 init_krb5_typed_data(&typed_data[0]);
2867 if (typed_data == NULL) {
2868 retval = ENOMEM;
2869 goto cleanup;
2871 typed_data[0]->type = TD_DH_PARAMETERS;
2872 typed_data[0]->length = encoded_algId->length;
2873 typed_data[0]->data = (unsigned char *)encoded_algId->data;
2874 retval = k5int_encode_krb5_typed_data((const krb5_typed_data**)typed_data,
2875 &data);
2876 if (retval) {
2877 pkiDebug("encode_krb5_typed_data failed\n");
2878 goto cleanup;
2880 #ifdef DEBUG_ASN1
2881 print_buffer_bin((unsigned char *)data->data, data->length,
2882 "/tmp/kdc_edata");
2883 #endif
2884 *out_data = (krb5_data *)malloc(sizeof(krb5_data));
2885 if (*out_data == NULL)
2886 goto cleanup;
2887 (*out_data)->length = data->length;
2888 (*out_data)->data = (char *)malloc(data->length);
2889 if ((*out_data)->data == NULL) {
2890 free(*out_data);
2891 *out_data = NULL;
2892 goto cleanup;
2894 (void) memcpy((*out_data)->data, data->data, data->length);
2896 retval = 0;
2897 cleanup:
2899 free(buf1);
2900 free(buf2);
2901 free(buf3);
2902 if (data != NULL) {
2903 free(data->data);
2904 free(data);
2906 if (typed_data != NULL)
2907 free_krb5_typed_data(&typed_data);
2908 free(encoded_algId);
2910 if (algId != NULL) {
2911 while(algId[i] != NULL) {
2912 free(algId[i]->parameters.data);
2913 free(algId[i]);
2914 i++;
2916 free(algId);
2919 return retval;
2922 /* ARGSUSED */
2923 krb5_error_code
2924 pkinit_check_kdc_pkid(krb5_context context,
2925 pkinit_plg_crypto_context plg_cryptoctx,
2926 pkinit_req_crypto_context req_cryptoctx,
2927 pkinit_identity_crypto_context id_cryptoctx,
2928 unsigned char *pdid_buf,
2929 unsigned int pkid_len,
2930 int *valid_kdcPkId)
2932 krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2933 PKCS7_ISSUER_AND_SERIAL *is = NULL;
2934 const unsigned char *p = pdid_buf;
2935 int status = 1;
2936 X509 *kdc_cert = sk_X509_value(id_cryptoctx->my_certs, id_cryptoctx->cert_index);
2938 *valid_kdcPkId = 0;
2939 pkiDebug("found kdcPkId in AS REQ\n");
2940 is = d2i_PKCS7_ISSUER_AND_SERIAL(NULL, &p, (int)pkid_len);
2941 if (is == NULL)
2942 goto cleanup;
2944 status = X509_NAME_cmp(X509_get_issuer_name(kdc_cert), is->issuer);
2945 if (!status) {
2946 status = ASN1_INTEGER_cmp(X509_get_serialNumber(kdc_cert), is->serial);
2947 if (!status)
2948 *valid_kdcPkId = 1;
2951 retval = 0;
2952 cleanup:
2953 X509_NAME_free(is->issuer);
2954 ASN1_INTEGER_free(is->serial);
2955 free(is);
2957 return retval;
2960 static int
2961 pkinit_check_dh_params(BIGNUM * p1, BIGNUM * p2, BIGNUM * g1, BIGNUM * q1)
2963 BIGNUM *g2 = NULL, *q2 = NULL;
2964 /* Solaris Kerberos */
2965 int retval = EINVAL;
2967 if (!BN_cmp(p1, p2)) {
2968 g2 = BN_new();
2969 BN_set_word(g2, DH_GENERATOR_2);
2970 if (!BN_cmp(g1, g2)) {
2971 q2 = BN_new();
2972 BN_rshift1(q2, p1);
2973 if (!BN_cmp(q1, q2)) {
2974 pkiDebug("good %d dhparams\n", BN_num_bits(p1));
2975 retval = 0;
2976 } else
2977 pkiDebug("bad group 2 q dhparameter\n");
2978 BN_free(q2);
2979 } else
2980 pkiDebug("bad g dhparameter\n");
2981 BN_free(g2);
2982 } else
2983 pkiDebug("p is not well-known group 2 dhparameter\n");
2985 return retval;
2988 /* ARGSUSED */
2989 krb5_error_code
2990 pkinit_process_td_dh_params(krb5_context context,
2991 pkinit_plg_crypto_context cryptoctx,
2992 pkinit_req_crypto_context req_cryptoctx,
2993 pkinit_identity_crypto_context id_cryptoctx,
2994 krb5_algorithm_identifier **algId,
2995 int *new_dh_size)
2997 krb5_error_code retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
2998 int i = 0, use_sent_dh = 0, ok = 0;
3000 pkiDebug("dh parameters\n");
3002 while (algId[i] != NULL) {
3003 DH *dh = NULL;
3004 unsigned char *tmp = NULL;
3005 int dh_prime_bits = 0;
3007 if (algId[i]->algorithm.length != dh_oid.length ||
3008 memcmp(algId[i]->algorithm.data, dh_oid.data, dh_oid.length))
3009 goto cleanup;
3011 tmp = algId[i]->parameters.data;
3012 dh = DH_new();
3013 dh = pkinit_decode_dh_params(&dh, &tmp, algId[i]->parameters.length);
3014 dh_prime_bits = BN_num_bits(dh->p);
3015 pkiDebug("client sent %d DH bits server prefers %d DH bits\n",
3016 *new_dh_size, dh_prime_bits);
3017 switch(dh_prime_bits) {
3018 case 1024:
3019 if (pkinit_check_dh_params(cryptoctx->dh_1024->p, dh->p,
3020 dh->g, dh->q) == 0) {
3021 *new_dh_size = 1024;
3022 ok = 1;
3024 break;
3025 case 2048:
3026 if (pkinit_check_dh_params(cryptoctx->dh_2048->p, dh->p,
3027 dh->g, dh->q) == 0) {
3028 *new_dh_size = 2048;
3029 ok = 1;
3031 break;
3032 case 4096:
3033 if (pkinit_check_dh_params(cryptoctx->dh_4096->p, dh->p,
3034 dh->g, dh->q) == 0) {
3035 *new_dh_size = 4096;
3036 ok = 1;
3038 break;
3039 default:
3040 break;
3042 if (!ok) {
3043 DH_check(dh, &retval);
3044 if (retval != 0) {
3045 pkiDebug("DH parameters provided by server are unacceptable\n");
3046 retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
3048 else {
3049 use_sent_dh = 1;
3050 ok = 1;
3053 if (!use_sent_dh)
3054 DH_free(dh);
3055 if (ok) {
3056 if (req_cryptoctx->dh != NULL) {
3057 DH_free(req_cryptoctx->dh);
3058 req_cryptoctx->dh = NULL;
3060 if (use_sent_dh)
3061 req_cryptoctx->dh = dh;
3062 break;
3064 i++;
3067 if (ok)
3068 retval = 0;
3070 cleanup:
3071 return retval;
3074 /* ARGSUSED */
3075 static int
3076 openssl_callback(int ok, X509_STORE_CTX * ctx)
3078 #ifdef DEBUG
3079 if (!ok) {
3080 char buf[DN_BUF_LEN];
3082 X509_NAME_oneline(X509_get_subject_name(ctx->current_cert), buf, sizeof(buf));
3083 pkiDebug("cert = %s\n", buf);
3084 pkiDebug("callback function: %d (%s)\n", ctx->error,
3085 X509_verify_cert_error_string(ctx->error));
3087 #endif
3088 return ok;
3091 static int
3092 openssl_callback_ignore_crls(int ok, X509_STORE_CTX * ctx)
3094 if (!ok) {
3095 switch (ctx->error) {
3096 case X509_V_ERR_UNABLE_TO_GET_CRL:
3097 return 1;
3098 default:
3099 return 0;
3102 return ok;
3105 static ASN1_OBJECT *
3106 pkinit_pkcs7type2oid(pkinit_plg_crypto_context cryptoctx, int pkcs7_type)
3108 int nid;
3110 switch (pkcs7_type) {
3111 case CMS_SIGN_CLIENT:
3112 return cryptoctx->id_pkinit_authData;
3113 case CMS_SIGN_DRAFT9:
3115 * Delay creating this OID until we know we need it.
3116 * It shadows an existing OpenSSL oid. If it
3117 * is created too early, it breaks things like
3118 * the use of pkcs12 (which uses pkcs7 structures).
3119 * We need this shadow version because our code
3120 * depends on the "other" type to be unknown to the
3121 * OpenSSL code.
3123 if (cryptoctx->id_pkinit_authData9 == NULL) {
3124 pkiDebug("%s: Creating shadow instance of pkcs7-data oid\n",
3125 __FUNCTION__);
3126 nid = OBJ_create("1.2.840.113549.1.7.1", "id-pkcs7-data",
3127 "PKCS7 data");
3128 if (nid == NID_undef)
3129 return NULL;
3130 cryptoctx->id_pkinit_authData9 = OBJ_nid2obj(nid);
3132 return cryptoctx->id_pkinit_authData9;
3133 case CMS_SIGN_SERVER:
3134 return cryptoctx->id_pkinit_DHKeyData;
3135 case CMS_ENVEL_SERVER:
3136 return cryptoctx->id_pkinit_rkeyData;
3137 default:
3138 return NULL;
3143 #ifdef LONGHORN_BETA_COMPAT
3144 #if 0
3146 * This is a version that worked with Longhorn Beta 3.
3148 static int
3149 wrap_signeddata(unsigned char *data, unsigned int data_len,
3150 unsigned char **out, unsigned int *out_len,
3151 int is_longhorn_server)
3154 unsigned int orig_len = 0, oid_len = 0, tot_len = 0;
3155 ASN1_OBJECT *oid = NULL;
3156 unsigned char *p = NULL;
3158 pkiDebug("%s: This is the Longhorn version and is_longhorn_server = %d\n",
3159 __FUNCTION__, is_longhorn_server);
3161 /* Get length to wrap the original data with SEQUENCE tag */
3162 tot_len = orig_len = ASN1_object_size(1, (int)data_len, V_ASN1_SEQUENCE);
3164 if (is_longhorn_server == 0) {
3165 /* Add the signedData OID and adjust lengths */
3166 oid = OBJ_nid2obj(NID_pkcs7_signed);
3167 oid_len = i2d_ASN1_OBJECT(oid, NULL);
3169 tot_len = ASN1_object_size(1, (int)(orig_len+oid_len), V_ASN1_SEQUENCE);
3172 p = *out = (unsigned char *)malloc(tot_len);
3173 if (p == NULL) return -1;
3175 if (is_longhorn_server == 0) {
3176 ASN1_put_object(&p, 1, (int)(orig_len+oid_len),
3177 V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3179 i2d_ASN1_OBJECT(oid, &p);
3181 ASN1_put_object(&p, 1, (int)data_len, 0, V_ASN1_CONTEXT_SPECIFIC);
3182 } else {
3183 ASN1_put_object(&p, 1, (int)data_len, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3185 memcpy(p, data, data_len);
3187 *out_len = tot_len;
3189 return 0;
3191 #else
3193 * This is a version that works with a patched Longhorn KDC.
3194 * (Which should match SP1 ??).
3196 static int
3197 wrap_signeddata(unsigned char *data, unsigned int data_len,
3198 unsigned char **out, unsigned int *out_len,
3199 int is_longhorn_server)
3202 unsigned int oid_len = 0, tot_len = 0, wrap_len = 0, tag_len = 0;
3203 ASN1_OBJECT *oid = NULL;
3204 unsigned char *p = NULL;
3206 pkiDebug("%s: This is the Longhorn version and is_longhorn_server = %d\n",
3207 __FUNCTION__, is_longhorn_server);
3209 /* New longhorn is missing another sequence */
3210 if (is_longhorn_server == 1)
3211 wrap_len = ASN1_object_size(1, (int)(data_len), V_ASN1_SEQUENCE);
3212 else
3213 wrap_len = data_len;
3215 /* Get length to wrap the original data with SEQUENCE tag */
3216 tag_len = ASN1_object_size(1, (int)wrap_len, V_ASN1_SEQUENCE);
3218 /* Always add oid */
3219 oid = OBJ_nid2obj(NID_pkcs7_signed);
3220 oid_len = i2d_ASN1_OBJECT(oid, NULL);
3221 oid_len += tag_len;
3223 tot_len = ASN1_object_size(1, (int)(oid_len), V_ASN1_SEQUENCE);
3225 p = *out = (unsigned char *)malloc(tot_len);
3226 if (p == NULL)
3227 return -1;
3229 ASN1_put_object(&p, 1, (int)(oid_len),
3230 V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3232 i2d_ASN1_OBJECT(oid, &p);
3234 ASN1_put_object(&p, 1, (int)wrap_len, 0, V_ASN1_CONTEXT_SPECIFIC);
3236 /* Wrap in extra seq tag */
3237 if (is_longhorn_server == 1) {
3238 ASN1_put_object(&p, 1, (int)data_len, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3240 (void) memcpy(p, data, data_len);
3242 *out_len = tot_len;
3244 return 0;
3247 #endif
3248 #else
3249 static int
3250 wrap_signeddata(unsigned char *data, unsigned int data_len,
3251 unsigned char **out, unsigned int *out_len)
3254 unsigned int orig_len = 0, oid_len = 0, tot_len = 0;
3255 ASN1_OBJECT *oid = NULL;
3256 unsigned char *p = NULL;
3258 /* Get length to wrap the original data with SEQUENCE tag */
3259 tot_len = orig_len = ASN1_object_size(1, (int)data_len, V_ASN1_SEQUENCE);
3261 /* Add the signedData OID and adjust lengths */
3262 oid = OBJ_nid2obj(NID_pkcs7_signed);
3263 oid_len = i2d_ASN1_OBJECT(oid, NULL);
3265 tot_len = ASN1_object_size(1, (int)(orig_len+oid_len), V_ASN1_SEQUENCE);
3267 p = *out = (unsigned char *)malloc(tot_len);
3268 if (p == NULL) return -1;
3270 ASN1_put_object(&p, 1, (int)(orig_len+oid_len),
3271 V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3273 i2d_ASN1_OBJECT(oid, &p);
3275 ASN1_put_object(&p, 1, (int)data_len, 0, V_ASN1_CONTEXT_SPECIFIC);
3276 (void) memcpy(p, data, data_len);
3278 *out_len = tot_len;
3280 return 0;
3282 #endif
3284 static int
3285 prepare_enc_data(unsigned char *indata,
3286 int indata_len,
3287 unsigned char **outdata,
3288 int *outdata_len)
3290 /* Solaris Kerberos */
3291 ASN1_const_CTX c;
3292 long length = indata_len;
3293 int Ttag, Tclass;
3294 long Tlen;
3296 c.pp = (const unsigned char **)&indata;
3297 c.q = *(const unsigned char **)&indata;
3298 c.error = ERR_R_NESTED_ASN1_ERROR;
3299 c.p= *(const unsigned char **)&indata;
3300 c.max = (length == 0)?0:(c.p+length);
3302 asn1_GetSequence(&c,&length);
3304 ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen);
3305 c.p += Tlen;
3306 ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen);
3308 asn1_const_Finish(&c);
3310 *outdata = (unsigned char *)malloc((size_t)Tlen);
3311 /* Solaris Kerberos */
3312 if (outdata == NULL)
3313 return ENOMEM;
3315 (void) memcpy(*outdata, c.p, (size_t)Tlen);
3316 *outdata_len = Tlen;
3318 return 0;
3321 #ifndef WITHOUT_PKCS11
3322 static void *
3323 pkinit_C_LoadModule(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p)
3325 void *handle;
3326 CK_RV (*getflist)(CK_FUNCTION_LIST_PTR_PTR);
3328 pkiDebug("loading module \"%s\"... ", modname);
3329 /* Solaris Kerberos */
3330 handle = dlopen(modname, RTLD_NOW | RTLD_GROUP);
3331 if (handle == NULL) {
3332 pkiDebug("not found\n");
3333 return NULL;
3335 getflist = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR)) dlsym(handle, "C_GetFunctionList");
3336 if (getflist == NULL || (*getflist)(p11p) != CKR_OK) {
3337 (void) dlclose(handle);
3338 pkiDebug("failed\n");
3339 return NULL;
3341 pkiDebug("ok\n");
3342 return handle;
3345 static CK_RV
3346 pkinit_C_UnloadModule(void *handle)
3348 /* Solaris Kerberos */
3349 if (dlclose(handle) != 0)
3350 return CKR_GENERAL_ERROR;
3352 return CKR_OK;
3356 * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3357 * code.
3359 * labelstr will be C string containing token label with trailing white space
3360 * removed.
3362 static void
3363 trim_token_label(CK_TOKEN_INFO *tinfo, char *labelstr, unsigned int labelstr_len)
3365 int i;
3367 assert(labelstr_len > sizeof (tinfo->label));
3369 * \0 terminate labelstr in case the last char in the token label is
3370 * non-whitespace
3372 labelstr[sizeof (tinfo->label)] = '\0';
3373 (void) memcpy(labelstr, (char *) tinfo->label, sizeof (tinfo->label));
3375 /* init i so terminating \0 is skipped */
3376 for (i = sizeof (tinfo->label) - 1; i >= 0; i--) {
3377 if (labelstr[i] == ' ')
3378 labelstr[i] = '\0';
3379 else
3380 break;
3385 * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3386 * code.
3388 static krb5_error_code
3389 pkinit_prompt_user(krb5_context context,
3390 pkinit_identity_crypto_context cctx,
3391 krb5_data *reply,
3392 char *prompt,
3393 int hidden)
3395 krb5_error_code r;
3396 krb5_prompt kprompt;
3397 krb5_prompt_type prompt_type;
3399 if (cctx->prompter == NULL)
3400 return (EINVAL);
3402 kprompt.prompt = prompt;
3403 kprompt.hidden = hidden;
3404 kprompt.reply = reply;
3406 * Note, assuming this type for now, may need to be passed in in the future.
3408 prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
3410 /* PROMPTER_INVOCATION */
3411 k5int_set_prompt_types(context, &prompt_type);
3412 r = (*cctx->prompter)(context, cctx->prompter_data,
3413 NULL, NULL, 1, &kprompt);
3414 k5int_set_prompt_types(context, NULL);
3415 return (r);
3419 * Solaris Kerberos: this function was changed to support a PIN being passed
3420 * in. If that is the case the user will not be prompted for their PIN.
3422 static krb5_error_code
3423 pkinit_login(krb5_context context,
3424 pkinit_identity_crypto_context id_cryptoctx,
3425 CK_TOKEN_INFO *tip)
3427 krb5_data rdat;
3428 char *prompt;
3429 int prompt_len;
3430 int r = 0;
3432 if (tip->flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
3433 rdat.data = NULL;
3434 rdat.length = 0;
3435 } else if (id_cryptoctx->PIN != NULL) {
3436 if ((rdat.data = strdup(id_cryptoctx->PIN)) == NULL)
3437 return (ENOMEM);
3439 * Don't include NULL string terminator in length calculation as this
3440 * PIN is passed to the C_Login function and only the text chars should
3441 * be considered to be the PIN.
3443 rdat.length = strlen(id_cryptoctx->PIN);
3444 } else {
3445 /* Solaris Kerberos - trim token label */
3446 char tmplabel[sizeof (tip->label) + 1];
3448 if (!id_cryptoctx->prompter) {
3449 pkiDebug("pkinit_login: id_cryptoctx->prompter is NULL\n");
3450 /* Solaris Kerberos: Improved error messages */
3451 krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
3452 gettext("Failed to log into token: prompter function is NULL"));
3453 return (KRB5KDC_ERR_PREAUTH_FAILED);
3455 /* Solaris Kerberos - Changes for gettext() */
3456 prompt_len = sizeof (tip->label) + 256;
3457 if ((prompt = (char *) malloc(prompt_len)) == NULL)
3458 return ENOMEM;
3460 /* Solaris Kerberos - trim token label which can be padded with space */
3461 trim_token_label(tip, tmplabel, sizeof (tmplabel));
3462 (void) snprintf(prompt, prompt_len, gettext("%s PIN"), tmplabel);
3464 /* Solaris Kerberos */
3465 if (tip->flags & CKF_USER_PIN_LOCKED)
3466 (void) strlcat(prompt, gettext(" (Warning: PIN locked)"), prompt_len);
3467 else if (tip->flags & CKF_USER_PIN_FINAL_TRY)
3468 (void) strlcat(prompt, gettext(" (Warning: PIN final try)"), prompt_len);
3469 else if (tip->flags & CKF_USER_PIN_COUNT_LOW)
3470 (void) strlcat(prompt, gettext(" (Warning: PIN count low)"), prompt_len);
3471 rdat.data = malloc(tip->ulMaxPinLen + 2);
3472 rdat.length = tip->ulMaxPinLen + 1;
3474 * Note that the prompter function will set rdat.length such that the
3475 * NULL terminator is not included
3477 /* PROMPTER_INVOCATION */
3478 r = pkinit_prompt_user(context, id_cryptoctx, &rdat, prompt, 1);
3479 free(prompt);
3482 if (r == 0) {
3483 r = id_cryptoctx->p11->C_Login(id_cryptoctx->session, CKU_USER,
3484 (u_char *) rdat.data, rdat.length);
3486 if (r != CKR_OK) {
3487 pkiDebug("C_Login: %s\n", pkinit_pkcs11_code_to_text(r));
3488 /* Solaris Kerberos: Improved error messages */
3489 krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
3490 gettext("Failed to log into token: %s"),
3491 pkinit_pkcs11_code_to_text(r));
3492 r = KRB5KDC_ERR_PREAUTH_FAILED;
3493 } else {
3494 /* Solaris Kerberos: only need to login once */
3495 id_cryptoctx->p11flags |= C_LOGIN_DONE;
3498 if (rdat.data) {
3499 (void) memset(rdat.data, 0, rdat.length);
3500 free(rdat.data);
3503 return (r);
3507 * Solaris Kerberos: added these structs in support of prompting user for
3508 * missing token.
3510 struct _token_entry {
3511 CK_SLOT_ID slotID;
3512 CK_SESSION_HANDLE session;
3513 CK_TOKEN_INFO token_info;
3515 struct _token_choices {
3516 unsigned int numtokens;
3517 struct _token_entry *token_array;
3522 * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3523 * code.
3525 static krb5_error_code
3526 pkinit_prompt_token(krb5_context context,
3527 pkinit_identity_crypto_context cctx)
3529 char tmpbuf[4];
3530 krb5_data reply;
3531 char *token_prompt = gettext("If you have a smartcard insert it now. "
3532 "Press enter to continue");
3534 reply.data = tmpbuf;
3535 reply.length = sizeof(tmpbuf);
3537 /* note, don't care about the reply */
3538 return (pkinit_prompt_user(context, cctx, &reply, token_prompt, 0));
3542 * Solaris Kerberos: new defines for prompting support.
3544 #define CHOOSE_THIS_TOKEN 0
3545 #define CHOOSE_RESCAN 1
3546 #define CHOOSE_SKIP 2
3547 #define CHOOSE_SEE_NEXT 3
3549 #define RESCAN_TOKENS -1
3550 #define SKIP_TOKENS -2
3553 * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3554 * code.
3556 * This prompts to user for various choices regarding a token to use. Note
3557 * that if there is no error, choice will be set to one of:
3558 * - the token_choices->token_array entry
3559 * - RESCAN_TOKENS
3560 * - SKIP_TOKENS
3562 static int
3563 pkinit_choose_tokens(krb5_context context,
3564 pkinit_identity_crypto_context cctx,
3565 struct _token_choices *token_choices,
3566 int *choice)
3568 krb5_error_code r;
3570 * Assuming that PAM_MAX_MSG_SIZE is a reasonable restriction. Note that -
3571 * 2 is to account for the fact that a krb prompter to PAM conv bridge will
3572 * add ": ".
3574 char prompt[PAM_MAX_MSG_SIZE - 2];
3575 char tmpbuf[4];
3576 char tmplabel[sizeof (token_choices->token_array->token_info.label) + 1];
3577 krb5_data reply;
3578 int i, num_used, tmpchoice;
3580 assert(token_choices != NULL);
3581 assert(choice != NULL);
3583 /* Create the menu prompt */
3585 /* only need to do this once before the for loop */
3586 reply.data = tmpbuf;
3588 for (i = 0; i < token_choices->numtokens; i++) {
3590 trim_token_label(&token_choices->token_array[i].token_info, tmplabel,
3591 sizeof (tmplabel));
3593 if (i == (token_choices->numtokens - 1)) {
3594 /* no more smartcards/tokens */
3595 if ((num_used = snprintf(prompt, sizeof (prompt),
3596 "%s\n%d: %s \"%s\" %s %d\n%d: %s\n%d: %s\n",
3598 * TRANSLATION_NOTE: Translations of the
3599 * following 5 strings must not exceed 450
3600 * bytes total.
3602 gettext("Select one of the following and press enter:"),
3603 CHOOSE_THIS_TOKEN, gettext("Use smartcard"), tmplabel,
3604 gettext("in slot"), token_choices->token_array[i].slotID,
3605 CHOOSE_RESCAN, gettext("Rescan for newly inserted smartcard"),
3606 CHOOSE_SKIP, gettext("Skip smartcard authentication")))
3607 >= sizeof (prompt)) {
3608 pkiDebug("pkinit_choose_tokens: buffer overflow num_used: %d,"
3609 " sizeof prompt: %d\n", num_used, sizeof (prompt));
3610 krb5_set_error_message(context, EINVAL,
3611 gettext("In pkinit_choose_tokens: prompt size"
3612 " %d exceeds prompt buffer size %d"),
3613 num_used, sizeof(prompt));
3614 (void) snprintf(prompt, sizeof (prompt), "%s",
3615 gettext("Error: PKINIT prompt message is too large for buffer, "
3616 "please alert the system administrator. Press enter to "
3617 "continue"));
3618 reply.length = sizeof(tmpbuf);
3619 if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
3620 return (r);
3621 return (EINVAL);
3623 } else {
3624 if ((num_used = snprintf(prompt, sizeof (prompt),
3625 "%s\n%d: %s \"%s\" %s %d\n%d: %s\n%d: %s\n%d: %s\n",
3627 * TRANSLATION_NOTE: Translations of the
3628 * following 6 strings must not exceed 445
3629 * bytes total.
3631 gettext("Select one of the following and press enter:"),
3632 CHOOSE_THIS_TOKEN, gettext("Use smartcard"), tmplabel,
3633 gettext("in slot"), token_choices->token_array[i].slotID,
3634 CHOOSE_RESCAN, gettext("Rescan for newly inserted smartcard"),
3635 CHOOSE_SKIP, gettext("Skip smartcard authentication"),
3636 CHOOSE_SEE_NEXT, gettext("See next smartcard")))
3637 >= sizeof (prompt)) {
3639 pkiDebug("pkinit_choose_tokens: buffer overflow num_used: %d,"
3640 " sizeof prompt: %d\n", num_used, sizeof (prompt));
3641 krb5_set_error_message(context, EINVAL,
3642 gettext("In pkinit_choose_tokens: prompt size"
3643 " %d exceeds prompt buffer size %d"),
3644 num_used, sizeof(prompt));
3645 (void) snprintf(prompt, sizeof (prompt), "%s",
3646 gettext("Error: PKINIT prompt message is too large for buffer, "
3647 "please alert the system administrator. Press enter to "
3648 "continue"));
3649 reply.length = sizeof(tmpbuf);
3650 if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
3651 return (r);
3652 return (EINVAL);
3657 * reply.length needs to be reset to length of tmpbuf before calling
3658 * prompter
3660 reply.length = sizeof(tmpbuf);
3661 if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
3662 return (r);
3664 if (reply.length == 0) {
3665 return (EINVAL);
3666 } else {
3667 char *cp = reply.data;
3668 /* reply better be digits */
3669 while (*cp != '\0') {
3670 if (!isdigit(*cp++))
3671 return (EINVAL);
3673 errno = 0;
3674 tmpchoice = (int) strtol(reply.data, (char **)NULL, 10);
3675 if (errno != 0)
3676 return (errno);
3679 switch (tmpchoice) {
3680 case CHOOSE_THIS_TOKEN:
3681 *choice = i; /* chosen entry of token_choices->token_array */
3682 return (0);
3683 case CHOOSE_RESCAN:
3684 *choice = RESCAN_TOKENS; /* rescan for new smartcard */
3685 return (0);
3686 case CHOOSE_SKIP:
3687 *choice = SKIP_TOKENS; /* skip smartcard auth */
3688 return (0);
3689 case CHOOSE_SEE_NEXT: /* see next smartcard */
3690 continue;
3691 default:
3692 return (EINVAL);
3696 return (0);
3700 * Solaris Kerberos: this is a new function that does not exist yet in the MIT
3701 * code.
3703 * Note, this isn't the best solution to providing a function to check the
3704 * certs in a token however I wanted to avoid rewriting a bunch of code so I
3705 * settled for some duplication of processing.
3707 static krb5_error_code
3708 check_load_certs(krb5_context context,
3709 CK_SESSION_HANDLE session,
3710 pkinit_plg_crypto_context plg_cryptoctx,
3711 pkinit_req_crypto_context req_cryptoctx,
3712 pkinit_identity_crypto_context id_cryptoctx,
3713 krb5_principal princ,
3714 int do_matching,
3715 int load_cert)
3717 CK_OBJECT_CLASS cls;
3718 CK_OBJECT_HANDLE obj;
3719 CK_ATTRIBUTE attrs[4];
3720 CK_ULONG count;
3721 CK_CERTIFICATE_TYPE certtype;
3722 CK_BYTE_PTR cert = NULL, cert_id = NULL;
3723 const unsigned char *cp;
3724 int i, r;
3725 unsigned int nattrs;
3726 X509 *x = NULL;
3728 cls = CKO_CERTIFICATE;
3729 attrs[0].type = CKA_CLASS;
3730 attrs[0].pValue = &cls;
3731 attrs[0].ulValueLen = sizeof cls;
3733 certtype = CKC_X_509;
3734 attrs[1].type = CKA_CERTIFICATE_TYPE;
3735 attrs[1].pValue = &certtype;
3736 attrs[1].ulValueLen = sizeof certtype;
3738 nattrs = 2;
3740 /* If a cert id and/or label were given, use them too */
3741 if (id_cryptoctx->cert_id_len > 0) {
3742 attrs[nattrs].type = CKA_ID;
3743 attrs[nattrs].pValue = id_cryptoctx->cert_id;
3744 attrs[nattrs].ulValueLen = id_cryptoctx->cert_id_len;
3745 nattrs++;
3747 if (id_cryptoctx->cert_label != NULL) {
3748 attrs[nattrs].type = CKA_LABEL;
3749 attrs[nattrs].pValue = id_cryptoctx->cert_label;
3750 attrs[nattrs].ulValueLen = strlen(id_cryptoctx->cert_label);
3751 nattrs++;
3754 r = id_cryptoctx->p11->C_FindObjectsInit(session, attrs, nattrs);
3755 if (r != CKR_OK) {
3756 pkiDebug("C_FindObjectsInit: %s\n", pkinit_pkcs11_code_to_text(r));
3757 krb5_set_error_message(context, EINVAL,
3758 gettext("PKCS11 error from C_FindObjectsInit: %s"),
3759 pkinit_pkcs11_code_to_text(r));
3760 r = EINVAL;
3761 goto out;
3764 for (i = 0; ; i++) {
3765 if (i >= MAX_CREDS_ALLOWED) {
3766 r = EINVAL;
3767 goto out;
3770 /* Look for x.509 cert */
3771 /* Solaris Kerberos */
3772 if ((r = id_cryptoctx->p11->C_FindObjects(session, &obj, 1, &count))
3773 != CKR_OK || count == 0) {
3774 id_cryptoctx->creds[i] = NULL;
3775 break;
3778 /* Get cert and id len */
3779 attrs[0].type = CKA_VALUE;
3780 attrs[0].pValue = NULL;
3781 attrs[0].ulValueLen = 0;
3783 attrs[1].type = CKA_ID;
3784 attrs[1].pValue = NULL;
3785 attrs[1].ulValueLen = 0;
3787 if ((r = id_cryptoctx->p11->C_GetAttributeValue(session,
3788 obj,
3789 attrs,
3790 2)) != CKR_OK &&
3791 r != CKR_BUFFER_TOO_SMALL) {
3792 pkiDebug("C_GetAttributeValue: %s\n", pkinit_pkcs11_code_to_text(r));
3793 krb5_set_error_message(context, EINVAL,
3794 gettext("Error from PKCS11 C_GetAttributeValue: %s"),
3795 pkinit_pkcs11_code_to_text(r));
3796 r = EINVAL;
3797 goto out;
3799 cert = malloc((size_t) attrs[0].ulValueLen + 1);
3800 if (cert == NULL) {
3801 r = ENOMEM;
3802 goto out;
3804 cert_id = malloc((size_t) attrs[1].ulValueLen + 1);
3805 if (cert_id == NULL) {
3806 r = ENOMEM;
3807 goto out;
3810 /* Read the cert and id off the card */
3812 attrs[0].type = CKA_VALUE;
3813 attrs[0].pValue = cert;
3815 attrs[1].type = CKA_ID;
3816 attrs[1].pValue = cert_id;
3818 if ((r = id_cryptoctx->p11->C_GetAttributeValue(session,
3819 obj, attrs, 2)) != CKR_OK) {
3820 pkiDebug("C_GetAttributeValue: %s\n", pkinit_pkcs11_code_to_text(r));
3821 krb5_set_error_message(context, EINVAL,
3822 gettext("Error from PKCS11 C_GetAttributeValue: %s"),
3823 pkinit_pkcs11_code_to_text(r));
3824 r = EINVAL;
3825 goto out;
3828 pkiDebug("cert %d size %d id %d idlen %d\n", i,
3829 (int) attrs[0].ulValueLen, (int) cert_id[0],
3830 (int) attrs[1].ulValueLen);
3832 cp = (unsigned char *) cert;
3833 x = d2i_X509(NULL, &cp, (int) attrs[0].ulValueLen);
3834 if (x == NULL) {
3835 r = EINVAL;
3836 goto out;
3839 id_cryptoctx->creds[i] = malloc(sizeof(struct _pkinit_cred_info));
3840 if (id_cryptoctx->creds[i] == NULL) {
3841 r = ENOMEM;
3842 goto out;
3844 id_cryptoctx->creds[i]->cert = x;
3845 id_cryptoctx->creds[i]->key = NULL;
3846 id_cryptoctx->creds[i]->cert_id = cert_id;
3847 cert_id = NULL;
3848 id_cryptoctx->creds[i]->cert_id_len = attrs[1].ulValueLen;
3849 free(cert);
3850 cert = NULL;
3852 id_cryptoctx->p11->C_FindObjectsFinal(session);
3854 if (id_cryptoctx->creds[0] == NULL || id_cryptoctx->creds[0]->cert == NULL) {
3855 r = ENOENT;
3856 } else if (do_matching){
3858 * Do not let pkinit_cert_matching set the primary cert in id_cryptoctx
3859 * as this will be done later.
3861 r = pkinit_cert_matching(context, plg_cryptoctx, req_cryptoctx,
3862 id_cryptoctx, princ, FALSE);
3865 out:
3866 if ((r != 0 || !load_cert) &&
3867 id_cryptoctx->creds[0] != NULL &&
3868 id_cryptoctx->creds[0]->cert != NULL) {
3870 * If there's an error or load_cert isn't 1 free all the certs loaded
3871 * onto id_cryptoctx.
3873 (void) crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
3874 id_cryptoctx);
3877 free(cert);
3879 free(cert_id);
3881 return (r);
3885 * Solaris Kerberos: this function has been significantly modified to prompt
3886 * the user in certain cases so defer to this version when resyncing MIT code.
3888 * pkinit_open_session now does several things including prompting the user if
3889 * do_matching is set which indicates the code is executing in a client
3890 * context. This function fills out a pkinit_identity_crypto_context with a
3891 * set of certs and a open session if a token can be found that matches all
3892 * supplied criteria. If no token is found then the user is prompted one time
3893 * to insert their token. If there is more than one token that matches all
3894 * client criteria the user is prompted to make a choice if in client context.
3895 * If do_matching is false (KDC context) then the first token matching all
3896 * server criteria is chosen.
3898 static krb5_error_code
3899 pkinit_open_session(krb5_context context,
3900 pkinit_plg_crypto_context plg_cryptoctx,
3901 pkinit_req_crypto_context req_cryptoctx,
3902 pkinit_identity_crypto_context cctx,
3903 krb5_principal princ,
3904 int do_matching)
3906 int i, r;
3907 CK_ULONG count = 0;
3908 CK_SLOT_ID_PTR slotlist = NULL, tmpslotlist = NULL;
3909 CK_TOKEN_INFO tinfo;
3910 krb5_boolean tokenmatch = FALSE;
3911 CK_SESSION_HANDLE tmpsession = CK_INVALID_HANDLE;
3912 struct _token_choices token_choices;
3913 int choice = 0;
3915 if (cctx->session != CK_INVALID_HANDLE)
3916 return 0; /* session already open */
3918 /* Load module */
3919 if (cctx->p11_module == NULL) {
3920 cctx->p11_module =
3921 pkinit_C_LoadModule(cctx->p11_module_name, &cctx->p11);
3922 if (cctx->p11_module == NULL)
3923 return KRB5KDC_ERR_PREAUTH_FAILED;
3926 /* Init */
3927 /* Solaris Kerberos: Don't fail if cryptoki is already initialized */
3928 r = cctx->p11->C_Initialize(NULL);
3929 if (r != CKR_OK && r != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
3930 pkiDebug("C_Initialize: %s\n", pkinit_pkcs11_code_to_text(r));
3931 krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
3932 gettext("Error from PKCS11 C_Initialize: %s"),
3933 pkinit_pkcs11_code_to_text(r));
3934 return KRB5KDC_ERR_PREAUTH_FAILED;
3937 (void) memset(&token_choices, 0, sizeof(token_choices));
3940 * Solaris Kerberos:
3941 * If C_Initialize was already called by the process before the pkinit
3942 * module was loaded then record that fact.
3943 * "finalize_pkcs11" is used by pkinit_fini_pkcs11 to determine whether
3944 * or not C_Finalize() should be called.
3946 cctx->finalize_pkcs11 =
3947 (r == CKR_CRYPTOKI_ALREADY_INITIALIZED ? FALSE : TRUE);
3949 * First make sure that is an applicable slot otherwise fail.
3951 * Start by getting a count of all slots with or without tokens.
3954 if ((r = cctx->p11->C_GetSlotList(FALSE, NULL, &count)) != CKR_OK) {
3955 pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
3956 krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
3957 gettext("Error trying to get PKCS11 slot list: %s"),
3958 pkinit_pkcs11_code_to_text(r));
3959 r = KRB5KDC_ERR_PREAUTH_FAILED;
3960 goto out;
3963 if (count == 0) {
3964 /* There are no slots so bail */
3965 r = KRB5KDC_ERR_PREAUTH_FAILED;
3966 krb5_set_error_message(context, r,
3967 gettext("No PKCS11 slots found"));
3968 pkiDebug("pkinit_open_session: no slots, count: %d\n", count);
3969 goto out;
3970 } else if (cctx->slotid != PK_NOSLOT) {
3971 /* See if any of the slots match the specified slotID */
3972 tmpslotlist = malloc(count * sizeof (CK_SLOT_ID));
3973 if (tmpslotlist == NULL) {
3974 krb5_set_error_message(context, ENOMEM,
3975 gettext("Memory allocation error:"));
3976 r = KRB5KDC_ERR_PREAUTH_FAILED;
3977 goto out;
3979 if ((r = cctx->p11->C_GetSlotList(FALSE, tmpslotlist, &count)) != CKR_OK) {
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 pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
3984 r = KRB5KDC_ERR_PREAUTH_FAILED;
3985 goto out;
3988 for (i = 0; i < count && cctx->slotid != tmpslotlist[i]; i++)
3989 continue;
3991 if (i >= count) {
3992 /* no slots match */
3993 r = KRB5KDC_ERR_PREAUTH_FAILED;
3994 krb5_set_error_message(context, r,
3995 gettext("Requested PKCS11 slot ID %d not found"),
3996 cctx->slotid);
3997 pkiDebug("open_session: no matching slot found for slotID %d\n",
3998 cctx->slotid);
3999 goto out;
4003 tryagain:
4004 /* get count of slots that have tokens */
4005 if ((r = cctx->p11->C_GetSlotList(TRUE, NULL, &count)) != CKR_OK) {
4006 pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
4007 krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4008 gettext("Error trying to get PKCS11 slot list: %s"),
4009 pkinit_pkcs11_code_to_text(r));
4010 r = KRB5KDC_ERR_PREAUTH_FAILED;
4011 goto out;
4014 if (count == 0) {
4016 * Note, never prompt if !do_matching as this implies KDC side
4017 * processing
4019 if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
4020 /* found slot(s) but no token so prompt and try again */
4021 if ((r = pkinit_prompt_token(context, cctx)) == 0) {
4022 cctx->p11flags |= C_PROMPTED_USER;
4023 goto tryagain;
4024 } else {
4025 pkiDebug("open_session: prompt for token/smart card failed\n");
4026 krb5_set_error_message(context, r,
4027 gettext("Prompt for token/smart card failed"));
4028 r = KRB5KDC_ERR_PREAUTH_FAILED;
4029 goto out;
4032 } else {
4033 /* already prompted once so bailing */
4034 r = KRB5KDC_ERR_PREAUTH_FAILED;
4035 krb5_set_error_message(context, r,
4036 gettext("No smart card tokens found"));
4037 pkiDebug("pkinit_open_session: no token, already prompted\n");
4038 goto out;
4042 free(slotlist);
4044 slotlist = malloc(count * sizeof (CK_SLOT_ID));
4045 if (slotlist == NULL) {
4046 krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4047 gettext("Memory allocation error"));
4048 r = KRB5KDC_ERR_PREAUTH_FAILED;
4049 goto out;
4052 * Solaris Kerberos: get list of PKCS11 slotid's that have tokens.
4054 if (cctx->p11->C_GetSlotList(TRUE, slotlist, &count) != CKR_OK) {
4055 krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4056 gettext("Error trying to get PKCS11 slot list: %s"),
4057 pkinit_pkcs11_code_to_text(r));
4058 pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
4059 r = KRB5KDC_ERR_PREAUTH_FAILED;
4060 goto out;
4063 token_choices.numtokens = 0;
4064 token_choices.token_array = malloc(count * sizeof (*token_choices.token_array));
4065 if (token_choices.token_array == NULL) {
4066 r = KRB5KDC_ERR_PREAUTH_FAILED;
4067 krb5_set_error_message(context, r,
4068 gettext("Memory allocation error"));
4069 goto out;
4072 /* examine all the tokens */
4073 for (i = 0; i < count; i++) {
4075 * Solaris Kerberos: if a slotid was specified skip slots that don't
4076 * match.
4078 if (cctx->slotid != PK_NOSLOT && cctx->slotid != slotlist[i])
4079 continue;
4081 /* Open session */
4082 if ((r = cctx->p11->C_OpenSession(slotlist[i], CKF_SERIAL_SESSION,
4083 NULL, NULL, &tmpsession)) != CKR_OK) {
4084 pkiDebug("C_OpenSession: %s\n", pkinit_pkcs11_code_to_text(r));
4085 krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4086 gettext("Error trying to open PKCS11 session: %s"),
4087 pkinit_pkcs11_code_to_text(r));
4088 r = KRB5KDC_ERR_PREAUTH_FAILED;
4089 goto out;
4092 /* Get token info */
4093 if ((r = cctx->p11->C_GetTokenInfo(slotlist[i], &tinfo)) != CKR_OK) {
4094 pkiDebug("C_GetTokenInfo: %s\n", pkinit_pkcs11_code_to_text(r));
4095 krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4096 gettext("Error trying to read PKCS11 token: %s"),
4097 pkinit_pkcs11_code_to_text(r));
4098 r = KRB5KDC_ERR_PREAUTH_FAILED;
4099 cctx->p11->C_CloseSession(tmpsession);
4100 goto out;
4103 if (cctx->token_label == NULL) {
4105 * If the token doesn't require login to examine the certs then
4106 * let's check the certs out to see if any match the criteria if
4107 * any.
4109 if (!(tinfo.flags & CKF_LOGIN_REQUIRED)) {
4111 * It's okay to check the certs if we don't have to login but
4112 * don't load the certs onto cctx at this point, this will be
4113 * done later in this function for the chosen token.
4115 if ((r = check_load_certs(context, tmpsession, plg_cryptoctx,
4116 req_cryptoctx, cctx, princ,
4117 do_matching, 0)) == 0) {
4118 tokenmatch = TRUE;
4119 } else if (r != ENOENT){
4120 r = KRB5KDC_ERR_PREAUTH_FAILED;
4121 cctx->p11->C_CloseSession(tmpsession);
4122 goto out;
4123 } else {
4124 /* ignore ENOENT here */
4125 r = 0;
4127 } else {
4128 tokenmatch = TRUE;
4130 } else {
4131 /* + 1 so tokenlabelstr can be \0 terminated */
4132 char tokenlabelstr[sizeof (tinfo.label) + 1];
4135 * Convert token label into C string with trailing white space
4136 * trimmed.
4138 trim_token_label(&tinfo, tokenlabelstr, sizeof (tokenlabelstr));
4140 pkiDebug("open_session: slotid %d token found: \"%s\", "
4141 "cctx->token_label: \"%s\"\n",
4142 slotlist[i], tokenlabelstr, (char *) cctx->token_label);
4144 if (!strcmp(cctx->token_label, tokenlabelstr)) {
4145 if (!(tinfo.flags & CKF_LOGIN_REQUIRED)) {
4147 * It's okay to check the certs if we don't have to login but
4148 * don't load the certs onto cctx at this point, this will be
4149 * done later in this function for the chosen token.
4151 if ((r = check_load_certs(context, tmpsession, plg_cryptoctx,
4152 req_cryptoctx, cctx, princ,
4153 do_matching, 0)) == 0) {
4154 tokenmatch = TRUE;
4155 } else if (r != ENOENT){
4156 r = KRB5KDC_ERR_PREAUTH_FAILED;
4157 cctx->p11->C_CloseSession(tmpsession);
4158 goto out;
4159 } else {
4160 /* ignore ENOENT here */
4161 r = 0;
4163 } else {
4164 tokenmatch = TRUE;
4169 if (tokenmatch == TRUE) {
4170 /* add the token to token_choices.token_array */
4171 token_choices.token_array[token_choices.numtokens].slotID = slotlist[i];
4172 token_choices.token_array[token_choices.numtokens].session = tmpsession;
4173 token_choices.token_array[token_choices.numtokens].token_info = tinfo;
4174 token_choices.numtokens++;
4175 /* !do_matching implies we take the first matching token */
4176 if (!do_matching)
4177 break;
4178 else
4179 tokenmatch = FALSE;
4180 } else {
4181 cctx->p11->C_CloseSession(tmpsession);
4185 if (token_choices.numtokens == 0) {
4187 * Solaris Kerberos: prompt for token one time if there was no token
4188 * and do_matching is 1 (see earlier comment about do_matching).
4190 if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
4191 if ((r = pkinit_prompt_token(context, cctx)) == 0) {
4192 cctx->p11flags |= C_PROMPTED_USER;
4193 goto tryagain;
4194 } else {
4195 pkiDebug("open_session: prompt for token/smart card failed\n");
4196 krb5_set_error_message(context, r,
4197 gettext("Prompt for token/smart card failed"));
4198 r = KRB5KDC_ERR_PREAUTH_FAILED;
4199 goto out;
4201 } else {
4202 r = KRB5KDC_ERR_PREAUTH_FAILED;
4203 krb5_set_error_message(context, r,
4204 gettext("No smart card tokens found"));
4205 pkiDebug("open_session: no matching token found\n");
4206 goto out;
4208 } else if (token_choices.numtokens == 1) {
4209 if ((token_choices.token_array[0].token_info.flags & CKF_LOGIN_REQUIRED) &&
4210 !(cctx->p11flags & C_PROMPTED_USER) &&
4211 do_matching) {
4212 if ((r = pkinit_choose_tokens(context, cctx, &token_choices, &choice)) != 0) {
4213 pkiDebug("pkinit_open_session: pkinit_choose_tokens failed: %d\n", r);
4214 r = KRB5KDC_ERR_PREAUTH_FAILED;
4215 krb5_set_error_message(context, r,
4216 gettext("Prompt for token/smart card failed"));
4217 goto out;
4219 if (choice == RESCAN_TOKENS) {
4220 /* rescan for new smartcard/token */
4221 for (i = 0; i < token_choices.numtokens; i++) {
4222 /* close all sessions */
4223 cctx->p11->C_CloseSession(token_choices.token_array[i].session);
4225 free(token_choices.token_array);
4226 token_choices.token_array = NULL;
4227 token_choices.numtokens = 0;
4228 goto tryagain;
4229 } else if (choice == SKIP_TOKENS) {
4230 /* do not use smartcard/token for auth */
4231 cctx->p11flags |= (C_PROMPTED_USER|C_SKIP_PKCS11_AUTH);
4232 r = KRB5KDC_ERR_PREAUTH_FAILED;
4233 goto out;
4234 } else {
4235 cctx->p11flags |= C_PROMPTED_USER;
4237 } else {
4238 choice = 0; /* really the only choice is the first token_array entry */
4240 } else if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
4241 /* > 1 token so present menu of token choices, let the user decide. */
4242 if ((r = pkinit_choose_tokens(context, cctx, &token_choices, &choice)) != 0) {
4243 pkiDebug("pkinit_open_session: pkinit_choose_tokens failed: %d\n", r);
4244 r = KRB5KDC_ERR_PREAUTH_FAILED;
4245 krb5_set_error_message(context, r,
4246 gettext("Prompt for token/smart card failed"));
4247 goto out;
4249 if (choice == RESCAN_TOKENS) {
4250 /* rescan for new smartcard/token */
4251 for (i = 0; i < token_choices.numtokens; i++) {
4252 /* close all sessions */
4253 cctx->p11->C_CloseSession(token_choices.token_array[i].session);
4255 free(token_choices.token_array);
4256 token_choices.token_array = NULL;
4257 token_choices.numtokens = 0;
4258 goto tryagain;
4259 } else if (choice == SKIP_TOKENS) {
4260 /* do not use smartcard/token for auth */
4261 cctx->p11flags |= (C_PROMPTED_USER|C_SKIP_PKCS11_AUTH);
4262 r = KRB5KDC_ERR_PREAUTH_FAILED;
4263 goto out;
4264 } else {
4265 cctx->p11flags |= C_PROMPTED_USER;
4267 } else {
4268 r = KRB5KDC_ERR_PREAUTH_FAILED;
4269 goto out;
4272 cctx->slotid = token_choices.token_array[choice].slotID;
4273 cctx->session = token_choices.token_array[choice].session;
4275 pkiDebug("open_session: slotid %d (%d of %d)\n", (int) cctx->slotid,
4276 i + 1, (int) count);
4278 /* Login if needed */
4279 /* Solaris Kerberos: added cctx->p11flags check */
4280 if ((token_choices.token_array[choice].token_info.flags & CKF_LOGIN_REQUIRED) &&
4281 !(cctx->p11flags & C_LOGIN_DONE)) {
4282 r = pkinit_login(context, cctx, &token_choices.token_array[choice].token_info);
4285 if (r == 0) {
4286 /* Doing this again to load the certs into cctx. */
4287 r = check_load_certs(context, cctx->session, plg_cryptoctx,
4288 req_cryptoctx, cctx, princ, do_matching, 1);
4291 out:
4292 free(slotlist);
4294 free(tmpslotlist);
4296 if (token_choices.token_array != NULL) {
4297 if (r != 0) {
4298 /* close all sessions if there's an error */
4299 for (i = 0; i < token_choices.numtokens; i++) {
4300 cctx->p11->C_CloseSession(token_choices.token_array[i].session);
4302 cctx->session = CK_INVALID_HANDLE;
4303 } else {
4304 /* close sessions not chosen */
4305 for (i = 0; i < token_choices.numtokens; i++) {
4306 if (i != choice) {
4307 cctx->p11->C_CloseSession(token_choices.token_array[i].session);
4311 free(token_choices.token_array);
4314 return (r);
4318 * Look for a key that's:
4319 * 1. private
4320 * 2. capable of the specified operation (usually signing or decrypting)
4321 * 3. RSA (this may be wrong but it's all we can do for now)
4322 * 4. matches the id of the cert we chose
4324 * You must call pkinit_get_certs before calling pkinit_find_private_key
4325 * (that's because we need the ID of the private key)
4327 * pkcs11 says the id of the key doesn't have to match that of the cert, but
4328 * I can't figure out any other way to decide which key to use.
4330 * We should only find one key that fits all the requirements.
4331 * If there are more than one, we just take the first one.
4334 /* ARGSUSED */
4335 krb5_error_code
4336 pkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx,
4337 CK_ATTRIBUTE_TYPE usage,
4338 CK_OBJECT_HANDLE *objp)
4340 CK_OBJECT_CLASS cls;
4341 CK_ATTRIBUTE attrs[4];
4342 CK_ULONG count;
4343 CK_KEY_TYPE keytype;
4344 unsigned int nattrs = 0;
4345 int r;
4346 #ifdef PKINIT_USE_KEY_USAGE
4347 CK_BBOOL true_false;
4348 #endif
4350 cls = CKO_PRIVATE_KEY;
4351 attrs[nattrs].type = CKA_CLASS;
4352 attrs[nattrs].pValue = &cls;
4353 attrs[nattrs].ulValueLen = sizeof cls;
4354 nattrs++;
4356 #ifdef PKINIT_USE_KEY_USAGE
4358 * Some cards get confused if you try to specify a key usage,
4359 * so don't, and hope for the best. This will fail if you have
4360 * several keys with the same id and different usages but I have
4361 * not seen this on real cards.
4363 true_false = TRUE;
4364 attrs[nattrs].type = usage;
4365 attrs[nattrs].pValue = &true_false;
4366 attrs[nattrs].ulValueLen = sizeof true_false;
4367 nattrs++;
4368 #endif
4370 keytype = CKK_RSA;
4371 attrs[nattrs].type = CKA_KEY_TYPE;
4372 attrs[nattrs].pValue = &keytype;
4373 attrs[nattrs].ulValueLen = sizeof keytype;
4374 nattrs++;
4376 attrs[nattrs].type = CKA_ID;
4377 attrs[nattrs].pValue = id_cryptoctx->cert_id;
4378 attrs[nattrs].ulValueLen = id_cryptoctx->cert_id_len;
4379 nattrs++;
4381 r = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs, nattrs);
4382 if (r != CKR_OK) {
4383 pkiDebug("krb5_pkinit_sign_data: C_FindObjectsInit: %s\n",
4384 pkinit_pkcs11_code_to_text(r));
4385 return KRB5KDC_ERR_PREAUTH_FAILED;
4388 r = id_cryptoctx->p11->C_FindObjects(id_cryptoctx->session, objp, 1, &count);
4389 id_cryptoctx->p11->C_FindObjectsFinal(id_cryptoctx->session);
4390 pkiDebug("found %d private keys (%s)\n", (int) count, pkinit_pkcs11_code_to_text(r));
4393 * Solaris Kerberos:
4394 * The CKA_ID may not be correctly set for the private key. For e.g. when
4395 * storing a private key in softtoken pktool(1) doesn't generate or store
4396 * a CKA_ID for the private key. Another way to identify the private key is
4397 * to look for a private key with the same RSA modulus as the public key
4398 * in the certificate.
4400 if (r == CKR_OK && count != 1) {
4402 EVP_PKEY *priv;
4403 X509 *cert;
4404 unsigned int n_len;
4405 unsigned char *n_bytes;
4407 cert = sk_X509_value(id_cryptoctx->my_certs, 0);
4408 priv = X509_get_pubkey(cert);
4409 if (priv == NULL) {
4410 pkiDebug("Failed to extract pub key from cert\n");
4411 return KRB5KDC_ERR_PREAUTH_FAILED;
4414 nattrs = 0;
4415 cls = CKO_PRIVATE_KEY;
4416 attrs[nattrs].type = CKA_CLASS;
4417 attrs[nattrs].pValue = &cls;
4418 attrs[nattrs].ulValueLen = sizeof cls;
4419 nattrs++;
4421 #ifdef PKINIT_USE_KEY_USAGE
4422 true_false = TRUE;
4423 attrs[nattrs].type = usage;
4424 attrs[nattrs].pValue = &true_false;
4425 attrs[nattrs].ulValueLen = sizeof true_false;
4426 nattrs++;
4427 #endif
4429 keytype = CKK_RSA;
4430 attrs[nattrs].type = CKA_KEY_TYPE;
4431 attrs[nattrs].pValue = &keytype;
4432 attrs[nattrs].ulValueLen = sizeof keytype;
4433 nattrs++;
4435 n_len = BN_num_bytes(priv->pkey.rsa->n);
4436 n_bytes = (unsigned char *) malloc((size_t) n_len);
4437 if (n_bytes == NULL) {
4438 return (ENOMEM);
4441 if (BN_bn2bin(priv->pkey.rsa->n, n_bytes) == 0) {
4442 free (n_bytes);
4443 pkiDebug("zero-byte key modulus\n");
4444 return KRB5KDC_ERR_PREAUTH_FAILED;
4447 attrs[nattrs].type = CKA_MODULUS;
4448 attrs[nattrs].ulValueLen = n_len;
4449 attrs[nattrs].pValue = n_bytes;
4451 nattrs++;
4453 r = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs, nattrs);
4454 free (n_bytes);
4455 if (r != CKR_OK) {
4456 pkiDebug("krb5_pkinit_sign_data: C_FindObjectsInit: %s\n",
4457 pkinit_pkcs11_code_to_text(r));
4458 return KRB5KDC_ERR_PREAUTH_FAILED;
4461 r = id_cryptoctx->p11->C_FindObjects(id_cryptoctx->session, objp, 1, &count);
4462 id_cryptoctx->p11->C_FindObjectsFinal(id_cryptoctx->session);
4463 pkiDebug("found %d private keys (%s)\n", (int) count, pkinit_pkcs11_code_to_text(r));
4467 if (r != CKR_OK || count < 1)
4468 return KRB5KDC_ERR_PREAUTH_FAILED;
4469 return 0;
4471 #endif
4473 /* ARGSUSED */
4474 static krb5_error_code
4475 pkinit_decode_data_fs(krb5_context context,
4476 pkinit_identity_crypto_context id_cryptoctx,
4477 unsigned char *data,
4478 unsigned int data_len,
4479 unsigned char **decoded_data,
4480 unsigned int *decoded_data_len)
4482 if (decode_data(decoded_data, decoded_data_len, data, data_len,
4483 id_cryptoctx->my_key, sk_X509_value(id_cryptoctx->my_certs,
4484 id_cryptoctx->cert_index)) <= 0) {
4485 pkiDebug("failed to decode data\n");
4486 return KRB5KDC_ERR_PREAUTH_FAILED;
4488 return 0;
4491 #ifndef WITHOUT_PKCS11
4492 #ifdef SILLYDECRYPT
4493 CK_RV
4494 pkinit_C_Decrypt(pkinit_identity_crypto_context id_cryptoctx,
4495 CK_BYTE_PTR pEncryptedData,
4496 CK_ULONG ulEncryptedDataLen,
4497 CK_BYTE_PTR pData,
4498 CK_ULONG_PTR pulDataLen)
4500 CK_RV rv = CKR_OK;
4502 rv = id_cryptoctx->p11->C_Decrypt(id_cryptoctx->session, pEncryptedData,
4503 ulEncryptedDataLen, pData, pulDataLen);
4504 if (rv == CKR_OK) {
4505 pkiDebug("pData %x *pulDataLen %d\n", (int) pData, (int) *pulDataLen);
4507 return rv;
4509 #endif
4511 static krb5_error_code
4512 pkinit_decode_data_pkcs11(krb5_context context,
4513 pkinit_identity_crypto_context id_cryptoctx,
4514 unsigned char *data,
4515 unsigned int data_len,
4516 unsigned char **decoded_data,
4517 unsigned int *decoded_data_len)
4519 CK_OBJECT_HANDLE obj;
4520 CK_ULONG len;
4521 CK_MECHANISM mech;
4522 unsigned char *cp;
4523 int r;
4526 * Solaris Kerberos: assume session is open and libpkcs11 funcs have been
4527 * loaded.
4529 assert(id_cryptoctx->p11 != NULL);
4531 /* Solaris Kerberos: Login, if needed, to access private object */
4532 if (!(id_cryptoctx->p11flags & C_LOGIN_DONE)) {
4533 CK_TOKEN_INFO tinfo;
4535 r = id_cryptoctx->p11->C_GetTokenInfo(id_cryptoctx->slotid, &tinfo);
4536 if (r != 0)
4537 return r;
4539 r = pkinit_login(context, id_cryptoctx, &tinfo);
4540 if (r != 0)
4541 return r;
4544 r = pkinit_find_private_key(id_cryptoctx, CKA_DECRYPT, &obj);
4545 if (r != 0)
4546 return r;
4548 mech.mechanism = CKM_RSA_PKCS;
4549 mech.pParameter = NULL;
4550 mech.ulParameterLen = 0;
4552 if ((r = id_cryptoctx->p11->C_DecryptInit(id_cryptoctx->session, &mech,
4553 obj)) != CKR_OK) {
4554 pkiDebug("C_DecryptInit: 0x%x\n", (int) r);
4555 return KRB5KDC_ERR_PREAUTH_FAILED;
4557 pkiDebug("data_len = %d\n", data_len);
4558 cp = (unsigned char *)malloc((size_t) data_len);
4559 if (cp == NULL)
4560 return ENOMEM;
4561 len = data_len;
4562 #ifdef SILLYDECRYPT
4563 pkiDebug("session %x edata %x edata_len %d data %x datalen @%x %d\n",
4564 (int) id_cryptoctx->session, (int) data, (int) data_len, (int) cp,
4565 (int) &len, (int) len);
4566 if ((r = pkinit_C_Decrypt(id_cryptoctx, data, (CK_ULONG) data_len,
4567 cp, &len)) != CKR_OK) {
4568 #else
4569 if ((r = id_cryptoctx->p11->C_Decrypt(id_cryptoctx->session, data,
4570 (CK_ULONG) data_len, cp, &len)) != CKR_OK) {
4571 #endif
4572 pkiDebug("C_Decrypt: %s\n", pkinit_pkcs11_code_to_text(r));
4573 if (r == CKR_BUFFER_TOO_SMALL)
4574 pkiDebug("decrypt %d needs %d\n", (int) data_len, (int) len);
4575 return KRB5KDC_ERR_PREAUTH_FAILED;
4577 pkiDebug("decrypt %d -> %d\n", (int) data_len, (int) len);
4578 *decoded_data_len = len;
4579 *decoded_data = cp;
4581 return 0;
4583 #endif
4585 krb5_error_code
4586 pkinit_decode_data(krb5_context context,
4587 pkinit_identity_crypto_context id_cryptoctx,
4588 unsigned char *data,
4589 unsigned int data_len,
4590 unsigned char **decoded_data,
4591 unsigned int *decoded_data_len)
4593 krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
4595 if (id_cryptoctx->pkcs11_method != 1)
4596 retval = pkinit_decode_data_fs(context, id_cryptoctx, data, data_len,
4597 decoded_data, decoded_data_len);
4598 #ifndef WITHOUT_PKCS11
4599 else
4600 retval = pkinit_decode_data_pkcs11(context, id_cryptoctx, data,
4601 data_len, decoded_data, decoded_data_len);
4602 #endif
4604 return retval;
4607 /* ARGSUSED */
4608 static krb5_error_code
4609 pkinit_sign_data_fs(krb5_context context,
4610 pkinit_identity_crypto_context id_cryptoctx,
4611 unsigned char *data,
4612 unsigned int data_len,
4613 unsigned char **sig,
4614 unsigned int *sig_len)
4616 if (create_signature(sig, sig_len, data, data_len,
4617 id_cryptoctx->my_key) != 0) {
4618 pkiDebug("failed to create the signature\n");
4619 return KRB5KDC_ERR_PREAUTH_FAILED;
4621 return 0;
4624 #ifndef WITHOUT_PKCS11
4625 static krb5_error_code
4626 pkinit_sign_data_pkcs11(krb5_context context,
4627 pkinit_identity_crypto_context id_cryptoctx,
4628 unsigned char *data,
4629 unsigned int data_len,
4630 unsigned char **sig,
4631 unsigned int *sig_len)
4633 CK_OBJECT_HANDLE obj;
4634 CK_ULONG len;
4635 CK_MECHANISM mech;
4636 unsigned char *cp;
4637 int r;
4640 * Solaris Kerberos: assume session is open and libpkcs11 funcs have been
4641 * loaded.
4643 assert(id_cryptoctx->p11 != NULL);
4645 /* Solaris Kerberos: Login, if needed, to access private object */
4646 if (!(id_cryptoctx->p11flags & C_LOGIN_DONE)) {
4647 CK_TOKEN_INFO tinfo;
4649 r = id_cryptoctx->p11->C_GetTokenInfo(id_cryptoctx->slotid, &tinfo);
4650 if (r != 0)
4651 return r;
4653 r = pkinit_login(context, id_cryptoctx, &tinfo);
4654 if (r != 0)
4655 return r;
4658 r = pkinit_find_private_key(id_cryptoctx, CKA_SIGN, &obj);
4659 if (r != 0 )
4660 return r;
4662 mech.mechanism = id_cryptoctx->mech;
4663 mech.pParameter = NULL;
4664 mech.ulParameterLen = 0;
4666 if ((r = id_cryptoctx->p11->C_SignInit(id_cryptoctx->session, &mech,
4667 obj)) != CKR_OK) {
4668 pkiDebug("C_SignInit: %s\n", pkinit_pkcs11_code_to_text(r));
4669 return KRB5KDC_ERR_PREAUTH_FAILED;
4673 * Key len would give an upper bound on sig size, but there's no way to
4674 * get that. So guess, and if it's too small, re-malloc.
4676 len = PK_SIGLEN_GUESS;
4677 cp = (unsigned char *)malloc((size_t) len);
4678 if (cp == NULL)
4679 return ENOMEM;
4681 r = id_cryptoctx->p11->C_Sign(id_cryptoctx->session, data,
4682 (CK_ULONG) data_len, cp, &len);
4683 if (r == CKR_BUFFER_TOO_SMALL || (r == CKR_OK && len >= PK_SIGLEN_GUESS)) {
4684 free(cp);
4685 pkiDebug("C_Sign realloc %d\n", (int) len);
4686 cp = (unsigned char *)malloc((size_t) len);
4687 r = id_cryptoctx->p11->C_Sign(id_cryptoctx->session, data,
4688 (CK_ULONG) data_len, cp, &len);
4690 if (r != CKR_OK) {
4691 pkiDebug("C_Sign: %s\n", pkinit_pkcs11_code_to_text(r));
4692 return KRB5KDC_ERR_PREAUTH_FAILED;
4694 pkiDebug("sign %d -> %d\n", (int) data_len, (int) len);
4695 *sig_len = len;
4696 *sig = cp;
4698 return 0;
4700 #endif
4702 krb5_error_code
4703 pkinit_sign_data(krb5_context context,
4704 pkinit_identity_crypto_context id_cryptoctx,
4705 unsigned char *data,
4706 unsigned int data_len,
4707 unsigned char **sig,
4708 unsigned int *sig_len)
4710 krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
4712 if (id_cryptoctx == NULL || id_cryptoctx->pkcs11_method != 1)
4713 retval = pkinit_sign_data_fs(context, id_cryptoctx, data, data_len,
4714 sig, sig_len);
4715 #ifndef WITHOUT_PKCS11
4716 else
4717 retval = pkinit_sign_data_pkcs11(context, id_cryptoctx, data, data_len,
4718 sig, sig_len);
4719 #endif
4721 return retval;
4725 static krb5_error_code
4726 decode_data(unsigned char **out_data, unsigned int *out_data_len,
4727 unsigned char *data, unsigned int data_len,
4728 EVP_PKEY *pkey, X509 *cert)
4730 /* Solaris Kerberos */
4731 int len;
4732 unsigned char *buf = NULL;
4733 int buf_len = 0;
4735 /* Solaris Kerberos */
4736 if (out_data == NULL || out_data_len == NULL)
4737 return EINVAL;
4739 if (cert && !X509_check_private_key(cert, pkey)) {
4740 pkiDebug("private key does not match certificate\n");
4741 /* Solaris Kerberos */
4742 return EINVAL;
4745 buf_len = EVP_PKEY_size(pkey);
4746 buf = (unsigned char *)malloc((size_t) buf_len + 10);
4747 if (buf == NULL)
4748 return ENOMEM;
4750 #if OPENSSL_VERSION_NUMBER < 0x10000000L
4751 len = EVP_PKEY_decrypt(buf, data, (int)data_len, pkey);
4752 #else
4753 len = EVP_PKEY_decrypt_old(buf, data, (int)data_len, pkey);
4754 #endif
4755 if (len <= 0) {
4756 pkiDebug("unable to decrypt received data (len=%d)\n", data_len);
4757 /* Solaris Kerberos */
4758 free(buf);
4759 return KRB5KRB_ERR_GENERIC;
4761 *out_data = buf;
4762 *out_data_len = len;
4764 return 0;
4767 static krb5_error_code
4768 create_signature(unsigned char **sig, unsigned int *sig_len,
4769 unsigned char *data, unsigned int data_len, EVP_PKEY *pkey)
4771 krb5_error_code retval = ENOMEM;
4772 EVP_MD_CTX md_ctx;
4774 if (pkey == NULL)
4775 /* Solaris Kerberos */
4776 return EINVAL;
4778 EVP_VerifyInit(&md_ctx, EVP_sha1());
4779 EVP_SignUpdate(&md_ctx, data, data_len);
4780 *sig_len = EVP_PKEY_size(pkey);
4781 if ((*sig = (unsigned char *) malloc((size_t) *sig_len)) == NULL)
4782 goto cleanup;
4783 EVP_SignFinal(&md_ctx, *sig, sig_len, pkey);
4785 retval = 0;
4787 cleanup:
4788 EVP_MD_CTX_cleanup(&md_ctx);
4790 return retval;
4794 * Note:
4795 * This is not the routine the KDC uses to get its certificate.
4796 * This routine is intended to be called by the client
4797 * to obtain the KDC's certificate from some local storage
4798 * to be sent as a hint in its request to the KDC.
4800 /* ARGSUSED */
4801 krb5_error_code
4802 pkinit_get_kdc_cert(krb5_context context,
4803 pkinit_plg_crypto_context plg_cryptoctx,
4804 pkinit_req_crypto_context req_cryptoctx,
4805 pkinit_identity_crypto_context id_cryptoctx,
4806 krb5_principal princ)
4808 /* Solaris Kerberos */
4809 if (req_cryptoctx == NULL)
4810 return EINVAL;
4812 req_cryptoctx->received_cert = NULL;
4813 return 0;
4816 /* ARGSUSED */
4817 static krb5_error_code
4818 pkinit_get_certs_pkcs12(krb5_context context,
4819 pkinit_plg_crypto_context plg_cryptoctx,
4820 pkinit_req_crypto_context req_cryptoctx,
4821 pkinit_identity_opts *idopts,
4822 pkinit_identity_crypto_context id_cryptoctx,
4823 krb5_principal princ)
4825 krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
4826 X509 *x = NULL;
4827 PKCS12 *p12 = NULL;
4828 int ret;
4829 FILE *fp;
4830 EVP_PKEY *y = NULL;
4832 if (idopts->cert_filename == NULL) {
4833 /* Solaris Kerberos: Improved error messages */
4834 krb5_set_error_message(context, retval,
4835 gettext("Failed to get certificate location"));
4836 pkiDebug("%s: failed to get user's cert location\n", __FUNCTION__);
4837 goto cleanup;
4840 if (idopts->key_filename == NULL) {
4841 /* Solaris Kerberos: Improved error messages */
4842 krb5_set_error_message(context, retval,
4843 gettext("Failed to get private key location"));
4844 pkiDebug("%s: failed to get user's private key location\n", __FUNCTION__);
4845 goto cleanup;
4848 fp = fopen(idopts->cert_filename, "rb");
4849 if (fp == NULL) {
4850 /* Solaris Kerberos: Improved error messages */
4851 krb5_set_error_message(context, retval,
4852 gettext("Failed to open PKCS12 file '%s': %s"),
4853 idopts->cert_filename, error_message(errno));
4854 pkiDebug("Failed to open PKCS12 file '%s', error %d\n",
4855 idopts->cert_filename, errno);
4856 goto cleanup;
4859 p12 = d2i_PKCS12_fp(fp, NULL);
4860 (void) fclose(fp);
4861 if (p12 == NULL) {
4862 krb5_set_error_message(context, retval,
4863 gettext("Failed to decode PKCS12 file '%s' contents"),
4864 idopts->cert_filename);
4865 pkiDebug("Failed to decode PKCS12 file '%s' contents\n",
4866 idopts->cert_filename);
4867 goto cleanup;
4870 * Try parsing with no pass phrase first. If that fails,
4871 * prompt for the pass phrase and try again.
4873 ret = PKCS12_parse(p12, NULL, &y, &x, NULL);
4874 if (ret == 0) {
4875 krb5_data rdat;
4876 krb5_prompt kprompt;
4877 krb5_prompt_type prompt_type;
4878 int r = 0;
4879 char prompt_string[128];
4880 char prompt_reply[128];
4881 /* Solaris Kerberos */
4882 char *prompt_prefix = gettext("Pass phrase for");
4884 pkiDebug("Initial PKCS12_parse with no password failed\n");
4886 if (id_cryptoctx->PIN != NULL) {
4887 /* Solaris Kerberos: use PIN if set */
4888 rdat.data = id_cryptoctx->PIN;
4889 /* note rdat.length isn't needed in this case */
4890 } else {
4891 (void) memset(prompt_reply, '\0', sizeof(prompt_reply));
4892 rdat.data = prompt_reply;
4893 rdat.length = sizeof(prompt_reply);
4895 r = snprintf(prompt_string, sizeof(prompt_string), "%s %s",
4896 prompt_prefix, idopts->cert_filename);
4897 if (r >= sizeof(prompt_string)) {
4898 pkiDebug("Prompt string, '%s %s', is too long!\n",
4899 prompt_prefix, idopts->cert_filename);
4900 goto cleanup;
4902 kprompt.prompt = prompt_string;
4903 kprompt.hidden = 1;
4904 kprompt.reply = &rdat;
4905 prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
4907 /* PROMPTER_INVOCATION */
4908 k5int_set_prompt_types(context, &prompt_type);
4909 r = (*id_cryptoctx->prompter)(context, id_cryptoctx->prompter_data,
4910 NULL, NULL, 1, &kprompt);
4911 k5int_set_prompt_types(context, NULL);
4914 ret = PKCS12_parse(p12, rdat.data, &y, &x, NULL);
4915 if (ret == 0) {
4916 /* Solaris Kerberos: Improved error messages */
4917 krb5_set_error_message(context, retval,
4918 gettext("Failed to parse PKCS12 file '%s' with password"),
4919 idopts->cert_filename);
4920 pkiDebug("Seconde PKCS12_parse with password failed\n");
4921 goto cleanup;
4924 id_cryptoctx->creds[0] = malloc(sizeof(struct _pkinit_cred_info));
4925 if (id_cryptoctx->creds[0] == NULL)
4926 goto cleanup;
4927 id_cryptoctx->creds[0]->cert = x;
4928 #ifndef WITHOUT_PKCS11
4929 id_cryptoctx->creds[0]->cert_id = NULL;
4930 id_cryptoctx->creds[0]->cert_id_len = 0;
4931 #endif
4932 id_cryptoctx->creds[0]->key = y;
4933 id_cryptoctx->creds[1] = NULL;
4935 retval = 0;
4937 cleanup:
4938 if (p12)
4939 PKCS12_free(p12);
4940 if (retval) {
4941 if (x != NULL)
4942 X509_free(x);
4943 if (y != NULL)
4944 EVP_PKEY_free(y);
4946 return retval;
4949 static krb5_error_code
4950 pkinit_load_fs_cert_and_key(krb5_context context,
4951 pkinit_identity_crypto_context id_cryptoctx,
4952 char *certname,
4953 char *keyname,
4954 int cindex)
4956 krb5_error_code retval;
4957 X509 *x = NULL;
4958 EVP_PKEY *y = NULL;
4960 /* load the certificate */
4961 retval = get_cert(certname, &x);
4962 if (retval != 0 || x == NULL) {
4963 /* Solaris Kerberos: Improved error messages */
4964 krb5_set_error_message(context, retval,
4965 gettext("Failed to load user's certificate from %s: %s"),
4966 certname, error_message(retval));
4967 pkiDebug("failed to load user's certificate from '%s'\n", certname);
4968 goto cleanup;
4970 retval = get_key(keyname, &y);
4971 if (retval != 0 || y == NULL) {
4972 /* Solaris Kerberos: Improved error messages */
4973 krb5_set_error_message(context, retval,
4974 gettext("Failed to load user's private key from %s: %s"),
4975 keyname, error_message(retval));
4976 pkiDebug("failed to load user's private key from '%s'\n", keyname);
4977 goto cleanup;
4980 id_cryptoctx->creds[cindex] = malloc(sizeof(struct _pkinit_cred_info));
4981 if (id_cryptoctx->creds[cindex] == NULL) {
4982 retval = ENOMEM;
4983 goto cleanup;
4985 id_cryptoctx->creds[cindex]->cert = x;
4986 #ifndef WITHOUT_PKCS11
4987 id_cryptoctx->creds[cindex]->cert_id = NULL;
4988 id_cryptoctx->creds[cindex]->cert_id_len = 0;
4989 #endif
4990 id_cryptoctx->creds[cindex]->key = y;
4991 id_cryptoctx->creds[cindex+1] = NULL;
4993 retval = 0;
4995 cleanup:
4996 if (retval) {
4997 if (x != NULL)
4998 X509_free(x);
4999 if (y != NULL)
5000 EVP_PKEY_free(y);
5002 return retval;
5005 /* ARGSUSED */
5006 static krb5_error_code
5007 pkinit_get_certs_fs(krb5_context context,
5008 pkinit_plg_crypto_context plg_cryptoctx,
5009 pkinit_req_crypto_context req_cryptoctx,
5010 pkinit_identity_opts *idopts,
5011 pkinit_identity_crypto_context id_cryptoctx,
5012 krb5_principal princ)
5014 krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
5016 if (idopts->cert_filename == NULL) {
5017 pkiDebug("%s: failed to get user's cert location\n", __FUNCTION__);
5018 goto cleanup;
5021 if (idopts->key_filename == NULL) {
5022 pkiDebug("%s: failed to get user's private key location\n",
5023 __FUNCTION__);
5024 goto cleanup;
5027 retval = pkinit_load_fs_cert_and_key(context, id_cryptoctx,
5028 idopts->cert_filename,
5029 idopts->key_filename, 0);
5030 cleanup:
5031 return retval;
5034 /* ARGSUSED */
5035 static krb5_error_code
5036 pkinit_get_certs_dir(krb5_context context,
5037 pkinit_plg_crypto_context plg_cryptoctx,
5038 pkinit_req_crypto_context req_cryptoctx,
5039 pkinit_identity_opts *idopts,
5040 pkinit_identity_crypto_context id_cryptoctx,
5041 krb5_principal princ)
5043 /* Solaris Kerberos */
5044 krb5_error_code retval = KRB5KRB_ERR_GENERIC;
5045 DIR *d = NULL;
5046 struct dirent *dentry = NULL;
5047 char certname[1024];
5048 char keyname[1024];
5049 int i = 0, len;
5050 char *dirname, *suf;
5052 /* Solaris Kerberos */
5053 if (idopts == NULL)
5054 return EINVAL;
5056 if (idopts->cert_filename == NULL) {
5057 pkiDebug("%s: failed to get user's certificate directory location\n",
5058 __FUNCTION__);
5059 return ENOENT;
5062 dirname = idopts->cert_filename;
5063 d = opendir(dirname);
5064 if (d == NULL) {
5065 /* Solaris Kerberos: Improved error messages */
5066 krb5_set_error_message(context, errno,
5067 gettext("Failed to open directory \"%s\": %s"),
5068 dirname, error_message(errno));
5069 return errno;
5073 * We'll assume that certs are named XXX.crt and the corresponding
5074 * key is named XXX.key
5076 while ((i < MAX_CREDS_ALLOWED) && (dentry = readdir(d)) != NULL) {
5077 /* Ignore subdirectories and anything starting with a dot */
5078 #ifdef DT_DIR
5079 if (dentry->d_type == DT_DIR)
5080 continue;
5081 #endif
5082 if (dentry->d_name[0] == '.')
5083 continue;
5084 len = strlen(dentry->d_name);
5085 if (len < 5)
5086 continue;
5087 suf = dentry->d_name + (len - 4);
5088 if (strncmp(suf, ".crt", 4) != 0)
5089 continue;
5091 /* Checked length */
5092 if (strlen(dirname) + strlen(dentry->d_name) + 2 > sizeof(certname)) {
5093 pkiDebug("%s: Path too long -- directory '%s' and file '%s'\n",
5094 __FUNCTION__, dirname, dentry->d_name);
5095 continue;
5097 (void) snprintf(certname, sizeof(certname), "%s/%s", dirname, dentry->d_name);
5098 (void) snprintf(keyname, sizeof(keyname), "%s/%s", dirname, dentry->d_name);
5099 len = strlen(keyname);
5100 keyname[len - 3] = 'k';
5101 keyname[len - 2] = 'e';
5102 keyname[len - 1] = 'y';
5104 retval = pkinit_load_fs_cert_and_key(context, id_cryptoctx,
5105 certname, keyname, i);
5106 if (retval == 0) {
5107 pkiDebug("%s: Successfully loaded cert (and key) for %s\n",
5108 __FUNCTION__, dentry->d_name);
5109 i++;
5111 else
5112 continue;
5115 if (i == 0) {
5116 /* Solaris Kerberos: Improved error messages */
5117 krb5_set_error_message(context, ENOENT,
5118 gettext("No suitable cert/key pairs found in directory '%s'"),
5119 idopts->cert_filename);
5120 pkiDebug("%s: No cert/key pairs found in directory '%s'\n",
5121 __FUNCTION__, idopts->cert_filename);
5122 retval = ENOENT;
5123 goto cleanup;
5126 retval = 0;
5128 cleanup:
5129 if (d)
5130 (void) closedir(d);
5132 return retval;
5135 #ifndef WITHOUT_PKCS11
5136 /* ARGSUSED */
5137 static krb5_error_code
5138 pkinit_get_certs_pkcs11(krb5_context context,
5139 pkinit_plg_crypto_context plg_cryptoctx,
5140 pkinit_req_crypto_context req_cryptoctx,
5141 pkinit_identity_opts *idopts,
5142 pkinit_identity_crypto_context id_cryptoctx,
5143 krb5_principal princ,
5144 int do_matching)
5146 #ifdef PKINIT_USE_MECH_LIST
5147 CK_MECHANISM_TYPE_PTR mechp = NULL;
5148 CK_MECHANISM_INFO info;
5149 #endif
5151 if (id_cryptoctx->p11flags & C_SKIP_PKCS11_AUTH)
5152 return KRB5KDC_ERR_PREAUTH_FAILED;
5154 /* Copy stuff from idopts -> id_cryptoctx */
5155 if (idopts->p11_module_name != NULL) {
5156 id_cryptoctx->p11_module_name = strdup(idopts->p11_module_name);
5157 if (id_cryptoctx->p11_module_name == NULL)
5158 return ENOMEM;
5160 if (idopts->token_label != NULL) {
5161 id_cryptoctx->token_label = strdup(idopts->token_label);
5162 if (id_cryptoctx->token_label == NULL)
5163 return ENOMEM;
5165 if (idopts->cert_label != NULL) {
5166 id_cryptoctx->cert_label = strdup(idopts->cert_label);
5167 if (id_cryptoctx->cert_label == NULL)
5168 return ENOMEM;
5170 if (idopts->PIN != NULL) {
5171 id_cryptoctx->PIN = strdup(idopts->PIN);
5172 if (id_cryptoctx->PIN == NULL)
5173 return ENOMEM;
5175 /* Convert the ascii cert_id string into a binary blob */
5177 * Solaris Kerberos:
5178 * If the cert_id_string is empty then behave in a similar way to how
5179 * an empty certlabel is treated - i.e. don't fail now but rather continue
5180 * as though the certid wasn't specified.
5182 if (idopts->cert_id_string != NULL && strlen(idopts->cert_id_string) != 0) {
5183 BIGNUM *bn = NULL;
5184 BN_hex2bn(&bn, idopts->cert_id_string);
5185 if (bn == NULL)
5186 return ENOMEM;
5187 id_cryptoctx->cert_id_len = BN_num_bytes(bn);
5188 id_cryptoctx->cert_id = malloc((size_t) id_cryptoctx->cert_id_len);
5189 if (id_cryptoctx->cert_id == NULL) {
5190 BN_free(bn);
5191 return ENOMEM;
5193 BN_bn2bin(bn, id_cryptoctx->cert_id);
5194 BN_free(bn);
5196 id_cryptoctx->slotid = idopts->slotid;
5197 id_cryptoctx->pkcs11_method = 1;
5199 #ifndef PKINIT_USE_MECH_LIST
5201 * We'd like to use CKM_SHA1_RSA_PKCS for signing if it's available, but
5202 * many cards seems to be confused about whether they are capable of
5203 * this or not. The safe thing seems to be to ignore the mechanism list,
5204 * always use CKM_RSA_PKCS and calculate the sha1 digest ourselves.
5207 id_cryptoctx->mech = CKM_RSA_PKCS;
5208 #else
5209 if ((r = id_cryptoctx->p11->C_GetMechanismList(id_cryptoctx->slotid, NULL,
5210 &count)) != CKR_OK || count <= 0) {
5211 pkiDebug("C_GetMechanismList: %s\n", pkinit_pkcs11_code_to_text(r));
5212 return KRB5KDC_ERR_PREAUTH_FAILED;
5214 mechp = (CK_MECHANISM_TYPE_PTR) malloc(count * sizeof (CK_MECHANISM_TYPE));
5215 if (mechp == NULL)
5216 return ENOMEM;
5217 if ((r = id_cryptoctx->p11->C_GetMechanismList(id_cryptoctx->slotid,
5218 mechp, &count)) != CKR_OK) {
5219 free(mechp);
5220 return KRB5KDC_ERR_PREAUTH_FAILED;
5222 for (i = 0; i < count; i++) {
5223 if ((r = id_cryptoctx->p11->C_GetMechanismInfo(id_cryptoctx->slotid,
5224 mechp[i], &info)) != CKR_OK) {
5225 free(mechp);
5226 return KRB5KDC_ERR_PREAUTH_FAILED;
5228 #ifdef DEBUG_MECHINFO
5229 pkiDebug("mech %x flags %x\n", (int) mechp[i], (int) info.flags);
5230 if ((info.flags & (CKF_SIGN|CKF_DECRYPT)) == (CKF_SIGN|CKF_DECRYPT))
5231 pkiDebug(" this mech is good for sign & decrypt\n");
5232 #endif
5233 if (mechp[i] == CKM_RSA_PKCS) {
5234 /* This seems backwards... */
5235 id_cryptoctx->mech =
5236 (info.flags & CKF_SIGN) ? CKM_SHA1_RSA_PKCS : CKM_RSA_PKCS;
5239 free(mechp);
5241 pkiDebug("got %d mechs from card\n", (int) count);
5242 #endif
5244 return (pkinit_open_session(context, plg_cryptoctx, req_cryptoctx,
5245 id_cryptoctx, princ, do_matching));
5247 #endif
5249 /* ARGSUSED */
5250 static void
5251 free_cred_info(krb5_context context,
5252 pkinit_identity_crypto_context id_cryptoctx,
5253 struct _pkinit_cred_info *cred)
5255 if (cred != NULL) {
5256 if (cred->cert != NULL)
5257 X509_free(cred->cert);
5258 if (cred->key != NULL)
5259 EVP_PKEY_free(cred->key);
5260 #ifndef WITHOUT_PKCS11
5261 free(cred->cert_id);
5262 #endif
5263 free(cred);
5267 /* ARGSUSED */
5268 krb5_error_code
5269 crypto_free_cert_info(krb5_context context,
5270 pkinit_plg_crypto_context plg_cryptoctx,
5271 pkinit_req_crypto_context req_cryptoctx,
5272 pkinit_identity_crypto_context id_cryptoctx)
5274 int i;
5276 if (id_cryptoctx == NULL)
5277 return EINVAL;
5279 for (i = 0; i < MAX_CREDS_ALLOWED; i++) {
5280 if (id_cryptoctx->creds[i] != NULL) {
5281 free_cred_info(context, id_cryptoctx, id_cryptoctx->creds[i]);
5282 id_cryptoctx->creds[i] = NULL;
5285 return 0;
5288 krb5_error_code
5289 crypto_load_certs(krb5_context context,
5290 pkinit_plg_crypto_context plg_cryptoctx,
5291 pkinit_req_crypto_context req_cryptoctx,
5292 pkinit_identity_opts *idopts,
5293 pkinit_identity_crypto_context id_cryptoctx,
5294 krb5_principal princ,
5295 int do_matching)
5297 krb5_error_code retval;
5299 switch(idopts->idtype) {
5300 case IDTYPE_FILE:
5301 retval = pkinit_get_certs_fs(context, plg_cryptoctx,
5302 req_cryptoctx, idopts,
5303 id_cryptoctx, princ);
5304 break;
5305 case IDTYPE_DIR:
5306 retval = pkinit_get_certs_dir(context, plg_cryptoctx,
5307 req_cryptoctx, idopts,
5308 id_cryptoctx, princ);
5309 break;
5310 #ifndef WITHOUT_PKCS11
5311 case IDTYPE_PKCS11:
5312 retval = pkinit_get_certs_pkcs11(context, plg_cryptoctx,
5313 req_cryptoctx, idopts,
5314 id_cryptoctx, princ, do_matching);
5315 break;
5316 #endif
5317 case IDTYPE_PKCS12:
5318 retval = pkinit_get_certs_pkcs12(context, plg_cryptoctx,
5319 req_cryptoctx, idopts,
5320 id_cryptoctx, princ);
5321 break;
5322 default:
5323 retval = EINVAL;
5325 /* Solaris Kerberos */
5327 return retval;
5331 * Get number of certificates available after crypto_load_certs()
5333 /* ARGSUSED */
5334 krb5_error_code
5335 crypto_cert_get_count(krb5_context context,
5336 pkinit_plg_crypto_context plg_cryptoctx,
5337 pkinit_req_crypto_context req_cryptoctx,
5338 pkinit_identity_crypto_context id_cryptoctx,
5339 int *cert_count)
5341 int count;
5343 if (id_cryptoctx == NULL || id_cryptoctx->creds[0] == NULL)
5344 return EINVAL;
5346 for (count = 0;
5347 count <= MAX_CREDS_ALLOWED && id_cryptoctx->creds[count] != NULL;
5348 count++);
5349 *cert_count = count;
5350 return 0;
5355 * Begin iteration over the certs loaded in crypto_load_certs()
5357 /* ARGSUSED */
5358 krb5_error_code
5359 crypto_cert_iteration_begin(krb5_context context,
5360 pkinit_plg_crypto_context plg_cryptoctx,
5361 pkinit_req_crypto_context req_cryptoctx,
5362 pkinit_identity_crypto_context id_cryptoctx,
5363 pkinit_cert_iter_handle *ih_ret)
5365 struct _pkinit_cert_iter_data *id;
5367 if (id_cryptoctx == NULL || ih_ret == NULL)
5368 return EINVAL;
5369 if (id_cryptoctx->creds[0] == NULL) /* No cred info available */
5370 return ENOENT;
5372 id = calloc(1, sizeof(*id));
5373 if (id == NULL)
5374 return ENOMEM;
5375 id->magic = ITER_MAGIC;
5376 id->plgctx = plg_cryptoctx,
5377 id->reqctx = req_cryptoctx,
5378 id->idctx = id_cryptoctx;
5379 id->index = 0;
5380 *ih_ret = (pkinit_cert_iter_handle) id;
5381 return 0;
5385 * End iteration over the certs loaded in crypto_load_certs()
5387 /* ARGSUSED */
5388 krb5_error_code
5389 crypto_cert_iteration_end(krb5_context context,
5390 pkinit_cert_iter_handle ih)
5392 struct _pkinit_cert_iter_data *id = (struct _pkinit_cert_iter_data *)ih;
5394 if (id == NULL || id->magic != ITER_MAGIC)
5395 return EINVAL;
5396 free(ih);
5397 return 0;
5401 * Get next certificate handle
5403 /* ARGSUSED */
5404 krb5_error_code
5405 crypto_cert_iteration_next(krb5_context context,
5406 pkinit_cert_iter_handle ih,
5407 pkinit_cert_handle *ch_ret)
5409 struct _pkinit_cert_iter_data *id = (struct _pkinit_cert_iter_data *)ih;
5410 struct _pkinit_cert_data *cd;
5411 pkinit_identity_crypto_context id_cryptoctx;
5413 if (id == NULL || id->magic != ITER_MAGIC)
5414 return EINVAL;
5416 if (ch_ret == NULL)
5417 return EINVAL;
5419 id_cryptoctx = id->idctx;
5420 if (id_cryptoctx == NULL)
5421 return EINVAL;
5423 if (id_cryptoctx->creds[id->index] == NULL)
5424 return PKINIT_ITER_NO_MORE;
5426 cd = calloc(1, sizeof(*cd));
5427 if (cd == NULL)
5428 return ENOMEM;
5430 cd->magic = CERT_MAGIC;
5431 cd->plgctx = id->plgctx;
5432 cd->reqctx = id->reqctx;
5433 cd->idctx = id->idctx;
5434 cd->index = id->index;
5435 cd->cred = id_cryptoctx->creds[id->index++];
5436 *ch_ret = (pkinit_cert_handle)cd;
5437 return 0;
5441 * Release cert handle
5443 /* ARGSUSED */
5444 krb5_error_code
5445 crypto_cert_release(krb5_context context,
5446 pkinit_cert_handle ch)
5448 struct _pkinit_cert_data *cd = (struct _pkinit_cert_data *)ch;
5449 if (cd == NULL || cd->magic != CERT_MAGIC)
5450 return EINVAL;
5451 free(cd);
5452 return 0;
5456 * Get certificate Key Usage and Extended Key Usage
5458 /* ARGSUSED */
5459 static krb5_error_code
5460 crypto_retieve_X509_key_usage(krb5_context context,
5461 pkinit_plg_crypto_context plgcctx,
5462 pkinit_req_crypto_context reqcctx,
5463 X509 *x,
5464 unsigned int *ret_ku_bits,
5465 unsigned int *ret_eku_bits)
5467 /* Solaris Kerberos */
5468 int i;
5469 unsigned int eku_bits = 0, ku_bits = 0;
5470 ASN1_BIT_STRING *usage = NULL;
5472 if (ret_ku_bits == NULL && ret_eku_bits == NULL)
5473 return EINVAL;
5475 if (ret_eku_bits)
5476 *ret_eku_bits = 0;
5477 else {
5478 pkiDebug("%s: EKUs not requested, not checking\n", __FUNCTION__);
5479 goto check_kus;
5482 /* Start with Extended Key usage */
5483 i = X509_get_ext_by_NID(x, NID_ext_key_usage, -1);
5484 if (i >= 0) {
5485 EXTENDED_KEY_USAGE *eku;
5487 eku = X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL);
5488 if (eku) {
5489 for (i = 0; i < sk_ASN1_OBJECT_num(eku); i++) {
5490 ASN1_OBJECT *certoid;
5491 certoid = sk_ASN1_OBJECT_value(eku, i);
5492 if ((OBJ_cmp(certoid, plgcctx->id_pkinit_KPClientAuth)) == 0)
5493 eku_bits |= PKINIT_EKU_PKINIT;
5494 else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_ms_smartcard_login))) == 0)
5495 eku_bits |= PKINIT_EKU_MSSCLOGIN;
5496 else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_client_auth))) == 0)
5497 eku_bits |= PKINIT_EKU_CLIENTAUTH;
5498 else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_email_protect))) == 0)
5499 eku_bits |= PKINIT_EKU_EMAILPROTECTION;
5501 EXTENDED_KEY_USAGE_free(eku);
5504 pkiDebug("%s: returning eku 0x%08x\n", __FUNCTION__, eku_bits);
5505 *ret_eku_bits = eku_bits;
5507 check_kus:
5508 /* Now the Key Usage bits */
5509 if (ret_ku_bits)
5510 *ret_ku_bits = 0;
5511 else {
5512 pkiDebug("%s: KUs not requested, not checking\n", __FUNCTION__);
5513 goto out;
5516 /* Make sure usage exists before checking bits */
5517 usage = X509_get_ext_d2i(x, NID_key_usage, NULL, NULL);
5518 if (usage) {
5519 if (!ku_reject(x, X509v3_KU_DIGITAL_SIGNATURE))
5520 ku_bits |= PKINIT_KU_DIGITALSIGNATURE;
5521 if (!ku_reject(x, X509v3_KU_KEY_ENCIPHERMENT))
5522 ku_bits |= PKINIT_KU_KEYENCIPHERMENT;
5523 ASN1_BIT_STRING_free(usage);
5526 pkiDebug("%s: returning ku 0x%08x\n", __FUNCTION__, ku_bits);
5527 *ret_ku_bits = ku_bits;
5529 out:
5530 return 0;
5534 * Return a string format of an X509_NAME in buf where
5535 * size is an in/out parameter. On input it is the size
5536 * of the buffer, and on output it is the actual length
5537 * of the name.
5538 * If buf is NULL, returns the length req'd to hold name
5540 static char *
5541 X509_NAME_oneline_ex(X509_NAME * a,
5542 char *buf,
5543 unsigned int *size,
5544 unsigned long flag)
5546 BIO *out = NULL;
5548 out = BIO_new(BIO_s_mem ());
5549 if (X509_NAME_print_ex(out, a, 0, flag) > 0) {
5550 if (buf != NULL && *size > (int) BIO_number_written(out)) {
5551 (void) memset(buf, 0, *size);
5552 BIO_read(out, buf, (int) BIO_number_written(out));
5554 else {
5555 *size = BIO_number_written(out);
5558 BIO_free(out);
5559 return (buf);
5563 * Get certificate information
5565 krb5_error_code
5566 crypto_cert_get_matching_data(krb5_context context,
5567 pkinit_cert_handle ch,
5568 pkinit_cert_matching_data **ret_md)
5570 krb5_error_code retval;
5571 pkinit_cert_matching_data *md;
5572 krb5_principal *pkinit_sans =NULL, *upn_sans = NULL;
5573 struct _pkinit_cert_data *cd = (struct _pkinit_cert_data *)ch;
5574 int i, j;
5575 char buf[DN_BUF_LEN];
5576 unsigned int bufsize = sizeof(buf);
5578 if (cd == NULL || cd->magic != CERT_MAGIC)
5579 return EINVAL;
5580 if (ret_md == NULL)
5581 return EINVAL;
5583 md = calloc(1, sizeof(*md));
5584 if (md == NULL)
5585 return ENOMEM;
5587 md->ch = ch;
5589 /* get the subject name (in rfc2253 format) */
5590 X509_NAME_oneline_ex(X509_get_subject_name(cd->cred->cert),
5591 buf, &bufsize, XN_FLAG_SEP_COMMA_PLUS);
5592 md->subject_dn = strdup(buf);
5593 if (md->subject_dn == NULL) {
5594 retval = ENOMEM;
5595 goto cleanup;
5598 /* get the issuer name (in rfc2253 format) */
5599 X509_NAME_oneline_ex(X509_get_issuer_name(cd->cred->cert),
5600 buf, &bufsize, XN_FLAG_SEP_COMMA_PLUS);
5601 md->issuer_dn = strdup(buf);
5602 if (md->issuer_dn == NULL) {
5603 retval = ENOMEM;
5604 goto cleanup;
5607 /* get the san data */
5608 retval = crypto_retrieve_X509_sans(context, cd->plgctx, cd->reqctx,
5609 cd->cred->cert, &pkinit_sans,
5610 &upn_sans, NULL);
5611 if (retval)
5612 goto cleanup;
5614 j = 0;
5615 if (pkinit_sans != NULL) {
5616 for (i = 0; pkinit_sans[i] != NULL; i++)
5617 j++;
5619 if (upn_sans != NULL) {
5620 for (i = 0; upn_sans[i] != NULL; i++)
5621 j++;
5623 if (j != 0) {
5624 md->sans = calloc((size_t)j+1, sizeof(*md->sans));
5625 if (md->sans == NULL) {
5626 retval = ENOMEM;
5627 goto cleanup;
5629 j = 0;
5630 if (pkinit_sans != NULL) {
5631 for (i = 0; pkinit_sans[i] != NULL; i++)
5632 md->sans[j++] = pkinit_sans[i];
5633 free(pkinit_sans);
5635 if (upn_sans != NULL) {
5636 for (i = 0; upn_sans[i] != NULL; i++)
5637 md->sans[j++] = upn_sans[i];
5638 free(upn_sans);
5640 md->sans[j] = NULL;
5641 } else
5642 md->sans = NULL;
5644 /* get the KU and EKU data */
5646 retval = crypto_retieve_X509_key_usage(context, cd->plgctx, cd->reqctx,
5647 cd->cred->cert,
5648 &md->ku_bits, &md->eku_bits);
5649 if (retval)
5650 goto cleanup;
5652 *ret_md = md;
5653 retval = 0;
5654 cleanup:
5655 if (retval) {
5656 if (md)
5657 crypto_cert_free_matching_data(context, md);
5659 return retval;
5663 * Free certificate information
5665 krb5_error_code
5666 crypto_cert_free_matching_data(krb5_context context,
5667 pkinit_cert_matching_data *md)
5669 krb5_principal p;
5670 int i;
5672 if (md == NULL)
5673 return EINVAL;
5674 free(md->subject_dn);
5675 free(md->issuer_dn);
5676 if (md->sans) {
5677 for (i = 0, p = md->sans[i]; p != NULL; p = md->sans[++i])
5678 krb5_free_principal(context, p);
5679 free(md->sans);
5681 free(md);
5682 return 0;
5686 * Make this matching certificate "the chosen one"
5688 /* ARGSUSED */
5689 krb5_error_code
5690 crypto_cert_select(krb5_context context,
5691 pkinit_cert_matching_data *md)
5693 struct _pkinit_cert_data *cd;
5694 if (md == NULL)
5695 return EINVAL;
5697 cd = (struct _pkinit_cert_data *)md->ch;
5698 if (cd == NULL || cd->magic != CERT_MAGIC)
5699 return EINVAL;
5701 /* copy the selected cert into our id_cryptoctx */
5702 if (cd->idctx->my_certs != NULL) {
5703 sk_X509_pop_free(cd->idctx->my_certs, X509_free);
5705 cd->idctx->my_certs = sk_X509_new_null();
5706 sk_X509_push(cd->idctx->my_certs, cd->cred->cert);
5707 cd->idctx->creds[cd->index]->cert = NULL; /* Don't free it twice */
5708 cd->idctx->cert_index = 0;
5710 if (cd->idctx->pkcs11_method != 1) {
5711 cd->idctx->my_key = cd->cred->key;
5712 cd->idctx->creds[cd->index]->key = NULL; /* Don't free it twice */
5714 #ifndef WITHOUT_PKCS11
5715 else {
5716 cd->idctx->cert_id = cd->cred->cert_id;
5717 cd->idctx->creds[cd->index]->cert_id = NULL; /* Don't free it twice */
5718 cd->idctx->cert_id_len = cd->cred->cert_id_len;
5720 #endif
5721 return 0;
5725 * Choose the default certificate as "the chosen one"
5727 krb5_error_code
5728 crypto_cert_select_default(krb5_context context,
5729 pkinit_plg_crypto_context plg_cryptoctx,
5730 pkinit_req_crypto_context req_cryptoctx,
5731 pkinit_identity_crypto_context id_cryptoctx)
5733 krb5_error_code retval;
5734 int cert_count = 0;
5736 retval = crypto_cert_get_count(context, plg_cryptoctx, req_cryptoctx,
5737 id_cryptoctx, &cert_count);
5738 if (retval) {
5739 pkiDebug("%s: crypto_cert_get_count error %d, %s\n",
5740 __FUNCTION__, retval, error_message(retval));
5741 goto errout;
5743 if (cert_count != 1) {
5744 /* Solaris Kerberos: Improved error messages */
5745 retval = EINVAL;
5746 krb5_set_error_message(context, retval,
5747 gettext("Failed to select default certificate: "
5748 "found %d certs to choose from but there must be exactly one"),
5749 cert_count);
5750 pkiDebug("%s: ERROR: There are %d certs to choose from, "
5751 "but there must be exactly one.\n",
5752 __FUNCTION__, cert_count);
5753 goto errout;
5755 /* copy the selected cert into our id_cryptoctx */
5756 if (id_cryptoctx->my_certs != NULL) {
5757 sk_X509_pop_free(id_cryptoctx->my_certs, X509_free);
5759 id_cryptoctx->my_certs = sk_X509_new_null();
5760 sk_X509_push(id_cryptoctx->my_certs, id_cryptoctx->creds[0]->cert);
5761 id_cryptoctx->creds[0]->cert = NULL; /* Don't free it twice */
5762 id_cryptoctx->cert_index = 0;
5764 if (id_cryptoctx->pkcs11_method != 1) {
5765 id_cryptoctx->my_key = id_cryptoctx->creds[0]->key;
5766 id_cryptoctx->creds[0]->key = NULL; /* Don't free it twice */
5768 #ifndef WITHOUT_PKCS11
5769 else {
5770 id_cryptoctx->cert_id = id_cryptoctx->creds[0]->cert_id;
5771 id_cryptoctx->creds[0]->cert_id = NULL; /* Don't free it twice */
5772 id_cryptoctx->cert_id_len = id_cryptoctx->creds[0]->cert_id_len;
5774 #endif
5775 retval = 0;
5776 errout:
5777 return retval;
5781 /* ARGSUSED */
5782 static krb5_error_code
5783 load_cas_and_crls(krb5_context context,
5784 pkinit_plg_crypto_context plg_cryptoctx,
5785 pkinit_req_crypto_context req_cryptoctx,
5786 pkinit_identity_crypto_context id_cryptoctx,
5787 int catype,
5788 char *filename)
5790 STACK_OF(X509_INFO) *sk = NULL;
5791 STACK_OF(X509) *ca_certs = NULL;
5792 STACK_OF(X509_CRL) *ca_crls = NULL;
5793 BIO *in = NULL;
5794 /* Solaris Kerberos */
5795 krb5_error_code retval = KRB5KRB_ERR_GENERIC;
5796 int i = 0;
5798 /* If there isn't already a stack in the context,
5799 * create a temporary one now */
5800 switch(catype) {
5801 case CATYPE_ANCHORS:
5802 if (id_cryptoctx->trustedCAs != NULL)
5803 ca_certs = id_cryptoctx->trustedCAs;
5804 else {
5805 ca_certs = sk_X509_new_null();
5806 if (ca_certs == NULL)
5807 return ENOMEM;
5809 break;
5810 case CATYPE_INTERMEDIATES:
5811 if (id_cryptoctx->intermediateCAs != NULL)
5812 ca_certs = id_cryptoctx->intermediateCAs;
5813 else {
5814 ca_certs = sk_X509_new_null();
5815 if (ca_certs == NULL)
5816 return ENOMEM;
5818 break;
5819 case CATYPE_CRLS:
5820 if (id_cryptoctx->revoked != NULL)
5821 ca_crls = id_cryptoctx->revoked;
5822 else {
5823 ca_crls = sk_X509_CRL_new_null();
5824 if (ca_crls == NULL)
5825 return ENOMEM;
5827 break;
5828 default:
5829 return ENOTSUP;
5832 if (!(in = BIO_new_file(filename, "r"))) {
5833 retval = errno;
5834 pkiDebug("%s: error opening file '%s': %s\n", __FUNCTION__,
5835 filename, error_message(errno));
5836 goto cleanup;
5839 /* This loads from a file, a stack of x509/crl/pkey sets */
5840 if ((sk = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL)) == NULL) {
5841 pkiDebug("%s: error reading file '%s'\n", __FUNCTION__, filename);
5842 retval = EIO;
5843 goto cleanup;
5846 /* scan over the stack created from loading the file contents,
5847 * weed out duplicates, and push new ones onto the return stack
5849 for (i = 0; i < sk_X509_INFO_num(sk); i++) {
5850 X509_INFO *xi = sk_X509_INFO_value(sk, i);
5851 if (xi != NULL && xi->x509 != NULL && catype != CATYPE_CRLS) {
5852 int j = 0, size = sk_X509_num(ca_certs), flag = 0;
5854 if (!size) {
5855 sk_X509_push(ca_certs, xi->x509);
5856 xi->x509 = NULL;
5857 continue;
5859 for (j = 0; j < size; j++) {
5860 X509 *x = sk_X509_value(ca_certs, j);
5861 flag = X509_cmp(x, xi->x509);
5862 if (flag == 0)
5863 break;
5864 else
5865 continue;
5867 if (flag != 0) {
5868 sk_X509_push(ca_certs, X509_dup(xi->x509));
5870 } else if (xi != NULL && xi->crl != NULL && catype == CATYPE_CRLS) {
5871 int j = 0, size = sk_X509_CRL_num(ca_crls), flag = 0;
5872 if (!size) {
5873 sk_X509_CRL_push(ca_crls, xi->crl);
5874 xi->crl = NULL;
5875 continue;
5877 for (j = 0; j < size; j++) {
5878 X509_CRL *x = sk_X509_CRL_value(ca_crls, j);
5879 flag = X509_CRL_cmp(x, xi->crl);
5880 if (flag == 0)
5881 break;
5882 else
5883 continue;
5885 if (flag != 0) {
5886 sk_X509_CRL_push(ca_crls, X509_CRL_dup(xi->crl));
5891 /* If we added something and there wasn't a stack in the
5892 * context before, add the temporary stack to the context.
5894 switch(catype) {
5895 case CATYPE_ANCHORS:
5896 if (sk_X509_num(ca_certs) == 0) {
5897 pkiDebug("no anchors in file, %s\n", filename);
5898 if (id_cryptoctx->trustedCAs == NULL)
5899 sk_X509_free(ca_certs);
5900 } else {
5901 if (id_cryptoctx->trustedCAs == NULL)
5902 id_cryptoctx->trustedCAs = ca_certs;
5904 break;
5905 case CATYPE_INTERMEDIATES:
5906 if (sk_X509_num(ca_certs) == 0) {
5907 pkiDebug("no intermediates in file, %s\n", filename);
5908 if (id_cryptoctx->intermediateCAs == NULL)
5909 sk_X509_free(ca_certs);
5910 } else {
5911 if (id_cryptoctx->intermediateCAs == NULL)
5912 id_cryptoctx->intermediateCAs = ca_certs;
5914 break;
5915 case CATYPE_CRLS:
5916 if (sk_X509_CRL_num(ca_crls) == 0) {
5917 pkiDebug("no crls in file, %s\n", filename);
5918 if (id_cryptoctx->revoked == NULL)
5919 sk_X509_CRL_free(ca_crls);
5920 } else {
5921 if (id_cryptoctx->revoked == NULL)
5922 id_cryptoctx->revoked = ca_crls;
5924 break;
5925 default:
5926 /* Should have been caught above! */
5927 retval = EINVAL;
5928 goto cleanup;
5929 /* Solaris Kerberos: removed "break" as it's never reached */
5932 retval = 0;
5934 cleanup:
5935 if (in != NULL)
5936 BIO_free(in);
5937 if (sk != NULL)
5938 sk_X509_INFO_pop_free(sk, X509_INFO_free);
5940 return retval;
5943 static krb5_error_code
5944 load_cas_and_crls_dir(krb5_context context,
5945 pkinit_plg_crypto_context plg_cryptoctx,
5946 pkinit_req_crypto_context req_cryptoctx,
5947 pkinit_identity_crypto_context id_cryptoctx,
5948 int catype,
5949 char *dirname)
5951 krb5_error_code retval = EINVAL;
5952 DIR *d = NULL;
5953 struct dirent *dentry = NULL;
5954 char filename[1024];
5956 if (dirname == NULL)
5957 return EINVAL;
5959 d = opendir(dirname);
5960 if (d == NULL)
5961 return ENOENT;
5963 while ((dentry = readdir(d))) {
5964 if (strlen(dirname) + strlen(dentry->d_name) + 2 > sizeof(filename)) {
5965 pkiDebug("%s: Path too long -- directory '%s' and file '%s'\n",
5966 __FUNCTION__, dirname, dentry->d_name);
5967 goto cleanup;
5969 /* Ignore subdirectories and anything starting with a dot */
5970 #ifdef DT_DIR
5971 if (dentry->d_type == DT_DIR)
5972 continue;
5973 #endif
5974 if (dentry->d_name[0] == '.')
5975 continue;
5976 (void) snprintf(filename, sizeof(filename), "%s/%s", dirname, dentry->d_name);
5978 retval = load_cas_and_crls(context, plg_cryptoctx, req_cryptoctx,
5979 id_cryptoctx, catype, filename);
5980 if (retval)
5981 goto cleanup;
5984 retval = 0;
5986 cleanup:
5987 if (d != NULL)
5988 (void) closedir(d);
5990 return retval;
5993 /* ARGSUSED */
5994 krb5_error_code
5995 crypto_load_cas_and_crls(krb5_context context,
5996 pkinit_plg_crypto_context plg_cryptoctx,
5997 pkinit_req_crypto_context req_cryptoctx,
5998 pkinit_identity_opts *idopts,
5999 pkinit_identity_crypto_context id_cryptoctx,
6000 int idtype,
6001 int catype,
6002 char *id)
6004 pkiDebug("%s: called with idtype %s and catype %s\n",
6005 __FUNCTION__, idtype2string(idtype), catype2string(catype));
6006 /* Solaris Kerberos: Removed "break"'s as they are never reached */
6007 switch (idtype) {
6008 case IDTYPE_FILE:
6009 return load_cas_and_crls(context, plg_cryptoctx, req_cryptoctx,
6010 id_cryptoctx, catype, id);
6011 case IDTYPE_DIR:
6012 return load_cas_and_crls_dir(context, plg_cryptoctx, req_cryptoctx,
6013 id_cryptoctx, catype, id);
6014 default:
6015 return ENOTSUP;
6019 static krb5_error_code
6020 create_identifiers_from_stack(STACK_OF(X509) *sk,
6021 krb5_external_principal_identifier *** ids)
6023 krb5_error_code retval = ENOMEM;
6024 int i = 0, sk_size = sk_X509_num(sk);
6025 krb5_external_principal_identifier **krb5_cas = NULL;
6026 X509 *x = NULL;
6027 X509_NAME *xn = NULL;
6028 unsigned char *p = NULL;
6029 int len = 0;
6030 PKCS7_ISSUER_AND_SERIAL *is = NULL;
6031 char buf[DN_BUF_LEN];
6033 *ids = NULL;
6035 krb5_cas =
6036 malloc((sk_size + 1) * sizeof(krb5_external_principal_identifier *));
6037 if (krb5_cas == NULL)
6038 return ENOMEM;
6039 krb5_cas[sk_size] = NULL;
6041 for (i = 0; i < sk_size; i++) {
6042 krb5_cas[i] = (krb5_external_principal_identifier *)malloc(sizeof(krb5_external_principal_identifier));
6044 x = sk_X509_value(sk, i);
6046 X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
6047 pkiDebug("#%d cert= %s\n", i, buf);
6049 /* fill-in subjectName */
6050 krb5_cas[i]->subjectName.magic = 0;
6051 krb5_cas[i]->subjectName.length = 0;
6052 krb5_cas[i]->subjectName.data = NULL;
6054 xn = X509_get_subject_name(x);
6055 len = i2d_X509_NAME(xn, NULL);
6056 if ((p = krb5_cas[i]->subjectName.data = (unsigned char *)malloc((size_t) len)) == NULL)
6057 goto cleanup;
6058 i2d_X509_NAME(xn, &p);
6059 krb5_cas[i]->subjectName.length = len;
6061 /* fill-in issuerAndSerialNumber */
6062 krb5_cas[i]->issuerAndSerialNumber.length = 0;
6063 krb5_cas[i]->issuerAndSerialNumber.magic = 0;
6064 krb5_cas[i]->issuerAndSerialNumber.data = NULL;
6066 #ifdef LONGHORN_BETA_COMPAT
6067 if (longhorn == 0) { /* XXX Longhorn doesn't like this */
6068 #endif
6069 is = PKCS7_ISSUER_AND_SERIAL_new();
6070 X509_NAME_set(&is->issuer, X509_get_issuer_name(x));
6071 M_ASN1_INTEGER_free(is->serial);
6072 is->serial = M_ASN1_INTEGER_dup(X509_get_serialNumber(x));
6073 len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
6074 if ((p = krb5_cas[i]->issuerAndSerialNumber.data =
6075 (unsigned char *)malloc((size_t) len)) == NULL)
6076 goto cleanup;
6077 i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
6078 krb5_cas[i]->issuerAndSerialNumber.length = len;
6079 #ifdef LONGHORN_BETA_COMPAT
6081 #endif
6083 /* fill-in subjectKeyIdentifier */
6084 krb5_cas[i]->subjectKeyIdentifier.length = 0;
6085 krb5_cas[i]->subjectKeyIdentifier.magic = 0;
6086 krb5_cas[i]->subjectKeyIdentifier.data = NULL;
6089 #ifdef LONGHORN_BETA_COMPAT
6090 if (longhorn == 0) { /* XXX Longhorn doesn't like this */
6091 #endif
6092 if (X509_get_ext_by_NID(x, NID_subject_key_identifier, -1) >= 0) {
6093 ASN1_OCTET_STRING *ikeyid = NULL;
6095 if ((ikeyid = X509_get_ext_d2i(x, NID_subject_key_identifier, NULL,
6096 NULL))) {
6097 len = i2d_ASN1_OCTET_STRING(ikeyid, NULL);
6098 if ((p = krb5_cas[i]->subjectKeyIdentifier.data =
6099 (unsigned char *)malloc((size_t) len)) == NULL)
6100 goto cleanup;
6101 i2d_ASN1_OCTET_STRING(ikeyid, &p);
6102 krb5_cas[i]->subjectKeyIdentifier.length = len;
6104 if (ikeyid != NULL)
6105 ASN1_OCTET_STRING_free(ikeyid);
6107 #ifdef LONGHORN_BETA_COMPAT
6109 #endif
6110 if (is != NULL) {
6111 if (is->issuer != NULL)
6112 X509_NAME_free(is->issuer);
6113 if (is->serial != NULL)
6114 ASN1_INTEGER_free(is->serial);
6115 free(is);
6119 *ids = krb5_cas;
6121 retval = 0;
6122 cleanup:
6123 if (retval)
6124 free_krb5_external_principal_identifier(&krb5_cas);
6126 return retval;
6129 /* ARGSUSED */
6130 static krb5_error_code
6131 create_krb5_invalidCertificates(krb5_context context,
6132 pkinit_plg_crypto_context plg_cryptoctx,
6133 pkinit_req_crypto_context req_cryptoctx,
6134 pkinit_identity_crypto_context id_cryptoctx,
6135 krb5_external_principal_identifier *** ids)
6138 krb5_error_code retval = ENOMEM;
6139 STACK_OF(X509) *sk = NULL;
6141 *ids = NULL;
6142 if (req_cryptoctx->received_cert == NULL)
6143 return KRB5KDC_ERR_PREAUTH_FAILED;
6145 sk = sk_X509_new_null();
6146 if (sk == NULL)
6147 goto cleanup;
6148 sk_X509_push(sk, req_cryptoctx->received_cert);
6150 retval = create_identifiers_from_stack(sk, ids);
6152 sk_X509_free(sk);
6153 cleanup:
6155 return retval;
6158 /* ARGSUSED */
6159 krb5_error_code
6160 create_krb5_supportedCMSTypes(krb5_context context,
6161 pkinit_plg_crypto_context plg_cryptoctx,
6162 pkinit_req_crypto_context req_cryptoctx,
6163 pkinit_identity_crypto_context id_cryptoctx,
6164 krb5_algorithm_identifier ***oids)
6167 krb5_error_code retval = ENOMEM;
6168 krb5_algorithm_identifier **loids = NULL;
6169 krb5_octet_data des3oid = {0, 8, (unsigned char *)"\x2A\x86\x48\x86\xF7\x0D\x03\x07" };
6171 *oids = NULL;
6172 loids = malloc(2 * sizeof(krb5_algorithm_identifier *));
6173 if (loids == NULL)
6174 goto cleanup;
6175 loids[1] = NULL;
6176 loids[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
6177 if (loids[0] == NULL) {
6178 free(loids);
6179 goto cleanup;
6181 retval = pkinit_copy_krb5_octet_data(&loids[0]->algorithm, &des3oid);
6182 if (retval) {
6183 free(loids[0]);
6184 free(loids);
6185 goto cleanup;
6187 loids[0]->parameters.length = 0;
6188 loids[0]->parameters.data = NULL;
6190 *oids = loids;
6191 retval = 0;
6192 cleanup:
6194 return retval;
6197 /* ARGSUSED */
6198 krb5_error_code
6199 create_krb5_trustedCertifiers(krb5_context context,
6200 pkinit_plg_crypto_context plg_cryptoctx,
6201 pkinit_req_crypto_context req_cryptoctx,
6202 pkinit_identity_crypto_context id_cryptoctx,
6203 krb5_external_principal_identifier *** ids)
6206 /* Solaris Kerberos */
6207 STACK_OF(X509) *sk = id_cryptoctx->trustedCAs;
6209 *ids = NULL;
6210 if (id_cryptoctx->trustedCAs == NULL)
6211 return KRB5KDC_ERR_PREAUTH_FAILED;
6213 return create_identifiers_from_stack(sk, ids);
6217 /* ARGSUSED */
6218 krb5_error_code
6219 create_krb5_trustedCas(krb5_context context,
6220 pkinit_plg_crypto_context plg_cryptoctx,
6221 pkinit_req_crypto_context req_cryptoctx,
6222 pkinit_identity_crypto_context id_cryptoctx,
6223 int flag,
6224 krb5_trusted_ca *** ids)
6226 krb5_error_code retval = ENOMEM;
6227 STACK_OF(X509) *sk = id_cryptoctx->trustedCAs;
6228 int i = 0, len = 0, sk_size = sk_X509_num(sk);
6229 krb5_trusted_ca **krb5_cas = NULL;
6230 X509 *x = NULL;
6231 char buf[DN_BUF_LEN];
6232 X509_NAME *xn = NULL;
6233 unsigned char *p = NULL;
6234 PKCS7_ISSUER_AND_SERIAL *is = NULL;
6236 *ids = NULL;
6237 if (id_cryptoctx->trustedCAs == NULL)
6238 return KRB5KDC_ERR_PREAUTH_FAILED;
6240 krb5_cas = malloc((sk_size + 1) * sizeof(krb5_trusted_ca *));
6241 if (krb5_cas == NULL)
6242 return ENOMEM;
6243 krb5_cas[sk_size] = NULL;
6245 for (i = 0; i < sk_size; i++) {
6246 krb5_cas[i] = (krb5_trusted_ca *)malloc(sizeof(krb5_trusted_ca));
6247 if (krb5_cas[i] == NULL)
6248 goto cleanup;
6249 x = sk_X509_value(sk, i);
6251 X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
6252 pkiDebug("#%d cert= %s\n", i, buf);
6254 switch (flag) {
6255 case choice_trusted_cas_principalName:
6256 krb5_cas[i]->choice = choice_trusted_cas_principalName;
6257 break;
6258 case choice_trusted_cas_caName:
6259 krb5_cas[i]->choice = choice_trusted_cas_caName;
6260 krb5_cas[i]->u.caName.data = NULL;
6261 krb5_cas[i]->u.caName.length = 0;
6262 xn = X509_get_subject_name(x);
6263 len = i2d_X509_NAME(xn, NULL);
6264 if ((p = krb5_cas[i]->u.caName.data =
6265 (unsigned char *)malloc((size_t) len)) == NULL)
6266 goto cleanup;
6267 i2d_X509_NAME(xn, &p);
6268 krb5_cas[i]->u.caName.length = len;
6269 break;
6270 case choice_trusted_cas_issuerAndSerial:
6271 krb5_cas[i]->choice = choice_trusted_cas_issuerAndSerial;
6272 krb5_cas[i]->u.issuerAndSerial.data = NULL;
6273 krb5_cas[i]->u.issuerAndSerial.length = 0;
6274 is = PKCS7_ISSUER_AND_SERIAL_new();
6275 X509_NAME_set(&is->issuer, X509_get_issuer_name(x));
6276 M_ASN1_INTEGER_free(is->serial);
6277 is->serial = M_ASN1_INTEGER_dup(X509_get_serialNumber(x));
6278 len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
6279 if ((p = krb5_cas[i]->u.issuerAndSerial.data =
6280 (unsigned char *)malloc((size_t) len)) == NULL)
6281 goto cleanup;
6282 i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
6283 krb5_cas[i]->u.issuerAndSerial.length = len;
6284 if (is != NULL) {
6285 if (is->issuer != NULL)
6286 X509_NAME_free(is->issuer);
6287 if (is->serial != NULL)
6288 ASN1_INTEGER_free(is->serial);
6289 free(is);
6291 break;
6292 default: break;
6295 retval = 0;
6296 *ids = krb5_cas;
6297 cleanup:
6298 if (retval)
6299 free_krb5_trusted_ca(&krb5_cas);
6301 return retval;
6304 /* ARGSUSED */
6305 krb5_error_code
6306 create_issuerAndSerial(krb5_context context,
6307 pkinit_plg_crypto_context plg_cryptoctx,
6308 pkinit_req_crypto_context req_cryptoctx,
6309 pkinit_identity_crypto_context id_cryptoctx,
6310 unsigned char **out,
6311 unsigned int *out_len)
6313 unsigned char *p = NULL;
6314 PKCS7_ISSUER_AND_SERIAL *is = NULL;
6315 int len = 0;
6316 krb5_error_code retval = ENOMEM;
6317 X509 *cert = req_cryptoctx->received_cert;
6319 *out = NULL;
6320 *out_len = 0;
6321 if (req_cryptoctx->received_cert == NULL)
6322 return 0;
6324 is = PKCS7_ISSUER_AND_SERIAL_new();
6325 X509_NAME_set(&is->issuer, X509_get_issuer_name(cert));
6326 M_ASN1_INTEGER_free(is->serial);
6327 is->serial = M_ASN1_INTEGER_dup(X509_get_serialNumber(cert));
6328 len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
6329 if ((p = *out = (unsigned char *)malloc((size_t) len)) == NULL)
6330 goto cleanup;
6331 i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
6332 *out_len = len;
6333 retval = 0;
6335 cleanup:
6336 X509_NAME_free(is->issuer);
6337 ASN1_INTEGER_free(is->serial);
6338 free(is);
6340 return retval;
6343 static int
6344 pkcs7_decrypt(krb5_context context,
6345 pkinit_identity_crypto_context id_cryptoctx,
6346 PKCS7 *p7,
6347 BIO *data)
6349 BIO *tmpmem = NULL;
6350 /* Solaris Kerberos */
6351 int i = 0;
6352 char buf[4096];
6354 if(p7 == NULL)
6355 return 0;
6357 if(!PKCS7_type_is_enveloped(p7)) {
6358 pkiDebug("wrong pkcs7 content type\n");
6359 return 0;
6362 if(!(tmpmem = pkcs7_dataDecode(context, id_cryptoctx, p7))) {
6363 pkiDebug("unable to decrypt pkcs7 object\n");
6364 return 0;
6366 /* Solaris Kerberos: Suppress sun studio compiler warning */
6367 #pragma error_messages (off, E_END_OF_LOOP_CODE_NOT_REACHED)
6368 for(;;) {
6369 i = BIO_read(tmpmem, buf, sizeof(buf));
6370 if (i <= 0) break;
6371 BIO_write(data, buf, i);
6372 BIO_free_all(tmpmem);
6373 return 1;
6375 #pragma error_messages (default, E_END_OF_LOOP_CODE_NOT_REACHED)
6377 return 0;
6380 krb5_error_code
6381 pkinit_process_td_trusted_certifiers(
6382 krb5_context context,
6383 pkinit_plg_crypto_context plg_cryptoctx,
6384 pkinit_req_crypto_context req_cryptoctx,
6385 pkinit_identity_crypto_context id_cryptoctx,
6386 krb5_external_principal_identifier **krb5_trusted_certifiers,
6387 int td_type)
6389 krb5_error_code retval = ENOMEM;
6390 STACK_OF(X509_NAME) *sk_xn = NULL;
6391 X509_NAME *xn = NULL;
6392 PKCS7_ISSUER_AND_SERIAL *is = NULL;
6393 ASN1_OCTET_STRING *id = NULL;
6394 const unsigned char *p = NULL;
6395 char buf[DN_BUF_LEN];
6396 int i = 0;
6398 if (td_type == TD_TRUSTED_CERTIFIERS)
6399 pkiDebug("received trusted certifiers\n");
6400 else
6401 pkiDebug("received invalid certificate\n");
6403 sk_xn = sk_X509_NAME_new_null();
6404 while(krb5_trusted_certifiers[i] != NULL) {
6405 if (krb5_trusted_certifiers[i]->subjectName.data != NULL) {
6406 p = krb5_trusted_certifiers[i]->subjectName.data;
6407 xn = d2i_X509_NAME(NULL, &p,
6408 (int)krb5_trusted_certifiers[i]->subjectName.length);
6409 if (xn == NULL)
6410 goto cleanup;
6411 X509_NAME_oneline(xn, buf, sizeof(buf));
6412 if (td_type == TD_TRUSTED_CERTIFIERS)
6413 pkiDebug("#%d cert = %s is trusted by kdc\n", i, buf);
6414 else
6415 pkiDebug("#%d cert = %s is invalid\n", i, buf);
6416 sk_X509_NAME_push(sk_xn, xn);
6419 if (krb5_trusted_certifiers[i]->issuerAndSerialNumber.data != NULL) {
6420 p = krb5_trusted_certifiers[i]->issuerAndSerialNumber.data;
6421 is = d2i_PKCS7_ISSUER_AND_SERIAL(NULL, &p,
6422 (int)krb5_trusted_certifiers[i]->issuerAndSerialNumber.length);
6423 if (is == NULL)
6424 goto cleanup;
6425 X509_NAME_oneline(is->issuer, buf, sizeof(buf));
6426 if (td_type == TD_TRUSTED_CERTIFIERS)
6427 pkiDebug("#%d issuer = %s serial = %ld is trusted bu kdc\n", i,
6428 buf, ASN1_INTEGER_get(is->serial));
6429 else
6430 pkiDebug("#%d issuer = %s serial = %ld is invalid\n", i, buf,
6431 ASN1_INTEGER_get(is->serial));
6432 PKCS7_ISSUER_AND_SERIAL_free(is);
6435 if (krb5_trusted_certifiers[i]->subjectKeyIdentifier.data != NULL) {
6436 p = krb5_trusted_certifiers[i]->subjectKeyIdentifier.data;
6437 id = d2i_ASN1_OCTET_STRING(NULL, &p,
6438 (int)krb5_trusted_certifiers[i]->subjectKeyIdentifier.length);
6439 if (id == NULL)
6440 goto cleanup;
6441 /* XXX */
6442 ASN1_OCTET_STRING_free(id);
6444 i++;
6446 /* XXX Since we not doing anything with received trusted certifiers
6447 * return an error. this is the place where we can pick a different
6448 * client certificate based on the information in td_trusted_certifiers
6450 retval = KRB5KDC_ERR_PREAUTH_FAILED;
6451 cleanup:
6452 if (sk_xn != NULL)
6453 sk_X509_NAME_pop_free(sk_xn, X509_NAME_free);
6455 return retval;
6458 static BIO *
6459 pkcs7_dataDecode(krb5_context context,
6460 pkinit_identity_crypto_context id_cryptoctx,
6461 PKCS7 *p7)
6463 int i = 0;
6464 unsigned int jj = 0, tmp_len = 0;
6465 BIO *out=NULL,*etmp=NULL,*bio=NULL;
6466 unsigned char *tmp=NULL;
6467 ASN1_OCTET_STRING *data_body=NULL;
6468 const EVP_CIPHER *evp_cipher=NULL;
6469 EVP_CIPHER_CTX *evp_ctx=NULL;
6470 X509_ALGOR *enc_alg=NULL;
6471 STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL;
6472 /* Solaris Kerberos: Not used */
6473 #if 0
6474 X509_ALGOR *xalg=NULL;
6475 #endif
6476 PKCS7_RECIP_INFO *ri=NULL;
6477 X509 *cert = sk_X509_value(id_cryptoctx->my_certs,
6478 id_cryptoctx->cert_index);
6480 p7->state=PKCS7_S_HEADER;
6482 rsk=p7->d.enveloped->recipientinfo;
6483 enc_alg=p7->d.enveloped->enc_data->algorithm;
6484 data_body=p7->d.enveloped->enc_data->enc_data;
6485 evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm);
6486 if (evp_cipher == NULL) {
6487 PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
6488 goto cleanup;
6490 /* Solaris Kerberos: Not used */
6491 #if 0
6492 xalg=p7->d.enveloped->enc_data->algorithm;
6493 #endif
6495 if ((etmp=BIO_new(BIO_f_cipher())) == NULL) {
6496 PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB);
6497 goto cleanup;
6500 /* It was encrypted, we need to decrypt the secret key
6501 * with the private key */
6503 /* Find the recipientInfo which matches the passed certificate
6504 * (if any)
6507 if (cert) {
6508 for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) {
6509 int tmp_ret = 0;
6510 ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
6511 tmp_ret = X509_NAME_cmp(ri->issuer_and_serial->issuer,
6512 cert->cert_info->issuer);
6513 if (!tmp_ret) {
6514 tmp_ret = M_ASN1_INTEGER_cmp(cert->cert_info->serialNumber,
6515 ri->issuer_and_serial->serial);
6516 if (!tmp_ret)
6517 break;
6519 ri=NULL;
6521 if (ri == NULL) {
6522 PKCS7err(PKCS7_F_PKCS7_DATADECODE,
6523 PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE);
6524 goto cleanup;
6528 /* If we haven't got a certificate try each ri in turn */
6530 if (cert == NULL) {
6531 for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) {
6532 ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
6533 jj = pkinit_decode_data(context, id_cryptoctx,
6534 M_ASN1_STRING_data(ri->enc_key),
6535 (unsigned int) M_ASN1_STRING_length(ri->enc_key),
6536 &tmp, &tmp_len);
6537 if (jj) {
6538 PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_EVP_LIB);
6539 goto cleanup;
6542 if (!jj && tmp_len > 0) {
6543 jj = tmp_len;
6544 break;
6547 ERR_clear_error();
6548 ri = NULL;
6551 if (ri == NULL) {
6552 PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_RECIPIENT_MATCHES_KEY);
6553 goto cleanup;
6556 else {
6557 jj = pkinit_decode_data(context, id_cryptoctx,
6558 M_ASN1_STRING_data(ri->enc_key),
6559 (unsigned int) M_ASN1_STRING_length(ri->enc_key),
6560 &tmp, &tmp_len);
6561 /* Solaris Kerberos: tmp_len is unsigned. Cannot be < 0 */
6562 if (jj || tmp_len == 0) {
6563 PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_EVP_LIB);
6564 goto cleanup;
6566 jj = tmp_len;
6569 evp_ctx=NULL;
6570 BIO_get_cipher_ctx(etmp,&evp_ctx);
6571 if (EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0) <= 0)
6572 goto cleanup;
6573 if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0)
6574 goto cleanup;
6576 if (jj != EVP_CIPHER_CTX_key_length(evp_ctx)) {
6577 /* Some S/MIME clients don't use the same key
6578 * and effective key length. The key length is
6579 * determined by the size of the decrypted RSA key.
6581 if(!EVP_CIPHER_CTX_set_key_length(evp_ctx, (int)jj)) {
6582 PKCS7err(PKCS7_F_PKCS7_DATADECODE,
6583 PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH);
6584 goto cleanup;
6587 if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,tmp,NULL,0) <= 0)
6588 goto cleanup;
6590 OPENSSL_cleanse(tmp,jj);
6592 if (out == NULL)
6593 out=etmp;
6594 else
6595 BIO_push(out,etmp);
6596 etmp=NULL;
6598 if (data_body->length > 0)
6599 bio = BIO_new_mem_buf(data_body->data, data_body->length);
6600 else {
6601 bio=BIO_new(BIO_s_mem());
6602 BIO_set_mem_eof_return(bio,0);
6604 BIO_push(out,bio);
6605 bio=NULL;
6607 /* Solaris Kerberos */
6608 goto out;
6610 cleanup:
6611 if (out != NULL) BIO_free_all(out);
6612 if (etmp != NULL) BIO_free_all(etmp);
6613 if (bio != NULL) BIO_free_all(bio);
6614 out=NULL;
6616 out:
6617 if (tmp != NULL)
6618 free(tmp);
6620 return(out);
6623 static krb5_error_code
6624 der_decode_data(unsigned char *data, long data_len,
6625 unsigned char **out, long *out_len)
6627 /* Solaris Kerberos */
6628 krb5_error_code retval = KRB5KRB_ERR_GENERIC;
6629 ASN1_OCTET_STRING *s = NULL;
6630 const unsigned char *p = data;
6632 if ((s = d2i_ASN1_BIT_STRING(NULL, &p, data_len)) == NULL)
6633 goto cleanup;
6634 *out_len = s->length;
6635 if ((*out = (unsigned char *) malloc((size_t) *out_len + 1)) == NULL) {
6636 retval = ENOMEM;
6637 goto cleanup;
6639 (void) memcpy(*out, s->data, (size_t) s->length);
6640 (*out)[s->length] = '\0';
6642 retval = 0;
6643 cleanup:
6644 if (s != NULL)
6645 ASN1_OCTET_STRING_free(s);
6647 return retval;
6651 #ifdef DEBUG_DH
6652 static void
6653 print_dh(DH * dh, char *msg)
6655 BIO *bio_err = NULL;
6657 bio_err = BIO_new(BIO_s_file());
6658 BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
6660 if (msg)
6661 BIO_puts(bio_err, (const char *)msg);
6662 if (dh)
6663 DHparams_print(bio_err, dh);
6665 BN_print(bio_err, dh->q);
6666 BIO_puts(bio_err, (const char *)"\n");
6667 BIO_free(bio_err);
6671 static void
6672 print_pubkey(BIGNUM * key, char *msg)
6674 BIO *bio_err = NULL;
6676 bio_err = BIO_new(BIO_s_file());
6677 BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
6679 if (msg)
6680 BIO_puts(bio_err, (const char *)msg);
6681 if (key)
6682 BN_print(bio_err, key);
6683 BIO_puts(bio_err, "\n");
6685 BIO_free(bio_err);
6688 #endif
6691 * Solaris Kerberos:
6692 * Error message generation has changed so gettext() can be used
6694 #if 0
6695 static char *
6696 pkinit_pkcs11_code_to_text(int err)
6698 int i;
6699 static char uc[64];
6701 for (i = 0; pkcs11_errstrings[i].text != NULL; i++)
6702 if (pkcs11_errstrings[i].code == err)
6703 break;
6704 if (pkcs11_errstrings[i].text != NULL)
6705 return (pkcs11_errstrings[i].text);
6706 snprintf(uc, 64, gettext("unknown code 0x%x"), err);
6707 return (uc);
6709 #endif
6711 static char *
6712 pkinit_pkcs11_code_to_text(int err) {
6713 return pkcs11_error_table(err);