1159d09a2SMark Phalan /*
2159d09a2SMark Phalan  * COPYRIGHT (C) 2006,2007
3159d09a2SMark Phalan  * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
4159d09a2SMark Phalan  * ALL RIGHTS RESERVED
5159d09a2SMark Phalan  *
6159d09a2SMark Phalan  * Permission is granted to use, copy, create derivative works
7159d09a2SMark Phalan  * and redistribute this software and such derivative works
8159d09a2SMark Phalan  * for any purpose, so long as the name of The University of
9159d09a2SMark Phalan  * Michigan is not used in any advertising or publicity
10159d09a2SMark Phalan  * pertaining to the use of distribution of this software
11159d09a2SMark Phalan  * without specific, written prior authorization.  If the
12159d09a2SMark Phalan  * above copyright notice or any other identification of the
13159d09a2SMark Phalan  * University of Michigan is included in any copy of any
14159d09a2SMark Phalan  * portion of this software, then the disclaimer below must
15159d09a2SMark Phalan  * also be included.
16159d09a2SMark Phalan  *
17159d09a2SMark Phalan  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
18159d09a2SMark Phalan  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
19159d09a2SMark Phalan  * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
20159d09a2SMark Phalan  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
21159d09a2SMark Phalan  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
22159d09a2SMark Phalan  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
23159d09a2SMark Phalan  * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
24159d09a2SMark Phalan  * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
25159d09a2SMark Phalan  * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
26159d09a2SMark Phalan  * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
27159d09a2SMark Phalan  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
28159d09a2SMark Phalan  * SUCH DAMAGES.
29159d09a2SMark Phalan  */
30159d09a2SMark Phalan 
31159d09a2SMark Phalan /*
3231a29035SMark Phalan  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
3370f9559bSTheo Schlossnagle  * Copyright (c) 2012, OmniTI Computer Consulting, Inc. All rights reserved.
34300fdee2SAndy Fiddaman  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
35553e44ceSAndrew Stormont  * Copyright 2018 RackTop Systems.
36159d09a2SMark Phalan  */
37159d09a2SMark Phalan 
38159d09a2SMark Phalan #include <errno.h>
39159d09a2SMark Phalan #include <string.h>
40159d09a2SMark Phalan #include <stdio.h>
41159d09a2SMark Phalan #include <stdlib.h>
42159d09a2SMark Phalan #include <dlfcn.h>
43159d09a2SMark Phalan #include <unistd.h>
44159d09a2SMark Phalan #include <dirent.h>
45159d09a2SMark Phalan 
4631a29035SMark Phalan 
47159d09a2SMark Phalan /* Solaris Kerberos */
48159d09a2SMark Phalan #include <libintl.h>
499e11d51cSWill Fiveash #include <assert.h>
509e11d51cSWill Fiveash #include <security/pam_appl.h>
519e11d51cSWill Fiveash #include <ctype.h>
5231a29035SMark Phalan #include "k5-int.h"
5303e68e16SWill Fiveash #include <ctype.h>
54159d09a2SMark Phalan 
55159d09a2SMark Phalan /*
56159d09a2SMark Phalan  * Q: What is this SILLYDECRYPT stuff about?
57159d09a2SMark Phalan  * A: When using the ActivCard Linux pkcs11 library (v2.0.1),
58159d09a2SMark Phalan  *    the decrypt function fails.  By inserting an extra
59159d09a2SMark Phalan  *    function call, which serves nothing but to change the
60159d09a2SMark Phalan  *    stack, we were able to work around the issue.  If the
61159d09a2SMark Phalan  *    ActivCard library is fixed in the future, this
62159d09a2SMark Phalan  *    definition and related code can be removed.
63159d09a2SMark Phalan  */
64159d09a2SMark Phalan #define SILLYDECRYPT
65159d09a2SMark Phalan 
66159d09a2SMark Phalan #include "pkinit_crypto_openssl.h"
67159d09a2SMark Phalan 
68159d09a2SMark Phalan /*
69159d09a2SMark Phalan  * Solaris Kerberos:
70159d09a2SMark Phalan  * Changed to a switch statement so gettext() can be used
71159d09a2SMark Phalan  * for internationization.
72159d09a2SMark Phalan  * Use defined constants rather than raw numbers for error codes.
73159d09a2SMark Phalan  */
74159d09a2SMark Phalan static char *
pkcs11_error_table(short code)75159d09a2SMark Phalan pkcs11_error_table(short code) {
76159d09a2SMark Phalan 	switch (code) {
77159d09a2SMark Phalan 	    case CKR_OK:
78159d09a2SMark Phalan 		return (gettext("ok"));
79159d09a2SMark Phalan 	    case CKR_CANCEL:
80159d09a2SMark Phalan 		return (gettext("cancel"));
81159d09a2SMark Phalan 	    case CKR_HOST_MEMORY:
82159d09a2SMark Phalan 		return (gettext("host memory"));
83159d09a2SMark Phalan 	    case CKR_SLOT_ID_INVALID:
84159d09a2SMark Phalan 		return (gettext("slot id invalid"));
85159d09a2SMark Phalan 	    case CKR_GENERAL_ERROR:
86159d09a2SMark Phalan 		return (gettext("general error"));
87159d09a2SMark Phalan 	    case CKR_FUNCTION_FAILED:
88159d09a2SMark Phalan 		return (gettext("function failed"));
89159d09a2SMark Phalan 	    case CKR_ARGUMENTS_BAD:
90159d09a2SMark Phalan 		return (gettext("arguments bad"));
91159d09a2SMark Phalan 	    case CKR_NO_EVENT:
92159d09a2SMark Phalan 		return (gettext("no event"));
93159d09a2SMark Phalan 	    case CKR_NEED_TO_CREATE_THREADS:
94159d09a2SMark Phalan 		return (gettext("need to create threads"));
95159d09a2SMark Phalan 	    case CKR_CANT_LOCK:
96159d09a2SMark Phalan 		return (gettext("cant lock"));
97159d09a2SMark Phalan 	    case CKR_ATTRIBUTE_READ_ONLY:
98159d09a2SMark Phalan 		return (gettext("attribute read only"));
99159d09a2SMark Phalan 	    case CKR_ATTRIBUTE_SENSITIVE:
100159d09a2SMark Phalan 		return (gettext("attribute sensitive"));
101159d09a2SMark Phalan 	    case CKR_ATTRIBUTE_TYPE_INVALID:
102159d09a2SMark Phalan 		return (gettext("attribute type invalid"));
103159d09a2SMark Phalan 	    case CKR_ATTRIBUTE_VALUE_INVALID:
104159d09a2SMark Phalan 		return (gettext("attribute value invalid"));
105159d09a2SMark Phalan 	    case CKR_DATA_INVALID:
106159d09a2SMark Phalan 		return (gettext("data invalid"));
107159d09a2SMark Phalan 	    case CKR_DATA_LEN_RANGE:
108159d09a2SMark Phalan 		return (gettext("data len range"));
109159d09a2SMark Phalan 	    case CKR_DEVICE_ERROR:
110159d09a2SMark Phalan 		return (gettext("device error"));
111159d09a2SMark Phalan 	    case CKR_DEVICE_MEMORY:
112159d09a2SMark Phalan 		return (gettext("device memory"));
113159d09a2SMark Phalan 	    case CKR_DEVICE_REMOVED:
114159d09a2SMark Phalan 		return (gettext("device removed"));
115159d09a2SMark Phalan 	    case CKR_ENCRYPTED_DATA_INVALID:
116159d09a2SMark Phalan 		return (gettext("encrypted data invalid"));
117159d09a2SMark Phalan 	    case CKR_ENCRYPTED_DATA_LEN_RANGE:
118159d09a2SMark Phalan 		return (gettext("encrypted data len range"));
119159d09a2SMark Phalan 	    case CKR_FUNCTION_CANCELED:
120159d09a2SMark Phalan 		return (gettext("function canceled"));
121159d09a2SMark Phalan 	    case CKR_FUNCTION_NOT_PARALLEL:
122159d09a2SMark Phalan 		return (gettext("function not parallel"));
123159d09a2SMark Phalan 	    case CKR_FUNCTION_NOT_SUPPORTED:
124159d09a2SMark Phalan 		return (gettext("function not supported"));
125159d09a2SMark Phalan 	    case CKR_KEY_HANDLE_INVALID:
126159d09a2SMark Phalan 		return (gettext("key handle invalid"));
127159d09a2SMark Phalan 	    case CKR_KEY_SIZE_RANGE:
128159d09a2SMark Phalan 		return (gettext("key size range"));
129159d09a2SMark Phalan 	    case CKR_KEY_TYPE_INCONSISTENT:
130159d09a2SMark Phalan 		return (gettext("key type inconsistent"));
131159d09a2SMark Phalan 	    case CKR_KEY_NOT_NEEDED:
132159d09a2SMark Phalan 		return (gettext("key not needed"));
133159d09a2SMark Phalan 	    case CKR_KEY_CHANGED:
134159d09a2SMark Phalan 		return (gettext("key changed"));
135159d09a2SMark Phalan 	    case CKR_KEY_NEEDED:
136159d09a2SMark Phalan 		return (gettext("key needed"));
137159d09a2SMark Phalan 	    case CKR_KEY_INDIGESTIBLE:
138159d09a2SMark Phalan 		return (gettext("key indigestible"));
139159d09a2SMark Phalan 	    case CKR_KEY_FUNCTION_NOT_PERMITTED:
140159d09a2SMark Phalan 		return (gettext("key function not permitted"));
141159d09a2SMark Phalan 	    case CKR_KEY_NOT_WRAPPABLE:
142159d09a2SMark Phalan 		return (gettext("key not wrappable"));
143159d09a2SMark Phalan 	    case CKR_KEY_UNEXTRACTABLE:
144159d09a2SMark Phalan 		return (gettext("key unextractable"));
145159d09a2SMark Phalan 	    case CKR_MECHANISM_INVALID:
146159d09a2SMark Phalan 		return (gettext("mechanism invalid"));
147159d09a2SMark Phalan 	    case CKR_MECHANISM_PARAM_INVALID:
148159d09a2SMark Phalan 		return (gettext("mechanism param invalid"));
149159d09a2SMark Phalan 	    case CKR_OBJECT_HANDLE_INVALID:
150159d09a2SMark Phalan 		return (gettext("object handle invalid"));
151159d09a2SMark Phalan 	    case CKR_OPERATION_ACTIVE:
152159d09a2SMark Phalan 		return (gettext("operation active"));
153159d09a2SMark Phalan 	    case CKR_OPERATION_NOT_INITIALIZED:
154159d09a2SMark Phalan 		return (gettext("operation not initialized"));
155159d09a2SMark Phalan 	    case CKR_PIN_INCORRECT:
156159d09a2SMark Phalan 		return (gettext("pin incorrect"));
157159d09a2SMark Phalan 	    case CKR_PIN_INVALID:
158159d09a2SMark Phalan 		return (gettext("pin invalid"));
159159d09a2SMark Phalan 	    case CKR_PIN_LEN_RANGE:
160159d09a2SMark Phalan 		return (gettext("pin len range"));
161159d09a2SMark Phalan 	    case CKR_PIN_EXPIRED:
162159d09a2SMark Phalan 		return (gettext("pin expired"));
163159d09a2SMark Phalan 	    case CKR_PIN_LOCKED:
164159d09a2SMark Phalan 		return (gettext("pin locked"));
165159d09a2SMark Phalan 	    case CKR_SESSION_CLOSED:
166159d09a2SMark Phalan 		return (gettext("session closed"));
167159d09a2SMark Phalan 	    case CKR_SESSION_COUNT:
168159d09a2SMark Phalan 		return (gettext("session count"));
169159d09a2SMark Phalan 	    case CKR_SESSION_HANDLE_INVALID:
170159d09a2SMark Phalan 		return (gettext("session handle invalid"));
171159d09a2SMark Phalan 	    case CKR_SESSION_PARALLEL_NOT_SUPPORTED:
172159d09a2SMark Phalan 		return (gettext("session parallel not supported"));
173159d09a2SMark Phalan 	    case CKR_SESSION_READ_ONLY:
174159d09a2SMark Phalan 		return (gettext("session read only"));
175159d09a2SMark Phalan 	    case CKR_SESSION_EXISTS:
176159d09a2SMark Phalan 		return (gettext("session exists"));
177159d09a2SMark Phalan 	    case CKR_SESSION_READ_ONLY_EXISTS:
178159d09a2SMark Phalan 		return (gettext("session read only exists"));
179159d09a2SMark Phalan 	    case CKR_SESSION_READ_WRITE_SO_EXISTS:
180159d09a2SMark Phalan 		return (gettext("session read write so exists"));
181159d09a2SMark Phalan 	    case CKR_SIGNATURE_INVALID:
182159d09a2SMark Phalan 		return (gettext("signature invalid"));
183159d09a2SMark Phalan 	    case CKR_SIGNATURE_LEN_RANGE:
184159d09a2SMark Phalan 		return (gettext("signature len range"));
185159d09a2SMark Phalan 	    case CKR_TEMPLATE_INCOMPLETE:
186159d09a2SMark Phalan 		return (gettext("template incomplete"));
187159d09a2SMark Phalan 	    case CKR_TEMPLATE_INCONSISTENT:
188159d09a2SMark Phalan 		return (gettext("template inconsistent"));
189159d09a2SMark Phalan 	    case CKR_TOKEN_NOT_PRESENT:
190159d09a2SMark Phalan 		return (gettext("token not present"));
191159d09a2SMark Phalan 	    case CKR_TOKEN_NOT_RECOGNIZED:
192159d09a2SMark Phalan 		return (gettext("token not recognized"));
193159d09a2SMark Phalan 	    case CKR_TOKEN_WRITE_PROTECTED:
194159d09a2SMark Phalan 		return (gettext("token write protected"));
195159d09a2SMark Phalan 	    case CKR_UNWRAPPING_KEY_HANDLE_INVALID:
196159d09a2SMark Phalan 		return (gettext("unwrapping key handle invalid"));
197159d09a2SMark Phalan 	    case CKR_UNWRAPPING_KEY_SIZE_RANGE:
198159d09a2SMark Phalan 		return (gettext("unwrapping key size range"));
199159d09a2SMark Phalan 	    case CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT:
200159d09a2SMark Phalan 		return (gettext("unwrapping key type inconsistent"));
201159d09a2SMark Phalan 	    case CKR_USER_ALREADY_LOGGED_IN:
202159d09a2SMark Phalan 		return (gettext("user already logged in"));
203159d09a2SMark Phalan 	    case CKR_USER_NOT_LOGGED_IN:
204159d09a2SMark Phalan 		return (gettext("user not logged in"));
205159d09a2SMark Phalan 	    case CKR_USER_PIN_NOT_INITIALIZED:
206159d09a2SMark Phalan 		return (gettext("user pin not initialized"));
207159d09a2SMark Phalan 	    case CKR_USER_TYPE_INVALID:
208159d09a2SMark Phalan 		return (gettext("user type invalid"));
209159d09a2SMark Phalan 	    case CKR_USER_ANOTHER_ALREADY_LOGGED_IN:
210159d09a2SMark Phalan 		return (gettext("user another already logged in"));
211159d09a2SMark Phalan 	    case CKR_USER_TOO_MANY_TYPES:
212159d09a2SMark Phalan 		return (gettext("user too many types"));
213159d09a2SMark Phalan 	    case CKR_WRAPPED_KEY_INVALID:
214159d09a2SMark Phalan 		return (gettext("wrapped key invalid"));
215159d09a2SMark Phalan 	    case CKR_WRAPPED_KEY_LEN_RANGE:
216159d09a2SMark Phalan 		return (gettext("wrapped key len range"));
217159d09a2SMark Phalan 	    case CKR_WRAPPING_KEY_HANDLE_INVALID:
218159d09a2SMark Phalan 		return (gettext("wrapping key handle invalid"));
219159d09a2SMark Phalan 	    case CKR_WRAPPING_KEY_SIZE_RANGE:
220159d09a2SMark Phalan 		return (gettext("wrapping key size range"));
221159d09a2SMark Phalan 	    case CKR_WRAPPING_KEY_TYPE_INCONSISTENT:
222159d09a2SMark Phalan 		return (gettext("wrapping key type inconsistent"));
223159d09a2SMark Phalan 	    case CKR_RANDOM_SEED_NOT_SUPPORTED:
224159d09a2SMark Phalan 		return (gettext("random seed not supported"));
225159d09a2SMark Phalan 	    case CKR_RANDOM_NO_RNG:
226159d09a2SMark Phalan 		return (gettext("random no rng"));
227159d09a2SMark Phalan 	    case CKR_DOMAIN_PARAMS_INVALID:
228159d09a2SMark Phalan 		return (gettext("domain params invalid"));
229159d09a2SMark Phalan 	    case CKR_BUFFER_TOO_SMALL:
230159d09a2SMark Phalan 		return (gettext("buffer too small"));
231159d09a2SMark Phalan 	    case CKR_SAVED_STATE_INVALID:
232159d09a2SMark Phalan 		return (gettext("saved state invalid"));
233159d09a2SMark Phalan 	    case CKR_INFORMATION_SENSITIVE:
234159d09a2SMark Phalan 		return (gettext("information sensitive"));
235159d09a2SMark Phalan 	    case CKR_STATE_UNSAVEABLE:
236159d09a2SMark Phalan 		return (gettext("state unsaveable"));
237159d09a2SMark Phalan 	    case CKR_CRYPTOKI_NOT_INITIALIZED:
238159d09a2SMark Phalan 		return (gettext("cryptoki not initialized"));
239159d09a2SMark Phalan 	    case CKR_CRYPTOKI_ALREADY_INITIALIZED:
240159d09a2SMark Phalan 		return (gettext("cryptoki already initialized"));
241159d09a2SMark Phalan 	    case CKR_MUTEX_BAD:
242159d09a2SMark Phalan 		return (gettext("mutex bad"));
243159d09a2SMark Phalan 	    case CKR_MUTEX_NOT_LOCKED:
244159d09a2SMark Phalan 		return (gettext("mutex not locked"));
245159d09a2SMark Phalan 	    case CKR_FUNCTION_REJECTED:
246159d09a2SMark Phalan 		return (gettext("function rejected"));
247159d09a2SMark Phalan 	    default:
248159d09a2SMark Phalan 		return (gettext("unknown error"));
249159d09a2SMark Phalan 	}
250159d09a2SMark Phalan }
251159d09a2SMark Phalan 
252159d09a2SMark Phalan /* DH parameters */
253159d09a2SMark Phalan unsigned char pkinit_1024_dhprime[128] = {
254159d09a2SMark Phalan     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
255159d09a2SMark Phalan     0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
256159d09a2SMark Phalan     0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
257159d09a2SMark Phalan     0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
258159d09a2SMark Phalan     0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
259159d09a2SMark Phalan     0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
260159d09a2SMark Phalan     0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
261159d09a2SMark Phalan     0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
262159d09a2SMark Phalan     0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
263159d09a2SMark Phalan     0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
264159d09a2SMark Phalan     0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
265159d09a2SMark Phalan     0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
266159d09a2SMark Phalan     0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
267159d09a2SMark Phalan     0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
268159d09a2SMark Phalan     0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
269159d09a2SMark Phalan     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
270159d09a2SMark Phalan };
271159d09a2SMark Phalan 
272159d09a2SMark Phalan unsigned char pkinit_2048_dhprime[2048/8] = {
273159d09a2SMark Phalan     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
274159d09a2SMark Phalan     0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
275159d09a2SMark Phalan     0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
276159d09a2SMark Phalan     0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
277159d09a2SMark Phalan     0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
278159d09a2SMark Phalan     0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
279159d09a2SMark Phalan     0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
280159d09a2SMark Phalan     0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
281159d09a2SMark Phalan     0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
282159d09a2SMark Phalan     0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
283159d09a2SMark Phalan     0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
284159d09a2SMark Phalan     0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
285159d09a2SMark Phalan     0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
286159d09a2SMark Phalan     0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
287159d09a2SMark Phalan     0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
288159d09a2SMark Phalan     0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
289159d09a2SMark Phalan     0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
290159d09a2SMark Phalan     0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
291159d09a2SMark Phalan     0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
292159d09a2SMark Phalan     0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
293159d09a2SMark Phalan     0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
294159d09a2SMark Phalan     0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
295159d09a2SMark Phalan     0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
296159d09a2SMark Phalan     0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
297159d09a2SMark Phalan     0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
298159d09a2SMark Phalan     0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
299159d09a2SMark Phalan     0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
300159d09a2SMark Phalan     0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
301159d09a2SMark Phalan     0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
302159d09a2SMark Phalan     0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
303159d09a2SMark Phalan     0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
304159d09a2SMark Phalan     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
305159d09a2SMark Phalan };
306159d09a2SMark Phalan 
307159d09a2SMark Phalan unsigned char pkinit_4096_dhprime[4096/8] = {
308159d09a2SMark Phalan     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
309159d09a2SMark Phalan     0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
310159d09a2SMark Phalan     0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
311159d09a2SMark Phalan     0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
312159d09a2SMark Phalan     0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
313159d09a2SMark Phalan     0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
314159d09a2SMark Phalan     0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
315159d09a2SMark Phalan     0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
316159d09a2SMark Phalan     0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
317159d09a2SMark Phalan     0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
318159d09a2SMark Phalan     0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
319159d09a2SMark Phalan     0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
320159d09a2SMark Phalan     0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
321159d09a2SMark Phalan     0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
322159d09a2SMark Phalan     0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
323159d09a2SMark Phalan     0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
324159d09a2SMark Phalan     0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
325159d09a2SMark Phalan     0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
326159d09a2SMark Phalan     0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
327159d09a2SMark Phalan     0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
328159d09a2SMark Phalan     0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
329159d09a2SMark Phalan     0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
330159d09a2SMark Phalan     0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
331159d09a2SMark Phalan     0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
332159d09a2SMark Phalan     0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
333159d09a2SMark Phalan     0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
334159d09a2SMark Phalan     0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
335159d09a2SMark Phalan     0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
336159d09a2SMark Phalan     0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
337159d09a2SMark Phalan     0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
338159d09a2SMark Phalan     0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
339159d09a2SMark Phalan     0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
340159d09a2SMark Phalan     0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
341159d09a2SMark Phalan     0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
342159d09a2SMark Phalan     0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
343159d09a2SMark Phalan     0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
344159d09a2SMark Phalan     0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
345159d09a2SMark Phalan     0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
346159d09a2SMark Phalan     0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
347159d09a2SMark Phalan     0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
348159d09a2SMark Phalan     0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
349159d09a2SMark Phalan     0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
350159d09a2SMark Phalan     0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
351159d09a2SMark Phalan     0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
352159d09a2SMark Phalan     0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
353159d09a2SMark Phalan     0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
354159d09a2SMark Phalan     0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
355159d09a2SMark Phalan     0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
356159d09a2SMark Phalan     0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
357159d09a2SMark Phalan     0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
358159d09a2SMark Phalan     0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
359159d09a2SMark Phalan     0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
360159d09a2SMark Phalan     0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
361159d09a2SMark Phalan     0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
362159d09a2SMark Phalan     0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
363159d09a2SMark Phalan     0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
364159d09a2SMark Phalan     0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
365159d09a2SMark Phalan     0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
366159d09a2SMark Phalan     0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
367159d09a2SMark Phalan     0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
368159d09a2SMark Phalan     0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
369159d09a2SMark Phalan     0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
370159d09a2SMark Phalan     0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
371159d09a2SMark Phalan     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
372159d09a2SMark Phalan };
373159d09a2SMark Phalan 
374553e44ceSAndrew Stormont #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
375300fdee2SAndy Fiddaman /*
376300fdee2SAndy Fiddaman  * Many things have changed in OpenSSL 1.1. The code in this file has been
377300fdee2SAndy Fiddaman  * updated to use the v1.1 APIs but some are new and require emulation
378300fdee2SAndy Fiddaman  * for older OpenSSL versions.
379300fdee2SAndy Fiddaman  */
380300fdee2SAndy Fiddaman 
381300fdee2SAndy Fiddaman /* EVP_MD_CTX construct and destructor names have changed */
382300fdee2SAndy Fiddaman 
383300fdee2SAndy Fiddaman #define EVP_MD_CTX_new EVP_MD_CTX_create
384300fdee2SAndy Fiddaman #define EVP_MD_CTX_free EVP_MD_CTX_destroy
385300fdee2SAndy Fiddaman 
386300fdee2SAndy Fiddaman /* ASN1_STRING_data is deprecated */
387300fdee2SAndy Fiddaman #define ASN1_STRING_get0_data ASN1_STRING_data
388300fdee2SAndy Fiddaman 
389300fdee2SAndy Fiddaman /* X509_STORE_CTX_trusted_stack is deprecated */
390300fdee2SAndy Fiddaman #define X509_STORE_CTX_set0_trusted_stack X509_STORE_CTX_trusted_stack
391300fdee2SAndy Fiddaman 
392300fdee2SAndy Fiddaman /* get_rfc2409_prime_1024() has been renamed. */
393300fdee2SAndy Fiddaman #define BN_get_rfc2409_prime_1024 get_rfc2409_prime_1024
394300fdee2SAndy Fiddaman 
395300fdee2SAndy Fiddaman #define OBJ_get0_data(o) ((o)->data)
396300fdee2SAndy Fiddaman #define OBJ_length(o) ((o)->length)
397300fdee2SAndy Fiddaman 
398300fdee2SAndy Fiddaman /* Some new DH functions that aren't in OpenSSL 1.0.x */
399300fdee2SAndy Fiddaman #define DH_bits(dh) BN_num_bits((dh)->p);
400300fdee2SAndy Fiddaman 
401300fdee2SAndy Fiddaman #define DH_set0_pqg(dh, p, q, g) __DH_set0_pqg(dh, p, q, g)
402300fdee2SAndy Fiddaman static int
__DH_set0_pqg(DH * dh,BIGNUM * p,BIGNUM * q,BIGNUM * g)403300fdee2SAndy Fiddaman __DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
404300fdee2SAndy Fiddaman {
405300fdee2SAndy Fiddaman     if ((dh->p == NULL && p == NULL) || (dh->g == NULL && g == NULL))
406300fdee2SAndy Fiddaman         return 0;
407300fdee2SAndy Fiddaman 
408300fdee2SAndy Fiddaman     if (p != NULL) {
409300fdee2SAndy Fiddaman         BN_free(dh->p);
410300fdee2SAndy Fiddaman         dh->p = p;
411300fdee2SAndy Fiddaman     }
412300fdee2SAndy Fiddaman     if (q != NULL) {
413300fdee2SAndy Fiddaman         BN_free(dh->q);
414300fdee2SAndy Fiddaman         dh->q = q;
415300fdee2SAndy Fiddaman     }
416300fdee2SAndy Fiddaman     if (g != NULL) {
417300fdee2SAndy Fiddaman         BN_free(dh->g);
418300fdee2SAndy Fiddaman         dh->g = g;
419300fdee2SAndy Fiddaman     }
420300fdee2SAndy Fiddaman 
421300fdee2SAndy Fiddaman     if (q != NULL) {
422300fdee2SAndy Fiddaman         dh->length = BN_num_bits(q);
423300fdee2SAndy Fiddaman     }
424300fdee2SAndy Fiddaman 
425300fdee2SAndy Fiddaman     return 1;
426300fdee2SAndy Fiddaman }
427300fdee2SAndy Fiddaman 
428300fdee2SAndy Fiddaman #define DH_get0_pqg(dh, p, q, g) __DH_get0_pqg(dh, p, q, g)
429300fdee2SAndy Fiddaman static void
__DH_get0_pqg(const DH * dh,const BIGNUM ** p,const BIGNUM ** q,const BIGNUM ** g)430300fdee2SAndy Fiddaman __DH_get0_pqg(const DH *dh, const BIGNUM **p, const BIGNUM **q,
431300fdee2SAndy Fiddaman     const BIGNUM **g)
432300fdee2SAndy Fiddaman {
433300fdee2SAndy Fiddaman     if (p != NULL)
434300fdee2SAndy Fiddaman         *p = dh->p;
435300fdee2SAndy Fiddaman     if (q != NULL)
436300fdee2SAndy Fiddaman         *q = dh->q;
437300fdee2SAndy Fiddaman     if (g != NULL)
438300fdee2SAndy Fiddaman         *g = dh->g;
439300fdee2SAndy Fiddaman }
440300fdee2SAndy Fiddaman 
441300fdee2SAndy Fiddaman #define DH_set0_key(dh, pub, priv) __DH_set0_key(dh, pub, priv)
442300fdee2SAndy Fiddaman static int
__DH_set0_key(DH * dh,BIGNUM * pub_key,BIGNUM * priv_key)443300fdee2SAndy Fiddaman __DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
444300fdee2SAndy Fiddaman {
445300fdee2SAndy Fiddaman     if (pub_key != NULL) {
446300fdee2SAndy Fiddaman         BN_free(dh->pub_key);
447300fdee2SAndy Fiddaman         dh->pub_key = pub_key;
448300fdee2SAndy Fiddaman     }
449300fdee2SAndy Fiddaman     if (priv_key != NULL) {
450300fdee2SAndy Fiddaman         BN_free(dh->priv_key);
451300fdee2SAndy Fiddaman         dh->priv_key = priv_key;
452300fdee2SAndy Fiddaman     }
453300fdee2SAndy Fiddaman 
454300fdee2SAndy Fiddaman     return 1;
455300fdee2SAndy Fiddaman }
456300fdee2SAndy Fiddaman 
457300fdee2SAndy Fiddaman #define DH_get0_key(dh, pub, priv) __DH_get0_key(dh, pub, priv)
458300fdee2SAndy Fiddaman static void
__DH_get0_key(const DH * dh,const BIGNUM ** pub,const BIGNUM ** priv)459300fdee2SAndy Fiddaman __DH_get0_key(const DH *dh, const BIGNUM **pub, const BIGNUM **priv)
460300fdee2SAndy Fiddaman {
461300fdee2SAndy Fiddaman     if (pub != NULL)
462300fdee2SAndy Fiddaman         *pub = dh->pub_key;
463300fdee2SAndy Fiddaman     if (priv != NULL)
464300fdee2SAndy Fiddaman         *priv = dh->priv_key;
465300fdee2SAndy Fiddaman }
466300fdee2SAndy Fiddaman 
467553e44ceSAndrew Stormont #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L || LIBRESSL_VERSION_NUMBER */
468159d09a2SMark Phalan 
469159d09a2SMark Phalan krb5_error_code
pkinit_init_plg_crypto(pkinit_plg_crypto_context * cryptoctx)470159d09a2SMark Phalan pkinit_init_plg_crypto(pkinit_plg_crypto_context *cryptoctx) {
471159d09a2SMark Phalan 
472159d09a2SMark Phalan     krb5_error_code retval = ENOMEM;
473159d09a2SMark Phalan     pkinit_plg_crypto_context ctx = NULL;
474159d09a2SMark Phalan 
475159d09a2SMark Phalan     /* initialize openssl routines */
47631a29035SMark Phalan     /* Solaris Kerberos */
47731a29035SMark Phalan     retval = openssl_init();
47831a29035SMark Phalan     if (retval != 0)
47931a29035SMark Phalan 	goto out;
480159d09a2SMark Phalan 
481159d09a2SMark Phalan     ctx = (pkinit_plg_crypto_context)malloc(sizeof(*ctx));
482159d09a2SMark Phalan     if (ctx == NULL)
483159d09a2SMark Phalan 	goto out;
484159d09a2SMark Phalan     (void) memset(ctx, 0, sizeof(*ctx));
485159d09a2SMark Phalan 
486159d09a2SMark Phalan     pkiDebug("%s: initializing openssl crypto context at %p\n",
487159d09a2SMark Phalan 	     __FUNCTION__, ctx);
488159d09a2SMark Phalan     retval = pkinit_init_pkinit_oids(ctx);
489159d09a2SMark Phalan     if (retval)
490159d09a2SMark Phalan 	goto out;
491159d09a2SMark Phalan 
492159d09a2SMark Phalan     retval = pkinit_init_dh_params(ctx);
493159d09a2SMark Phalan     if (retval)
494159d09a2SMark Phalan 	goto out;
495159d09a2SMark Phalan 
496159d09a2SMark Phalan     *cryptoctx = ctx;
497159d09a2SMark Phalan 
498159d09a2SMark Phalan out:
499159d09a2SMark Phalan     if (retval && ctx != NULL)
500159d09a2SMark Phalan 	    pkinit_fini_plg_crypto(ctx);
501159d09a2SMark Phalan 
502159d09a2SMark Phalan     return retval;
503159d09a2SMark Phalan }
504159d09a2SMark Phalan 
505159d09a2SMark Phalan void
pkinit_fini_plg_crypto(pkinit_plg_crypto_context cryptoctx)506159d09a2SMark Phalan pkinit_fini_plg_crypto(pkinit_plg_crypto_context cryptoctx)
507159d09a2SMark Phalan {
508159d09a2SMark Phalan     pkiDebug("%s: freeing context at %p\n", __FUNCTION__, cryptoctx);
509159d09a2SMark Phalan 
510159d09a2SMark Phalan     if (cryptoctx == NULL)
511159d09a2SMark Phalan 	return;
512159d09a2SMark Phalan     pkinit_fini_pkinit_oids(cryptoctx);
513159d09a2SMark Phalan     pkinit_fini_dh_params(cryptoctx);
514159d09a2SMark Phalan     free(cryptoctx);
515159d09a2SMark Phalan }
516159d09a2SMark Phalan 
517159d09a2SMark Phalan krb5_error_code
pkinit_init_identity_crypto(pkinit_identity_crypto_context * idctx)518159d09a2SMark Phalan pkinit_init_identity_crypto(pkinit_identity_crypto_context *idctx)
519159d09a2SMark Phalan {
520159d09a2SMark Phalan     krb5_error_code retval = ENOMEM;
521159d09a2SMark Phalan     pkinit_identity_crypto_context ctx = NULL;
522159d09a2SMark Phalan 
523159d09a2SMark Phalan     ctx = (pkinit_identity_crypto_context)malloc(sizeof(*ctx));
524159d09a2SMark Phalan     if (ctx == NULL)
525159d09a2SMark Phalan 	goto out;
526159d09a2SMark Phalan     (void) memset(ctx, 0, sizeof(*ctx));
527159d09a2SMark Phalan 
528159d09a2SMark Phalan     retval = pkinit_init_certs(ctx);
529159d09a2SMark Phalan     if (retval)
530159d09a2SMark Phalan 	goto out;
531159d09a2SMark Phalan 
532159d09a2SMark Phalan     retval = pkinit_init_pkcs11(ctx);
533159d09a2SMark Phalan     if (retval)
534159d09a2SMark Phalan 	goto out;
535159d09a2SMark Phalan 
536159d09a2SMark Phalan     pkiDebug("%s: returning ctx at %p\n", __FUNCTION__, ctx);
537159d09a2SMark Phalan     *idctx = ctx;
538159d09a2SMark Phalan 
539159d09a2SMark Phalan out:
540159d09a2SMark Phalan     if (retval) {
541159d09a2SMark Phalan 	if (ctx)
542159d09a2SMark Phalan 	    pkinit_fini_identity_crypto(ctx);
543159d09a2SMark Phalan     }
544159d09a2SMark Phalan 
545159d09a2SMark Phalan     return retval;
546159d09a2SMark Phalan }
547159d09a2SMark Phalan 
548159d09a2SMark Phalan void
pkinit_fini_identity_crypto(pkinit_identity_crypto_context idctx)549159d09a2SMark Phalan pkinit_fini_identity_crypto(pkinit_identity_crypto_context idctx)
550159d09a2SMark Phalan {
551159d09a2SMark Phalan     if (idctx == NULL)
552159d09a2SMark Phalan 	return;
553159d09a2SMark Phalan 
554159d09a2SMark Phalan     pkiDebug("%s: freeing   ctx at %p\n", __FUNCTION__, idctx);
555159d09a2SMark Phalan     pkinit_fini_certs(idctx);
556159d09a2SMark Phalan     pkinit_fini_pkcs11(idctx);
557159d09a2SMark Phalan     free(idctx);
558159d09a2SMark Phalan }
559159d09a2SMark Phalan 
560159d09a2SMark Phalan krb5_error_code
pkinit_init_req_crypto(pkinit_req_crypto_context * cryptoctx)561159d09a2SMark Phalan pkinit_init_req_crypto(pkinit_req_crypto_context *cryptoctx)
562159d09a2SMark Phalan {
563159d09a2SMark Phalan 
564159d09a2SMark Phalan     pkinit_req_crypto_context ctx = NULL;
565159d09a2SMark Phalan 
566159d09a2SMark Phalan     /* Solaris Kerberos */
567159d09a2SMark Phalan     if (cryptoctx == NULL)
568159d09a2SMark Phalan 	return EINVAL;
569159d09a2SMark Phalan 
570159d09a2SMark Phalan     ctx = (pkinit_req_crypto_context)malloc(sizeof(*ctx));
571159d09a2SMark Phalan     if (ctx == NULL)
572159d09a2SMark Phalan 	return ENOMEM;
573159d09a2SMark Phalan     (void) memset(ctx, 0, sizeof(*ctx));
574159d09a2SMark Phalan 
575159d09a2SMark Phalan     ctx->dh = NULL;
576159d09a2SMark Phalan     ctx->received_cert = NULL;
577159d09a2SMark Phalan 
578159d09a2SMark Phalan     *cryptoctx = ctx;
579159d09a2SMark Phalan 
580159d09a2SMark Phalan     pkiDebug("%s: returning ctx at %p\n", __FUNCTION__, ctx);
581159d09a2SMark Phalan 
582159d09a2SMark Phalan     return 0;
583159d09a2SMark Phalan }
584159d09a2SMark Phalan 
585159d09a2SMark Phalan void
pkinit_fini_req_crypto(pkinit_req_crypto_context req_cryptoctx)586159d09a2SMark Phalan pkinit_fini_req_crypto(pkinit_req_crypto_context req_cryptoctx)
587159d09a2SMark Phalan {
588159d09a2SMark Phalan     if (req_cryptoctx == NULL)
589159d09a2SMark Phalan 	return;
590159d09a2SMark Phalan 
591159d09a2SMark Phalan     pkiDebug("%s: freeing   ctx at %p\n", __FUNCTION__, req_cryptoctx);
592159d09a2SMark Phalan     if (req_cryptoctx->dh != NULL)
593159d09a2SMark Phalan       DH_free(req_cryptoctx->dh);
594159d09a2SMark Phalan     if (req_cryptoctx->received_cert != NULL)
595159d09a2SMark Phalan       X509_free(req_cryptoctx->received_cert);
596159d09a2SMark Phalan 
597159d09a2SMark Phalan     free(req_cryptoctx);
598159d09a2SMark Phalan }
599159d09a2SMark Phalan 
600159d09a2SMark Phalan static krb5_error_code
pkinit_init_pkinit_oids(pkinit_plg_crypto_context ctx)601159d09a2SMark Phalan pkinit_init_pkinit_oids(pkinit_plg_crypto_context ctx)
602159d09a2SMark Phalan {
603553e44ceSAndrew Stormont     ctx->id_pkinit_san = OBJ_txt2obj("1.3.6.1.5.2.2", 1);
604553e44ceSAndrew Stormont     if (ctx->id_pkinit_san == NULL)
605553e44ceSAndrew Stormont         return ENOMEM;
606159d09a2SMark Phalan 
607553e44ceSAndrew Stormont     ctx->id_pkinit_authData = OBJ_txt2obj("1.3.6.1.5.2.3.1", 1);
608553e44ceSAndrew Stormont     if (ctx->id_pkinit_authData == NULL)
609553e44ceSAndrew Stormont         return ENOMEM;
610159d09a2SMark Phalan 
611553e44ceSAndrew Stormont     ctx->id_pkinit_DHKeyData = OBJ_txt2obj("1.3.6.1.5.2.3.2", 1);
612553e44ceSAndrew Stormont     if (ctx->id_pkinit_DHKeyData == NULL)
613553e44ceSAndrew Stormont         return ENOMEM;
614159d09a2SMark Phalan 
615553e44ceSAndrew Stormont     ctx->id_pkinit_rkeyData = OBJ_txt2obj("1.3.6.1.5.2.3.3", 1);
616553e44ceSAndrew Stormont     if (ctx->id_pkinit_rkeyData == NULL)
617553e44ceSAndrew Stormont         return ENOMEM;
618159d09a2SMark Phalan 
619553e44ceSAndrew Stormont     ctx->id_pkinit_KPClientAuth = OBJ_txt2obj("1.3.6.1.5.2.3.4", 1);
620553e44ceSAndrew Stormont     if (ctx->id_pkinit_KPClientAuth == NULL)
621553e44ceSAndrew Stormont         return ENOMEM;
622159d09a2SMark Phalan 
623553e44ceSAndrew Stormont     ctx->id_pkinit_KPKdc = OBJ_txt2obj("1.3.6.1.5.2.3.5", 1);
624553e44ceSAndrew Stormont     if (ctx->id_pkinit_KPKdc == NULL)
625553e44ceSAndrew Stormont         return ENOMEM;
626159d09a2SMark Phalan 
627553e44ceSAndrew Stormont     ctx->id_ms_kp_sc_logon = OBJ_txt2obj("1.3.6.1.4.1.311.20.2.2", 1);
628553e44ceSAndrew Stormont     if (ctx->id_ms_kp_sc_logon == NULL)
629553e44ceSAndrew Stormont         return ENOMEM;
630159d09a2SMark Phalan 
631553e44ceSAndrew Stormont     ctx->id_ms_san_upn = OBJ_txt2obj("1.3.6.1.4.1.311.20.2.3", 1);
632553e44ceSAndrew Stormont     if (ctx->id_ms_san_upn == NULL)
633553e44ceSAndrew Stormont         return ENOMEM;
634300fdee2SAndy Fiddaman 
635553e44ceSAndrew Stormont     ctx->id_kp_serverAuth = OBJ_txt2obj("1.3.6.1.5.5.7.3.1", 1);
636553e44ceSAndrew Stormont     if (ctx->id_kp_serverAuth == NULL)
637553e44ceSAndrew Stormont         return ENOMEM;
638159d09a2SMark Phalan 
639553e44ceSAndrew Stormont     return 0;
640159d09a2SMark Phalan }
641159d09a2SMark Phalan 
642159d09a2SMark Phalan static krb5_error_code
get_cert(char * filename,X509 ** retcert)643159d09a2SMark Phalan get_cert(char *filename, X509 **retcert)
644159d09a2SMark Phalan {
645159d09a2SMark Phalan     X509 *cert = NULL;
646159d09a2SMark Phalan     BIO *tmp = NULL;
647159d09a2SMark Phalan     int code;
648159d09a2SMark Phalan     krb5_error_code retval;
649159d09a2SMark Phalan 
650159d09a2SMark Phalan     if (filename == NULL || retcert == NULL)
651159d09a2SMark Phalan 	return EINVAL;
652159d09a2SMark Phalan 
653159d09a2SMark Phalan     *retcert = NULL;
654159d09a2SMark Phalan 
655159d09a2SMark Phalan     tmp = BIO_new(BIO_s_file());
656159d09a2SMark Phalan     if (tmp == NULL)
657159d09a2SMark Phalan 	return ENOMEM;
658159d09a2SMark Phalan 
659159d09a2SMark Phalan     code = BIO_read_filename(tmp, filename);
660159d09a2SMark Phalan     if (code == 0) {
661159d09a2SMark Phalan 	retval = errno;
662159d09a2SMark Phalan 	goto cleanup;
663159d09a2SMark Phalan     }
664159d09a2SMark Phalan 
665159d09a2SMark Phalan     cert = (X509 *) PEM_read_bio_X509(tmp, NULL, NULL, NULL);
666159d09a2SMark Phalan     if (cert == NULL) {
667159d09a2SMark Phalan 	retval = EIO;
668159d09a2SMark Phalan 	pkiDebug("failed to read certificate from %s\n", filename);
669159d09a2SMark Phalan 	goto cleanup;
670159d09a2SMark Phalan     }
671159d09a2SMark Phalan     *retcert = cert;
672159d09a2SMark Phalan     retval = 0;
673159d09a2SMark Phalan cleanup:
674159d09a2SMark Phalan     if (tmp != NULL)
675159d09a2SMark Phalan 	BIO_free(tmp);
676159d09a2SMark Phalan     return retval;
677159d09a2SMark Phalan }
678159d09a2SMark Phalan 
679159d09a2SMark Phalan static krb5_error_code
get_key(char * filename,EVP_PKEY ** retkey)680159d09a2SMark Phalan get_key(char *filename, EVP_PKEY **retkey)
681159d09a2SMark Phalan {
682159d09a2SMark Phalan     EVP_PKEY *pkey = NULL;
683159d09a2SMark Phalan     BIO *tmp = NULL;
684159d09a2SMark Phalan     int code;
685159d09a2SMark Phalan     krb5_error_code retval;
686159d09a2SMark Phalan 
687159d09a2SMark Phalan     if (filename == NULL || retkey == NULL)
688159d09a2SMark Phalan 	return EINVAL;
689159d09a2SMark Phalan 
690159d09a2SMark Phalan     tmp = BIO_new(BIO_s_file());
691159d09a2SMark Phalan     if (tmp == NULL)
692159d09a2SMark Phalan 	return ENOMEM;
693159d09a2SMark Phalan 
694159d09a2SMark Phalan     code = BIO_read_filename(tmp, filename);
695159d09a2SMark Phalan     if (code == 0) {
696159d09a2SMark Phalan 	retval = errno;
697159d09a2SMark Phalan 	goto cleanup;
698159d09a2SMark Phalan     }
699159d09a2SMark Phalan     pkey = (EVP_PKEY *) PEM_read_bio_PrivateKey(tmp, NULL, NULL, NULL);
700159d09a2SMark Phalan     if (pkey == NULL) {
701159d09a2SMark Phalan 	retval = EIO;
702159d09a2SMark Phalan 	pkiDebug("failed to read private key from %s\n", filename);
703159d09a2SMark Phalan 	goto cleanup;
704159d09a2SMark Phalan     }
705159d09a2SMark Phalan     *retkey = pkey;
706159d09a2SMark Phalan     retval = 0;
707159d09a2SMark Phalan cleanup:
708159d09a2SMark Phalan     if (tmp != NULL)
709159d09a2SMark Phalan 	BIO_free(tmp);
710159d09a2SMark Phalan     return retval;
711159d09a2SMark Phalan }
712159d09a2SMark Phalan 
713159d09a2SMark Phalan static void
pkinit_fini_pkinit_oids(pkinit_plg_crypto_context ctx)714159d09a2SMark Phalan pkinit_fini_pkinit_oids(pkinit_plg_crypto_context ctx)
715159d09a2SMark Phalan {
716159d09a2SMark Phalan     if (ctx == NULL)
717159d09a2SMark Phalan 	return;
718553e44ceSAndrew Stormont     ASN1_OBJECT_free(ctx->id_pkinit_san);
719553e44ceSAndrew Stormont     ASN1_OBJECT_free(ctx->id_pkinit_authData);
720553e44ceSAndrew Stormont     ASN1_OBJECT_free(ctx->id_pkinit_DHKeyData);
721553e44ceSAndrew Stormont     ASN1_OBJECT_free(ctx->id_pkinit_rkeyData);
722553e44ceSAndrew Stormont     ASN1_OBJECT_free(ctx->id_pkinit_KPClientAuth);
723553e44ceSAndrew Stormont     ASN1_OBJECT_free(ctx->id_pkinit_KPKdc);
724553e44ceSAndrew Stormont     ASN1_OBJECT_free(ctx->id_ms_kp_sc_logon);
725553e44ceSAndrew Stormont     ASN1_OBJECT_free(ctx->id_ms_san_upn);
726553e44ceSAndrew Stormont     ASN1_OBJECT_free(ctx->id_kp_serverAuth);
727159d09a2SMark Phalan }
728159d09a2SMark Phalan 
729300fdee2SAndy Fiddaman static DH *
make_dhprime(uint8_t * prime,size_t len)730300fdee2SAndy Fiddaman make_dhprime(uint8_t *prime, size_t len)
731300fdee2SAndy Fiddaman {
732300fdee2SAndy Fiddaman     DH *dh = NULL;
733300fdee2SAndy Fiddaman     BIGNUM *p = NULL, *q = NULL, *g = NULL;
734300fdee2SAndy Fiddaman 
735300fdee2SAndy Fiddaman     if ((p = BN_bin2bn(prime, len, NULL)) == NULL)
736300fdee2SAndy Fiddaman 	goto cleanup;
737300fdee2SAndy Fiddaman     if ((q = BN_new()) == NULL)
738300fdee2SAndy Fiddaman 	goto cleanup;
739300fdee2SAndy Fiddaman     if (!BN_rshift1(q, p))
740300fdee2SAndy Fiddaman 	goto cleanup;
741300fdee2SAndy Fiddaman     if ((g = BN_new()) == NULL)
742300fdee2SAndy Fiddaman 	goto cleanup;
743300fdee2SAndy Fiddaman     if (!BN_set_word(g, DH_GENERATOR_2))
744300fdee2SAndy Fiddaman 	goto cleanup;
745300fdee2SAndy Fiddaman 
746300fdee2SAndy Fiddaman     dh = DH_new();
747300fdee2SAndy Fiddaman     if (dh == NULL)
748300fdee2SAndy Fiddaman 	goto cleanup;
749300fdee2SAndy Fiddaman     DH_set0_pqg(dh, p, q, g);
750300fdee2SAndy Fiddaman     p = g = q = NULL;
751300fdee2SAndy Fiddaman 
752300fdee2SAndy Fiddaman cleanup:
753300fdee2SAndy Fiddaman     BN_free(p);
754300fdee2SAndy Fiddaman     BN_free(q);
755300fdee2SAndy Fiddaman     BN_free(g);
756300fdee2SAndy Fiddaman     return dh;
757300fdee2SAndy Fiddaman }
758300fdee2SAndy Fiddaman 
759159d09a2SMark Phalan static krb5_error_code
pkinit_init_dh_params(pkinit_plg_crypto_context plgctx)760159d09a2SMark Phalan pkinit_init_dh_params(pkinit_plg_crypto_context plgctx)
761159d09a2SMark Phalan {
762159d09a2SMark Phalan     krb5_error_code retval = ENOMEM;
763159d09a2SMark Phalan 
764300fdee2SAndy Fiddaman     plgctx->dh_1024 = make_dhprime(pkinit_1024_dhprime,
765300fdee2SAndy Fiddaman         sizeof(pkinit_1024_dhprime));
766159d09a2SMark Phalan     if (plgctx->dh_1024 == NULL)
767159d09a2SMark Phalan 	goto cleanup;
768159d09a2SMark Phalan 
769300fdee2SAndy Fiddaman     plgctx->dh_2048 = make_dhprime(pkinit_2048_dhprime,
770300fdee2SAndy Fiddaman         sizeof(pkinit_2048_dhprime));
771159d09a2SMark Phalan     if (plgctx->dh_2048 == NULL)
772159d09a2SMark Phalan 	goto cleanup;
773159d09a2SMark Phalan 
774300fdee2SAndy Fiddaman     plgctx->dh_4096 = make_dhprime(pkinit_4096_dhprime,
775300fdee2SAndy Fiddaman         sizeof(pkinit_4096_dhprime));
776159d09a2SMark Phalan     if (plgctx->dh_4096 == NULL)
777159d09a2SMark Phalan 	goto cleanup;
778159d09a2SMark Phalan 
779159d09a2SMark Phalan     retval = 0;
780159d09a2SMark Phalan 
781159d09a2SMark Phalan cleanup:
782159d09a2SMark Phalan     if (retval)
783159d09a2SMark Phalan 	pkinit_fini_dh_params(plgctx);
784159d09a2SMark Phalan 
785159d09a2SMark Phalan     return retval;
786159d09a2SMark Phalan }
787159d09a2SMark Phalan 
788159d09a2SMark Phalan static void
pkinit_fini_dh_params(pkinit_plg_crypto_context plgctx)789159d09a2SMark Phalan pkinit_fini_dh_params(pkinit_plg_crypto_context plgctx)
790159d09a2SMark Phalan {
791159d09a2SMark Phalan     if (plgctx->dh_1024 != NULL)
792159d09a2SMark Phalan 	DH_free(plgctx->dh_1024);
793159d09a2SMark Phalan     if (plgctx->dh_2048 != NULL)
794159d09a2SMark Phalan 	DH_free(plgctx->dh_2048);
795159d09a2SMark Phalan     if (plgctx->dh_4096 != NULL)
796159d09a2SMark Phalan 	DH_free(plgctx->dh_4096);
797159d09a2SMark Phalan 
798159d09a2SMark Phalan     plgctx->dh_1024 = plgctx->dh_2048 = plgctx->dh_4096 = NULL;
799159d09a2SMark Phalan }
800159d09a2SMark Phalan 
801159d09a2SMark Phalan static krb5_error_code
pkinit_init_certs(pkinit_identity_crypto_context ctx)802159d09a2SMark Phalan pkinit_init_certs(pkinit_identity_crypto_context ctx)
803159d09a2SMark Phalan {
804159d09a2SMark Phalan     /* Solaris Kerberos */
805159d09a2SMark Phalan     int i;
806159d09a2SMark Phalan 
807159d09a2SMark Phalan     for (i = 0; i < MAX_CREDS_ALLOWED; i++)
808159d09a2SMark Phalan 	ctx->creds[i] = NULL;
809159d09a2SMark Phalan     ctx->my_certs = NULL;
810159d09a2SMark Phalan     ctx->cert_index = 0;
811159d09a2SMark Phalan     ctx->my_key = NULL;
812159d09a2SMark Phalan     ctx->trustedCAs = NULL;
813159d09a2SMark Phalan     ctx->intermediateCAs = NULL;
814159d09a2SMark Phalan     ctx->revoked = NULL;
815159d09a2SMark Phalan 
816159d09a2SMark Phalan     return 0;
817159d09a2SMark Phalan }
818159d09a2SMark Phalan 
819159d09a2SMark Phalan static void
pkinit_fini_certs(pkinit_identity_crypto_context ctx)820159d09a2SMark Phalan pkinit_fini_certs(pkinit_identity_crypto_context ctx)
821159d09a2SMark Phalan {
822159d09a2SMark Phalan     if (ctx == NULL)
823159d09a2SMark Phalan 	return;
824159d09a2SMark Phalan 
825159d09a2SMark Phalan     if (ctx->my_certs != NULL)
826159d09a2SMark Phalan 	sk_X509_pop_free(ctx->my_certs, X509_free);
827159d09a2SMark Phalan 
828159d09a2SMark Phalan     if (ctx->my_key != NULL)
829159d09a2SMark Phalan 	EVP_PKEY_free(ctx->my_key);
830159d09a2SMark Phalan 
831159d09a2SMark Phalan     if (ctx->trustedCAs != NULL)
832159d09a2SMark Phalan 	sk_X509_pop_free(ctx->trustedCAs, X509_free);
833159d09a2SMark Phalan 
834159d09a2SMark Phalan     if (ctx->intermediateCAs != NULL)
835159d09a2SMark Phalan 	sk_X509_pop_free(ctx->intermediateCAs, X509_free);
836159d09a2SMark Phalan 
837159d09a2SMark Phalan     if (ctx->revoked != NULL)
838159d09a2SMark Phalan 	sk_X509_CRL_pop_free(ctx->revoked, X509_CRL_free);
839159d09a2SMark Phalan }
840159d09a2SMark Phalan 
841159d09a2SMark Phalan static krb5_error_code
pkinit_init_pkcs11(pkinit_identity_crypto_context ctx)842159d09a2SMark Phalan pkinit_init_pkcs11(pkinit_identity_crypto_context ctx)
843159d09a2SMark Phalan {
844159d09a2SMark Phalan     /* Solaris Kerberos */
845159d09a2SMark Phalan 
846159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
847159d09a2SMark Phalan     ctx->p11_module_name = strdup(PKCS11_MODNAME);
848159d09a2SMark Phalan     if (ctx->p11_module_name == NULL)
849159d09a2SMark Phalan 	return ENOMEM;
850159d09a2SMark Phalan     ctx->p11_module = NULL;
851159d09a2SMark Phalan     ctx->slotid = PK_NOSLOT;
852159d09a2SMark Phalan     ctx->token_label = NULL;
853159d09a2SMark Phalan     ctx->cert_label = NULL;
854488060a6SWill Fiveash     ctx->PIN = NULL;
855159d09a2SMark Phalan     ctx->session = CK_INVALID_HANDLE;
856159d09a2SMark Phalan     ctx->p11 = NULL;
8577d2d870eSWill Fiveash     ctx->p11flags = 0; /* Solaris Kerberos */
858159d09a2SMark Phalan #endif
859159d09a2SMark Phalan     ctx->pkcs11_method = 0;
8609e11d51cSWill Fiveash     (void) memset(ctx->creds, 0, sizeof(ctx->creds));
861159d09a2SMark Phalan 
862159d09a2SMark Phalan     return 0;
863159d09a2SMark Phalan }
864159d09a2SMark Phalan 
865159d09a2SMark Phalan static void
pkinit_fini_pkcs11(pkinit_identity_crypto_context ctx)866159d09a2SMark Phalan pkinit_fini_pkcs11(pkinit_identity_crypto_context ctx)
867159d09a2SMark Phalan {
868159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
869159d09a2SMark Phalan     if (ctx == NULL)
870159d09a2SMark Phalan 	return;
871159d09a2SMark Phalan 
872159d09a2SMark Phalan     if (ctx->p11 != NULL) {
8739e11d51cSWill Fiveash 	if (ctx->session != CK_INVALID_HANDLE) {
874159d09a2SMark Phalan 	    ctx->p11->C_CloseSession(ctx->session);
875159d09a2SMark Phalan 	    ctx->session = CK_INVALID_HANDLE;
876159d09a2SMark Phalan 	}
877159d09a2SMark Phalan 	/*
878159d09a2SMark Phalan 	 * Solaris Kerberos:
879159d09a2SMark Phalan 	 * Only call C_Finalize if the process was not already using pkcs11.
880159d09a2SMark Phalan 	 */
881159d09a2SMark Phalan 	if (ctx->finalize_pkcs11 == TRUE)
882159d09a2SMark Phalan 	    ctx->p11->C_Finalize(NULL_PTR);
883159d09a2SMark Phalan 
884159d09a2SMark Phalan 	ctx->p11 = NULL;
885159d09a2SMark Phalan     }
886159d09a2SMark Phalan     if (ctx->p11_module != NULL) {
887159d09a2SMark Phalan 	pkinit_C_UnloadModule(ctx->p11_module);
888159d09a2SMark Phalan 	ctx->p11_module = NULL;
889159d09a2SMark Phalan     }
890159d09a2SMark Phalan     if (ctx->p11_module_name != NULL)
891159d09a2SMark Phalan 	free(ctx->p11_module_name);
892159d09a2SMark Phalan     if (ctx->token_label != NULL)
893159d09a2SMark Phalan 	free(ctx->token_label);
894159d09a2SMark Phalan     if (ctx->cert_id != NULL)
895159d09a2SMark Phalan 	free(ctx->cert_id);
896159d09a2SMark Phalan     if (ctx->cert_label != NULL)
897159d09a2SMark Phalan 	free(ctx->cert_label);
898488060a6SWill Fiveash     if (ctx->PIN != NULL) {
899488060a6SWill Fiveash 	(void) memset(ctx->PIN, 0, strlen(ctx->PIN));
900488060a6SWill Fiveash 	free(ctx->PIN);
901488060a6SWill Fiveash     }
902159d09a2SMark Phalan #endif
903159d09a2SMark Phalan }
904159d09a2SMark Phalan 
905159d09a2SMark Phalan krb5_error_code
pkinit_identity_set_prompter(pkinit_identity_crypto_context id_cryptoctx,krb5_prompter_fct prompter,void * prompter_data)906159d09a2SMark Phalan pkinit_identity_set_prompter(pkinit_identity_crypto_context id_cryptoctx,
907159d09a2SMark Phalan 			     krb5_prompter_fct prompter,
908159d09a2SMark Phalan 			     void *prompter_data)
909159d09a2SMark Phalan {
910159d09a2SMark Phalan     id_cryptoctx->prompter = prompter;
911159d09a2SMark Phalan     id_cryptoctx->prompter_data = prompter_data;
912159d09a2SMark Phalan 
913159d09a2SMark Phalan     return 0;
914159d09a2SMark Phalan }
915159d09a2SMark Phalan 
916553e44ceSAndrew Stormont /* Create a CMS ContentInfo of type oid containing the octet string in data. */
917553e44ceSAndrew Stormont static krb5_error_code
create_contentinfo(krb5_context context,ASN1_OBJECT * oid,unsigned char * data,size_t data_len,PKCS7 ** p7_out)918553e44ceSAndrew Stormont create_contentinfo(krb5_context context,
919553e44ceSAndrew Stormont 		   ASN1_OBJECT *oid,
920553e44ceSAndrew Stormont 		   unsigned char *data,
921553e44ceSAndrew Stormont 		   size_t data_len,
922553e44ceSAndrew Stormont 		   PKCS7 **p7_out)
923553e44ceSAndrew Stormont {
924553e44ceSAndrew Stormont     PKCS7 *p7 = NULL;
925553e44ceSAndrew Stormont     ASN1_OCTET_STRING *ostr = NULL;
926553e44ceSAndrew Stormont 
927553e44ceSAndrew Stormont     *p7_out = NULL;
928553e44ceSAndrew Stormont 
929553e44ceSAndrew Stormont     ostr = ASN1_OCTET_STRING_new();
930553e44ceSAndrew Stormont     if (ostr == NULL)
931553e44ceSAndrew Stormont         goto oom;
932553e44ceSAndrew Stormont     if (!ASN1_OCTET_STRING_set(ostr, (unsigned char *)data, data_len))
933553e44ceSAndrew Stormont         goto oom;
934553e44ceSAndrew Stormont 
935553e44ceSAndrew Stormont     p7 = PKCS7_new();
936553e44ceSAndrew Stormont     if (p7 == NULL)
937553e44ceSAndrew Stormont         goto oom;
938553e44ceSAndrew Stormont     p7->type = OBJ_dup(oid);
939553e44ceSAndrew Stormont     if (p7->type == NULL)
940553e44ceSAndrew Stormont         goto oom;
941553e44ceSAndrew Stormont 
942553e44ceSAndrew Stormont     if (OBJ_obj2nid(oid) == NID_pkcs7_data) {
943553e44ceSAndrew Stormont         /* Draft 9 uses id-pkcs7-data for signed data.  For this type OpenSSL
944553e44ceSAndrew Stormont          * expects an octet string in d.data. */
945553e44ceSAndrew Stormont         p7->d.data = ostr;
946553e44ceSAndrew Stormont     } else {
947553e44ceSAndrew Stormont         p7->d.other = ASN1_TYPE_new();
948553e44ceSAndrew Stormont         if (p7->d.other == NULL)
949553e44ceSAndrew Stormont             goto oom;
950553e44ceSAndrew Stormont         p7->d.other->type = V_ASN1_OCTET_STRING;
951553e44ceSAndrew Stormont         p7->d.other->value.octet_string = ostr;
952553e44ceSAndrew Stormont     }
953553e44ceSAndrew Stormont 
954553e44ceSAndrew Stormont     *p7_out = p7;
955553e44ceSAndrew Stormont     return 0;
956553e44ceSAndrew Stormont 
957553e44ceSAndrew Stormont oom:
958553e44ceSAndrew Stormont     if (ostr != NULL)
959553e44ceSAndrew Stormont         ASN1_OCTET_STRING_free(ostr);
960553e44ceSAndrew Stormont     if (p7 != NULL)
961553e44ceSAndrew Stormont         PKCS7_free(p7);
962553e44ceSAndrew Stormont     return ENOMEM;
963553e44ceSAndrew Stormont }
964553e44ceSAndrew Stormont 
965159d09a2SMark Phalan /* ARGSUSED */
966159d09a2SMark Phalan krb5_error_code
cms_signeddata_create(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,int cms_msg_type,int include_certchain,unsigned char * data,unsigned int data_len,unsigned char ** signed_data,unsigned int * signed_data_len)967159d09a2SMark Phalan cms_signeddata_create(krb5_context context,
968159d09a2SMark Phalan 		      pkinit_plg_crypto_context plg_cryptoctx,
969159d09a2SMark Phalan 		      pkinit_req_crypto_context req_cryptoctx,
970159d09a2SMark Phalan 		      pkinit_identity_crypto_context id_cryptoctx,
971159d09a2SMark Phalan 		      int cms_msg_type,
972159d09a2SMark Phalan 		      int include_certchain,
973159d09a2SMark Phalan 		      unsigned char *data,
974159d09a2SMark Phalan 		      unsigned int data_len,
975159d09a2SMark Phalan 		      unsigned char **signed_data,
976159d09a2SMark Phalan 		      unsigned int *signed_data_len)
977159d09a2SMark Phalan {
978159d09a2SMark Phalan     /* Solaris Kerberos */
979159d09a2SMark Phalan     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
980159d09a2SMark Phalan     PKCS7  *p7 = NULL, *inner_p7 = NULL;
981159d09a2SMark Phalan     PKCS7_SIGNED *p7s = NULL;
982159d09a2SMark Phalan     PKCS7_SIGNER_INFO *p7si = NULL;
983159d09a2SMark Phalan     unsigned char *p;
984159d09a2SMark Phalan     STACK_OF(X509) * cert_stack = NULL;
985159d09a2SMark Phalan     ASN1_OCTET_STRING *digest_attr = NULL;
986300fdee2SAndy Fiddaman     EVP_MD_CTX *ctx = NULL, *ctx2 = NULL;
987159d09a2SMark Phalan     const EVP_MD *md_tmp = NULL;
988159d09a2SMark Phalan     unsigned char md_data[EVP_MAX_MD_SIZE], md_data2[EVP_MAX_MD_SIZE];
989159d09a2SMark Phalan     unsigned char *digestInfo_buf = NULL, *abuf = NULL;
990159d09a2SMark Phalan     unsigned int md_len, md_len2, alen, digestInfo_len;
991159d09a2SMark Phalan     STACK_OF(X509_ATTRIBUTE) * sk;
992159d09a2SMark Phalan     unsigned char *sig = NULL;
993159d09a2SMark Phalan     unsigned int sig_len = 0;
994159d09a2SMark Phalan     X509_ALGOR *alg = NULL;
995159d09a2SMark Phalan     ASN1_OCTET_STRING *digest = NULL;
996159d09a2SMark Phalan     unsigned int alg_len = 0, digest_len = 0;
997159d09a2SMark Phalan     unsigned char *y = NULL, *alg_buf = NULL, *digest_buf = NULL;
998159d09a2SMark Phalan     X509 *cert = NULL;
999553e44ceSAndrew Stormont     ASN1_OBJECT *oid = NULL, *oid_copy;
1000159d09a2SMark Phalan 
1001159d09a2SMark Phalan     /* Solaris Kerberos */
1002159d09a2SMark Phalan     if (signed_data == NULL)
1003159d09a2SMark Phalan 	return EINVAL;
1004159d09a2SMark Phalan 
1005159d09a2SMark Phalan     if (signed_data_len == NULL)
1006159d09a2SMark Phalan 	return EINVAL;
1007159d09a2SMark Phalan 
1008159d09a2SMark Phalan     /* start creating PKCS7 data */
1009159d09a2SMark Phalan     if ((p7 = PKCS7_new()) == NULL)
1010159d09a2SMark Phalan 	goto cleanup;
1011159d09a2SMark Phalan     p7->type = OBJ_nid2obj(NID_pkcs7_signed);
1012159d09a2SMark Phalan 
1013159d09a2SMark Phalan     if ((p7s = PKCS7_SIGNED_new()) == NULL)
1014159d09a2SMark Phalan 	goto cleanup;
1015159d09a2SMark Phalan     p7->d.sign = p7s;
1016159d09a2SMark Phalan     if (!ASN1_INTEGER_set(p7s->version, 3))
1017159d09a2SMark Phalan 	goto cleanup;
1018159d09a2SMark Phalan 
1019159d09a2SMark Phalan     /* create a cert chain that has at least the signer's certificate */
1020159d09a2SMark Phalan     if ((cert_stack = sk_X509_new_null()) == NULL)
1021159d09a2SMark Phalan 	goto cleanup;
1022159d09a2SMark Phalan 
1023159d09a2SMark Phalan     cert = sk_X509_value(id_cryptoctx->my_certs, id_cryptoctx->cert_index);
1024159d09a2SMark Phalan     if (!include_certchain) {
1025159d09a2SMark Phalan 	pkiDebug("only including signer's certificate\n");
1026159d09a2SMark Phalan 	sk_X509_push(cert_stack, X509_dup(cert));
1027159d09a2SMark Phalan     } else {
1028159d09a2SMark Phalan 	/* create a cert chain */
1029159d09a2SMark Phalan 	X509_STORE *certstore = NULL;
1030300fdee2SAndy Fiddaman 	X509_STORE_CTX *certctx;
1031159d09a2SMark Phalan 	STACK_OF(X509) *certstack = NULL;
1032159d09a2SMark Phalan 	char buf[DN_BUF_LEN];
1033159d09a2SMark Phalan 	int i = 0, size = 0;
1034159d09a2SMark Phalan 
1035159d09a2SMark Phalan 	if ((certstore = X509_STORE_new()) == NULL)
1036159d09a2SMark Phalan 	    goto cleanup;
1037300fdee2SAndy Fiddaman 	if ((certctx = X509_STORE_CTX_new()) == NULL)
1038300fdee2SAndy Fiddaman 	    goto cleanup;
1039159d09a2SMark Phalan 	pkiDebug("building certificate chain\n");
1040300fdee2SAndy Fiddaman 	X509_STORE_set_verify_cb(certstore, openssl_callback);
1041300fdee2SAndy Fiddaman 	X509_STORE_CTX_init(certctx, certstore, cert,
1042159d09a2SMark Phalan 			    id_cryptoctx->intermediateCAs);
1043300fdee2SAndy Fiddaman 	X509_STORE_CTX_set0_trusted_stack(certctx, id_cryptoctx->trustedCAs);
10447801e5e8SMark Phalan 	/* Solaris Kerberos */
1045300fdee2SAndy Fiddaman 	if (X509_verify_cert(certctx) <= 0) {
1046300fdee2SAndy Fiddaman 	    pkiDebug("failed to create a certificate chain: %s\n",
1047300fdee2SAndy Fiddaman 	    X509_verify_cert_error_string(X509_STORE_CTX_get_error(certctx)));
1048300fdee2SAndy Fiddaman 	    if (!sk_X509_num(id_cryptoctx->trustedCAs))
1049159d09a2SMark Phalan 		pkiDebug("No trusted CAs found. Check your X509_anchors\n");
1050159d09a2SMark Phalan 	    goto cleanup;
1051159d09a2SMark Phalan 	}
1052300fdee2SAndy Fiddaman 	certstack = X509_STORE_CTX_get1_chain(certctx);
1053159d09a2SMark Phalan 	size = sk_X509_num(certstack);
1054159d09a2SMark Phalan 	pkiDebug("size of certificate chain = %d\n", size);
1055159d09a2SMark Phalan 	for(i = 0; i < size - 1; i++) {
1056159d09a2SMark Phalan 	    X509 *x = sk_X509_value(certstack, i);
1057159d09a2SMark Phalan 	    X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
1058159d09a2SMark Phalan 	    pkiDebug("cert #%d: %s\n", i, buf);
1059159d09a2SMark Phalan 	    sk_X509_push(cert_stack, X509_dup(x));
1060159d09a2SMark Phalan 	}
1061300fdee2SAndy Fiddaman 	X509_STORE_CTX_free(certctx);
1062159d09a2SMark Phalan 	X509_STORE_free(certstore);
1063159d09a2SMark Phalan 	sk_X509_pop_free(certstack, X509_free);
1064159d09a2SMark Phalan     }
1065159d09a2SMark Phalan     p7s->cert = cert_stack;
1066159d09a2SMark Phalan 
1067159d09a2SMark Phalan     /* fill-in PKCS7_SIGNER_INFO */
1068159d09a2SMark Phalan     if ((p7si = PKCS7_SIGNER_INFO_new()) == NULL)
1069159d09a2SMark Phalan 	goto cleanup;
1070159d09a2SMark Phalan     if (!ASN1_INTEGER_set(p7si->version, 1))
1071159d09a2SMark Phalan 	goto cleanup;
1072159d09a2SMark Phalan     if (!X509_NAME_set(&p7si->issuer_and_serial->issuer,
1073159d09a2SMark Phalan 		       X509_get_issuer_name(cert)))
1074159d09a2SMark Phalan 	goto cleanup;
1075159d09a2SMark Phalan     /* because ASN1_INTEGER_set is used to set a 'long' we will do
1076159d09a2SMark Phalan      * things the ugly way. */
1077300fdee2SAndy Fiddaman     ASN1_INTEGER_free(p7si->issuer_and_serial->serial);
1078159d09a2SMark Phalan     if (!(p7si->issuer_and_serial->serial =
1079300fdee2SAndy Fiddaman 	  ASN1_INTEGER_dup(X509_get_serialNumber(cert))))
1080159d09a2SMark Phalan 	goto cleanup;
1081159d09a2SMark Phalan 
1082159d09a2SMark Phalan     /* will not fill-out EVP_PKEY because it's on the smartcard */
1083159d09a2SMark Phalan 
1084159d09a2SMark Phalan     /* Set digest algs */
1085159d09a2SMark Phalan     p7si->digest_alg->algorithm = OBJ_nid2obj(NID_sha1);
1086159d09a2SMark Phalan 
1087159d09a2SMark Phalan     if (p7si->digest_alg->parameter != NULL)
1088159d09a2SMark Phalan 	ASN1_TYPE_free(p7si->digest_alg->parameter);
1089159d09a2SMark Phalan     if ((p7si->digest_alg->parameter = ASN1_TYPE_new()) == NULL)
1090159d09a2SMark Phalan 	goto cleanup;
1091159d09a2SMark Phalan     p7si->digest_alg->parameter->type = V_ASN1_NULL;
1092159d09a2SMark Phalan 
1093159d09a2SMark Phalan     /* Set sig algs */
1094159d09a2SMark Phalan     if (p7si->digest_enc_alg->parameter != NULL)
1095159d09a2SMark Phalan 	ASN1_TYPE_free(p7si->digest_enc_alg->parameter);
1096159d09a2SMark Phalan     p7si->digest_enc_alg->algorithm = OBJ_nid2obj(NID_sha1WithRSAEncryption);
1097159d09a2SMark Phalan     if (!(p7si->digest_enc_alg->parameter = ASN1_TYPE_new()))
1098159d09a2SMark Phalan 	goto cleanup;
1099159d09a2SMark Phalan     p7si->digest_enc_alg->parameter->type = V_ASN1_NULL;
1100159d09a2SMark Phalan 
1101159d09a2SMark Phalan     /* pick the correct oid for the eContentInfo */
1102159d09a2SMark Phalan     oid = pkinit_pkcs7type2oid(plg_cryptoctx, cms_msg_type);
1103159d09a2SMark Phalan     if (oid == NULL)
1104159d09a2SMark Phalan 	goto cleanup;
1105159d09a2SMark Phalan 
1106159d09a2SMark Phalan     if (cms_msg_type == CMS_SIGN_DRAFT9) {
1107159d09a2SMark Phalan 	/* don't include signed attributes for pa-type 15 request */
1108159d09a2SMark Phalan 	abuf = data;
1109159d09a2SMark Phalan 	alen = data_len;
1110159d09a2SMark Phalan     } else {
1111159d09a2SMark Phalan 	/* add signed attributes */
1112159d09a2SMark Phalan 	/* compute sha1 digest over the EncapsulatedContentInfo */
1113300fdee2SAndy Fiddaman 	ctx = EVP_MD_CTX_new();
1114300fdee2SAndy Fiddaman 	if (ctx == NULL)
1115300fdee2SAndy Fiddaman 	    goto cleanup2;
1116300fdee2SAndy Fiddaman 	EVP_MD_CTX_init(ctx);
1117300fdee2SAndy Fiddaman 	EVP_DigestInit_ex(ctx, EVP_sha1(), NULL);
1118300fdee2SAndy Fiddaman 	EVP_DigestUpdate(ctx, data, data_len);
1119300fdee2SAndy Fiddaman 	md_tmp = EVP_MD_CTX_md(ctx);
1120300fdee2SAndy Fiddaman 	EVP_DigestFinal_ex(ctx, md_data, &md_len);
1121300fdee2SAndy Fiddaman 	EVP_MD_CTX_free(ctx);
1122300fdee2SAndy Fiddaman 	ctx = NULL;
1123159d09a2SMark Phalan 
1124159d09a2SMark Phalan 	/* create a message digest attr */
1125159d09a2SMark Phalan 	digest_attr = ASN1_OCTET_STRING_new();
1126159d09a2SMark Phalan 	ASN1_OCTET_STRING_set(digest_attr, md_data, (int)md_len);
1127159d09a2SMark Phalan 	PKCS7_add_signed_attribute(p7si, NID_pkcs9_messageDigest,
1128159d09a2SMark Phalan 				   V_ASN1_OCTET_STRING, (char *) digest_attr);
1129159d09a2SMark Phalan 
1130159d09a2SMark Phalan 	/* create a content-type attr */
1131553e44ceSAndrew Stormont 	oid_copy = OBJ_dup(oid);
1132553e44ceSAndrew Stormont 	if (oid_copy == NULL)
1133553e44ceSAndrew Stormont 		goto cleanup2;
1134300fdee2SAndy Fiddaman 	PKCS7_add_signed_attribute(p7si, NID_pkcs9_contentType,
1135553e44ceSAndrew Stormont 				   V_ASN1_OBJECT, oid_copy);
1136159d09a2SMark Phalan 
1137159d09a2SMark Phalan 	/* create the signature over signed attributes. get DER encoded value */
1138159d09a2SMark Phalan 	/* This is the place where smartcard signature needs to be calculated */
1139159d09a2SMark Phalan 	sk = p7si->auth_attr;
1140159d09a2SMark Phalan 	alen = ASN1_item_i2d((ASN1_VALUE *) sk, &abuf,
1141159d09a2SMark Phalan 			     ASN1_ITEM_rptr(PKCS7_ATTR_SIGN));
1142159d09a2SMark Phalan 	if (abuf == NULL)
1143159d09a2SMark Phalan 	    goto cleanup2;
1144159d09a2SMark Phalan     }
1145159d09a2SMark Phalan 
1146159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
1147159d09a2SMark Phalan     /* Some tokens can only do RSAEncryption without sha1 hash */
1148159d09a2SMark Phalan     /* to compute sha1WithRSAEncryption, encode the algorithm ID for the hash
1149159d09a2SMark Phalan      * function and the hash value into an ASN.1 value of type DigestInfo
1150159d09a2SMark Phalan      * DigestInfo::=SEQUENCE {
1151159d09a2SMark Phalan      *	digestAlgorithm  AlgorithmIdentifier,
1152159d09a2SMark Phalan      *	digest OCTET STRING }
1153159d09a2SMark Phalan      */
1154300fdee2SAndy Fiddaman     if (id_cryptoctx->pkcs11_method == 1 &&
1155159d09a2SMark Phalan 	    id_cryptoctx->mech == CKM_RSA_PKCS) {
1156159d09a2SMark Phalan 	pkiDebug("mech = CKM_RSA_PKCS\n");
1157300fdee2SAndy Fiddaman 	ctx2 = EVP_MD_CTX_new();
1158300fdee2SAndy Fiddaman 	if (ctx2 == NULL)
1159300fdee2SAndy Fiddaman 	    goto cleanup2;
1160300fdee2SAndy Fiddaman 	EVP_MD_CTX_init(ctx2);
1161159d09a2SMark Phalan 	/* if this is not draft9 request, include digest signed attribute */
1162300fdee2SAndy Fiddaman 	if (cms_msg_type != CMS_SIGN_DRAFT9)
1163300fdee2SAndy Fiddaman 	    EVP_DigestInit_ex(ctx2, md_tmp, NULL);
1164159d09a2SMark Phalan 	else
1165300fdee2SAndy Fiddaman 	    EVP_DigestInit_ex(ctx2, EVP_sha1(), NULL);
1166300fdee2SAndy Fiddaman 	EVP_DigestUpdate(ctx2, abuf, alen);
1167300fdee2SAndy Fiddaman 	EVP_DigestFinal_ex(ctx2, md_data2, &md_len2);
1168300fdee2SAndy Fiddaman 	EVP_MD_CTX_free(ctx2);
1169300fdee2SAndy Fiddaman 	ctx2 = NULL;
1170159d09a2SMark Phalan 
1171159d09a2SMark Phalan 	alg = X509_ALGOR_new();
1172159d09a2SMark Phalan 	if (alg == NULL)
1173159d09a2SMark Phalan 	    goto cleanup2;
1174159d09a2SMark Phalan 	alg->algorithm = OBJ_nid2obj(NID_sha1);
1175159d09a2SMark Phalan 	alg->parameter = NULL;
1176159d09a2SMark Phalan 	alg_len = i2d_X509_ALGOR(alg, NULL);
1177159d09a2SMark Phalan 	alg_buf = (unsigned char *)malloc(alg_len);
1178159d09a2SMark Phalan 	if (alg_buf == NULL)
1179159d09a2SMark Phalan 	    goto cleanup2;
1180159d09a2SMark Phalan 
1181159d09a2SMark Phalan 	digest = ASN1_OCTET_STRING_new();
1182159d09a2SMark Phalan 	if (digest == NULL)
1183159d09a2SMark Phalan 	    goto cleanup2;
1184159d09a2SMark Phalan 	ASN1_OCTET_STRING_set(digest, md_data2, (int)md_len2);
1185159d09a2SMark Phalan 	digest_len = i2d_ASN1_OCTET_STRING(digest, NULL);
1186159d09a2SMark Phalan 	digest_buf = (unsigned char *)malloc(digest_len);
1187159d09a2SMark Phalan 	if (digest_buf == NULL)
1188159d09a2SMark Phalan 	    goto cleanup2;
1189159d09a2SMark Phalan 
1190159d09a2SMark Phalan 	digestInfo_len = ASN1_object_size(1, (int)(alg_len + digest_len),
1191159d09a2SMark Phalan 					  V_ASN1_SEQUENCE);
1192159d09a2SMark Phalan 	y = digestInfo_buf = (unsigned char *)malloc(digestInfo_len);
1193159d09a2SMark Phalan 	if (digestInfo_buf == NULL)
1194159d09a2SMark Phalan 	    goto cleanup2;
1195159d09a2SMark Phalan 	ASN1_put_object(&y, 1, (int)(alg_len + digest_len), V_ASN1_SEQUENCE,
1196159d09a2SMark Phalan 			V_ASN1_UNIVERSAL);
1197159d09a2SMark Phalan 	i2d_X509_ALGOR(alg, &y);
1198159d09a2SMark Phalan 	i2d_ASN1_OCTET_STRING(digest, &y);
1199159d09a2SMark Phalan #ifdef DEBUG_SIG
1200159d09a2SMark Phalan 	pkiDebug("signing buffer\n");
1201159d09a2SMark Phalan 	print_buffer(digestInfo_buf, digestInfo_len);
1202159d09a2SMark Phalan 	print_buffer_bin(digestInfo_buf, digestInfo_len, "/tmp/pkcs7_tosign");
1203159d09a2SMark Phalan #endif
1204159d09a2SMark Phalan 	retval = pkinit_sign_data(context, id_cryptoctx, digestInfo_buf,
1205159d09a2SMark Phalan 				  digestInfo_len, &sig, &sig_len);
1206159d09a2SMark Phalan     } else
1207159d09a2SMark Phalan #endif
1208159d09a2SMark Phalan     {
1209159d09a2SMark Phalan 	pkiDebug("mech = %s\n",
1210159d09a2SMark Phalan 	    id_cryptoctx->pkcs11_method == 1 ? "CKM_SHA1_RSA_PKCS" : "FS");
1211159d09a2SMark Phalan 	retval = pkinit_sign_data(context, id_cryptoctx, abuf, alen,
1212159d09a2SMark Phalan 				  &sig, &sig_len);
1213159d09a2SMark Phalan     }
1214159d09a2SMark Phalan #ifdef DEBUG_SIG
1215159d09a2SMark Phalan     print_buffer(sig, sig_len);
1216159d09a2SMark Phalan #endif
1217300fdee2SAndy Fiddaman     if (cms_msg_type != CMS_SIGN_DRAFT9)
1218159d09a2SMark Phalan 	free(abuf);
1219159d09a2SMark Phalan     if (retval)
1220159d09a2SMark Phalan 	goto cleanup2;
1221159d09a2SMark Phalan 
1222159d09a2SMark Phalan     /* Add signature */
1223159d09a2SMark Phalan     if (!ASN1_STRING_set(p7si->enc_digest, (unsigned char *) sig,
1224159d09a2SMark Phalan 			 (int)sig_len)) {
1225159d09a2SMark Phalan 	unsigned long err = ERR_peek_error();
1226159d09a2SMark Phalan 	retval = KRB5KDC_ERR_PREAUTH_FAILED;
1227159d09a2SMark Phalan 	krb5_set_error_message(context, retval, "%s\n",
1228159d09a2SMark Phalan 			       ERR_error_string(err, NULL));
1229159d09a2SMark Phalan 	pkiDebug("failed to add a signed digest attribute\n");
1230159d09a2SMark Phalan 	goto cleanup2;
1231159d09a2SMark Phalan     }
1232159d09a2SMark Phalan     /* adder signer_info to pkcs7 signed */
1233159d09a2SMark Phalan     if (!PKCS7_add_signer(p7, p7si))
1234159d09a2SMark Phalan 	goto cleanup2;
1235159d09a2SMark Phalan 
1236159d09a2SMark Phalan     /* start on adding data to the pkcs7 signed */
1237553e44ceSAndrew Stormont     retval = create_contentinfo(context, oid, data, data_len, &inner_p7);
1238159d09a2SMark Phalan     if (p7s->contents != NULL)
1239159d09a2SMark Phalan 	PKCS7_free(p7s->contents);
1240159d09a2SMark Phalan     p7s->contents = inner_p7;
1241159d09a2SMark Phalan 
1242159d09a2SMark Phalan     *signed_data_len = i2d_PKCS7(p7, NULL);
1243159d09a2SMark Phalan     if (!(*signed_data_len)) {
1244159d09a2SMark Phalan 	unsigned long err = ERR_peek_error();
1245159d09a2SMark Phalan 	retval = KRB5KDC_ERR_PREAUTH_FAILED;
1246159d09a2SMark Phalan 	krb5_set_error_message(context, retval, "%s\n",
1247159d09a2SMark Phalan 			       ERR_error_string(err, NULL));
1248159d09a2SMark Phalan 	pkiDebug("failed to der encode pkcs7\n");
1249159d09a2SMark Phalan 	goto cleanup2;
1250159d09a2SMark Phalan     }
1251159d09a2SMark Phalan     if ((p = *signed_data =
1252159d09a2SMark Phalan 	 (unsigned char *) malloc((size_t)*signed_data_len)) == NULL)
1253159d09a2SMark Phalan 	goto cleanup2;
1254159d09a2SMark Phalan 
1255159d09a2SMark Phalan     /* DER encode PKCS7 data */
1256159d09a2SMark Phalan     retval = i2d_PKCS7(p7, &p);
1257159d09a2SMark Phalan     if (!retval) {
1258159d09a2SMark Phalan 	unsigned long err = ERR_peek_error();
1259159d09a2SMark Phalan 	retval = KRB5KDC_ERR_PREAUTH_FAILED;
1260159d09a2SMark Phalan 	krb5_set_error_message(context, retval, "%s\n",
1261159d09a2SMark Phalan 			       ERR_error_string(err, NULL));
1262159d09a2SMark Phalan 	pkiDebug("failed to der encode pkcs7\n");
1263159d09a2SMark Phalan 	goto cleanup2;
1264159d09a2SMark Phalan     }
1265159d09a2SMark Phalan     retval = 0;
1266159d09a2SMark Phalan 
1267159d09a2SMark Phalan #ifdef DEBUG_ASN1
1268159d09a2SMark Phalan     if (cms_msg_type == CMS_SIGN_CLIENT) {
1269159d09a2SMark Phalan 	print_buffer_bin(*signed_data, *signed_data_len,
1270159d09a2SMark Phalan 			 "/tmp/client_pkcs7_signeddata");
1271159d09a2SMark Phalan     } else {
1272159d09a2SMark Phalan 	if (cms_msg_type == CMS_SIGN_SERVER) {
1273159d09a2SMark Phalan 	    print_buffer_bin(*signed_data, *signed_data_len,
1274159d09a2SMark Phalan 			     "/tmp/kdc_pkcs7_signeddata");
1275159d09a2SMark Phalan 	} else {
1276159d09a2SMark Phalan 	    print_buffer_bin(*signed_data, *signed_data_len,
1277159d09a2SMark Phalan 			     "/tmp/draft9_pkcs7_signeddata");
1278159d09a2SMark Phalan 	}
1279159d09a2SMark Phalan     }
1280159d09a2SMark Phalan #endif
1281159d09a2SMark Phalan 
1282159d09a2SMark Phalan   cleanup2:
1283300fdee2SAndy Fiddaman     if (cms_msg_type != CMS_SIGN_DRAFT9)
1284300fdee2SAndy Fiddaman 	if (ctx != NULL)
1285300fdee2SAndy Fiddaman 		EVP_MD_CTX_free(ctx);
1286159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
1287300fdee2SAndy Fiddaman     if (id_cryptoctx->pkcs11_method == 1 &&
1288159d09a2SMark Phalan 	    id_cryptoctx->mech == CKM_RSA_PKCS) {
1289300fdee2SAndy Fiddaman 	if (ctx2 != NULL)
1290300fdee2SAndy Fiddaman 		EVP_MD_CTX_free(ctx2);
1291159d09a2SMark Phalan 	if (digest_buf != NULL)
1292159d09a2SMark Phalan 	    free(digest_buf);
1293159d09a2SMark Phalan 	if (digestInfo_buf != NULL)
1294159d09a2SMark Phalan 	    free(digestInfo_buf);
1295159d09a2SMark Phalan 	if (alg_buf != NULL)
1296159d09a2SMark Phalan 	    free(alg_buf);
1297159d09a2SMark Phalan 	if (digest != NULL)
1298159d09a2SMark Phalan 	    ASN1_OCTET_STRING_free(digest);
1299159d09a2SMark Phalan     }
1300159d09a2SMark Phalan #endif
1301159d09a2SMark Phalan     if (alg != NULL)
1302159d09a2SMark Phalan 	X509_ALGOR_free(alg);
1303159d09a2SMark Phalan   cleanup:
1304300fdee2SAndy Fiddaman     if (p7 != NULL)
1305159d09a2SMark Phalan 	PKCS7_free(p7);
1306159d09a2SMark Phalan     if (sig != NULL)
1307159d09a2SMark Phalan 	free(sig);
1308159d09a2SMark Phalan 
1309159d09a2SMark Phalan     return retval;
1310159d09a2SMark Phalan }
1311159d09a2SMark Phalan 
1312159d09a2SMark Phalan krb5_error_code
cms_signeddata_verify(krb5_context context,pkinit_plg_crypto_context plgctx,pkinit_req_crypto_context reqctx,pkinit_identity_crypto_context idctx,int cms_msg_type,int require_crl_checking,unsigned char * signed_data,unsigned int signed_data_len,unsigned char ** data,unsigned int * data_len,unsigned char ** authz_data,unsigned int * authz_data_len)1313159d09a2SMark Phalan cms_signeddata_verify(krb5_context context,
1314159d09a2SMark Phalan 		      pkinit_plg_crypto_context plgctx,
1315159d09a2SMark Phalan 		      pkinit_req_crypto_context reqctx,
1316159d09a2SMark Phalan 		      pkinit_identity_crypto_context idctx,
1317159d09a2SMark Phalan 		      int cms_msg_type,
1318159d09a2SMark Phalan 		      int require_crl_checking,
1319159d09a2SMark Phalan 		      unsigned char *signed_data,
1320159d09a2SMark Phalan 		      unsigned int signed_data_len,
1321159d09a2SMark Phalan 		      unsigned char **data,
1322159d09a2SMark Phalan 		      unsigned int *data_len,
1323159d09a2SMark Phalan 		      unsigned char **authz_data,
1324159d09a2SMark Phalan 		      unsigned int *authz_data_len)
1325159d09a2SMark Phalan {
1326159d09a2SMark Phalan     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
1327159d09a2SMark Phalan     PKCS7 *p7 = NULL;
1328159d09a2SMark Phalan     BIO *out = NULL;
1329159d09a2SMark Phalan     int flags = PKCS7_NOVERIFY, i = 0;
1330159d09a2SMark Phalan     unsigned int vflags = 0, size = 0;
1331159d09a2SMark Phalan     const unsigned char *p = signed_data;
1332159d09a2SMark Phalan     STACK_OF(PKCS7_SIGNER_INFO) *si_sk = NULL;
1333159d09a2SMark Phalan     PKCS7_SIGNER_INFO *si = NULL;
1334159d09a2SMark Phalan     X509 *x = NULL;
1335159d09a2SMark Phalan     X509_STORE *store = NULL;
1336300fdee2SAndy Fiddaman     X509_STORE_CTX *cert_ctx;
1337159d09a2SMark Phalan     STACK_OF(X509) *intermediateCAs = NULL;
1338159d09a2SMark Phalan     STACK_OF(X509_CRL) *revoked = NULL;
1339159d09a2SMark Phalan     STACK_OF(X509) *verified_chain = NULL;
1340159d09a2SMark Phalan     ASN1_OBJECT *oid = NULL;
1341159d09a2SMark Phalan     krb5_external_principal_identifier **krb5_verified_chain = NULL;
1342159d09a2SMark Phalan     krb5_data *authz = NULL;
1343159d09a2SMark Phalan     char buf[DN_BUF_LEN];
1344159d09a2SMark Phalan 
1345159d09a2SMark Phalan #ifdef DEBUG_ASN1
1346159d09a2SMark Phalan     print_buffer_bin(signed_data, signed_data_len,
1347159d09a2SMark Phalan 		     "/tmp/client_received_pkcs7_signeddata");
1348159d09a2SMark Phalan #endif
1349159d09a2SMark Phalan 
1350159d09a2SMark Phalan     oid = pkinit_pkcs7type2oid(plgctx, cms_msg_type);
1351159d09a2SMark Phalan     if (oid == NULL)
1352159d09a2SMark Phalan 	goto cleanup;
1353159d09a2SMark Phalan 
1354159d09a2SMark Phalan     /* decode received PKCS7 message */
1355159d09a2SMark Phalan     if ((p7 = d2i_PKCS7(NULL, &p, (int)signed_data_len)) == NULL) {
1356159d09a2SMark Phalan 	unsigned long err = ERR_peek_error();
1357159d09a2SMark Phalan 	krb5_set_error_message(context, retval, "%s\n",
1358159d09a2SMark Phalan 			       ERR_error_string(err, NULL));
1359159d09a2SMark Phalan 	pkiDebug("%s: failed to decode message: %s\n",
1360159d09a2SMark Phalan 		 __FUNCTION__, ERR_error_string(err, NULL));
1361159d09a2SMark Phalan 	goto cleanup;
1362159d09a2SMark Phalan     }
1363159d09a2SMark Phalan 
1364159d09a2SMark Phalan     /* verify that the received message is PKCS7 SignedData message */
1365159d09a2SMark Phalan     if (OBJ_obj2nid(p7->type) != NID_pkcs7_signed) {
1366159d09a2SMark Phalan 	pkiDebug("Expected id-signedData PKCS7 msg (received type = %d)\n",
1367159d09a2SMark Phalan 		 OBJ_obj2nid(p7->type));
1368159d09a2SMark Phalan 	krb5_set_error_message(context, retval, "wrong oid\n");
1369159d09a2SMark Phalan 	goto cleanup;
1370159d09a2SMark Phalan     }
1371159d09a2SMark Phalan 
1372159d09a2SMark Phalan     /* setup to verify X509 certificate used to sign PKCS7 message */
1373159d09a2SMark Phalan     if (!(store = X509_STORE_new()))
1374159d09a2SMark Phalan 	goto cleanup;
1375159d09a2SMark Phalan 
1376159d09a2SMark Phalan     /* check if we are inforcing CRL checking */
1377159d09a2SMark Phalan     vflags = X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL;
1378159d09a2SMark Phalan     if (require_crl_checking)
1379300fdee2SAndy Fiddaman 	X509_STORE_set_verify_cb(store, openssl_callback);
1380159d09a2SMark Phalan     else
1381300fdee2SAndy Fiddaman 	X509_STORE_set_verify_cb(store, openssl_callback_ignore_crls);
1382159d09a2SMark Phalan     X509_STORE_set_flags(store, vflags);
1383159d09a2SMark Phalan 
1384159d09a2SMark Phalan     /* get the signer's information from the PKCS7 message */
1385159d09a2SMark Phalan     if ((si_sk = PKCS7_get_signer_info(p7)) == NULL)
1386159d09a2SMark Phalan 	goto cleanup;
1387159d09a2SMark Phalan     if ((si = sk_PKCS7_SIGNER_INFO_value(si_sk, 0)) == NULL)
1388159d09a2SMark Phalan 	goto cleanup;
1389159d09a2SMark Phalan     if ((x = PKCS7_cert_from_signer_info(p7, si)) == NULL)
1390159d09a2SMark Phalan 	goto cleanup;
1391159d09a2SMark Phalan 
1392159d09a2SMark Phalan     /* create available CRL information (get local CRLs and include CRLs
1393159d09a2SMark Phalan      * received in the PKCS7 message
1394159d09a2SMark Phalan      */
1395159d09a2SMark Phalan     if (idctx->revoked == NULL)
1396159d09a2SMark Phalan 	revoked = p7->d.sign->crl;
1397159d09a2SMark Phalan     else if (p7->d.sign->crl == NULL)
1398159d09a2SMark Phalan 	revoked = idctx->revoked;
1399159d09a2SMark Phalan     else {
1400159d09a2SMark Phalan 	size = sk_X509_CRL_num(idctx->revoked);
1401159d09a2SMark Phalan 	revoked = sk_X509_CRL_new_null();
1402159d09a2SMark Phalan 	for (i = 0; i < size; i++)
1403159d09a2SMark Phalan 	    sk_X509_CRL_push(revoked, sk_X509_CRL_value(idctx->revoked, i));
140470f9559bSTheo Schlossnagle 	size = sk_X509_CRL_num(p7->d.sign->crl);
1405159d09a2SMark Phalan 	for (i = 0; i < size; i++)
1406159d09a2SMark Phalan 	    sk_X509_CRL_push(revoked, sk_X509_CRL_value(p7->d.sign->crl, i));
1407159d09a2SMark Phalan     }
1408159d09a2SMark Phalan 
1409159d09a2SMark Phalan     /* create available intermediate CAs chains (get local intermediateCAs and
1410159d09a2SMark Phalan      * include the CA chain received in the PKCS7 message
1411159d09a2SMark Phalan      */
1412159d09a2SMark Phalan     if (idctx->intermediateCAs == NULL)
1413159d09a2SMark Phalan 	intermediateCAs = p7->d.sign->cert;
1414159d09a2SMark Phalan     else if (p7->d.sign->cert == NULL)
1415159d09a2SMark Phalan 	intermediateCAs = idctx->intermediateCAs;
1416159d09a2SMark Phalan     else {
1417159d09a2SMark Phalan 	size = sk_X509_num(idctx->intermediateCAs);
1418159d09a2SMark Phalan 	intermediateCAs = sk_X509_new_null();
1419159d09a2SMark Phalan 	for (i = 0; i < size; i++) {
1420159d09a2SMark Phalan 	    sk_X509_push(intermediateCAs,
1421159d09a2SMark Phalan 		sk_X509_value(idctx->intermediateCAs, i));
1422159d09a2SMark Phalan 	}
1423159d09a2SMark Phalan 	size = sk_X509_num(p7->d.sign->cert);
1424159d09a2SMark Phalan 	for (i = 0; i < size; i++) {
1425159d09a2SMark Phalan 	    sk_X509_push(intermediateCAs, sk_X509_value(p7->d.sign->cert, i));
1426159d09a2SMark Phalan 	}
1427159d09a2SMark Phalan     }
1428159d09a2SMark Phalan 
1429159d09a2SMark Phalan     /* initialize x509 context with the received certificate and
1430159d09a2SMark Phalan      * trusted and intermediate CA chains and CRLs
1431159d09a2SMark Phalan      */
1432300fdee2SAndy Fiddaman     if ((cert_ctx = X509_STORE_CTX_new()) == NULL)
1433300fdee2SAndy Fiddaman 	goto cleanup;
1434300fdee2SAndy Fiddaman     if (!X509_STORE_CTX_init(cert_ctx, store, x, intermediateCAs))
1435159d09a2SMark Phalan 	goto cleanup;
1436159d09a2SMark Phalan 
1437300fdee2SAndy Fiddaman     X509_STORE_CTX_set0_crls(cert_ctx, revoked);
1438159d09a2SMark Phalan 
1439159d09a2SMark Phalan     /* add trusted CAs certificates for cert verification */
1440159d09a2SMark Phalan     if (idctx->trustedCAs != NULL)
1441300fdee2SAndy Fiddaman 	X509_STORE_CTX_set0_trusted_stack(cert_ctx, idctx->trustedCAs);
1442159d09a2SMark Phalan     else {
1443159d09a2SMark Phalan 	pkiDebug("unable to find any trusted CAs\n");
1444159d09a2SMark Phalan 	goto cleanup;
1445159d09a2SMark Phalan     }
1446159d09a2SMark Phalan #ifdef DEBUG_CERTCHAIN
1447159d09a2SMark Phalan     if (intermediateCAs != NULL) {
1448159d09a2SMark Phalan 	size = sk_X509_num(intermediateCAs);
1449159d09a2SMark Phalan 	pkiDebug("untrusted cert chain of size %d\n", size);
1450159d09a2SMark Phalan 	for (i = 0; i < size; i++) {
1451159d09a2SMark Phalan 	    X509_NAME_oneline(X509_get_subject_name(
1452159d09a2SMark Phalan 		sk_X509_value(intermediateCAs, i)), buf, sizeof(buf));
1453159d09a2SMark Phalan 	    pkiDebug("cert #%d: %s\n", i, buf);
1454159d09a2SMark Phalan 	}
1455159d09a2SMark Phalan     }
1456159d09a2SMark Phalan     if (idctx->trustedCAs != NULL) {
1457159d09a2SMark Phalan 	size = sk_X509_num(idctx->trustedCAs);
1458159d09a2SMark Phalan 	pkiDebug("trusted cert chain of size %d\n", size);
1459159d09a2SMark Phalan 	for (i = 0; i < size; i++) {
1460159d09a2SMark Phalan 	    X509_NAME_oneline(X509_get_subject_name(
1461159d09a2SMark Phalan 		sk_X509_value(idctx->trustedCAs, i)), buf, sizeof(buf));
1462159d09a2SMark Phalan 	    pkiDebug("cert #%d: %s\n", i, buf);
1463159d09a2SMark Phalan 	}
1464159d09a2SMark Phalan     }
1465159d09a2SMark Phalan     if (revoked != NULL) {
1466159d09a2SMark Phalan 	size = sk_X509_CRL_num(revoked);
1467159d09a2SMark Phalan 	pkiDebug("CRL chain of size %d\n", size);
1468159d09a2SMark Phalan 	for (i = 0; i < size; i++) {
1469159d09a2SMark Phalan 	    X509_CRL *crl = sk_X509_CRL_value(revoked, i);
1470159d09a2SMark Phalan 	    X509_NAME_oneline(X509_CRL_get_issuer(crl), buf, sizeof(buf));
1471159d09a2SMark Phalan 	    pkiDebug("crls by CA #%d: %s\n", i , buf);
1472159d09a2SMark Phalan 	}
1473159d09a2SMark Phalan     }
1474159d09a2SMark Phalan #endif
1475159d09a2SMark Phalan 
1476300fdee2SAndy Fiddaman     i = X509_verify_cert(cert_ctx);
1477159d09a2SMark Phalan     if (i <= 0) {
1478300fdee2SAndy Fiddaman 	int j = X509_STORE_CTX_get_error(cert_ctx);
1479159d09a2SMark Phalan 
1480300fdee2SAndy Fiddaman 	reqctx->received_cert = X509_dup(
1481300fdee2SAndy Fiddaman 	    X509_STORE_CTX_get_current_cert(cert_ctx));
1482159d09a2SMark Phalan 	switch(j) {
1483159d09a2SMark Phalan 	    case X509_V_ERR_CERT_REVOKED:
1484159d09a2SMark Phalan 		retval = KRB5KDC_ERR_REVOKED_CERTIFICATE;
1485159d09a2SMark Phalan 		break;
1486159d09a2SMark Phalan 	    case X509_V_ERR_UNABLE_TO_GET_CRL:
1487159d09a2SMark Phalan 		retval = KRB5KDC_ERR_REVOCATION_STATUS_UNKNOWN;
1488159d09a2SMark Phalan 		break;
1489159d09a2SMark Phalan 	    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
1490159d09a2SMark Phalan 	    case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
1491159d09a2SMark Phalan 		retval = KRB5KDC_ERR_CANT_VERIFY_CERTIFICATE;
1492159d09a2SMark Phalan 		break;
1493159d09a2SMark Phalan 	    default:
1494159d09a2SMark Phalan 		retval = KRB5KDC_ERR_INVALID_CERTIFICATE;
1495159d09a2SMark Phalan 	}
1496159d09a2SMark Phalan 	X509_NAME_oneline(X509_get_subject_name(
1497159d09a2SMark Phalan 	    reqctx->received_cert), buf, sizeof(buf));
1498159d09a2SMark Phalan 	pkiDebug("problem with cert DN = %s (error=%d) %s\n", buf, j,
1499159d09a2SMark Phalan 		 X509_verify_cert_error_string(j));
1500159d09a2SMark Phalan 	krb5_set_error_message(context, retval, "%s\n",
1501159d09a2SMark Phalan 	    X509_verify_cert_error_string(j));
1502159d09a2SMark Phalan #ifdef DEBUG_CERTCHAIN
1503159d09a2SMark Phalan 	size = sk_X509_num(p7->d.sign->cert);
1504159d09a2SMark Phalan 	pkiDebug("received cert chain of size %d\n", size);
1505159d09a2SMark Phalan 	for (j = 0; j < size; j++) {
1506159d09a2SMark Phalan 	    X509 *tmp_cert = sk_X509_value(p7->d.sign->cert, j);
1507159d09a2SMark Phalan 	    X509_NAME_oneline(X509_get_subject_name(tmp_cert), buf, sizeof(buf));
1508159d09a2SMark Phalan 	    pkiDebug("cert #%d: %s\n", j, buf);
1509159d09a2SMark Phalan 	}
1510159d09a2SMark Phalan #endif
1511159d09a2SMark Phalan     } else {
1512159d09a2SMark Phalan 	/* retrieve verified certificate chain */
1513300fdee2SAndy Fiddaman 	if (cms_msg_type == CMS_SIGN_CLIENT || cms_msg_type == CMS_SIGN_DRAFT9)
1514300fdee2SAndy Fiddaman 	    verified_chain = X509_STORE_CTX_get1_chain(cert_ctx);
1515159d09a2SMark Phalan     }
1516300fdee2SAndy Fiddaman     X509_STORE_CTX_free(cert_ctx);
1517159d09a2SMark Phalan     if (i <= 0)
1518159d09a2SMark Phalan 	goto cleanup;
1519159d09a2SMark Phalan 
1520159d09a2SMark Phalan     out = BIO_new(BIO_s_mem());
1521159d09a2SMark Phalan     if (cms_msg_type == CMS_SIGN_DRAFT9)
1522159d09a2SMark Phalan 	flags |= PKCS7_NOATTR;
1523159d09a2SMark Phalan     if (PKCS7_verify(p7, NULL, store, NULL, out, flags)) {
1524159d09a2SMark Phalan 	int valid_oid = 0;
1525159d09a2SMark Phalan 
1526300fdee2SAndy Fiddaman 	if (!OBJ_cmp(p7->d.sign->contents->type, oid))
1527159d09a2SMark Phalan 	    valid_oid = 1;
1528159d09a2SMark Phalan 	else if (cms_msg_type == CMS_SIGN_DRAFT9) {
1529159d09a2SMark Phalan 	    /*
1530159d09a2SMark Phalan 	     * Various implementations of the pa-type 15 request use
1531159d09a2SMark Phalan 	     * different OIDS.  We check that the returned object
1532159d09a2SMark Phalan 	     * has any of the acceptable OIDs
1533159d09a2SMark Phalan 	     */
1534159d09a2SMark Phalan 	    ASN1_OBJECT *client_oid = NULL, *server_oid = NULL, *rsa_oid = NULL;
1535159d09a2SMark Phalan 	    client_oid = pkinit_pkcs7type2oid(plgctx, CMS_SIGN_CLIENT);
1536159d09a2SMark Phalan 	    server_oid = pkinit_pkcs7type2oid(plgctx, CMS_SIGN_SERVER);
1537159d09a2SMark Phalan 	    rsa_oid = pkinit_pkcs7type2oid(plgctx, CMS_ENVEL_SERVER);
1538159d09a2SMark Phalan 	    if (!OBJ_cmp(p7->d.sign->contents->type, client_oid) ||
1539159d09a2SMark Phalan 		!OBJ_cmp(p7->d.sign->contents->type, server_oid) ||
1540159d09a2SMark Phalan 		!OBJ_cmp(p7->d.sign->contents->type, rsa_oid))
1541159d09a2SMark Phalan 		valid_oid = 1;
1542159d09a2SMark Phalan 	}
1543159d09a2SMark Phalan 
1544300fdee2SAndy Fiddaman 	if (valid_oid)
1545159d09a2SMark Phalan 	    pkiDebug("PKCS7 Verification successful\n");
1546159d09a2SMark Phalan 	else {
1547300fdee2SAndy Fiddaman 	    const ASN1_OBJECT *etype = p7->d.sign->contents->type;
1548159d09a2SMark Phalan 	    pkiDebug("wrong oid in eContentType\n");
1549300fdee2SAndy Fiddaman 	    print_buffer((unsigned char *)OBJ_get0_data(etype),
1550300fdee2SAndy Fiddaman 		OBJ_length(etype));
1551159d09a2SMark Phalan 	    retval = KRB5KDC_ERR_PREAUTH_FAILED;
1552159d09a2SMark Phalan 	    krb5_set_error_message(context, retval, "wrong oid\n");
1553159d09a2SMark Phalan 	    goto cleanup;
1554159d09a2SMark Phalan 	}
1555159d09a2SMark Phalan     }
1556159d09a2SMark Phalan     else {
1557159d09a2SMark Phalan 	unsigned long err = ERR_peek_error();
1558159d09a2SMark Phalan 	switch(ERR_GET_REASON(err)) {
1559159d09a2SMark Phalan 	    case PKCS7_R_DIGEST_FAILURE:
1560159d09a2SMark Phalan 		retval = KRB5KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED;
1561159d09a2SMark Phalan 		break;
1562159d09a2SMark Phalan 	    case PKCS7_R_SIGNATURE_FAILURE:
1563159d09a2SMark Phalan 	    default:
1564159d09a2SMark Phalan 		retval = KRB5KDC_ERR_INVALID_SIG;
1565159d09a2SMark Phalan 	}
1566159d09a2SMark Phalan 	pkiDebug("PKCS7 Verification failure\n");
1567159d09a2SMark Phalan 	krb5_set_error_message(context, retval, "%s\n",
1568159d09a2SMark Phalan 			       ERR_error_string(err, NULL));
1569159d09a2SMark Phalan 	goto cleanup;
1570159d09a2SMark Phalan     }
1571159d09a2SMark Phalan 
1572159d09a2SMark Phalan     /* transfer the data from PKCS7 message into return buffer */
1573159d09a2SMark Phalan     for (size = 0;;) {
1574159d09a2SMark Phalan 	if ((*data = realloc(*data, size + 1024 * 10)) == NULL)
1575159d09a2SMark Phalan 	    goto cleanup;
1576159d09a2SMark Phalan 	i = BIO_read(out, &((*data)[size]), 1024 * 10);
1577159d09a2SMark Phalan 	if (i <= 0)
1578159d09a2SMark Phalan 	    break;
1579159d09a2SMark Phalan 	else
1580159d09a2SMark Phalan 	    size += i;
1581159d09a2SMark Phalan     }
1582159d09a2SMark Phalan     *data_len = size;
1583159d09a2SMark Phalan 
1584159d09a2SMark Phalan     reqctx->received_cert = X509_dup(x);
1585159d09a2SMark Phalan 
1586159d09a2SMark Phalan     /* generate authorization data */
1587159d09a2SMark Phalan     if (cms_msg_type == CMS_SIGN_CLIENT || cms_msg_type == CMS_SIGN_DRAFT9) {
1588159d09a2SMark Phalan 
1589300fdee2SAndy Fiddaman 	if (authz_data == NULL || authz_data_len == NULL)
1590159d09a2SMark Phalan 	    goto out;
1591159d09a2SMark Phalan 
1592159d09a2SMark Phalan 	*authz_data = NULL;
1593300fdee2SAndy Fiddaman 	retval = create_identifiers_from_stack(verified_chain,
1594159d09a2SMark Phalan 					       &krb5_verified_chain);
1595159d09a2SMark Phalan 	if (retval) {
1596159d09a2SMark Phalan 	    pkiDebug("create_identifiers_from_stack failed\n");
1597159d09a2SMark Phalan 	    goto cleanup;
1598159d09a2SMark Phalan 	}
1599159d09a2SMark Phalan 
1600159d09a2SMark Phalan 	retval = k5int_encode_krb5_td_trusted_certifiers((const krb5_external_principal_identifier **)krb5_verified_chain, &authz);
1601159d09a2SMark Phalan 	if (retval) {
1602159d09a2SMark Phalan 	    pkiDebug("encode_krb5_td_trusted_certifiers failed\n");
1603159d09a2SMark Phalan 	    goto cleanup;
1604159d09a2SMark Phalan 	}
1605159d09a2SMark Phalan #ifdef DEBUG_ASN1
1606159d09a2SMark Phalan 	print_buffer_bin((unsigned char *)authz->data, authz->length,
1607159d09a2SMark Phalan 			 "/tmp/kdc_ad_initial_verified_cas");
1608159d09a2SMark Phalan #endif
1609159d09a2SMark Phalan 	*authz_data = (unsigned char *)malloc(authz->length);
1610159d09a2SMark Phalan 	if (*authz_data == NULL) {
1611159d09a2SMark Phalan 	    retval = ENOMEM;
1612159d09a2SMark Phalan 	    goto cleanup;
1613159d09a2SMark Phalan 	}
1614159d09a2SMark Phalan 	(void) memcpy(*authz_data, authz->data, authz->length);
1615159d09a2SMark Phalan 	*authz_data_len = authz->length;
1616159d09a2SMark Phalan     }
1617159d09a2SMark Phalan   out:
1618159d09a2SMark Phalan     retval = 0;
1619159d09a2SMark Phalan 
1620159d09a2SMark Phalan   cleanup:
1621159d09a2SMark Phalan     if (out != NULL)
1622159d09a2SMark Phalan 	BIO_free(out);
1623159d09a2SMark Phalan     if (store != NULL)
1624159d09a2SMark Phalan 	X509_STORE_free(store);
1625159d09a2SMark Phalan     if (p7 != NULL) {
1626159d09a2SMark Phalan 	if (idctx->intermediateCAs != NULL && p7->d.sign->cert)
1627159d09a2SMark Phalan 	    sk_X509_free(intermediateCAs);
1628159d09a2SMark Phalan 	if (idctx->revoked != NULL && p7->d.sign->crl)
1629159d09a2SMark Phalan 	    sk_X509_CRL_free(revoked);
1630159d09a2SMark Phalan 	PKCS7_free(p7);
1631159d09a2SMark Phalan     }
1632159d09a2SMark Phalan     if (verified_chain != NULL)
1633159d09a2SMark Phalan 	sk_X509_pop_free(verified_chain, X509_free);
1634159d09a2SMark Phalan     if (krb5_verified_chain != NULL)
1635159d09a2SMark Phalan 	free_krb5_external_principal_identifier(&krb5_verified_chain);
1636159d09a2SMark Phalan     if (authz != NULL)
1637159d09a2SMark Phalan 	krb5_free_data(context, authz);
1638159d09a2SMark Phalan 
1639159d09a2SMark Phalan     return retval;
1640159d09a2SMark Phalan }
1641159d09a2SMark Phalan 
1642159d09a2SMark Phalan krb5_error_code
cms_envelopeddata_create(krb5_context context,pkinit_plg_crypto_context plgctx,pkinit_req_crypto_context reqctx,pkinit_identity_crypto_context idctx,krb5_preauthtype pa_type,int include_certchain,unsigned char * key_pack,unsigned int key_pack_len,unsigned char ** out,unsigned int * out_len)1643159d09a2SMark Phalan cms_envelopeddata_create(krb5_context context,
1644159d09a2SMark Phalan 			 pkinit_plg_crypto_context plgctx,
1645159d09a2SMark Phalan 			 pkinit_req_crypto_context reqctx,
1646159d09a2SMark Phalan 			 pkinit_identity_crypto_context idctx,
1647159d09a2SMark Phalan 			 krb5_preauthtype pa_type,
1648159d09a2SMark Phalan 			 int include_certchain,
1649159d09a2SMark Phalan 			 unsigned char *key_pack,
1650159d09a2SMark Phalan 			 unsigned int key_pack_len,
1651159d09a2SMark Phalan 			 unsigned char **out,
1652159d09a2SMark Phalan 			 unsigned int *out_len)
1653159d09a2SMark Phalan {
1654159d09a2SMark Phalan 
1655159d09a2SMark Phalan     /* Solaris Kerberos */
1656159d09a2SMark Phalan     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
1657159d09a2SMark Phalan     PKCS7 *p7 = NULL;
1658159d09a2SMark Phalan     BIO *in = NULL;
1659159d09a2SMark Phalan     unsigned char *p = NULL, *signed_data = NULL, *enc_data = NULL;
1660159d09a2SMark Phalan     int signed_data_len = 0, enc_data_len = 0, flags = PKCS7_BINARY;
1661159d09a2SMark Phalan     STACK_OF(X509) *encerts = NULL;
1662159d09a2SMark Phalan     const EVP_CIPHER *cipher = NULL;
1663159d09a2SMark Phalan     int cms_msg_type;
1664159d09a2SMark Phalan 
1665159d09a2SMark Phalan     /* create the PKCS7 SignedData portion of the PKCS7 EnvelopedData */
1666159d09a2SMark Phalan     switch ((int)pa_type) {
1667159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ_OLD:
1668159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REP_OLD:
1669159d09a2SMark Phalan 	    cms_msg_type = CMS_SIGN_DRAFT9;
1670159d09a2SMark Phalan 	    break;
1671159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ:
1672159d09a2SMark Phalan 	    cms_msg_type = CMS_ENVEL_SERVER;
1673159d09a2SMark Phalan 	    break;
1674159d09a2SMark Phalan 	default:
1675159d09a2SMark Phalan 	    /* Solaris Kerberos */
1676159d09a2SMark Phalan 	    retval = EINVAL;
1677159d09a2SMark Phalan 	    goto cleanup;
1678159d09a2SMark Phalan     }
1679159d09a2SMark Phalan 
1680159d09a2SMark Phalan     retval = cms_signeddata_create(context, plgctx, reqctx, idctx,
1681159d09a2SMark Phalan 	cms_msg_type, include_certchain, key_pack, key_pack_len,
1682159d09a2SMark Phalan 	&signed_data, (unsigned int *)&signed_data_len);
1683159d09a2SMark Phalan     if (retval) {
1684159d09a2SMark Phalan 	pkiDebug("failed to create pkcs7 signed data\n");
1685159d09a2SMark Phalan 	goto cleanup;
1686159d09a2SMark Phalan     }
1687159d09a2SMark Phalan 
1688159d09a2SMark Phalan     /* check we have client's certificate */
1689159d09a2SMark Phalan     if (reqctx->received_cert == NULL) {
1690159d09a2SMark Phalan 	retval = KRB5KDC_ERR_PREAUTH_FAILED;
1691159d09a2SMark Phalan 	goto cleanup;
1692159d09a2SMark Phalan     }
1693159d09a2SMark Phalan     encerts = sk_X509_new_null();
1694159d09a2SMark Phalan     sk_X509_push(encerts, reqctx->received_cert);
1695159d09a2SMark Phalan 
1696159d09a2SMark Phalan     cipher = EVP_des_ede3_cbc();
1697159d09a2SMark Phalan     in = BIO_new(BIO_s_mem());
1698159d09a2SMark Phalan     switch (pa_type) {
1699159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ:
1700159d09a2SMark Phalan 	    prepare_enc_data(signed_data, signed_data_len, &enc_data,
1701159d09a2SMark Phalan 			     &enc_data_len);
1702159d09a2SMark Phalan 	    retval = BIO_write(in, enc_data, enc_data_len);
1703159d09a2SMark Phalan 	    if (retval != enc_data_len) {
1704159d09a2SMark Phalan 		pkiDebug("BIO_write only wrote %d\n", retval);
1705159d09a2SMark Phalan 		goto cleanup;
1706159d09a2SMark Phalan 	    }
1707159d09a2SMark Phalan 	    break;
1708159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REP_OLD:
1709159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ_OLD:
1710159d09a2SMark Phalan 	    retval = BIO_write(in, signed_data, signed_data_len);
1711159d09a2SMark Phalan 		if (retval != signed_data_len) {
1712159d09a2SMark Phalan 		    pkiDebug("BIO_write only wrote %d\n", retval);
1713159d09a2SMark Phalan 		    /* Solaris Kerberos */
1714159d09a2SMark Phalan 		    retval = KRB5KRB_ERR_GENERIC;
1715159d09a2SMark Phalan 		    goto cleanup;
1716159d09a2SMark Phalan 	    }
1717159d09a2SMark Phalan 	    break;
1718159d09a2SMark Phalan 	default:
1719159d09a2SMark Phalan 	    retval = -1;
1720159d09a2SMark Phalan 	    goto cleanup;
1721159d09a2SMark Phalan     }
1722159d09a2SMark Phalan 
1723159d09a2SMark Phalan     p7 = PKCS7_encrypt(encerts, in, cipher, flags);
1724159d09a2SMark Phalan     if (p7 == NULL) {
1725159d09a2SMark Phalan 	pkiDebug("failed to encrypt PKCS7 object\n");
1726159d09a2SMark Phalan 	retval = -1;
1727159d09a2SMark Phalan 	goto cleanup;
1728159d09a2SMark Phalan     }
1729159d09a2SMark Phalan     switch (pa_type) {
1730159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ:
1731300fdee2SAndy Fiddaman 	    p7->d.enveloped->enc_data->content_type =
1732159d09a2SMark Phalan 		OBJ_nid2obj(NID_pkcs7_signed);
1733159d09a2SMark Phalan 	    break;
1734159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REP_OLD:
1735159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REQ_OLD:
1736300fdee2SAndy Fiddaman 	    p7->d.enveloped->enc_data->content_type =
1737159d09a2SMark Phalan 		OBJ_nid2obj(NID_pkcs7_data);
1738159d09a2SMark Phalan 	    break;
1739300fdee2SAndy Fiddaman     }
1740159d09a2SMark Phalan 
1741159d09a2SMark Phalan     *out_len = i2d_PKCS7(p7, NULL);
1742159d09a2SMark Phalan     if (!*out_len || (p = *out = (unsigned char *)malloc(*out_len)) == NULL) {
1743159d09a2SMark Phalan 	retval = ENOMEM;
1744159d09a2SMark Phalan 	goto cleanup;
1745159d09a2SMark Phalan     }
1746159d09a2SMark Phalan     retval = i2d_PKCS7(p7, &p);
1747159d09a2SMark Phalan     if (!retval) {
1748159d09a2SMark Phalan 	pkiDebug("unable to write pkcs7 object\n");
1749159d09a2SMark Phalan 	goto cleanup;
1750159d09a2SMark Phalan     }
1751159d09a2SMark Phalan     retval = 0;
1752159d09a2SMark Phalan 
1753159d09a2SMark Phalan #ifdef DEBUG_ASN1
1754159d09a2SMark Phalan     print_buffer_bin(*out, *out_len, "/tmp/kdc_enveloped_data");
1755159d09a2SMark Phalan #endif
1756159d09a2SMark Phalan 
1757159d09a2SMark Phalan cleanup:
1758159d09a2SMark Phalan     if (p7 != NULL)
1759159d09a2SMark Phalan 	PKCS7_free(p7);
1760159d09a2SMark Phalan     if (in != NULL)
1761159d09a2SMark Phalan 	BIO_free(in);
1762159d09a2SMark Phalan     if (signed_data != NULL)
1763159d09a2SMark Phalan 	free(signed_data);
1764159d09a2SMark Phalan     if (enc_data != NULL)
1765159d09a2SMark Phalan 	free(enc_data);
1766159d09a2SMark Phalan     if (encerts != NULL)
1767159d09a2SMark Phalan 	sk_X509_free(encerts);
17683f8dd771SAndy Fiddaman 
1769159d09a2SMark Phalan     return retval;
1770159d09a2SMark Phalan }
1771159d09a2SMark Phalan 
1772159d09a2SMark Phalan krb5_error_code
cms_envelopeddata_verify(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_preauthtype pa_type,int require_crl_checking,unsigned char * enveloped_data,unsigned int enveloped_data_len,unsigned char ** data,unsigned int * data_len)1773159d09a2SMark Phalan cms_envelopeddata_verify(krb5_context context,
1774159d09a2SMark Phalan 			 pkinit_plg_crypto_context plg_cryptoctx,
1775159d09a2SMark Phalan 			 pkinit_req_crypto_context req_cryptoctx,
1776159d09a2SMark Phalan 			 pkinit_identity_crypto_context id_cryptoctx,
1777159d09a2SMark Phalan 			 krb5_preauthtype pa_type,
1778159d09a2SMark Phalan 			 int require_crl_checking,
1779159d09a2SMark Phalan 			 unsigned char *enveloped_data,
1780159d09a2SMark Phalan 			 unsigned int enveloped_data_len,
1781159d09a2SMark Phalan 			 unsigned char **data,
1782159d09a2SMark Phalan 			 unsigned int *data_len)
1783159d09a2SMark Phalan {
1784159d09a2SMark Phalan     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
1785159d09a2SMark Phalan     PKCS7 *p7 = NULL;
1786159d09a2SMark Phalan     BIO *out = NULL;
1787159d09a2SMark Phalan     int i = 0;
1788159d09a2SMark Phalan     unsigned int size = 0;
1789159d09a2SMark Phalan     const unsigned char *p = enveloped_data;
1790159d09a2SMark Phalan     unsigned int tmp_buf_len = 0, tmp_buf2_len = 0, vfy_buf_len = 0;
1791159d09a2SMark Phalan     unsigned char *tmp_buf = NULL, *tmp_buf2 = NULL, *vfy_buf = NULL;
1792159d09a2SMark Phalan     int msg_type = 0;
1793159d09a2SMark Phalan 
1794159d09a2SMark Phalan #ifdef DEBUG_ASN1
1795159d09a2SMark Phalan     print_buffer_bin(enveloped_data, enveloped_data_len,
1796159d09a2SMark Phalan 		     "/tmp/client_envelopeddata");
1797159d09a2SMark Phalan #endif
1798159d09a2SMark Phalan     /* decode received PKCS7 message */
1799159d09a2SMark Phalan     if ((p7 = d2i_PKCS7(NULL, &p, (int)enveloped_data_len)) == NULL) {
1800159d09a2SMark Phalan 	unsigned long err = ERR_peek_error();
1801159d09a2SMark Phalan 	pkiDebug("failed to decode pkcs7\n");
1802159d09a2SMark Phalan 	krb5_set_error_message(context, retval, "%s\n",
1803159d09a2SMark Phalan 			       ERR_error_string(err, NULL));
1804159d09a2SMark Phalan 	goto cleanup;
1805159d09a2SMark Phalan     }
1806159d09a2SMark Phalan 
1807159d09a2SMark Phalan     /* verify that the received message is PKCS7 EnvelopedData message */
1808159d09a2SMark Phalan     if (OBJ_obj2nid(p7->type) != NID_pkcs7_enveloped) {
1809159d09a2SMark Phalan 	pkiDebug("Expected id-enveloped PKCS7 msg (received type = %d)\n",
1810159d09a2SMark Phalan 		 OBJ_obj2nid(p7->type));
1811159d09a2SMark Phalan 	krb5_set_error_message(context, retval, "wrong oid\n");
1812159d09a2SMark Phalan 	goto cleanup;
1813159d09a2SMark Phalan     }
1814159d09a2SMark Phalan 
1815159d09a2SMark Phalan     /* decrypt received PKCS7 message */
1816159d09a2SMark Phalan     out = BIO_new(BIO_s_mem());
1817159d09a2SMark Phalan     if (pkcs7_decrypt(context, id_cryptoctx, p7, out)) {
1818159d09a2SMark Phalan 	pkiDebug("PKCS7 decryption successful\n");
1819159d09a2SMark Phalan     } else {
1820159d09a2SMark Phalan 	unsigned long err = ERR_peek_error();
1821159d09a2SMark Phalan 	if (err != 0)
1822159d09a2SMark Phalan 	    krb5_set_error_message(context, retval, "%s\n",
1823159d09a2SMark Phalan 				   ERR_error_string(err, NULL));
1824159d09a2SMark Phalan 	pkiDebug("PKCS7 decryption failed\n");
1825159d09a2SMark Phalan 	goto cleanup;
1826159d09a2SMark Phalan     }
1827159d09a2SMark Phalan 
1828159d09a2SMark Phalan     /* transfer the decoded PKCS7 SignedData message into a separate buffer */
1829159d09a2SMark Phalan     for (;;) {
1830159d09a2SMark Phalan 	if ((tmp_buf = realloc(tmp_buf, size + 1024 * 10)) == NULL)
1831159d09a2SMark Phalan 	    goto cleanup;
1832159d09a2SMark Phalan 	i = BIO_read(out, &(tmp_buf[size]), 1024 * 10);
1833159d09a2SMark Phalan 	if (i <= 0)
1834159d09a2SMark Phalan 	    break;
1835159d09a2SMark Phalan 	else
1836159d09a2SMark Phalan 	    size += i;
1837159d09a2SMark Phalan     }
1838159d09a2SMark Phalan     tmp_buf_len = size;
1839159d09a2SMark Phalan 
1840159d09a2SMark Phalan #ifdef DEBUG_ASN1
1841159d09a2SMark Phalan     print_buffer_bin(tmp_buf, tmp_buf_len, "/tmp/client_enc_keypack");
1842159d09a2SMark Phalan #endif
1843159d09a2SMark Phalan     /* verify PKCS7 SignedData message */
1844159d09a2SMark Phalan     switch (pa_type) {
1845159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REP:
1846159d09a2SMark Phalan 	    msg_type = CMS_ENVEL_SERVER;
1847159d09a2SMark Phalan 
1848159d09a2SMark Phalan 	    break;
1849159d09a2SMark Phalan 	case KRB5_PADATA_PK_AS_REP_OLD:
1850159d09a2SMark Phalan 	    msg_type = CMS_SIGN_DRAFT9;
1851159d09a2SMark Phalan 	    break;
1852159d09a2SMark Phalan 	default:
1853159d09a2SMark Phalan 	    pkiDebug("%s: unrecognized pa_type = %d\n", __FUNCTION__, pa_type);
1854159d09a2SMark Phalan 	    retval = KRB5KDC_ERR_PREAUTH_FAILED;
1855159d09a2SMark Phalan 	    goto cleanup;
1856159d09a2SMark Phalan     }
1857159d09a2SMark Phalan     /*
1858159d09a2SMark Phalan      * If this is the RFC style, wrap the signed data to make
1859159d09a2SMark Phalan      * decoding easier in the verify routine.
1860159d09a2SMark Phalan      * For draft9-compatible, we don't do anything because it
1861159d09a2SMark Phalan      * is already wrapped.
1862159d09a2SMark Phalan      */
1863159d09a2SMark Phalan #ifdef LONGHORN_BETA_COMPAT
1864159d09a2SMark Phalan     /*
1865159d09a2SMark Phalan      * The Longhorn server returns the expected RFC-style data, but
1866159d09a2SMark Phalan      * it is missing the sequence tag and length, so it requires
1867159d09a2SMark Phalan      * special processing when wrapping.
1868159d09a2SMark Phalan      * This will hopefully be fixed before the final release and
1869159d09a2SMark Phalan      * this can all be removed.
1870159d09a2SMark Phalan      */
1871159d09a2SMark Phalan     if (msg_type == CMS_ENVEL_SERVER || longhorn == 1) {
1872159d09a2SMark Phalan 	retval = wrap_signeddata(tmp_buf, tmp_buf_len,
1873159d09a2SMark Phalan 				 &tmp_buf2, &tmp_buf2_len, longhorn);
1874159d09a2SMark Phalan 	if (retval) {
1875159d09a2SMark Phalan 	    pkiDebug("failed to encode signeddata\n");
1876159d09a2SMark Phalan 	    goto cleanup;
1877159d09a2SMark Phalan 	}
1878159d09a2SMark Phalan 	vfy_buf = tmp_buf2;
1879159d09a2SMark Phalan 	vfy_buf_len = tmp_buf2_len;
1880159d09a2SMark Phalan 
1881159d09a2SMark Phalan     } else {
1882159d09a2SMark Phalan 	vfy_buf = tmp_buf;
1883159d09a2SMark Phalan 	vfy_buf_len = tmp_buf_len;
1884159d09a2SMark Phalan     }
1885159d09a2SMark Phalan #else
1886159d09a2SMark Phalan     if (msg_type == CMS_ENVEL_SERVER) {
1887159d09a2SMark Phalan 	retval = wrap_signeddata(tmp_buf, tmp_buf_len,
1888159d09a2SMark Phalan 				 &tmp_buf2, &tmp_buf2_len);
1889159d09a2SMark Phalan 	if (retval) {
1890159d09a2SMark Phalan 	    pkiDebug("failed to encode signeddata\n");
1891159d09a2SMark Phalan 	    goto cleanup;
1892159d09a2SMark Phalan 	}
1893159d09a2SMark Phalan 	vfy_buf = tmp_buf2;
1894159d09a2SMark Phalan 	vfy_buf_len = tmp_buf2_len;
1895159d09a2SMark Phalan 
1896159d09a2SMark Phalan     } else {
1897159d09a2SMark Phalan 	vfy_buf = tmp_buf;
1898159d09a2SMark Phalan 	vfy_buf_len = tmp_buf_len;
1899159d09a2SMark Phalan     }
1900159d09a2SMark Phalan #endif
1901159d09a2SMark Phalan 
1902159d09a2SMark Phalan #ifdef DEBUG_ASN1
1903159d09a2SMark Phalan     print_buffer_bin(vfy_buf, vfy_buf_len, "/tmp/client_enc_keypack2");
1904159d09a2SMark Phalan #endif
1905159d09a2SMark Phalan 
1906159d09a2SMark Phalan     retval = cms_signeddata_verify(context, plg_cryptoctx, req_cryptoctx,
1907159d09a2SMark Phalan 				   id_cryptoctx, msg_type,
1908159d09a2SMark Phalan 				   require_crl_checking,
1909159d09a2SMark Phalan 				   vfy_buf, vfy_buf_len,
1910159d09a2SMark Phalan 				   data, data_len, NULL, NULL);
1911159d09a2SMark Phalan 
1912159d09a2SMark Phalan     if (!retval)
1913159d09a2SMark Phalan 	pkiDebug("PKCS7 Verification Success\n");
19143f8dd771SAndy Fiddaman     else {
1915159d09a2SMark Phalan 	pkiDebug("PKCS7 Verification Failure\n");
1916159d09a2SMark Phalan 	goto cleanup;
1917159d09a2SMark Phalan     }
1918159d09a2SMark Phalan 
1919159d09a2SMark Phalan     retval = 0;
1920159d09a2SMark Phalan 
1921159d09a2SMark Phalan   cleanup:
1922159d09a2SMark Phalan 
1923159d09a2SMark Phalan     if (p7 != NULL)
1924159d09a2SMark Phalan 	PKCS7_free(p7);
1925159d09a2SMark Phalan     if (out != NULL)
1926159d09a2SMark Phalan 	BIO_free(out);
1927159d09a2SMark Phalan     if (tmp_buf != NULL)
1928159d09a2SMark Phalan 	free(tmp_buf);
1929159d09a2SMark Phalan     if (tmp_buf2 != NULL)
1930159d09a2SMark Phalan 	free(tmp_buf2);
1931159d09a2SMark Phalan 
1932159d09a2SMark Phalan     return retval;
1933159d09a2SMark Phalan }
1934159d09a2SMark Phalan 
1935159d09a2SMark Phalan /* ARGSUSED */
1936159d09a2SMark Phalan static krb5_error_code
crypto_retrieve_X509_sans(krb5_context context,pkinit_plg_crypto_context plgctx,pkinit_req_crypto_context reqctx,X509 * cert,krb5_principal ** princs_ret,krb5_principal ** upn_ret,unsigned char *** dns_ret)1937159d09a2SMark Phalan crypto_retrieve_X509_sans(krb5_context context,
1938159d09a2SMark Phalan 			  pkinit_plg_crypto_context plgctx,
1939159d09a2SMark Phalan 			  pkinit_req_crypto_context reqctx,
1940159d09a2SMark Phalan 			  X509 *cert,
1941159d09a2SMark Phalan 			  krb5_principal **princs_ret,
1942159d09a2SMark Phalan 			  krb5_principal **upn_ret,
1943159d09a2SMark Phalan 			  unsigned char ***dns_ret)
1944159d09a2SMark Phalan {
1945159d09a2SMark Phalan     krb5_error_code retval = EINVAL;
1946159d09a2SMark Phalan     char buf[DN_BUF_LEN];
1947159d09a2SMark Phalan     int p = 0, u = 0, d = 0;
1948159d09a2SMark Phalan     krb5_principal *princs = NULL;
1949159d09a2SMark Phalan     krb5_principal *upns = NULL;
1950159d09a2SMark Phalan     unsigned char **dnss = NULL;
1951159d09a2SMark Phalan     int i, num_found = 0;
1952159d09a2SMark Phalan 
1953159d09a2SMark Phalan     if (princs_ret == NULL && upn_ret == NULL && dns_ret == NULL) {
1954159d09a2SMark Phalan 	pkiDebug("%s: nowhere to return any values!\n", __FUNCTION__);
1955159d09a2SMark Phalan 	return retval;
1956159d09a2SMark Phalan     }
1957159d09a2SMark Phalan 
1958159d09a2SMark Phalan     if (cert == NULL) {
1959159d09a2SMark Phalan 	pkiDebug("%s: no certificate!\n", __FUNCTION__);
1960159d09a2SMark Phalan 	return retval;
1961159d09a2SMark Phalan     }
1962159d09a2SMark Phalan 
1963159d09a2SMark Phalan     X509_NAME_oneline(X509_get_subject_name(cert),
1964159d09a2SMark Phalan 		      buf, sizeof(buf));
1965159d09a2SMark Phalan     pkiDebug("%s: looking for SANs in cert = %s\n", __FUNCTION__, buf);
1966159d09a2SMark Phalan 
1967159d09a2SMark Phalan     if ((i = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1)) >= 0) {
1968159d09a2SMark Phalan 	X509_EXTENSION *ext = NULL;
1969159d09a2SMark Phalan 	GENERAL_NAMES *ialt = NULL;
1970159d09a2SMark Phalan 	GENERAL_NAME *gen = NULL;
1971159d09a2SMark Phalan 	int ret = 0;
1972159d09a2SMark Phalan 	unsigned int num_sans = 0;
1973159d09a2SMark Phalan 
1974159d09a2SMark Phalan 	if (!(ext = X509_get_ext(cert, i)) || !(ialt = X509V3_EXT_d2i(ext))) {
1975159d09a2SMark Phalan 	    pkiDebug("%s: found no subject alt name extensions\n",
1976159d09a2SMark Phalan 		     __FUNCTION__);
1977159d09a2SMark Phalan 	    goto cleanup;
1978159d09a2SMark Phalan 	}
1979159d09a2SMark Phalan 	num_sans = sk_GENERAL_NAME_num(ialt);
1980159d09a2SMark Phalan 
1981159d09a2SMark Phalan 	pkiDebug("%s: found %d subject alt name extension(s)\n",
1982159d09a2SMark Phalan 		 __FUNCTION__, num_sans);
1983159d09a2SMark Phalan 
1984159d09a2SMark Phalan 	/* OK, we're likely returning something. Allocate return values */
1985159d09a2SMark Phalan 	if (princs_ret != NULL) {
1986159d09a2SMark Phalan 	    princs = calloc(num_sans + 1, sizeof(krb5_principal));
1987159d09a2SMark Phalan 	    if (princs == NULL) {
1988159d09a2SMark Phalan 		retval = ENOMEM;
1989159d09a2SMark Phalan 		goto cleanup;
1990159d09a2SMark Phalan 	    }
1991159d09a2SMark Phalan 	}
1992159d09a2SMark Phalan 	if (upn_ret != NULL) {
1993159d09a2SMark Phalan 	    upns = calloc(num_sans + 1, sizeof(krb5_principal));
1994159d09a2SMark Phalan 	    if (upns == NULL) {
1995159d09a2SMark Phalan 		retval = ENOMEM;
1996159d09a2SMark Phalan 		goto cleanup;
1997159d09a2SMark Phalan 	    }
1998159d09a2SMark Phalan 	}
1999159d09a2SMark Phalan 	if (dns_ret != NULL) {
2000159d09a2SMark Phalan 	    dnss = calloc(num_sans + 1, sizeof(*dnss));
2001159d09a2SMark Phalan 	    if (dnss == NULL) {
2002159d09a2SMark Phalan 		retval = ENOMEM;
2003159d09a2SMark Phalan 		goto cleanup;
2004159d09a2SMark Phalan 	    }
2005159d09a2SMark Phalan 	}
2006159d09a2SMark Phalan 
2007159d09a2SMark Phalan 	for (i = 0; i < num_sans; i++) {
2008159d09a2SMark Phalan 	    krb5_data name = { 0, 0, NULL };
2009159d09a2SMark Phalan 
2010159d09a2SMark Phalan 	    gen = sk_GENERAL_NAME_value(ialt, i);
2011159d09a2SMark Phalan 	    switch (gen->type) {
2012159d09a2SMark Phalan 	    case GEN_OTHERNAME:
2013159d09a2SMark Phalan 		name.length = gen->d.otherName->value->value.sequence->length;
2014159d09a2SMark Phalan 		name.data = (char *)gen->d.otherName->value->value.sequence->data;
2015159d09a2SMark Phalan 		if (princs != NULL
2016159d09a2SMark Phalan 		    && OBJ_cmp(plgctx->id_pkinit_san,
2017159d09a2SMark Phalan 			       gen->d.otherName->type_id) == 0) {
2018159d09a2SMark Phalan #ifdef DEBUG_ASN1
2019159d09a2SMark Phalan 		    print_buffer_bin((unsigned char *)name.data, name.length,
2020159d09a2SMark Phalan 				     "/tmp/pkinit_san");
2021159d09a2SMark Phalan #endif
2022159d09a2SMark Phalan 		    ret = k5int_decode_krb5_principal_name(&name, &princs[p]);
2023159d09a2SMark Phalan 		    if (ret) {
2024159d09a2SMark Phalan 			pkiDebug("%s: failed decoding pkinit san value\n",
2025159d09a2SMark Phalan 				 __FUNCTION__);
2026159d09a2SMark Phalan 		    } else {
2027159d09a2SMark Phalan 			p++;
2028159d09a2SMark Phalan 			num_found++;
2029159d09a2SMark Phalan 		    }
2030159d09a2SMark Phalan 		} else if (upns != NULL
2031159d09a2SMark Phalan 			   && OBJ_cmp(plgctx->id_ms_san_upn,
2032159d09a2SMark Phalan 				      gen->d.otherName->type_id) == 0) {
2033159d09a2SMark Phalan 		    ret = krb5_parse_name(context, name.data, &upns[u]);
2034159d09a2SMark Phalan 		    if (ret) {
2035159d09a2SMark Phalan 			pkiDebug("%s: failed parsing ms-upn san value\n",
2036159d09a2SMark Phalan 				 __FUNCTION__);
2037159d09a2SMark Phalan 		    } else {
2038159d09a2SMark Phalan 			u++;
2039159d09a2SMark Phalan 			num_found++;
2040159d09a2SMark Phalan 		    }
2041159d09a2SMark Phalan 		} else {
2042159d09a2SMark Phalan 		    pkiDebug("%s: unrecognized othername oid in SAN\n",
2043159d09a2SMark Phalan 			     __FUNCTION__);
2044159d09a2SMark Phalan 		    continue;
2045159d09a2SMark Phalan 		}
2046159d09a2SMark Phalan 
2047159d09a2SMark Phalan 		break;
2048159d09a2SMark Phalan 	    case GEN_DNS:
2049159d09a2SMark Phalan 		if (dnss != NULL) {
2050159d09a2SMark Phalan 		    pkiDebug("%s: found dns name = %s\n",
2051159d09a2SMark Phalan 			     __FUNCTION__, gen->d.dNSName->data);
2052159d09a2SMark Phalan 		    dnss[d] = (unsigned char *)
2053300fdee2SAndy Fiddaman 				    strdup((char *)gen->d.dNSName->data);
2054159d09a2SMark Phalan 		    if (dnss[d] == NULL) {
2055159d09a2SMark Phalan 			pkiDebug("%s: failed to duplicate dns name\n",
2056159d09a2SMark Phalan 				 __FUNCTION__);
2057159d09a2SMark Phalan 		    } else {
2058159d09a2SMark Phalan 			d++;
2059159d09a2SMark Phalan 			num_found++;
2060159d09a2SMark Phalan 		    }
2061159d09a2SMark Phalan 		}
2062159d09a2SMark Phalan 		break;
2063159d09a2SMark Phalan 	    default:
2064159d09a2SMark Phalan 		pkiDebug("%s: SAN type = %d expecting %d\n",
2065159d09a2SMark Phalan 			 __FUNCTION__, gen->type, GEN_OTHERNAME);
2066159d09a2SMark Phalan 	    }
2067159d09a2SMark Phalan 	}
2068159d09a2SMark Phalan 	sk_GENERAL_NAME_pop_free(ialt, GENERAL_NAME_free);
2069159d09a2SMark Phalan     }
2070159d09a2SMark Phalan 
2071159d09a2SMark Phalan     retval = 0;
2072159d09a2SMark Phalan     if (princs)
2073159d09a2SMark Phalan 	*princs_ret = princs;
2074159d09a2SMark Phalan     if (upns)
2075159d09a2SMark Phalan 	*upn_ret = upns;
2076159d09a2SMark Phalan     if (dnss)
2077159d09a2SMark Phalan 	*dns_ret = dnss;
2078159d09a2SMark Phalan 
2079159d09a2SMark Phalan   cleanup:
2080159d09a2SMark Phalan     if (retval) {
2081159d09a2SMark Phalan 	if (princs != NULL) {
2082159d09a2SMark Phalan 	    for (i = 0; princs[i] != NULL; i++)
2083159d09a2SMark Phalan 		krb5_free_principal(context, princs[i]);
2084159d09a2SMark Phalan 	    free(princs);
2085159d09a2SMark Phalan 	}
2086159d09a2SMark Phalan 	if (upns != NULL) {
2087159d09a2SMark Phalan 	    for (i = 0; upns[i] != NULL; i++)
2088159d09a2SMark Phalan 		krb5_free_principal(context, upns[i]);
2089159d09a2SMark Phalan 	    free(upns);
2090159d09a2SMark Phalan 	}
2091159d09a2SMark Phalan 	if (dnss != NULL) {
2092159d09a2SMark Phalan 	    for (i = 0; dnss[i] != NULL; i++)
2093159d09a2SMark Phalan 		free(dnss[i]);
2094159d09a2SMark Phalan 	    free(dnss);
2095159d09a2SMark Phalan 	}
2096159d09a2SMark Phalan     }
2097159d09a2SMark Phalan     return retval;
2098159d09a2SMark Phalan }
2099159d09a2SMark Phalan 
2100159d09a2SMark Phalan /* ARGSUSED */
2101159d09a2SMark Phalan krb5_error_code
crypto_retrieve_cert_sans(krb5_context context,pkinit_plg_crypto_context plgctx,pkinit_req_crypto_context reqctx,pkinit_identity_crypto_context idctx,krb5_principal ** princs_ret,krb5_principal ** upn_ret,unsigned char *** dns_ret)2102159d09a2SMark Phalan crypto_retrieve_cert_sans(krb5_context context,
2103159d09a2SMark Phalan 			  pkinit_plg_crypto_context plgctx,
2104159d09a2SMark Phalan 			  pkinit_req_crypto_context reqctx,
2105159d09a2SMark Phalan 			  pkinit_identity_crypto_context idctx,
2106159d09a2SMark Phalan 			  krb5_principal **princs_ret,
2107159d09a2SMark Phalan 			  krb5_principal **upn_ret,
2108159d09a2SMark Phalan 			  unsigned char ***dns_ret)
2109159d09a2SMark Phalan {
2110159d09a2SMark Phalan     krb5_error_code retval = EINVAL;
2111159d09a2SMark Phalan 
2112159d09a2SMark Phalan     if (reqctx->received_cert == NULL) {
2113159d09a2SMark Phalan 	pkiDebug("%s: No certificate!\n", __FUNCTION__);
2114159d09a2SMark Phalan 	return retval;
2115159d09a2SMark Phalan     }
2116159d09a2SMark Phalan 
2117159d09a2SMark Phalan     return crypto_retrieve_X509_sans(context, plgctx, reqctx,
2118159d09a2SMark Phalan 				     reqctx->received_cert, princs_ret,
2119159d09a2SMark Phalan 				     upn_ret, dns_ret);
2120159d09a2SMark Phalan }
2121159d09a2SMark Phalan 
2122159d09a2SMark Phalan /* ARGSUSED */
2123159d09a2SMark Phalan krb5_error_code
crypto_check_cert_eku(krb5_context context,pkinit_plg_crypto_context plgctx,pkinit_req_crypto_context reqctx,pkinit_identity_crypto_context idctx,int checking_kdc_cert,int allow_secondary_usage,int * valid_eku)2124159d09a2SMark Phalan crypto_check_cert_eku(krb5_context context,
2125159d09a2SMark Phalan 		      pkinit_plg_crypto_context plgctx,
2126159d09a2SMark Phalan 		      pkinit_req_crypto_context reqctx,
2127159d09a2SMark Phalan 		      pkinit_identity_crypto_context idctx,
2128159d09a2SMark Phalan 		      int checking_kdc_cert,
2129159d09a2SMark Phalan 		      int allow_secondary_usage,
2130159d09a2SMark Phalan 		      int *valid_eku)
2131159d09a2SMark Phalan {
2132159d09a2SMark Phalan     char buf[DN_BUF_LEN];
2133159d09a2SMark Phalan     int found_eku = 0;
2134159d09a2SMark Phalan     krb5_error_code retval = EINVAL;
2135159d09a2SMark Phalan     int i;
2136159d09a2SMark Phalan 
2137159d09a2SMark Phalan     /* Solaris Kerberos */
2138159d09a2SMark Phalan     if (valid_eku == NULL)
2139159d09a2SMark Phalan 	return retval;
2140159d09a2SMark Phalan 
2141159d09a2SMark Phalan     *valid_eku = 0;
2142159d09a2SMark Phalan     if (reqctx->received_cert == NULL)
2143159d09a2SMark Phalan 	goto cleanup;
2144159d09a2SMark Phalan 
2145159d09a2SMark Phalan     X509_NAME_oneline(X509_get_subject_name(reqctx->received_cert),
2146159d09a2SMark Phalan 		      buf, sizeof(buf));
2147159d09a2SMark Phalan     pkiDebug("%s: looking for EKUs in cert = %s\n", __FUNCTION__, buf);
2148159d09a2SMark Phalan 
2149159d09a2SMark Phalan     if ((i = X509_get_ext_by_NID(reqctx->received_cert,
2150159d09a2SMark Phalan 				 NID_ext_key_usage, -1)) >= 0) {
2151159d09a2SMark Phalan 	EXTENDED_KEY_USAGE *extusage;
2152159d09a2SMark Phalan 
2153159d09a2SMark Phalan 	extusage = X509_get_ext_d2i(reqctx->received_cert, NID_ext_key_usage,
2154159d09a2SMark Phalan 				    NULL, NULL);
2155159d09a2SMark Phalan 	if (extusage) {
2156159d09a2SMark Phalan 	    pkiDebug("%s: found eku info in the cert\n", __FUNCTION__);
2157159d09a2SMark Phalan 	    for (i = 0; found_eku == 0 && i < sk_ASN1_OBJECT_num(extusage); i++) {
2158159d09a2SMark Phalan 		ASN1_OBJECT *tmp_oid;
2159159d09a2SMark Phalan 
2160159d09a2SMark Phalan 		tmp_oid = sk_ASN1_OBJECT_value(extusage, i);
2161159d09a2SMark Phalan 		pkiDebug("%s: checking eku %d of %d, allow_secondary = %d\n",
2162159d09a2SMark Phalan 			 __FUNCTION__, i+1, sk_ASN1_OBJECT_num(extusage),
2163159d09a2SMark Phalan 			 allow_secondary_usage);
2164159d09a2SMark Phalan 		if (checking_kdc_cert) {
2165159d09a2SMark Phalan 		    if ((OBJ_cmp(tmp_oid, plgctx->id_pkinit_KPKdc) == 0)
2166159d09a2SMark Phalan 			 || (allow_secondary_usage
2167159d09a2SMark Phalan 			 && OBJ_cmp(tmp_oid, plgctx->id_kp_serverAuth) == 0))
2168159d09a2SMark Phalan 			found_eku = 1;
2169159d09a2SMark Phalan 		} else {
2170159d09a2SMark Phalan 		    if ((OBJ_cmp(tmp_oid, plgctx->id_pkinit_KPClientAuth) == 0)
2171159d09a2SMark Phalan 			 || (allow_secondary_usage
2172159d09a2SMark Phalan 			 && OBJ_cmp(tmp_oid, plgctx->id_ms_kp_sc_logon) == 0))
2173159d09a2SMark Phalan 			found_eku = 1;
2174159d09a2SMark Phalan 		}
2175159d09a2SMark Phalan 	    }
2176159d09a2SMark Phalan 	}
2177159d09a2SMark Phalan 	EXTENDED_KEY_USAGE_free(extusage);
2178159d09a2SMark Phalan 
2179159d09a2SMark Phalan 	if (found_eku) {
2180159d09a2SMark Phalan 	    ASN1_BIT_STRING *usage = NULL;
2181159d09a2SMark Phalan 	    pkiDebug("%s: found acceptable EKU, checking for digitalSignature\n", __FUNCTION__);
2182159d09a2SMark Phalan 
2183159d09a2SMark Phalan 	    /* check that digitalSignature KeyUsage is present */
2184159d09a2SMark Phalan 	    if ((usage = X509_get_ext_d2i(reqctx->received_cert,
2185159d09a2SMark Phalan 					  NID_key_usage, NULL, NULL))) {
2186159d09a2SMark Phalan 
2187159d09a2SMark Phalan 		if (!ku_reject(reqctx->received_cert,
2188159d09a2SMark Phalan 			       X509v3_KU_DIGITAL_SIGNATURE)) {
2189159d09a2SMark Phalan 		    pkiDebug("%s: found digitalSignature KU\n",
2190159d09a2SMark Phalan 			     __FUNCTION__);
2191159d09a2SMark Phalan 		    *valid_eku = 1;
2192159d09a2SMark Phalan 		} else
2193159d09a2SMark Phalan 		    pkiDebug("%s: didn't find digitalSignature KU\n",
2194159d09a2SMark Phalan 			     __FUNCTION__);
2195159d09a2SMark Phalan 	    }
2196159d09a2SMark Phalan 	    ASN1_BIT_STRING_free(usage);
2197159d09a2SMark Phalan 	}
2198159d09a2SMark Phalan     }
2199159d09a2SMark Phalan     retval = 0;
2200159d09a2SMark Phalan cleanup:
2201159d09a2SMark Phalan     pkiDebug("%s: returning retval %d, valid_eku %d\n",
2202159d09a2SMark Phalan 	     __FUNCTION__, retval, *valid_eku);
2203159d09a2SMark Phalan     return retval;
2204159d09a2SMark Phalan }
2205159d09a2SMark Phalan 
2206159d09a2SMark Phalan krb5_error_code
pkinit_octetstring2key(krb5_context context,krb5_enctype etype,unsigned char * key,unsigned int dh_key_len,krb5_keyblock * key_block)2207159d09a2SMark Phalan pkinit_octetstring2key(krb5_context context,
2208159d09a2SMark Phalan 		       krb5_enctype etype,
2209159d09a2SMark Phalan 		       unsigned char *key,
2210159d09a2SMark Phalan 		       unsigned int dh_key_len,
2211159d09a2SMark Phalan 		       krb5_keyblock * key_block)
2212159d09a2SMark Phalan {
2213159d09a2SMark Phalan     krb5_error_code retval;
2214159d09a2SMark Phalan     unsigned char *buf = NULL;
2215159d09a2SMark Phalan     unsigned char md[SHA_DIGEST_LENGTH];
2216159d09a2SMark Phalan     unsigned char counter;
2217159d09a2SMark Phalan     size_t keybytes, keylength, offset;
2218159d09a2SMark Phalan     krb5_data random_data;
2219159d09a2SMark Phalan 
2220159d09a2SMark Phalan 
2221159d09a2SMark Phalan     if ((buf = (unsigned char *) malloc(dh_key_len)) == NULL) {
2222159d09a2SMark Phalan 	retval = ENOMEM;
2223159d09a2SMark Phalan 	goto cleanup;
2224159d09a2SMark Phalan     }
2225159d09a2SMark Phalan     (void) memset(buf, 0, dh_key_len);
2226159d09a2SMark Phalan 
2227159d09a2SMark Phalan     counter = 0;
2228159d09a2SMark Phalan     offset = 0;
2229159d09a2SMark Phalan     do {
2230159d09a2SMark Phalan 	SHA_CTX c;
2231159d09a2SMark Phalan 
2232159d09a2SMark Phalan 	SHA1_Init(&c);
2233159d09a2SMark Phalan 	SHA1_Update(&c, &counter, 1);
2234159d09a2SMark Phalan 	SHA1_Update(&c, key, dh_key_len);
2235159d09a2SMark Phalan 	SHA1_Final(md, &c);
2236159d09a2SMark Phalan 
2237159d09a2SMark Phalan 	if (dh_key_len - offset < sizeof(md))
2238159d09a2SMark Phalan 	    (void) memcpy(buf + offset, md, dh_key_len - offset);
2239159d09a2SMark Phalan 	else
2240159d09a2SMark Phalan 	    (void) memcpy(buf + offset, md, sizeof(md));
2241159d09a2SMark Phalan 
2242159d09a2SMark Phalan 	offset += sizeof(md);
2243159d09a2SMark Phalan 	counter++;
2244159d09a2SMark Phalan     } while (offset < dh_key_len);
2245159d09a2SMark Phalan 
2246159d09a2SMark Phalan     /* Solaris Kerberos */
2247159d09a2SMark Phalan     key_block->magic = KV5M_KEYBLOCK;
2248159d09a2SMark Phalan     key_block->enctype = etype;
2249159d09a2SMark Phalan 
2250159d09a2SMark Phalan     retval = krb5_c_keylengths(context, etype, &keybytes, &keylength);
2251159d09a2SMark Phalan     if (retval)
2252159d09a2SMark Phalan 	goto cleanup;
2253159d09a2SMark Phalan 
2254159d09a2SMark Phalan     key_block->length = keylength;
2255159d09a2SMark Phalan     key_block->contents = calloc(keylength, sizeof(unsigned char *));
2256159d09a2SMark Phalan     if (key_block->contents == NULL) {
2257159d09a2SMark Phalan 	retval = ENOMEM;
2258159d09a2SMark Phalan 	goto cleanup;
2259159d09a2SMark Phalan     }
2260159d09a2SMark Phalan 
2261159d09a2SMark Phalan     random_data.length = keybytes;
2262159d09a2SMark Phalan     random_data.data = (char *)buf;
2263159d09a2SMark Phalan 
2264159d09a2SMark Phalan     retval = krb5_c_random_to_key(context, etype, &random_data, key_block);
2265159d09a2SMark Phalan 
2266159d09a2SMark Phalan   cleanup:
2267159d09a2SMark Phalan     if (buf != NULL)
2268159d09a2SMark Phalan 	free(buf);
2269159d09a2SMark Phalan     if (retval && key_block->contents != NULL && key_block->length != 0) {
2270159d09a2SMark Phalan 	(void) memset(key_block->contents, 0, key_block->length);
2271159d09a2SMark Phalan 	key_block->length = 0;
2272159d09a2SMark Phalan     }
2273159d09a2SMark Phalan 
2274159d09a2SMark Phalan     return retval;
2275159d09a2SMark Phalan }
2276159d09a2SMark Phalan 
2277159d09a2SMark Phalan /* ARGSUSED */
2278159d09a2SMark Phalan krb5_error_code
client_create_dh(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context cryptoctx,pkinit_identity_crypto_context id_cryptoctx,int dh_size,unsigned char ** dh_params,unsigned int * dh_params_len,unsigned char ** dh_pubkey,unsigned int * dh_pubkey_len)2279159d09a2SMark Phalan client_create_dh(krb5_context context,
2280159d09a2SMark Phalan 		 pkinit_plg_crypto_context plg_cryptoctx,
2281159d09a2SMark Phalan 		 pkinit_req_crypto_context cryptoctx,
2282159d09a2SMark Phalan 		 pkinit_identity_crypto_context id_cryptoctx,
2283159d09a2SMark Phalan 		 int dh_size,
2284159d09a2SMark Phalan 		 unsigned char **dh_params,
2285159d09a2SMark Phalan 		 unsigned int *dh_params_len,
2286159d09a2SMark Phalan 		 unsigned char **dh_pubkey,
2287159d09a2SMark Phalan 		 unsigned int *dh_pubkey_len)
2288159d09a2SMark Phalan {
2289159d09a2SMark Phalan     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2290159d09a2SMark Phalan     unsigned char *buf = NULL;
2291159d09a2SMark Phalan     int dh_err = 0;
2292300fdee2SAndy Fiddaman     ASN1_INTEGER *asn_pub_key = NULL;
2293300fdee2SAndy Fiddaman     BIGNUM *p, *g, *q;
2294300fdee2SAndy Fiddaman     const BIGNUM *pub_key;
2295159d09a2SMark Phalan 
2296159d09a2SMark Phalan     if (cryptoctx->dh == NULL) {
2297159d09a2SMark Phalan 	if ((cryptoctx->dh = DH_new()) == NULL)
2298159d09a2SMark Phalan 	    goto cleanup;
2299300fdee2SAndy Fiddaman 	if ((g = BN_new()) == NULL || (q = BN_new()) == NULL)
2300159d09a2SMark Phalan 	    goto cleanup;
2301159d09a2SMark Phalan 
2302159d09a2SMark Phalan 	switch(dh_size) {
2303159d09a2SMark Phalan 	    case 1024:
2304159d09a2SMark Phalan 		pkiDebug("client uses 1024 DH keys\n");
2305300fdee2SAndy Fiddaman 		cryptoctx->dh = make_dhprime(pkinit_1024_dhprime,
2306300fdee2SAndy Fiddaman 		    sizeof(pkinit_1024_dhprime));
2307159d09a2SMark Phalan 		break;
2308159d09a2SMark Phalan 	    case 2048:
2309159d09a2SMark Phalan 		pkiDebug("client uses 2048 DH keys\n");
2310300fdee2SAndy Fiddaman 		cryptoctx->dh = make_dhprime(pkinit_2048_dhprime,
2311300fdee2SAndy Fiddaman 		    sizeof(pkinit_2048_dhprime));
2312159d09a2SMark Phalan 		break;
2313159d09a2SMark Phalan 	    case 4096:
2314159d09a2SMark Phalan 		pkiDebug("client uses 4096 DH keys\n");
2315300fdee2SAndy Fiddaman 		cryptoctx->dh = make_dhprime(pkinit_4096_dhprime,
2316300fdee2SAndy Fiddaman 		    sizeof(pkinit_4096_dhprime));
2317159d09a2SMark Phalan 		break;
2318159d09a2SMark Phalan 	}
2319300fdee2SAndy Fiddaman 	if (cryptoctx->dh == NULL)
2320300fdee2SAndy Fiddaman 		goto cleanup;
2321159d09a2SMark Phalan     }
2322159d09a2SMark Phalan 
2323159d09a2SMark Phalan     DH_generate_key(cryptoctx->dh);
2324300fdee2SAndy Fiddaman     DH_get0_key(cryptoctx->dh, &pub_key, NULL);
2325300fdee2SAndy Fiddaman 
2326159d09a2SMark Phalan /* Solaris Kerberos */
2327159d09a2SMark Phalan #ifdef DEBUG
2328159d09a2SMark Phalan     DH_check(cryptoctx->dh, &dh_err);
2329159d09a2SMark Phalan     if (dh_err != 0) {
2330159d09a2SMark Phalan 	pkiDebug("Warning: dh_check failed with %d\n", dh_err);
2331159d09a2SMark Phalan 	if (dh_err & DH_CHECK_P_NOT_PRIME)
2332159d09a2SMark Phalan 	    pkiDebug("p value is not prime\n");
2333159d09a2SMark Phalan 	if (dh_err & DH_CHECK_P_NOT_SAFE_PRIME)
2334159d09a2SMark Phalan 	    pkiDebug("p value is not a safe prime\n");
2335159d09a2SMark Phalan 	if (dh_err & DH_UNABLE_TO_CHECK_GENERATOR)
2336159d09a2SMark Phalan 	    pkiDebug("unable to check the generator value\n");
2337159d09a2SMark Phalan 	if (dh_err & DH_NOT_SUITABLE_GENERATOR)
2338159d09a2SMark Phalan 	    pkiDebug("the g value is not a generator\n");
2339159d09a2SMark Phalan     }
2340159d09a2SMark Phalan #endif
2341159d09a2SMark Phalan #ifdef DEBUG_DH
2342159d09a2SMark Phalan     print_dh(cryptoctx->dh, "client's DH params\n");
2343300fdee2SAndy Fiddaman     print_pubkey(pub_key, "client's pub_key=");
2344159d09a2SMark Phalan #endif
2345159d09a2SMark Phalan 
2346300fdee2SAndy Fiddaman     DH_check_pub_key(cryptoctx->dh, pub_key, &dh_err);
2347159d09a2SMark Phalan     if (dh_err != 0) {
2348159d09a2SMark Phalan 	pkiDebug("dh_check_pub_key failed with %d\n", dh_err);
2349159d09a2SMark Phalan 	goto cleanup;
2350159d09a2SMark Phalan     }
2351159d09a2SMark Phalan 
2352159d09a2SMark Phalan     /* pack DHparams */
2353159d09a2SMark Phalan     /* aglo: usually we could just call i2d_DHparams to encode DH params
2354159d09a2SMark Phalan      * however, PKINIT requires RFC3279 encoding and openssl does pkcs#3.
2355159d09a2SMark Phalan      */
2356300fdee2SAndy Fiddaman     DH_get0_pqg(cryptoctx->dh, (const BIGNUM **)&p, (const BIGNUM **)&q,
2357300fdee2SAndy Fiddaman 	(const BIGNUM **)&g);
2358300fdee2SAndy Fiddaman     retval = pkinit_encode_dh_params(p, g, q, dh_params, dh_params_len);
2359159d09a2SMark Phalan     if (retval)
2360159d09a2SMark Phalan 	goto cleanup;
2361159d09a2SMark Phalan 
2362159d09a2SMark Phalan     /* pack DH public key */
2363159d09a2SMark Phalan     /* Diffie-Hellman public key must be ASN1 encoded as an INTEGER; this
2364159d09a2SMark Phalan      * encoding shall be used as the contents (the value) of the
2365159d09a2SMark Phalan      * subjectPublicKey component (a BIT STRING) of the SubjectPublicKeyInfo
2366159d09a2SMark Phalan      * data element
2367159d09a2SMark Phalan      */
2368300fdee2SAndy Fiddaman     if ((asn_pub_key = BN_to_ASN1_INTEGER(pub_key, NULL)) == NULL)
2369159d09a2SMark Phalan 	goto cleanup;
2370300fdee2SAndy Fiddaman     *dh_pubkey_len = i2d_ASN1_INTEGER(asn_pub_key, NULL);
2371159d09a2SMark Phalan     if ((buf = *dh_pubkey = (unsigned char *)
2372300fdee2SAndy Fiddaman         malloc((size_t) *dh_pubkey_len)) == NULL) {
2373300fdee2SAndy Fiddaman 	    retval = ENOMEM;
2374300fdee2SAndy Fiddaman 	    goto cleanup;
2375159d09a2SMark Phalan     }
2376300fdee2SAndy Fiddaman     i2d_ASN1_INTEGER(asn_pub_key, &buf);
2377159d09a2SMark Phalan 
2378300fdee2SAndy Fiddaman     if (asn_pub_key != NULL)
2379300fdee2SAndy Fiddaman 	ASN1_INTEGER_free(asn_pub_key);
2380159d09a2SMark Phalan 
2381159d09a2SMark Phalan     retval = 0;
2382159d09a2SMark Phalan     return retval;
2383159d09a2SMark Phalan 
2384159d09a2SMark Phalan   cleanup:
2385159d09a2SMark Phalan     if (cryptoctx->dh != NULL)
2386159d09a2SMark Phalan 	DH_free(cryptoctx->dh);
2387159d09a2SMark Phalan     cryptoctx->dh = NULL;
2388159d09a2SMark Phalan     if (*dh_params != NULL)
2389159d09a2SMark Phalan 	free(*dh_params);
2390159d09a2SMark Phalan     *dh_params = NULL;
2391159d09a2SMark Phalan     if (*dh_pubkey != NULL)
2392159d09a2SMark Phalan 	free(*dh_pubkey);
2393159d09a2SMark Phalan     *dh_pubkey = NULL;
2394300fdee2SAndy Fiddaman     if (asn_pub_key != NULL)
2395300fdee2SAndy Fiddaman 	ASN1_INTEGER_free(asn_pub_key);
2396159d09a2SMark Phalan 
2397159d09a2SMark Phalan     return retval;
2398159d09a2SMark Phalan }
2399159d09a2SMark Phalan 
2400159d09a2SMark Phalan /* ARGSUSED */
2401159d09a2SMark Phalan krb5_error_code
client_process_dh(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context cryptoctx,pkinit_identity_crypto_context id_cryptoctx,unsigned char * subjectPublicKey_data,unsigned int subjectPublicKey_length,unsigned char ** client_key,unsigned int * client_key_len)2402159d09a2SMark Phalan client_process_dh(krb5_context context,
2403159d09a2SMark Phalan 		  pkinit_plg_crypto_context plg_cryptoctx,
2404159d09a2SMark Phalan 		  pkinit_req_crypto_context cryptoctx,
2405159d09a2SMark Phalan 		  pkinit_identity_crypto_context id_cryptoctx,
2406159d09a2SMark Phalan 		  unsigned char *subjectPublicKey_data,
2407159d09a2SMark Phalan 		  unsigned int subjectPublicKey_length,
2408159d09a2SMark Phalan 		  unsigned char **client_key,
2409159d09a2SMark Phalan 		  unsigned int *client_key_len)
2410159d09a2SMark Phalan {
2411159d09a2SMark Phalan     /* Solaris Kerberos */
2412159d09a2SMark Phalan     krb5_error_code retval = KRB5_PREAUTH_FAILED;
2413159d09a2SMark Phalan     BIGNUM *server_pub_key = NULL;
2414159d09a2SMark Phalan     ASN1_INTEGER *pub_key = NULL;
2415159d09a2SMark Phalan     const unsigned char *p = NULL;
2416159d09a2SMark Phalan     unsigned char *data = NULL;
2417159d09a2SMark Phalan     long data_len;
2418159d09a2SMark Phalan 
2419159d09a2SMark Phalan     /* decode subjectPublicKey (retrieve INTEGER from OCTET_STRING) */
2420159d09a2SMark Phalan 
2421159d09a2SMark Phalan     if (der_decode_data(subjectPublicKey_data, (long)subjectPublicKey_length,
2422159d09a2SMark Phalan 			&data, &data_len) != 0) {
2423159d09a2SMark Phalan 	pkiDebug("failed to decode subjectPublicKey\n");
2424159d09a2SMark Phalan 	/* Solaris Kerberos */
2425159d09a2SMark Phalan 	retval = KRB5_PREAUTH_FAILED;
2426159d09a2SMark Phalan 	goto cleanup;
2427159d09a2SMark Phalan     }
2428159d09a2SMark Phalan 
2429159d09a2SMark Phalan     *client_key_len = DH_size(cryptoctx->dh);
2430159d09a2SMark Phalan     if ((*client_key = (unsigned char *)
2431159d09a2SMark Phalan 	    malloc((size_t) *client_key_len)) == NULL) {
2432159d09a2SMark Phalan 	retval = ENOMEM;
2433159d09a2SMark Phalan 	goto cleanup;
2434159d09a2SMark Phalan     }
2435159d09a2SMark Phalan     p = data;
2436159d09a2SMark Phalan     if ((pub_key = d2i_ASN1_INTEGER(NULL, &p, data_len)) == NULL)
2437159d09a2SMark Phalan 	goto cleanup;
2438159d09a2SMark Phalan     if ((server_pub_key = ASN1_INTEGER_to_BN(pub_key, NULL)) == NULL)
2439159d09a2SMark Phalan 	goto cleanup;
2440159d09a2SMark Phalan 
2441159d09a2SMark Phalan     DH_compute_key(*client_key, server_pub_key, cryptoctx->dh);
2442159d09a2SMark Phalan #ifdef DEBUG_DH
2443159d09a2SMark Phalan     print_pubkey(server_pub_key, "server's pub_key=");
2444159d09a2SMark Phalan     pkiDebug("client secret key (%d)= ", *client_key_len);
2445159d09a2SMark Phalan     print_buffer(*client_key, *client_key_len);
2446159d09a2SMark Phalan #endif
2447159d09a2SMark Phalan 
2448159d09a2SMark Phalan     retval = 0;
2449159d09a2SMark Phalan     if (server_pub_key != NULL)
2450159d09a2SMark Phalan 	BN_free(server_pub_key);
2451159d09a2SMark Phalan     if (pub_key != NULL)
2452159d09a2SMark Phalan 	ASN1_INTEGER_free(pub_key);
2453159d09a2SMark Phalan     if (data != NULL)
2454159d09a2SMark Phalan 	free (data);
2455159d09a2SMark Phalan 
2456159d09a2SMark Phalan     return retval;
2457159d09a2SMark Phalan 
2458159d09a2SMark Phalan   cleanup:
2459159d09a2SMark Phalan     if (*client_key != NULL)
2460159d09a2SMark Phalan 	free(*client_key);
2461159d09a2SMark Phalan     *client_key = NULL;
2462159d09a2SMark Phalan     if (pub_key != NULL)
2463159d09a2SMark Phalan 	ASN1_INTEGER_free(pub_key);
2464159d09a2SMark Phalan     if (data != NULL)
2465159d09a2SMark Phalan 	free (data);
2466159d09a2SMark Phalan 
2467159d09a2SMark Phalan     return retval;
2468159d09a2SMark Phalan }
2469159d09a2SMark Phalan 
2470159d09a2SMark Phalan /* ARGSUSED */
2471159d09a2SMark Phalan krb5_error_code
server_check_dh(krb5_context context,pkinit_plg_crypto_context cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_octet_data * dh_params,int minbits)2472159d09a2SMark Phalan server_check_dh(krb5_context context,
2473159d09a2SMark Phalan 		pkinit_plg_crypto_context cryptoctx,
2474159d09a2SMark Phalan 		pkinit_req_crypto_context req_cryptoctx,
2475159d09a2SMark Phalan 		pkinit_identity_crypto_context id_cryptoctx,
2476159d09a2SMark Phalan 		krb5_octet_data *dh_params,
2477159d09a2SMark Phalan 		int minbits)
2478159d09a2SMark Phalan {
2479159d09a2SMark Phalan     DH *dh = NULL;
2480159d09a2SMark Phalan     unsigned char *tmp = NULL;
2481159d09a2SMark Phalan     int dh_prime_bits;
2482159d09a2SMark Phalan     krb5_error_code retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
2483300fdee2SAndy Fiddaman     const BIGNUM *p, *g, *q, *p2;
2484159d09a2SMark Phalan 
2485159d09a2SMark Phalan     tmp = dh_params->data;
2486159d09a2SMark Phalan     dh = DH_new();
2487159d09a2SMark Phalan     dh = pkinit_decode_dh_params(&dh, &tmp, dh_params->length);
2488159d09a2SMark Phalan     if (dh == NULL) {
2489159d09a2SMark Phalan 	pkiDebug("failed to decode dhparams\n");
2490159d09a2SMark Phalan 	goto cleanup;
2491159d09a2SMark Phalan     }
2492159d09a2SMark Phalan 
2493300fdee2SAndy Fiddaman     DH_get0_pqg(dh, &p, &q, &g);
2494300fdee2SAndy Fiddaman 
2495159d09a2SMark Phalan     /* KDC SHOULD check to see if the key parameters satisfy its policy */
2496300fdee2SAndy Fiddaman     dh_prime_bits = BN_num_bits(p);
2497159d09a2SMark Phalan     if (minbits && dh_prime_bits < minbits) {
2498159d09a2SMark Phalan 	pkiDebug("client sent dh params with %d bits, we require %d\n",
2499159d09a2SMark Phalan 		 dh_prime_bits, minbits);
2500159d09a2SMark Phalan 	goto cleanup;
2501159d09a2SMark Phalan     }
2502159d09a2SMark Phalan 
2503159d09a2SMark Phalan     /* check dhparams is group 2 */
2504300fdee2SAndy Fiddaman     DH_get0_pqg(cryptoctx->dh_1024, &p2, NULL, NULL);
2505300fdee2SAndy Fiddaman     if (pkinit_check_dh_params(p2, p, g, q) == 0) {
2506159d09a2SMark Phalan 	retval = 0;
2507159d09a2SMark Phalan 	goto cleanup;
2508159d09a2SMark Phalan     }
2509159d09a2SMark Phalan 
2510159d09a2SMark Phalan     /* check dhparams is group 14 */
2511300fdee2SAndy Fiddaman     DH_get0_pqg(cryptoctx->dh_2048, &p2, NULL, NULL);
2512300fdee2SAndy Fiddaman     if (pkinit_check_dh_params(p2, p, g, q) == 0) {
2513159d09a2SMark Phalan 	retval = 0;
2514159d09a2SMark Phalan 	goto cleanup;
2515159d09a2SMark Phalan     }
2516159d09a2SMark Phalan 
2517159d09a2SMark Phalan     /* check dhparams is group 16 */
2518300fdee2SAndy Fiddaman     DH_get0_pqg(cryptoctx->dh_4096, &p2, NULL, NULL);
2519300fdee2SAndy Fiddaman     if (pkinit_check_dh_params(p2, p, g, q) == 0) {
2520159d09a2SMark Phalan 	retval = 0;
2521159d09a2SMark Phalan 	goto cleanup;
2522159d09a2SMark Phalan     }
2523159d09a2SMark Phalan 
2524159d09a2SMark Phalan   cleanup:
2525159d09a2SMark Phalan     if (retval == 0)
2526159d09a2SMark Phalan 	req_cryptoctx->dh = dh;
2527159d09a2SMark Phalan     else
2528159d09a2SMark Phalan 	DH_free(dh);
2529159d09a2SMark Phalan 
2530159d09a2SMark Phalan     return retval;
2531159d09a2SMark Phalan }
2532159d09a2SMark Phalan 
2533159d09a2SMark Phalan /* kdc's dh function */
2534159d09a2SMark Phalan /* ARGSUSED */
2535159d09a2SMark Phalan krb5_error_code
server_process_dh(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context cryptoctx,pkinit_identity_crypto_context id_cryptoctx,unsigned char * data,unsigned int data_len,unsigned char ** dh_pubkey,unsigned int * dh_pubkey_len,unsigned char ** server_key,unsigned int * server_key_len)2536159d09a2SMark Phalan server_process_dh(krb5_context context,
2537159d09a2SMark Phalan 		  pkinit_plg_crypto_context plg_cryptoctx,
2538159d09a2SMark Phalan 		  pkinit_req_crypto_context cryptoctx,
2539159d09a2SMark Phalan 		  pkinit_identity_crypto_context id_cryptoctx,
2540159d09a2SMark Phalan 		  unsigned char *data,
2541159d09a2SMark Phalan 		  unsigned int data_len,
2542159d09a2SMark Phalan 		  unsigned char **dh_pubkey,
2543159d09a2SMark Phalan 		  unsigned int *dh_pubkey_len,
2544159d09a2SMark Phalan 		  unsigned char **server_key,
2545159d09a2SMark Phalan 		  unsigned int *server_key_len)
2546159d09a2SMark Phalan {
2547159d09a2SMark Phalan     /* Solaris Kerberos */
2548159d09a2SMark Phalan     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2549159d09a2SMark Phalan     DH *dh = NULL, *dh_server = NULL;
2550300fdee2SAndy Fiddaman     const BIGNUM *p, *g, *q, *s_pub_key;
2551300fdee2SAndy Fiddaman     BIGNUM *pub_key;
2552300fdee2SAndy Fiddaman     unsigned char *s = NULL;
2553300fdee2SAndy Fiddaman     ASN1_INTEGER *asn_pub_key = NULL;
2554159d09a2SMark Phalan 
2555159d09a2SMark Phalan     /* get client's received DH parameters that we saved in server_check_dh */
2556159d09a2SMark Phalan     dh = cryptoctx->dh;
2557159d09a2SMark Phalan 
2558159d09a2SMark Phalan     dh_server = DH_new();
2559159d09a2SMark Phalan     if (dh_server == NULL)
2560159d09a2SMark Phalan 	goto cleanup;
2561300fdee2SAndy Fiddaman     DH_get0_pqg(dh, &p, &g, &q);
2562300fdee2SAndy Fiddaman     DH_set0_pqg(dh_server, BN_dup(p), BN_dup(g), BN_dup(q));
2563159d09a2SMark Phalan 
2564159d09a2SMark Phalan     /* decode client's public key */
2565300fdee2SAndy Fiddaman     s = data;
2566300fdee2SAndy Fiddaman     asn_pub_key = d2i_ASN1_INTEGER(NULL,
2567300fdee2SAndy Fiddaman 	(const unsigned char **)&s, (int)data_len);
2568300fdee2SAndy Fiddaman     if (asn_pub_key == NULL)
2569159d09a2SMark Phalan 	goto cleanup;
2570300fdee2SAndy Fiddaman     pub_key = ASN1_INTEGER_to_BN(asn_pub_key, NULL);
2571300fdee2SAndy Fiddaman     if (pub_key == NULL)
2572159d09a2SMark Phalan 	goto cleanup;
2573300fdee2SAndy Fiddaman     DH_set0_key(dh, pub_key, NULL);
2574300fdee2SAndy Fiddaman     ASN1_INTEGER_free(asn_pub_key);
2575159d09a2SMark Phalan 
2576159d09a2SMark Phalan     if (!DH_generate_key(dh_server))
2577159d09a2SMark Phalan 	goto cleanup;
2578159d09a2SMark Phalan 
2579159d09a2SMark Phalan     /* generate DH session key */
2580159d09a2SMark Phalan     *server_key_len = DH_size(dh_server);
2581300fdee2SAndy Fiddaman     if ((*server_key = (unsigned char *) malloc((size_t)*server_key_len))
2582300fdee2SAndy Fiddaman 	== NULL)
2583300fdee2SAndy Fiddaman 	    goto cleanup;
2584300fdee2SAndy Fiddaman     DH_compute_key(*server_key, pub_key, dh_server);
2585300fdee2SAndy Fiddaman     DH_get0_key(dh_server, &s_pub_key, NULL);
2586159d09a2SMark Phalan 
2587159d09a2SMark Phalan #ifdef DEBUG_DH
2588159d09a2SMark Phalan     print_dh(dh_server, "client&server's DH params\n");
2589300fdee2SAndy Fiddaman     print_pubkey(pub_key, "client's pub_key=");
2590300fdee2SAndy Fiddaman     print_pubkey(s_pub_key, "server's pub_key=");
2591159d09a2SMark Phalan     pkiDebug("server secret key=");
2592159d09a2SMark Phalan     print_buffer(*server_key, *server_key_len);
2593159d09a2SMark Phalan #endif
2594159d09a2SMark Phalan 
2595159d09a2SMark Phalan     /* KDC reply */
2596159d09a2SMark Phalan     /* pack DH public key */
2597159d09a2SMark Phalan     /* Diffie-Hellman public key must be ASN1 encoded as an INTEGER; this
2598159d09a2SMark Phalan      * encoding shall be used as the contents (the value) of the
2599159d09a2SMark Phalan      * subjectPublicKey component (a BIT STRING) of the SubjectPublicKeyInfo
2600159d09a2SMark Phalan      * data element
2601159d09a2SMark Phalan      */
2602300fdee2SAndy Fiddaman     if ((asn_pub_key = BN_to_ASN1_INTEGER(s_pub_key, NULL)) == NULL)
2603159d09a2SMark Phalan 	goto cleanup;
2604300fdee2SAndy Fiddaman     *dh_pubkey_len = i2d_ASN1_INTEGER(asn_pub_key, NULL);
2605300fdee2SAndy Fiddaman     if ((s = *dh_pubkey = (unsigned char *) malloc((size_t)*dh_pubkey_len))
2606300fdee2SAndy Fiddaman 	== NULL)
2607300fdee2SAndy Fiddaman 	    goto cleanup;
2608300fdee2SAndy Fiddaman     i2d_ASN1_INTEGER(asn_pub_key, &s);
2609300fdee2SAndy Fiddaman     if (asn_pub_key != NULL)
2610300fdee2SAndy Fiddaman 	ASN1_INTEGER_free(asn_pub_key);
2611159d09a2SMark Phalan 
2612159d09a2SMark Phalan     retval = 0;
2613159d09a2SMark Phalan 
2614159d09a2SMark Phalan     if (dh_server != NULL)
2615159d09a2SMark Phalan 	DH_free(dh_server);
2616159d09a2SMark Phalan     return retval;
2617159d09a2SMark Phalan 
2618159d09a2SMark Phalan   cleanup:
2619159d09a2SMark Phalan     if (dh_server != NULL)
2620159d09a2SMark Phalan 	DH_free(dh_server);
2621159d09a2SMark Phalan     if (*dh_pubkey != NULL)
2622159d09a2SMark Phalan 	free(*dh_pubkey);
2623159d09a2SMark Phalan     if (*server_key != NULL)
2624159d09a2SMark Phalan 	free(*server_key);
2625159d09a2SMark Phalan 
2626159d09a2SMark Phalan     return retval;
2627159d09a2SMark Phalan }
2628159d09a2SMark Phalan 
262931a29035SMark Phalan /*
263031a29035SMark Phalan  * Solaris Kerberos:
263131a29035SMark Phalan  * Add locking around did_init to make it MT-safe.
263231a29035SMark Phalan  */
263331a29035SMark Phalan static krb5_error_code
openssl_init()2634159d09a2SMark Phalan openssl_init()
2635159d09a2SMark Phalan {
263631a29035SMark Phalan     krb5_error_code ret = 0;
2637159d09a2SMark Phalan     static int did_init = 0;
263831a29035SMark Phalan     static k5_mutex_t init_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
263931a29035SMark Phalan 
264031a29035SMark Phalan     ret = k5_mutex_lock(&init_mutex);
264131a29035SMark Phalan     if (ret == 0) {
264231a29035SMark Phalan 	if (!did_init) {
264331a29035SMark Phalan 	    /* initialize openssl routines */
2644553e44ceSAndrew Stormont #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
2645300fdee2SAndy Fiddaman 	    /*
2646300fdee2SAndy Fiddaman 	     * As of version 1.1.0, OpenSSL will automatically allocate
2647300fdee2SAndy Fiddaman 	     * resources as-needed.
2648300fdee2SAndy Fiddaman 	     */
264931a29035SMark Phalan 	    CRYPTO_malloc_init();
265031a29035SMark Phalan 	    ERR_load_crypto_strings();
265131a29035SMark Phalan 	    OpenSSL_add_all_algorithms();
2652300fdee2SAndy Fiddaman #endif
265331a29035SMark Phalan 	    did_init++;
265431a29035SMark Phalan 	}
265531a29035SMark Phalan 	k5_mutex_unlock(&init_mutex);
2656159d09a2SMark Phalan     }
265731a29035SMark Phalan     return (ret);
2658159d09a2SMark Phalan }
2659159d09a2SMark Phalan 
2660159d09a2SMark Phalan static krb5_error_code
pkinit_encode_dh_params(const BIGNUM * p,const BIGNUM * g,const BIGNUM * q,unsigned char ** buf,unsigned int * buf_len)2661300fdee2SAndy Fiddaman pkinit_encode_dh_params(const BIGNUM *p, const BIGNUM *g, const BIGNUM *q,
2662159d09a2SMark Phalan 			unsigned char **buf, unsigned int *buf_len)
2663159d09a2SMark Phalan {
2664159d09a2SMark Phalan     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
2665159d09a2SMark Phalan     int bufsize = 0, r = 0;
2666159d09a2SMark Phalan     unsigned char *tmp = NULL;
2667159d09a2SMark Phalan     ASN1_INTEGER *ap = NULL, *ag = NULL, *aq = NULL;
2668159d09a2SMark Phalan 
2669159d09a2SMark Phalan     if ((ap = BN_to_ASN1_INTEGER(p, NULL)) == NULL)
2670159d09a2SMark Phalan 	goto cleanup;
2671159d09a2SMark Phalan     if ((ag = BN_to_ASN1_INTEGER(g, NULL)) == NULL)
2672159d09a2SMark Phalan 	goto cleanup;
2673159d09a2SMark Phalan     if ((aq = BN_to_ASN1_INTEGER(q, NULL)) == NULL)
2674159d09a2SMark Phalan 	goto cleanup;
2675159d09a2SMark Phalan     bufsize = i2d_ASN1_INTEGER(ap, NULL);
2676159d09a2SMark Phalan     bufsize += i2d_ASN1_INTEGER(ag, NULL);
2677159d09a2SMark Phalan     bufsize += i2d_ASN1_INTEGER(aq, NULL);
2678159d09a2SMark Phalan 
2679159d09a2SMark Phalan     r = ASN1_object_size(1, bufsize, V_ASN1_SEQUENCE);
2680159d09a2SMark Phalan 
2681159d09a2SMark Phalan     tmp = *buf = (unsigned char *)malloc((size_t) r);
2682159d09a2SMark Phalan     if (tmp == NULL)
2683159d09a2SMark Phalan 	goto cleanup;
2684159d09a2SMark Phalan 
2685159d09a2SMark Phalan     ASN1_put_object(&tmp, 1, bufsize, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
2686159d09a2SMark Phalan 
2687159d09a2SMark Phalan     i2d_ASN1_INTEGER(ap, &tmp);
2688159d09a2SMark Phalan     i2d_ASN1_INTEGER(ag, &tmp);
2689159d09a2SMark Phalan     i2d_ASN1_INTEGER(aq, &tmp);
2690159d09a2SMark Phalan 
2691159d09a2SMark Phalan     *buf_len = r;
2692159d09a2SMark Phalan 
2693159d09a2SMark Phalan     retval = 0;
2694159d09a2SMark Phalan 
2695159d09a2SMark Phalan cleanup:
2696159d09a2SMark Phalan     if (ap != NULL)
2697159d09a2SMark Phalan 	ASN1_INTEGER_free(ap);
2698159d09a2SMark Phalan     if (ag != NULL)
2699159d09a2SMark Phalan 	ASN1_INTEGER_free(ag);
2700159d09a2SMark Phalan     if (aq != NULL)
2701159d09a2SMark Phalan 	ASN1_INTEGER_free(aq);
2702159d09a2SMark Phalan 
2703159d09a2SMark Phalan     return retval;
2704159d09a2SMark Phalan }
2705159d09a2SMark Phalan 
2706553e44ceSAndrew Stormont #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
2707300fdee2SAndy Fiddaman 
2708159d09a2SMark Phalan static DH *
pkinit_decode_dh_params(DH ** a,unsigned char ** pp,unsigned int len)2709159d09a2SMark Phalan pkinit_decode_dh_params(DH ** a, unsigned char **pp, unsigned int len)
2710159d09a2SMark Phalan {
2711159d09a2SMark Phalan     ASN1_INTEGER ai, *aip = NULL;
2712159d09a2SMark Phalan     long length = (long) len;
2713159d09a2SMark Phalan 
2714159d09a2SMark Phalan     M_ASN1_D2I_vars(a, DH *, DH_new);
2715159d09a2SMark Phalan 
2716159d09a2SMark Phalan     M_ASN1_D2I_Init();
2717159d09a2SMark Phalan     M_ASN1_D2I_start_sequence();
2718159d09a2SMark Phalan     aip = &ai;
2719159d09a2SMark Phalan     ai.data = NULL;
2720159d09a2SMark Phalan     ai.length = 0;
2721159d09a2SMark Phalan     M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER);
2722159d09a2SMark Phalan     if (aip == NULL)
2723159d09a2SMark Phalan 	return NULL;
2724159d09a2SMark Phalan     else {
2725159d09a2SMark Phalan 	(*a)->p = ASN1_INTEGER_to_BN(aip, NULL);
2726159d09a2SMark Phalan 	if ((*a)->p == NULL)
2727159d09a2SMark Phalan 	    return NULL;
2728159d09a2SMark Phalan 	if (ai.data != NULL) {
2729159d09a2SMark Phalan 	    OPENSSL_free(ai.data);
2730159d09a2SMark Phalan 	    ai.data = NULL;
2731159d09a2SMark Phalan 	    ai.length = 0;
2732159d09a2SMark Phalan 	}
2733159d09a2SMark Phalan     }
2734159d09a2SMark Phalan     M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER);
2735159d09a2SMark Phalan     if (aip == NULL)
2736159d09a2SMark Phalan 	return NULL;
2737159d09a2SMark Phalan     else {
2738159d09a2SMark Phalan 	(*a)->g = ASN1_INTEGER_to_BN(aip, NULL);
2739159d09a2SMark Phalan 	if ((*a)->g == NULL)
2740159d09a2SMark Phalan 	    return NULL;
2741159d09a2SMark Phalan 	if (ai.data != NULL) {
2742159d09a2SMark Phalan 	    OPENSSL_free(ai.data);
2743159d09a2SMark Phalan 	    ai.data = NULL;
2744159d09a2SMark Phalan 	    ai.length = 0;
2745159d09a2SMark Phalan 	}
2746159d09a2SMark Phalan 
2747159d09a2SMark Phalan     }
2748159d09a2SMark Phalan     M_ASN1_D2I_get_x(ASN1_INTEGER, aip, d2i_ASN1_INTEGER);
2749159d09a2SMark Phalan     if (aip == NULL)
2750159d09a2SMark Phalan 	return NULL;
2751159d09a2SMark Phalan     else {
2752159d09a2SMark Phalan 	(*a)->q = ASN1_INTEGER_to_BN(aip, NULL);
2753159d09a2SMark Phalan 	if ((*a)->q == NULL)
2754159d09a2SMark Phalan 	    return NULL;
2755159d09a2SMark Phalan 	if (ai.data != NULL) {
2756159d09a2SMark Phalan 	    OPENSSL_free(ai.data);
2757159d09a2SMark Phalan 	    ai.data = NULL;
2758159d09a2SMark Phalan 	    ai.length = 0;
2759159d09a2SMark Phalan 	}
2760159d09a2SMark Phalan 
2761159d09a2SMark Phalan     }
2762159d09a2SMark Phalan     M_ASN1_D2I_end_sequence();
2763159d09a2SMark Phalan     M_ASN1_D2I_Finish(a, DH_free, 0);
2764159d09a2SMark Phalan 
2765159d09a2SMark Phalan }
2766159d09a2SMark Phalan 
2767300fdee2SAndy Fiddaman #else
2768300fdee2SAndy Fiddaman 
2769300fdee2SAndy Fiddaman /*
2770300fdee2SAndy Fiddaman  * This is taken from the internal dh_asn1.c file in OpenSSL 1.1, modified to
2771300fdee2SAndy Fiddaman  * make q an optional field.
2772300fdee2SAndy Fiddaman  */
2773300fdee2SAndy Fiddaman 
2774300fdee2SAndy Fiddaman typedef struct {
2775300fdee2SAndy Fiddaman     ASN1_BIT_STRING *seed;
2776300fdee2SAndy Fiddaman     BIGNUM *counter;
2777300fdee2SAndy Fiddaman } int_dhvparams;
2778300fdee2SAndy Fiddaman 
2779300fdee2SAndy Fiddaman typedef struct {
2780300fdee2SAndy Fiddaman     BIGNUM *p;
2781300fdee2SAndy Fiddaman     BIGNUM *q;
2782300fdee2SAndy Fiddaman     BIGNUM *g;
2783300fdee2SAndy Fiddaman     BIGNUM *j;
2784300fdee2SAndy Fiddaman     int_dhvparams *vparams;
2785300fdee2SAndy Fiddaman } int_dhx942_dh;
2786300fdee2SAndy Fiddaman 
2787300fdee2SAndy Fiddaman ASN1_SEQUENCE(DHvparams) = {
2788300fdee2SAndy Fiddaman     ASN1_SIMPLE(int_dhvparams, seed, ASN1_BIT_STRING),
2789300fdee2SAndy Fiddaman     ASN1_SIMPLE(int_dhvparams, counter, BIGNUM)
2790300fdee2SAndy Fiddaman } static_ASN1_SEQUENCE_END_name(int_dhvparams, DHvparams)
2791300fdee2SAndy Fiddaman 
2792300fdee2SAndy Fiddaman ASN1_SEQUENCE(DHxparams) = {
2793300fdee2SAndy Fiddaman     ASN1_SIMPLE(int_dhx942_dh, p, BIGNUM),
2794300fdee2SAndy Fiddaman     ASN1_SIMPLE(int_dhx942_dh, g, BIGNUM),
2795300fdee2SAndy Fiddaman     ASN1_OPT(int_dhx942_dh, q, BIGNUM),
2796300fdee2SAndy Fiddaman     ASN1_OPT(int_dhx942_dh, j, BIGNUM),
2797300fdee2SAndy Fiddaman     ASN1_OPT(int_dhx942_dh, vparams, DHvparams),
2798300fdee2SAndy Fiddaman } static_ASN1_SEQUENCE_END_name(int_dhx942_dh, DHxparams)
2799300fdee2SAndy Fiddaman 
2800300fdee2SAndy Fiddaman static DH *
2801300fdee2SAndy Fiddaman pkinit_decode_dh_params(DH **a, unsigned char **pp, unsigned int len)
2802300fdee2SAndy Fiddaman {
2803300fdee2SAndy Fiddaman 	int_dhx942_dh *params;
2804300fdee2SAndy Fiddaman 	DH *dh = *a;
2805300fdee2SAndy Fiddaman 
2806300fdee2SAndy Fiddaman 	if (dh == NULL)
2807300fdee2SAndy Fiddaman 		return NULL;
2808300fdee2SAndy Fiddaman 
2809300fdee2SAndy Fiddaman 	params = (int_dhx942_dh *)ASN1_item_d2i(NULL,
2810300fdee2SAndy Fiddaman 	    (const unsigned char **)pp, len, ASN1_ITEM_rptr(DHxparams));
2811300fdee2SAndy Fiddaman 	if (params == NULL) {
2812300fdee2SAndy Fiddaman 		DH_free(dh);
2813300fdee2SAndy Fiddaman 		return NULL;
2814300fdee2SAndy Fiddaman 	}
2815300fdee2SAndy Fiddaman 
2816300fdee2SAndy Fiddaman 	DH_set0_pqg(dh, params->p, params->q, params->g);
2817300fdee2SAndy Fiddaman 	params->p = params->q = params->g = NULL;
2818300fdee2SAndy Fiddaman 	ASN1_item_free((ASN1_VALUE *)params, ASN1_ITEM_rptr(DHxparams));
2819300fdee2SAndy Fiddaman 	return dh;
2820300fdee2SAndy Fiddaman }
2821300fdee2SAndy Fiddaman 
2822553e44ceSAndrew Stormont #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L || LIBRESSL_VERSION_NUMBER */
2823300fdee2SAndy Fiddaman 
2824159d09a2SMark Phalan static krb5_error_code
pkinit_create_sequence_of_principal_identifiers(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,int type,krb5_data ** out_data)2825159d09a2SMark Phalan pkinit_create_sequence_of_principal_identifiers(
2826159d09a2SMark Phalan     krb5_context context,
2827159d09a2SMark Phalan     pkinit_plg_crypto_context plg_cryptoctx,
2828159d09a2SMark Phalan     pkinit_req_crypto_context req_cryptoctx,
2829159d09a2SMark Phalan     pkinit_identity_crypto_context id_cryptoctx,
2830159d09a2SMark Phalan     int type,
2831159d09a2SMark Phalan     krb5_data **out_data)
2832159d09a2SMark Phalan {
2833159d09a2SMark Phalan     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2834159d09a2SMark Phalan     krb5_external_principal_identifier **krb5_trusted_certifiers = NULL;
2835159d09a2SMark Phalan     krb5_data *td_certifiers = NULL, *data = NULL;
2836159d09a2SMark Phalan     krb5_typed_data **typed_data = NULL;
2837159d09a2SMark Phalan 
2838159d09a2SMark Phalan     switch(type) {
2839159d09a2SMark Phalan 	case TD_TRUSTED_CERTIFIERS:
2840159d09a2SMark Phalan 	    retval = create_krb5_trustedCertifiers(context, plg_cryptoctx,
2841159d09a2SMark Phalan 		req_cryptoctx, id_cryptoctx, &krb5_trusted_certifiers);
2842159d09a2SMark Phalan 	    if (retval) {
2843159d09a2SMark Phalan 		pkiDebug("create_krb5_trustedCertifiers failed\n");
2844159d09a2SMark Phalan 		goto cleanup;
28453f8dd771SAndy Fiddaman 	    }
2846159d09a2SMark Phalan 	    break;
2847159d09a2SMark Phalan 	case TD_INVALID_CERTIFICATES:
2848159d09a2SMark Phalan 	    retval = create_krb5_invalidCertificates(context, plg_cryptoctx,
2849159d09a2SMark Phalan 		req_cryptoctx, id_cryptoctx, &krb5_trusted_certifiers);
2850159d09a2SMark Phalan 	    if (retval) {
2851159d09a2SMark Phalan 		pkiDebug("create_krb5_invalidCertificates failed\n");
2852159d09a2SMark Phalan 		goto cleanup;
28533f8dd771SAndy Fiddaman 	    }
2854159d09a2SMark Phalan 	    break;
2855159d09a2SMark Phalan 	default:
2856159d09a2SMark Phalan 	    retval = -1;
2857159d09a2SMark Phalan 	    goto cleanup;
2858159d09a2SMark Phalan     }
2859159d09a2SMark Phalan 
2860159d09a2SMark Phalan     retval = k5int_encode_krb5_td_trusted_certifiers((const krb5_external_principal_identifier **)krb5_trusted_certifiers, &td_certifiers);
2861159d09a2SMark Phalan     if (retval) {
2862159d09a2SMark Phalan 	pkiDebug("encode_krb5_td_trusted_certifiers failed\n");
2863159d09a2SMark Phalan 	goto cleanup;
2864159d09a2SMark Phalan     }
2865159d09a2SMark Phalan #ifdef DEBUG_ASN1
2866159d09a2SMark Phalan     print_buffer_bin((unsigned char *)td_certifiers->data,
2867159d09a2SMark Phalan 		     td_certifiers->length, "/tmp/kdc_td_certifiers");
2868159d09a2SMark Phalan #endif
2869159d09a2SMark Phalan     typed_data = malloc (2 * sizeof(krb5_typed_data *));
2870159d09a2SMark Phalan     if (typed_data == NULL) {
2871159d09a2SMark Phalan 	retval = ENOMEM;
2872159d09a2SMark Phalan 	goto cleanup;
2873159d09a2SMark Phalan     }
2874159d09a2SMark Phalan     typed_data[1] = NULL;
2875159d09a2SMark Phalan     init_krb5_typed_data(&typed_data[0]);
2876159d09a2SMark Phalan     if (typed_data[0] == NULL) {
2877159d09a2SMark Phalan 	retval = ENOMEM;
2878159d09a2SMark Phalan 	goto cleanup;
2879159d09a2SMark Phalan     }
2880159d09a2SMark Phalan     typed_data[0]->type = type;
2881159d09a2SMark Phalan     typed_data[0]->length = td_certifiers->length;
2882159d09a2SMark Phalan     typed_data[0]->data = (unsigned char *)td_certifiers->data;
2883159d09a2SMark Phalan     retval = k5int_encode_krb5_typed_data((const krb5_typed_data **)typed_data,
2884159d09a2SMark Phalan 					  &data);
2885159d09a2SMark Phalan     if (retval) {
2886159d09a2SMark Phalan 	pkiDebug("encode_krb5_typed_data failed\n");
2887159d09a2SMark Phalan 	goto cleanup;
2888159d09a2SMark Phalan     }
2889159d09a2SMark Phalan #ifdef DEBUG_ASN1
2890159d09a2SMark Phalan     print_buffer_bin((unsigned char *)data->data, data->length,
2891159d09a2SMark Phalan 		     "/tmp/kdc_edata");
2892159d09a2SMark Phalan #endif
2893159d09a2SMark Phalan     *out_data = (krb5_data *)malloc(sizeof(krb5_data));
2894159d09a2SMark Phalan     (*out_data)->length = data->length;
2895159d09a2SMark Phalan     (*out_data)->data = (char *)malloc(data->length);
2896159d09a2SMark Phalan     (void) memcpy((*out_data)->data, data->data, data->length);
2897159d09a2SMark Phalan 
2898159d09a2SMark Phalan     retval = 0;
2899159d09a2SMark Phalan 
2900159d09a2SMark Phalan cleanup:
2901159d09a2SMark Phalan     if (krb5_trusted_certifiers != NULL)
2902159d09a2SMark Phalan 	free_krb5_external_principal_identifier(&krb5_trusted_certifiers);
2903159d09a2SMark Phalan 
2904159d09a2SMark Phalan     if (data != NULL) {
2905159d09a2SMark Phalan 	if (data->data != NULL)
2906159d09a2SMark Phalan 	    free(data->data);
2907159d09a2SMark Phalan 	free(data);
2908159d09a2SMark Phalan     }
2909159d09a2SMark Phalan 
2910159d09a2SMark Phalan     if (td_certifiers != NULL)
2911159d09a2SMark Phalan 	free(td_certifiers);
2912159d09a2SMark Phalan 
2913159d09a2SMark Phalan     if (typed_data != NULL)
2914159d09a2SMark Phalan 	free_krb5_typed_data(&typed_data);
2915159d09a2SMark Phalan 
2916159d09a2SMark Phalan     return retval;
2917159d09a2SMark Phalan }
2918159d09a2SMark Phalan 
2919159d09a2SMark Phalan krb5_error_code
pkinit_create_td_trusted_certifiers(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_data ** out_data)2920159d09a2SMark Phalan pkinit_create_td_trusted_certifiers(krb5_context context,
2921159d09a2SMark Phalan 				    pkinit_plg_crypto_context plg_cryptoctx,
2922159d09a2SMark Phalan 				    pkinit_req_crypto_context req_cryptoctx,
2923159d09a2SMark Phalan 				    pkinit_identity_crypto_context id_cryptoctx,
2924159d09a2SMark Phalan 				    krb5_data **out_data)
2925159d09a2SMark Phalan {
2926159d09a2SMark Phalan     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2927159d09a2SMark Phalan 
2928159d09a2SMark Phalan     retval = pkinit_create_sequence_of_principal_identifiers(context,
2929159d09a2SMark Phalan 	plg_cryptoctx, req_cryptoctx, id_cryptoctx,
2930159d09a2SMark Phalan 	TD_TRUSTED_CERTIFIERS, out_data);
2931159d09a2SMark Phalan 
2932159d09a2SMark Phalan     return retval;
2933159d09a2SMark Phalan }
2934159d09a2SMark Phalan 
2935159d09a2SMark Phalan krb5_error_code
pkinit_create_td_invalid_certificate(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_data ** out_data)2936159d09a2SMark Phalan pkinit_create_td_invalid_certificate(
2937159d09a2SMark Phalan 	krb5_context context,
2938159d09a2SMark Phalan 	pkinit_plg_crypto_context plg_cryptoctx,
2939159d09a2SMark Phalan 	pkinit_req_crypto_context req_cryptoctx,
2940159d09a2SMark Phalan 	pkinit_identity_crypto_context id_cryptoctx,
2941159d09a2SMark Phalan 	krb5_data **out_data)
2942159d09a2SMark Phalan {
2943159d09a2SMark Phalan     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2944159d09a2SMark Phalan 
2945159d09a2SMark Phalan     retval = pkinit_create_sequence_of_principal_identifiers(context,
2946159d09a2SMark Phalan 	plg_cryptoctx, req_cryptoctx, id_cryptoctx,
2947159d09a2SMark Phalan 	TD_INVALID_CERTIFICATES, out_data);
2948159d09a2SMark Phalan 
2949159d09a2SMark Phalan     return retval;
2950159d09a2SMark Phalan }
2951159d09a2SMark Phalan 
2952159d09a2SMark Phalan /* ARGSUSED */
2953159d09a2SMark Phalan krb5_error_code
pkinit_create_td_dh_parameters(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,pkinit_plg_opts * opts,krb5_data ** out_data)2954159d09a2SMark Phalan pkinit_create_td_dh_parameters(krb5_context context,
2955159d09a2SMark Phalan 			       pkinit_plg_crypto_context plg_cryptoctx,
2956159d09a2SMark Phalan 			       pkinit_req_crypto_context req_cryptoctx,
2957159d09a2SMark Phalan 			       pkinit_identity_crypto_context id_cryptoctx,
2958159d09a2SMark Phalan 			       pkinit_plg_opts *opts,
2959159d09a2SMark Phalan 			       krb5_data **out_data)
2960159d09a2SMark Phalan {
2961159d09a2SMark Phalan     /* Solaris Kerberos */
2962159d09a2SMark Phalan     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
2963159d09a2SMark Phalan     unsigned int buf1_len = 0, buf2_len = 0, buf3_len = 0, i = 0;
2964159d09a2SMark Phalan     unsigned char *buf1 = NULL, *buf2 = NULL, *buf3 = NULL;
2965159d09a2SMark Phalan     krb5_typed_data **typed_data = NULL;
2966159d09a2SMark Phalan     krb5_data *data = NULL, *encoded_algId = NULL;
2967159d09a2SMark Phalan     krb5_algorithm_identifier **algId = NULL;
2968300fdee2SAndy Fiddaman     const BIGNUM *p, *q, *g;
2969159d09a2SMark Phalan 
2970159d09a2SMark Phalan     /* Solaris Kerberos */
2971159d09a2SMark Phalan     if (opts->dh_min_bits > 4096) {
2972159d09a2SMark Phalan 	retval = EINVAL;
2973159d09a2SMark Phalan 	goto cleanup;
2974159d09a2SMark Phalan     }
2975159d09a2SMark Phalan 
2976159d09a2SMark Phalan     if (opts->dh_min_bits <= 1024) {
2977300fdee2SAndy Fiddaman 	DH_get0_pqg(plg_cryptoctx->dh_1024, &p, &q, &g);
2978300fdee2SAndy Fiddaman 	retval = pkinit_encode_dh_params(p, g, q, &buf1, &buf1_len);
2979159d09a2SMark Phalan 	if (retval)
2980159d09a2SMark Phalan 	    goto cleanup;
2981159d09a2SMark Phalan     }
2982159d09a2SMark Phalan     if (opts->dh_min_bits <= 2048) {
2983300fdee2SAndy Fiddaman 	DH_get0_pqg(plg_cryptoctx->dh_2048, &p, &q, &g);
2984300fdee2SAndy Fiddaman 	retval = pkinit_encode_dh_params(p, g, q, &buf2, &buf2_len);
2985159d09a2SMark Phalan 	if (retval)
2986159d09a2SMark Phalan 	    goto cleanup;
2987159d09a2SMark Phalan     }
2988300fdee2SAndy Fiddaman     DH_get0_pqg(plg_cryptoctx->dh_4096, &p, &q, &g);
2989300fdee2SAndy Fiddaman     retval = pkinit_encode_dh_params(p, g, q, &buf3, &buf3_len);
2990159d09a2SMark Phalan     if (retval)
2991159d09a2SMark Phalan 	goto cleanup;
2992159d09a2SMark Phalan 
2993159d09a2SMark Phalan     if (opts->dh_min_bits <= 1024) {
2994159d09a2SMark Phalan 	algId = malloc(4 * sizeof(krb5_algorithm_identifier *));
2995159d09a2SMark Phalan 	if (algId == NULL)
2996159d09a2SMark Phalan 	    goto cleanup;
2997159d09a2SMark Phalan 	algId[3] = NULL;
2998159d09a2SMark Phalan 	algId[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
2999159d09a2SMark Phalan 	if (algId[0] == NULL)
3000159d09a2SMark Phalan 	    goto cleanup;
3001159d09a2SMark Phalan 	algId[0]->parameters.data = (unsigned char *)malloc(buf2_len);
3002159d09a2SMark Phalan 	if (algId[0]->parameters.data == NULL)
3003159d09a2SMark Phalan 	    goto cleanup;
3004159d09a2SMark Phalan 	(void) memcpy(algId[0]->parameters.data, buf2, buf2_len);
3005159d09a2SMark Phalan 	algId[0]->parameters.length = buf2_len;
3006159d09a2SMark Phalan 	algId[0]->algorithm = dh_oid;
3007159d09a2SMark Phalan 
3008159d09a2SMark Phalan 	algId[1] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
3009159d09a2SMark Phalan 	if (algId[1] == NULL)
3010159d09a2SMark Phalan 	    goto cleanup;
3011159d09a2SMark Phalan 	algId[1]->parameters.data = (unsigned char *)malloc(buf3_len);
3012159d09a2SMark Phalan 	if (algId[1]->parameters.data == NULL)
3013159d09a2SMark Phalan 	    goto cleanup;
3014159d09a2SMark Phalan 	(void) memcpy(algId[1]->parameters.data, buf3, buf3_len);
3015159d09a2SMark Phalan 	algId[1]->parameters.length = buf3_len;
3016159d09a2SMark Phalan 	algId[1]->algorithm = dh_oid;
3017159d09a2SMark Phalan 
3018159d09a2SMark Phalan 	algId[2] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
3019159d09a2SMark Phalan 	if (algId[2] == NULL)
3020159d09a2SMark Phalan 	    goto cleanup;
3021159d09a2SMark Phalan 	algId[2]->parameters.data = (unsigned char *)malloc(buf1_len);
3022159d09a2SMark Phalan 	if (algId[2]->parameters.data == NULL)
3023159d09a2SMark Phalan 	    goto cleanup;
3024159d09a2SMark Phalan 	(void) memcpy(algId[2]->parameters.data, buf1, buf1_len);
3025159d09a2SMark Phalan 	algId[2]->parameters.length = buf1_len;
3026159d09a2SMark Phalan 	algId[2]->algorithm = dh_oid;
3027159d09a2SMark Phalan 
3028159d09a2SMark Phalan     } else if (opts->dh_min_bits <= 2048) {
3029159d09a2SMark Phalan 	algId = malloc(3 * sizeof(krb5_algorithm_identifier *));
3030159d09a2SMark Phalan 	if (algId == NULL)
3031159d09a2SMark Phalan 	    goto cleanup;
3032159d09a2SMark Phalan 	algId[2] = NULL;
3033159d09a2SMark Phalan 	algId[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
3034159d09a2SMark Phalan 	if (algId[0] == NULL)
3035159d09a2SMark Phalan 	    goto cleanup;
3036159d09a2SMark Phalan 	algId[0]->parameters.data = (unsigned char *)malloc(buf2_len);
3037159d09a2SMark Phalan 	if (algId[0]->parameters.data == NULL)
3038159d09a2SMark Phalan 	    goto cleanup;
3039159d09a2SMark Phalan 	(void) memcpy(algId[0]->parameters.data, buf2, buf2_len);
3040159d09a2SMark Phalan 	algId[0]->parameters.length = buf2_len;
3041159d09a2SMark Phalan 	algId[0]->algorithm = dh_oid;
3042159d09a2SMark Phalan 
3043159d09a2SMark Phalan 	algId[1] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
3044159d09a2SMark Phalan 	if (algId[1] == NULL)
3045159d09a2SMark Phalan 	    goto cleanup;
3046159d09a2SMark Phalan 	algId[1]->parameters.data = (unsigned char *)malloc(buf3_len);
3047159d09a2SMark Phalan 	if (algId[1]->parameters.data == NULL)
3048159d09a2SMark Phalan 	    goto cleanup;
3049159d09a2SMark Phalan 	(void) memcpy(algId[1]->parameters.data, buf3, buf3_len);
3050159d09a2SMark Phalan 	algId[1]->parameters.length = buf3_len;
3051159d09a2SMark Phalan 	algId[1]->algorithm = dh_oid;
3052159d09a2SMark Phalan 
3053159d09a2SMark Phalan     } else if (opts->dh_min_bits <= 4096) {
3054159d09a2SMark Phalan 	algId = malloc(2 * sizeof(krb5_algorithm_identifier *));
3055159d09a2SMark Phalan 	if (algId == NULL)
3056159d09a2SMark Phalan 	    goto cleanup;
3057159d09a2SMark Phalan 	algId[1] = NULL;
3058159d09a2SMark Phalan 	algId[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
3059159d09a2SMark Phalan 	if (algId[0] == NULL)
3060159d09a2SMark Phalan 	    goto cleanup;
3061159d09a2SMark Phalan 	algId[0]->parameters.data = (unsigned char *)malloc(buf3_len);
3062159d09a2SMark Phalan 	if (algId[0]->parameters.data == NULL)
3063159d09a2SMark Phalan 	    goto cleanup;
3064159d09a2SMark Phalan 	(void) memcpy(algId[0]->parameters.data, buf3, buf3_len);
3065159d09a2SMark Phalan 	algId[0]->parameters.length = buf3_len;
3066159d09a2SMark Phalan 	algId[0]->algorithm = dh_oid;
3067159d09a2SMark Phalan 
3068159d09a2SMark Phalan     }
3069159d09a2SMark Phalan     retval = k5int_encode_krb5_td_dh_parameters((const krb5_algorithm_identifier **)algId, &encoded_algId);
3070159d09a2SMark Phalan     if (retval)
3071159d09a2SMark Phalan 	goto cleanup;
3072159d09a2SMark Phalan #ifdef DEBUG_ASN1
3073159d09a2SMark Phalan     print_buffer_bin((unsigned char *)encoded_algId->data,
3074159d09a2SMark Phalan 		     encoded_algId->length, "/tmp/kdc_td_dh_params");
3075159d09a2SMark Phalan #endif
3076159d09a2SMark Phalan     typed_data = malloc (2 * sizeof(krb5_typed_data *));
3077159d09a2SMark Phalan     if (typed_data == NULL) {
3078159d09a2SMark Phalan 	retval = ENOMEM;
3079159d09a2SMark Phalan 	goto cleanup;
3080159d09a2SMark Phalan     }
3081159d09a2SMark Phalan     typed_data[1] = NULL;
3082159d09a2SMark Phalan     init_krb5_typed_data(&typed_data[0]);
3083159d09a2SMark Phalan     if (typed_data == NULL) {
3084159d09a2SMark Phalan 	retval = ENOMEM;
3085159d09a2SMark Phalan 	goto cleanup;
3086159d09a2SMark Phalan     }
3087159d09a2SMark Phalan     typed_data[0]->type = TD_DH_PARAMETERS;
3088159d09a2SMark Phalan     typed_data[0]->length = encoded_algId->length;
3089159d09a2SMark Phalan     typed_data[0]->data = (unsigned char *)encoded_algId->data;
3090159d09a2SMark Phalan     retval = k5int_encode_krb5_typed_data((const krb5_typed_data**)typed_data,
3091159d09a2SMark Phalan 					  &data);
3092159d09a2SMark Phalan     if (retval) {
3093159d09a2SMark Phalan 	pkiDebug("encode_krb5_typed_data failed\n");
3094159d09a2SMark Phalan 	goto cleanup;
3095159d09a2SMark Phalan     }
3096159d09a2SMark Phalan #ifdef DEBUG_ASN1
3097159d09a2SMark Phalan     print_buffer_bin((unsigned char *)data->data, data->length,
3098159d09a2SMark Phalan 		     "/tmp/kdc_edata");
3099159d09a2SMark Phalan #endif
3100159d09a2SMark Phalan     *out_data = (krb5_data *)malloc(sizeof(krb5_data));
3101159d09a2SMark Phalan     if (*out_data == NULL)
3102159d09a2SMark Phalan 	goto cleanup;
3103159d09a2SMark Phalan     (*out_data)->length = data->length;
3104159d09a2SMark Phalan     (*out_data)->data = (char *)malloc(data->length);
3105159d09a2SMark Phalan     if ((*out_data)->data == NULL) {
3106159d09a2SMark Phalan 	free(*out_data);
3107159d09a2SMark Phalan 	*out_data = NULL;
3108159d09a2SMark Phalan 	goto cleanup;
3109159d09a2SMark Phalan     }
3110159d09a2SMark Phalan     (void) memcpy((*out_data)->data, data->data, data->length);
3111159d09a2SMark Phalan 
3112159d09a2SMark Phalan     retval = 0;
3113159d09a2SMark Phalan cleanup:
3114159d09a2SMark Phalan 
3115159d09a2SMark Phalan     if (buf1 != NULL)
3116159d09a2SMark Phalan 	free(buf1);
3117159d09a2SMark Phalan     if (buf2 != NULL)
3118159d09a2SMark Phalan 	free(buf2);
3119159d09a2SMark Phalan     if (buf3 != NULL)
3120159d09a2SMark Phalan 	free(buf3);
3121159d09a2SMark Phalan     if (data != NULL) {
3122159d09a2SMark Phalan 	if (data->data != NULL)
3123159d09a2SMark Phalan 	    free(data->data);
3124159d09a2SMark Phalan 	free(data);
3125159d09a2SMark Phalan     }
3126159d09a2SMark Phalan     if (typed_data != NULL)
3127159d09a2SMark Phalan 	free_krb5_typed_data(&typed_data);
3128159d09a2SMark Phalan     if (encoded_algId != NULL)
3129159d09a2SMark Phalan 	free(encoded_algId);
3130159d09a2SMark Phalan 
3131159d09a2SMark Phalan     if (algId != NULL) {
3132159d09a2SMark Phalan 	while(algId[i] != NULL) {
3133159d09a2SMark Phalan 	    if (algId[i]->parameters.data != NULL)
3134159d09a2SMark Phalan 		free(algId[i]->parameters.data);
3135159d09a2SMark Phalan 	    free(algId[i]);
3136159d09a2SMark Phalan 	    i++;
3137159d09a2SMark Phalan 	}
3138159d09a2SMark Phalan 	free(algId);
3139159d09a2SMark Phalan     }
3140159d09a2SMark Phalan 
3141159d09a2SMark Phalan     return retval;
3142159d09a2SMark Phalan }
3143159d09a2SMark Phalan 
3144159d09a2SMark Phalan /* ARGSUSED */
3145159d09a2SMark Phalan krb5_error_code
pkinit_check_kdc_pkid(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,unsigned char * pdid_buf,unsigned int pkid_len,int * valid_kdcPkId)3146159d09a2SMark Phalan pkinit_check_kdc_pkid(krb5_context context,
3147159d09a2SMark Phalan 		      pkinit_plg_crypto_context plg_cryptoctx,
3148159d09a2SMark Phalan 		      pkinit_req_crypto_context req_cryptoctx,
3149159d09a2SMark Phalan 		      pkinit_identity_crypto_context id_cryptoctx,
3150159d09a2SMark Phalan 		      unsigned char *pdid_buf,
3151159d09a2SMark Phalan 		      unsigned int pkid_len,
3152159d09a2SMark Phalan 		      int *valid_kdcPkId)
3153159d09a2SMark Phalan {
3154159d09a2SMark Phalan     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
3155159d09a2SMark Phalan     PKCS7_ISSUER_AND_SERIAL *is = NULL;
3156159d09a2SMark Phalan     const unsigned char *p = pdid_buf;
3157159d09a2SMark Phalan     int status = 1;
3158159d09a2SMark Phalan     X509 *kdc_cert = sk_X509_value(id_cryptoctx->my_certs, id_cryptoctx->cert_index);
3159159d09a2SMark Phalan 
3160159d09a2SMark Phalan     *valid_kdcPkId = 0;
3161159d09a2SMark Phalan     pkiDebug("found kdcPkId in AS REQ\n");
3162159d09a2SMark Phalan     is = d2i_PKCS7_ISSUER_AND_SERIAL(NULL, &p, (int)pkid_len);
3163159d09a2SMark Phalan     if (is == NULL)
3164159d09a2SMark Phalan 	goto cleanup;
3165159d09a2SMark Phalan 
3166159d09a2SMark Phalan     status = X509_NAME_cmp(X509_get_issuer_name(kdc_cert), is->issuer);
3167159d09a2SMark Phalan     if (!status) {
3168159d09a2SMark Phalan 	status = ASN1_INTEGER_cmp(X509_get_serialNumber(kdc_cert), is->serial);
3169159d09a2SMark Phalan 	if (!status)
3170159d09a2SMark Phalan 	    *valid_kdcPkId = 1;
3171159d09a2SMark Phalan     }
3172159d09a2SMark Phalan 
3173159d09a2SMark Phalan     retval = 0;
3174159d09a2SMark Phalan cleanup:
3175159d09a2SMark Phalan     X509_NAME_free(is->issuer);
3176159d09a2SMark Phalan     ASN1_INTEGER_free(is->serial);
3177159d09a2SMark Phalan     free(is);
3178159d09a2SMark Phalan 
3179159d09a2SMark Phalan     return retval;
3180159d09a2SMark Phalan }
3181159d09a2SMark Phalan 
3182159d09a2SMark Phalan static int
pkinit_check_dh_params(const BIGNUM * p1,const BIGNUM * p2,const BIGNUM * g1,const BIGNUM * q1)3183300fdee2SAndy Fiddaman pkinit_check_dh_params(const BIGNUM *p1, const BIGNUM *p2, const BIGNUM *g1,
3184300fdee2SAndy Fiddaman     const BIGNUM *q1)
3185159d09a2SMark Phalan {
3186159d09a2SMark Phalan     BIGNUM *g2 = NULL, *q2 = NULL;
3187159d09a2SMark Phalan     /* Solaris Kerberos */
3188159d09a2SMark Phalan     int retval = EINVAL;
3189159d09a2SMark Phalan 
3190159d09a2SMark Phalan     if (!BN_cmp(p1, p2)) {
3191159d09a2SMark Phalan 	g2 = BN_new();
3192159d09a2SMark Phalan 	BN_set_word(g2, DH_GENERATOR_2);
3193159d09a2SMark Phalan 	if (!BN_cmp(g1, g2)) {
3194159d09a2SMark Phalan 	    q2 = BN_new();
3195159d09a2SMark Phalan 	    BN_rshift1(q2, p1);
3196159d09a2SMark Phalan 	    if (!BN_cmp(q1, q2)) {
3197159d09a2SMark Phalan 		pkiDebug("good %d dhparams\n", BN_num_bits(p1));
3198159d09a2SMark Phalan 		retval = 0;
3199159d09a2SMark Phalan 	    } else
3200159d09a2SMark Phalan 		pkiDebug("bad group 2 q dhparameter\n");
3201159d09a2SMark Phalan 	    BN_free(q2);
3202159d09a2SMark Phalan 	} else
3203159d09a2SMark Phalan 	    pkiDebug("bad g dhparameter\n");
3204159d09a2SMark Phalan 	BN_free(g2);
3205159d09a2SMark Phalan     } else
3206159d09a2SMark Phalan 	pkiDebug("p is not well-known group 2 dhparameter\n");
3207159d09a2SMark Phalan 
3208159d09a2SMark Phalan     return retval;
3209159d09a2SMark Phalan }
3210159d09a2SMark Phalan 
3211159d09a2SMark Phalan /* ARGSUSED */
3212159d09a2SMark Phalan krb5_error_code
pkinit_process_td_dh_params(krb5_context context,pkinit_plg_crypto_context cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_algorithm_identifier ** algId,int * new_dh_size)3213159d09a2SMark Phalan pkinit_process_td_dh_params(krb5_context context,
3214159d09a2SMark Phalan 			    pkinit_plg_crypto_context cryptoctx,
3215159d09a2SMark Phalan 			    pkinit_req_crypto_context req_cryptoctx,
3216159d09a2SMark Phalan 			    pkinit_identity_crypto_context id_cryptoctx,
3217159d09a2SMark Phalan 			    krb5_algorithm_identifier **algId,
3218159d09a2SMark Phalan 			    int *new_dh_size)
3219159d09a2SMark Phalan {
3220159d09a2SMark Phalan     krb5_error_code retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
3221159d09a2SMark Phalan     int i = 0, use_sent_dh = 0, ok = 0;
3222159d09a2SMark Phalan 
3223159d09a2SMark Phalan     pkiDebug("dh parameters\n");
3224159d09a2SMark Phalan 
3225159d09a2SMark Phalan     while (algId[i] != NULL) {
3226159d09a2SMark Phalan 	DH *dh = NULL;
3227159d09a2SMark Phalan 	unsigned char *tmp = NULL;
3228300fdee2SAndy Fiddaman 	const BIGNUM *p, *g, *q, *p2;
3229159d09a2SMark Phalan 	int dh_prime_bits = 0;
3230159d09a2SMark Phalan 
3231159d09a2SMark Phalan 	if (algId[i]->algorithm.length != dh_oid.length ||
3232159d09a2SMark Phalan 	    memcmp(algId[i]->algorithm.data, dh_oid.data, dh_oid.length))
3233159d09a2SMark Phalan 	    goto cleanup;
3234159d09a2SMark Phalan 
3235159d09a2SMark Phalan 	tmp = algId[i]->parameters.data;
3236159d09a2SMark Phalan 	dh = DH_new();
3237159d09a2SMark Phalan 	dh = pkinit_decode_dh_params(&dh, &tmp, algId[i]->parameters.length);
3238300fdee2SAndy Fiddaman 	dh_prime_bits = DH_bits(dh);
3239159d09a2SMark Phalan 	pkiDebug("client sent %d DH bits server prefers %d DH bits\n",
3240159d09a2SMark Phalan 		 *new_dh_size, dh_prime_bits);
3241300fdee2SAndy Fiddaman 	DH_get0_pqg(dh, &p, &q, &g);
3242159d09a2SMark Phalan 	switch(dh_prime_bits) {
3243159d09a2SMark Phalan 	    case 1024:
3244300fdee2SAndy Fiddaman 		DH_get0_pqg(cryptoctx->dh_1024, &p2, NULL, NULL);
3245300fdee2SAndy Fiddaman 		if (pkinit_check_dh_params(p2, p, g, q) == 0) {
3246159d09a2SMark Phalan 		    *new_dh_size = 1024;
3247159d09a2SMark Phalan 		    ok = 1;
3248159d09a2SMark Phalan 		}
3249159d09a2SMark Phalan 		break;
3250159d09a2SMark Phalan 	    case 2048:
3251300fdee2SAndy Fiddaman 		DH_get0_pqg(cryptoctx->dh_2048, &p2, NULL, NULL);
3252300fdee2SAndy Fiddaman 		if (pkinit_check_dh_params(p2, p, g, q) == 0) {
3253159d09a2SMark Phalan 		    *new_dh_size = 2048;
3254159d09a2SMark Phalan 		    ok = 1;
3255159d09a2SMark Phalan 		}
3256159d09a2SMark Phalan 		break;
3257159d09a2SMark Phalan 	    case 4096:
3258300fdee2SAndy Fiddaman 		DH_get0_pqg(cryptoctx->dh_4096, &p2, NULL, NULL);
3259300fdee2SAndy Fiddaman 		if (pkinit_check_dh_params(p2, p, g, q) == 0) {
3260159d09a2SMark Phalan 		    *new_dh_size = 4096;
3261159d09a2SMark Phalan 		    ok = 1;
3262159d09a2SMark Phalan 		}
3263159d09a2SMark Phalan 		break;
3264159d09a2SMark Phalan 	    default:
3265159d09a2SMark Phalan 		break;
3266159d09a2SMark Phalan 	}
3267159d09a2SMark Phalan 	if (!ok) {
3268159d09a2SMark Phalan 	    DH_check(dh, &retval);
3269159d09a2SMark Phalan 	    if (retval != 0) {
3270159d09a2SMark Phalan 		pkiDebug("DH parameters provided by server are unacceptable\n");
3271159d09a2SMark Phalan 		retval = KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED;
3272159d09a2SMark Phalan 	    }
3273159d09a2SMark Phalan 	    else {
3274159d09a2SMark Phalan 		use_sent_dh = 1;
3275159d09a2SMark Phalan 		ok = 1;
3276159d09a2SMark Phalan 	    }
3277159d09a2SMark Phalan 	}
3278159d09a2SMark Phalan 	if (!use_sent_dh)
3279159d09a2SMark Phalan 	    DH_free(dh);
3280159d09a2SMark Phalan 	if (ok) {
3281159d09a2SMark Phalan 	    if (req_cryptoctx->dh != NULL) {
3282159d09a2SMark Phalan 		DH_free(req_cryptoctx->dh);
3283159d09a2SMark Phalan 		req_cryptoctx->dh = NULL;
3284159d09a2SMark Phalan 	    }
3285159d09a2SMark Phalan 	    if (use_sent_dh)
3286159d09a2SMark Phalan 		req_cryptoctx->dh = dh;
3287159d09a2SMark Phalan 	    break;
3288159d09a2SMark Phalan 	}
3289159d09a2SMark Phalan 	i++;
3290159d09a2SMark Phalan     }
3291159d09a2SMark Phalan 
3292159d09a2SMark Phalan     if (ok)
3293159d09a2SMark Phalan 	retval = 0;
3294159d09a2SMark Phalan 
3295159d09a2SMark Phalan cleanup:
3296159d09a2SMark Phalan     return retval;
3297159d09a2SMark Phalan }
3298159d09a2SMark Phalan 
3299300fdee2SAndy Fiddaman /* ARGSUSED */
3300159d09a2SMark Phalan static int
openssl_callback(int ok,X509_STORE_CTX * ctx)3301159d09a2SMark Phalan openssl_callback(int ok, X509_STORE_CTX * ctx)
3302159d09a2SMark Phalan {
3303159d09a2SMark Phalan #ifdef DEBUG
3304159d09a2SMark Phalan     if (!ok) {
3305159d09a2SMark Phalan 	char buf[DN_BUF_LEN];
3306159d09a2SMark Phalan 
3307159d09a2SMark Phalan 	X509_NAME_oneline(X509_get_subject_name(ctx->current_cert), buf, sizeof(buf));
3308159d09a2SMark Phalan 	pkiDebug("cert = %s\n", buf);
3309159d09a2SMark Phalan 	pkiDebug("callback function: %d (%s)\n", ctx->error,
3310159d09a2SMark Phalan 		X509_verify_cert_error_string(ctx->error));
3311159d09a2SMark Phalan     }
3312159d09a2SMark Phalan #endif
3313159d09a2SMark Phalan     return ok;
3314159d09a2SMark Phalan }
3315159d09a2SMark Phalan 
3316159d09a2SMark Phalan static int
openssl_callback_ignore_crls(int ok,X509_STORE_CTX * ctx)3317159d09a2SMark Phalan openssl_callback_ignore_crls(int ok, X509_STORE_CTX * ctx)
3318159d09a2SMark Phalan {
3319300fdee2SAndy Fiddaman     if (!ok)
3320300fdee2SAndy Fiddaman 	return (X509_STORE_CTX_get_error(ctx) == X509_V_ERR_UNABLE_TO_GET_CRL);
3321159d09a2SMark Phalan     return ok;
3322159d09a2SMark Phalan }
3323159d09a2SMark Phalan 
3324159d09a2SMark Phalan static ASN1_OBJECT *
pkinit_pkcs7type2oid(pkinit_plg_crypto_context cryptoctx,int pkcs7_type)3325159d09a2SMark Phalan pkinit_pkcs7type2oid(pkinit_plg_crypto_context cryptoctx, int pkcs7_type)
3326159d09a2SMark Phalan {
3327159d09a2SMark Phalan     switch (pkcs7_type) {
3328159d09a2SMark Phalan 	case CMS_SIGN_CLIENT:
3329159d09a2SMark Phalan 	    return cryptoctx->id_pkinit_authData;
3330159d09a2SMark Phalan 	case CMS_SIGN_DRAFT9:
3331553e44ceSAndrew Stormont 	    return OBJ_nid2obj(NID_pkcs7_data);
3332159d09a2SMark Phalan 	case CMS_SIGN_SERVER:
3333159d09a2SMark Phalan 	    return cryptoctx->id_pkinit_DHKeyData;
3334159d09a2SMark Phalan 	case CMS_ENVEL_SERVER:
3335159d09a2SMark Phalan 	    return cryptoctx->id_pkinit_rkeyData;
3336159d09a2SMark Phalan 	default:
3337159d09a2SMark Phalan 	    return NULL;
3338159d09a2SMark Phalan     }
3339159d09a2SMark Phalan 
3340159d09a2SMark Phalan }
3341159d09a2SMark Phalan 
3342159d09a2SMark Phalan #ifdef LONGHORN_BETA_COMPAT
3343159d09a2SMark Phalan #if 0
3344159d09a2SMark Phalan /*
3345159d09a2SMark Phalan  * This is a version that worked with Longhorn Beta 3.
3346159d09a2SMark Phalan  */
3347159d09a2SMark Phalan static int
3348159d09a2SMark Phalan wrap_signeddata(unsigned char *data, unsigned int data_len,
3349159d09a2SMark Phalan 		unsigned char **out, unsigned int *out_len,
3350159d09a2SMark Phalan 		int is_longhorn_server)
3351159d09a2SMark Phalan {
3352159d09a2SMark Phalan 
3353159d09a2SMark Phalan     unsigned int orig_len = 0, oid_len = 0, tot_len = 0;
3354159d09a2SMark Phalan     ASN1_OBJECT *oid = NULL;
3355159d09a2SMark Phalan     unsigned char *p = NULL;
3356159d09a2SMark Phalan 
3357159d09a2SMark Phalan     pkiDebug("%s: This is the Longhorn version and is_longhorn_server = %d\n",
3358159d09a2SMark Phalan 	     __FUNCTION__, is_longhorn_server);
3359159d09a2SMark Phalan 
3360159d09a2SMark Phalan     /* Get length to wrap the original data with SEQUENCE tag */
3361159d09a2SMark Phalan     tot_len = orig_len = ASN1_object_size(1, (int)data_len, V_ASN1_SEQUENCE);
3362159d09a2SMark Phalan 
3363159d09a2SMark Phalan     if (is_longhorn_server == 0) {
3364159d09a2SMark Phalan 	/* Add the signedData OID and adjust lengths */
3365159d09a2SMark Phalan 	oid = OBJ_nid2obj(NID_pkcs7_signed);
3366159d09a2SMark Phalan 	oid_len = i2d_ASN1_OBJECT(oid, NULL);
3367159d09a2SMark Phalan 
3368159d09a2SMark Phalan 	tot_len = ASN1_object_size(1, (int)(orig_len+oid_len), V_ASN1_SEQUENCE);
3369159d09a2SMark Phalan     }
3370159d09a2SMark Phalan 
3371159d09a2SMark Phalan     p = *out = (unsigned char *)malloc(tot_len);
3372159d09a2SMark Phalan     if (p == NULL) return -1;
3373159d09a2SMark Phalan 
3374159d09a2SMark Phalan     if (is_longhorn_server == 0) {
3375159d09a2SMark Phalan 	ASN1_put_object(&p, 1, (int)(orig_len+oid_len),
3376159d09a2SMark Phalan 			V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3377159d09a2SMark Phalan 
3378159d09a2SMark Phalan 	i2d_ASN1_OBJECT(oid, &p);
3379159d09a2SMark Phalan 
3380159d09a2SMark Phalan 	ASN1_put_object(&p, 1, (int)data_len, 0, V_ASN1_CONTEXT_SPECIFIC);
3381159d09a2SMark Phalan     } else {
3382159d09a2SMark Phalan 	ASN1_put_object(&p, 1, (int)data_len, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3383159d09a2SMark Phalan     }
3384159d09a2SMark Phalan     memcpy(p, data, data_len);
3385159d09a2SMark Phalan 
3386159d09a2SMark Phalan     *out_len = tot_len;
3387159d09a2SMark Phalan 
3388159d09a2SMark Phalan     return 0;
3389159d09a2SMark Phalan }
3390159d09a2SMark Phalan #else
3391159d09a2SMark Phalan /*
3392159d09a2SMark Phalan  * This is a version that works with a patched Longhorn KDC.
3393159d09a2SMark Phalan  * (Which should match SP1 ??).
3394159d09a2SMark Phalan  */
3395159d09a2SMark Phalan static int
wrap_signeddata(unsigned char * data,unsigned int data_len,unsigned char ** out,unsigned int * out_len,int is_longhorn_server)3396159d09a2SMark Phalan wrap_signeddata(unsigned char *data, unsigned int data_len,
3397159d09a2SMark Phalan 	       unsigned char **out, unsigned int *out_len,
3398159d09a2SMark Phalan 	       int is_longhorn_server)
3399159d09a2SMark Phalan {
3400159d09a2SMark Phalan 
3401159d09a2SMark Phalan     unsigned int oid_len = 0, tot_len = 0, wrap_len = 0, tag_len = 0;
3402159d09a2SMark Phalan     ASN1_OBJECT *oid = NULL;
3403159d09a2SMark Phalan     unsigned char *p = NULL;
3404159d09a2SMark Phalan 
3405159d09a2SMark Phalan     pkiDebug("%s: This is the Longhorn version and is_longhorn_server = %d\n",
3406159d09a2SMark Phalan 	     __FUNCTION__, is_longhorn_server);
3407159d09a2SMark Phalan 
3408159d09a2SMark Phalan     /* New longhorn is missing another sequence */
3409159d09a2SMark Phalan     if (is_longhorn_server == 1)
3410159d09a2SMark Phalan        wrap_len = ASN1_object_size(1, (int)(data_len), V_ASN1_SEQUENCE);
3411159d09a2SMark Phalan     else
3412159d09a2SMark Phalan        wrap_len = data_len;
3413159d09a2SMark Phalan 
3414159d09a2SMark Phalan     /* Get length to wrap the original data with SEQUENCE tag */
3415159d09a2SMark Phalan     tag_len = ASN1_object_size(1, (int)wrap_len, V_ASN1_SEQUENCE);
3416159d09a2SMark Phalan 
3417159d09a2SMark Phalan     /* Always add oid */
3418159d09a2SMark Phalan     oid = OBJ_nid2obj(NID_pkcs7_signed);
3419159d09a2SMark Phalan     oid_len = i2d_ASN1_OBJECT(oid, NULL);
3420159d09a2SMark Phalan     oid_len += tag_len;
3421159d09a2SMark Phalan 
3422159d09a2SMark Phalan     tot_len = ASN1_object_size(1, (int)(oid_len), V_ASN1_SEQUENCE);
3423159d09a2SMark Phalan 
3424159d09a2SMark Phalan     p = *out = (unsigned char *)malloc(tot_len);
3425159d09a2SMark Phalan     if (p == NULL)
3426159d09a2SMark Phalan        return -1;
3427159d09a2SMark Phalan 
3428159d09a2SMark Phalan     ASN1_put_object(&p, 1, (int)(oid_len),
3429159d09a2SMark Phalan 		    V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3430159d09a2SMark Phalan 
3431159d09a2SMark Phalan     i2d_ASN1_OBJECT(oid, &p);
3432159d09a2SMark Phalan 
3433159d09a2SMark Phalan     ASN1_put_object(&p, 1, (int)wrap_len, 0, V_ASN1_CONTEXT_SPECIFIC);
3434159d09a2SMark Phalan 
3435159d09a2SMark Phalan     /* Wrap in extra seq tag */
3436159d09a2SMark Phalan     if (is_longhorn_server == 1) {
3437159d09a2SMark Phalan        ASN1_put_object(&p, 1, (int)data_len, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3438159d09a2SMark Phalan     }
3439159d09a2SMark Phalan     (void) memcpy(p, data, data_len);
3440159d09a2SMark Phalan 
3441159d09a2SMark Phalan     *out_len = tot_len;
3442159d09a2SMark Phalan 
3443159d09a2SMark Phalan     return 0;
3444159d09a2SMark Phalan }
3445159d09a2SMark Phalan 
3446159d09a2SMark Phalan #endif
3447159d09a2SMark Phalan #else
3448159d09a2SMark Phalan static int
wrap_signeddata(unsigned char * data,unsigned int data_len,unsigned char ** out,unsigned int * out_len)3449159d09a2SMark Phalan wrap_signeddata(unsigned char *data, unsigned int data_len,
3450159d09a2SMark Phalan 		unsigned char **out, unsigned int *out_len)
3451159d09a2SMark Phalan {
3452159d09a2SMark Phalan 
3453159d09a2SMark Phalan     unsigned int orig_len = 0, oid_len = 0, tot_len = 0;
3454159d09a2SMark Phalan     ASN1_OBJECT *oid = NULL;
3455159d09a2SMark Phalan     unsigned char *p = NULL;
3456159d09a2SMark Phalan 
3457159d09a2SMark Phalan     /* Get length to wrap the original data with SEQUENCE tag */
3458159d09a2SMark Phalan     tot_len = orig_len = ASN1_object_size(1, (int)data_len, V_ASN1_SEQUENCE);
3459159d09a2SMark Phalan 
3460159d09a2SMark Phalan     /* Add the signedData OID and adjust lengths */
3461159d09a2SMark Phalan     oid = OBJ_nid2obj(NID_pkcs7_signed);
3462159d09a2SMark Phalan     oid_len = i2d_ASN1_OBJECT(oid, NULL);
3463159d09a2SMark Phalan 
3464159d09a2SMark Phalan     tot_len = ASN1_object_size(1, (int)(orig_len+oid_len), V_ASN1_SEQUENCE);
3465159d09a2SMark Phalan 
3466159d09a2SMark Phalan     p = *out = (unsigned char *)malloc(tot_len);
3467159d09a2SMark Phalan     if (p == NULL) return -1;
3468159d09a2SMark Phalan 
3469159d09a2SMark Phalan     ASN1_put_object(&p, 1, (int)(orig_len+oid_len),
3470159d09a2SMark Phalan 		    V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL);
3471159d09a2SMark Phalan 
3472159d09a2SMark Phalan     i2d_ASN1_OBJECT(oid, &p);
3473159d09a2SMark Phalan 
3474159d09a2SMark Phalan     ASN1_put_object(&p, 1, (int)data_len, 0, V_ASN1_CONTEXT_SPECIFIC);
3475159d09a2SMark Phalan     (void) memcpy(p, data, data_len);
3476159d09a2SMark Phalan 
3477159d09a2SMark Phalan     *out_len = tot_len;
3478159d09a2SMark Phalan 
3479159d09a2SMark Phalan     return 0;
3480159d09a2SMark Phalan }
3481159d09a2SMark Phalan #endif
3482159d09a2SMark Phalan 
3483159d09a2SMark Phalan static int
prepare_enc_data(unsigned char * indata,int indata_len,unsigned char ** outdata,int * outdata_len)3484159d09a2SMark Phalan prepare_enc_data(unsigned char *indata,
3485159d09a2SMark Phalan 		 int indata_len,
3486159d09a2SMark Phalan 		 unsigned char **outdata,
3487159d09a2SMark Phalan 		 int *outdata_len)
3488159d09a2SMark Phalan {
3489300fdee2SAndy Fiddaman     int tag, class;
3490300fdee2SAndy Fiddaman     long tlen, slen;
3491300fdee2SAndy Fiddaman     const uint8_t *p = indata, *oldp;
3492300fdee2SAndy Fiddaman 
3493300fdee2SAndy Fiddaman     /* Top-bit set means that the conversion failed. */
3494300fdee2SAndy Fiddaman     if (ASN1_get_object(&p, &slen, &tag, &class, indata_len) & 0x80)
3495300fdee2SAndy Fiddaman         return EINVAL;
3496300fdee2SAndy Fiddaman     if (tag != V_ASN1_SEQUENCE)
3497300fdee2SAndy Fiddaman         return EINVAL;
3498300fdee2SAndy Fiddaman 
3499300fdee2SAndy Fiddaman     oldp = p;
3500300fdee2SAndy Fiddaman     if (ASN1_get_object(&p, &tlen, &tag, &class, slen) & 0x80)
3501300fdee2SAndy Fiddaman         return EINVAL;
3502300fdee2SAndy Fiddaman     p += tlen;
3503300fdee2SAndy Fiddaman     slen -= (p - oldp);
3504300fdee2SAndy Fiddaman 
3505300fdee2SAndy Fiddaman     if (ASN1_get_object(&p, &tlen, &tag, &class, slen) & 0x80)
3506300fdee2SAndy Fiddaman         return EINVAL;
3507300fdee2SAndy Fiddaman 
3508300fdee2SAndy Fiddaman     *outdata = malloc(tlen);
3509300fdee2SAndy Fiddaman     if (*outdata == NULL)
3510300fdee2SAndy Fiddaman         return ENOMEM;
3511300fdee2SAndy Fiddaman     memcpy(*outdata, p, tlen);
3512300fdee2SAndy Fiddaman     *outdata_len = tlen;
3513159d09a2SMark Phalan 
3514159d09a2SMark Phalan     return 0;
3515159d09a2SMark Phalan }
3516159d09a2SMark Phalan 
3517159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
3518159d09a2SMark Phalan static void *
pkinit_C_LoadModule(const char * modname,CK_FUNCTION_LIST_PTR_PTR p11p)3519159d09a2SMark Phalan pkinit_C_LoadModule(const char *modname, CK_FUNCTION_LIST_PTR_PTR p11p)
3520159d09a2SMark Phalan {
3521159d09a2SMark Phalan     void *handle;
3522159d09a2SMark Phalan     CK_RV (*getflist)(CK_FUNCTION_LIST_PTR_PTR);
3523159d09a2SMark Phalan 
3524159d09a2SMark Phalan     pkiDebug("loading module \"%s\"... ", modname);
3525159d09a2SMark Phalan     /* Solaris Kerberos */
3526159d09a2SMark Phalan     handle = dlopen(modname, RTLD_NOW | RTLD_GROUP);
3527159d09a2SMark Phalan     if (handle == NULL) {
3528159d09a2SMark Phalan 	pkiDebug("not found\n");
3529159d09a2SMark Phalan 	return NULL;
3530159d09a2SMark Phalan     }
3531159d09a2SMark Phalan     getflist = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR)) dlsym(handle, "C_GetFunctionList");
3532159d09a2SMark Phalan     if (getflist == NULL || (*getflist)(p11p) != CKR_OK) {
3533159d09a2SMark Phalan 	(void) dlclose(handle);
3534159d09a2SMark Phalan 	pkiDebug("failed\n");
3535159d09a2SMark Phalan 	return NULL;
3536159d09a2SMark Phalan     }
3537159d09a2SMark Phalan     pkiDebug("ok\n");
3538159d09a2SMark Phalan     return handle;
3539159d09a2SMark Phalan }
3540159d09a2SMark Phalan 
3541159d09a2SMark Phalan static CK_RV
pkinit_C_UnloadModule(void * handle)3542159d09a2SMark Phalan pkinit_C_UnloadModule(void *handle)
3543159d09a2SMark Phalan {
3544159d09a2SMark Phalan     /* Solaris Kerberos */
3545159d09a2SMark Phalan     if (dlclose(handle) != 0)
3546159d09a2SMark Phalan 	return CKR_GENERAL_ERROR;
3547159d09a2SMark Phalan 
3548159d09a2SMark Phalan     return CKR_OK;
3549159d09a2SMark Phalan }
3550159d09a2SMark Phalan 
35519e11d51cSWill Fiveash /*
35529e11d51cSWill Fiveash  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
35539e11d51cSWill Fiveash  * code.
35549e11d51cSWill Fiveash  *
35559e11d51cSWill Fiveash  * labelstr will be C string containing token label with trailing white space
35569e11d51cSWill Fiveash  * removed.
35579e11d51cSWill Fiveash  */
35589e11d51cSWill Fiveash static void
trim_token_label(CK_TOKEN_INFO * tinfo,char * labelstr,unsigned int labelstr_len)35599e11d51cSWill Fiveash trim_token_label(CK_TOKEN_INFO *tinfo, char *labelstr, unsigned int labelstr_len)
35609e11d51cSWill Fiveash {
35619e11d51cSWill Fiveash     int i;
35629e11d51cSWill Fiveash 
35639e11d51cSWill Fiveash     assert(labelstr_len > sizeof (tinfo->label));
35649e11d51cSWill Fiveash     /*
35659e11d51cSWill Fiveash      * \0 terminate labelstr in case the last char in the token label is
35669e11d51cSWill Fiveash      * non-whitespace
35679e11d51cSWill Fiveash      */
35689e11d51cSWill Fiveash     labelstr[sizeof (tinfo->label)] = '\0';
35699e11d51cSWill Fiveash     (void) memcpy(labelstr, (char *) tinfo->label, sizeof (tinfo->label));
35709e11d51cSWill Fiveash 
35719e11d51cSWill Fiveash     /* init i so terminating \0 is skipped */
35729e11d51cSWill Fiveash     for (i = sizeof (tinfo->label) - 1; i >= 0; i--) {
35739e11d51cSWill Fiveash 	if (labelstr[i] == ' ')
35749e11d51cSWill Fiveash 	    labelstr[i] = '\0';
35759e11d51cSWill Fiveash 	else
35769e11d51cSWill Fiveash 	    break;
35779e11d51cSWill Fiveash     }
35789e11d51cSWill Fiveash }
35799e11d51cSWill Fiveash 
35809e11d51cSWill Fiveash /*
35819e11d51cSWill Fiveash  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
35829e11d51cSWill Fiveash  * code.
35839e11d51cSWill Fiveash  */
35849e11d51cSWill Fiveash static krb5_error_code
pkinit_prompt_user(krb5_context context,pkinit_identity_crypto_context cctx,krb5_data * reply,char * prompt,int hidden)35859e11d51cSWill Fiveash pkinit_prompt_user(krb5_context context,
35869e11d51cSWill Fiveash 		   pkinit_identity_crypto_context cctx,
35879e11d51cSWill Fiveash 		   krb5_data *reply,
35889e11d51cSWill Fiveash 		   char *prompt,
35899e11d51cSWill Fiveash 		   int hidden)
35909e11d51cSWill Fiveash {
35919e11d51cSWill Fiveash     krb5_error_code r;
35929e11d51cSWill Fiveash     krb5_prompt kprompt;
35939e11d51cSWill Fiveash     krb5_prompt_type prompt_type;
35949e11d51cSWill Fiveash 
35959e11d51cSWill Fiveash     if (cctx->prompter == NULL)
35969e11d51cSWill Fiveash 	return (EINVAL);
35979e11d51cSWill Fiveash 
35989e11d51cSWill Fiveash     kprompt.prompt = prompt;
35999e11d51cSWill Fiveash     kprompt.hidden = hidden;
36009e11d51cSWill Fiveash     kprompt.reply = reply;
36019e11d51cSWill Fiveash     /*
36029e11d51cSWill Fiveash      * Note, assuming this type for now, may need to be passed in in the future.
36039e11d51cSWill Fiveash      */
36049e11d51cSWill Fiveash     prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
36059e11d51cSWill Fiveash 
36069e11d51cSWill Fiveash     /* PROMPTER_INVOCATION */
36079e11d51cSWill Fiveash     k5int_set_prompt_types(context, &prompt_type);
36089e11d51cSWill Fiveash     r = (*cctx->prompter)(context, cctx->prompter_data,
36099e11d51cSWill Fiveash 			  NULL, NULL, 1, &kprompt);
36109e11d51cSWill Fiveash     k5int_set_prompt_types(context, NULL);
36119e11d51cSWill Fiveash     return (r);
36129e11d51cSWill Fiveash }
36139e11d51cSWill Fiveash 
3614488060a6SWill Fiveash /*
3615488060a6SWill Fiveash  * Solaris Kerberos: this function was changed to support a PIN being passed
3616488060a6SWill Fiveash  * in.  If that is the case the user will not be prompted for their PIN.
3617488060a6SWill Fiveash  */
3618159d09a2SMark Phalan static krb5_error_code
pkinit_login(krb5_context context,pkinit_identity_crypto_context id_cryptoctx,CK_TOKEN_INFO * tip)3619159d09a2SMark Phalan pkinit_login(krb5_context context,
3620159d09a2SMark Phalan 	     pkinit_identity_crypto_context id_cryptoctx,
3621159d09a2SMark Phalan 	     CK_TOKEN_INFO *tip)
3622159d09a2SMark Phalan {
3623159d09a2SMark Phalan     krb5_data rdat;
3624159d09a2SMark Phalan     char *prompt;
3625159d09a2SMark Phalan     int prompt_len;
3626159d09a2SMark Phalan     int r = 0;
3627159d09a2SMark Phalan 
3628159d09a2SMark Phalan     if (tip->flags & CKF_PROTECTED_AUTHENTICATION_PATH) {
3629159d09a2SMark Phalan 	rdat.data = NULL;
3630159d09a2SMark Phalan 	rdat.length = 0;
3631488060a6SWill Fiveash     } else if (id_cryptoctx->PIN != NULL) {
3632488060a6SWill Fiveash 	if ((rdat.data = strdup(id_cryptoctx->PIN)) == NULL)
3633488060a6SWill Fiveash 	    return (ENOMEM);
3634488060a6SWill Fiveash 	/*
3635488060a6SWill Fiveash 	 * Don't include NULL string terminator in length calculation as this
3636488060a6SWill Fiveash 	 * PIN is passed to the C_Login function and only the text chars should
3637488060a6SWill Fiveash 	 * be considered to be the PIN.
3638488060a6SWill Fiveash 	 */
3639488060a6SWill Fiveash 	rdat.length = strlen(id_cryptoctx->PIN);
3640159d09a2SMark Phalan     } else {
36419e11d51cSWill Fiveash         /* Solaris Kerberos - trim token label */
36429e11d51cSWill Fiveash 	char tmplabel[sizeof (tip->label) + 1];
3643ee0dcabaSWill Fiveash 
3644ee0dcabaSWill Fiveash 	if (!id_cryptoctx->prompter) {
3645ee0dcabaSWill Fiveash 	    pkiDebug("pkinit_login: id_cryptoctx->prompter is NULL\n");
3646ee0dcabaSWill Fiveash 	    /* Solaris Kerberos: Improved error messages */
3647ee0dcabaSWill Fiveash 	    krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
36489e11d51cSWill Fiveash 		gettext("Failed to log into token: prompter function is NULL"));
3649ee0dcabaSWill Fiveash 	    return (KRB5KDC_ERR_PREAUTH_FAILED);
3650ee0dcabaSWill Fiveash 	}
3651159d09a2SMark Phalan 	/* Solaris Kerberos - Changes for gettext() */
3652159d09a2SMark Phalan         prompt_len = sizeof (tip->label) + 256;
3653159d09a2SMark Phalan 	if ((prompt = (char *) malloc(prompt_len)) == NULL)
3654159d09a2SMark Phalan 	    return ENOMEM;
3655011f53d9SWill Fiveash 
3656011f53d9SWill Fiveash 	/* Solaris Kerberos - trim token label which can be padded with space */
36579e11d51cSWill Fiveash 	trim_token_label(tip, tmplabel, sizeof (tmplabel));
36589e11d51cSWill Fiveash 	(void) snprintf(prompt, prompt_len, gettext("%s PIN"), tmplabel);
36599e11d51cSWill Fiveash 
3660159d09a2SMark Phalan 	/* Solaris Kerberos */
3661159d09a2SMark Phalan 	if (tip->flags & CKF_USER_PIN_LOCKED)
3662159d09a2SMark Phalan 	    (void) strlcat(prompt, gettext(" (Warning: PIN locked)"), prompt_len);
3663159d09a2SMark Phalan 	else if (tip->flags & CKF_USER_PIN_FINAL_TRY)
3664159d09a2SMark Phalan 	    (void) strlcat(prompt, gettext(" (Warning: PIN final try)"), prompt_len);
3665159d09a2SMark Phalan 	else if (tip->flags & CKF_USER_PIN_COUNT_LOW)
3666159d09a2SMark Phalan 	    (void) strlcat(prompt, gettext(" (Warning: PIN count low)"), prompt_len);
3667488060a6SWill Fiveash 	rdat.data = malloc(tip->ulMaxPinLen + 2);
3668159d09a2SMark Phalan 	rdat.length = tip->ulMaxPinLen + 1;
3669488060a6SWill Fiveash 	/*
3670488060a6SWill Fiveash 	 * Note that the prompter function will set rdat.length such that the
3671488060a6SWill Fiveash 	 * NULL terminator is not included
3672488060a6SWill Fiveash 	 */
3673159d09a2SMark Phalan 	/* PROMPTER_INVOCATION */
36749e11d51cSWill Fiveash 	r = pkinit_prompt_user(context, id_cryptoctx, &rdat, prompt, 1);
3675159d09a2SMark Phalan 	free(prompt);
3676159d09a2SMark Phalan     }
3677159d09a2SMark Phalan 
3678159d09a2SMark Phalan     if (r == 0) {
3679159d09a2SMark Phalan 	r = id_cryptoctx->p11->C_Login(id_cryptoctx->session, CKU_USER,
3680159d09a2SMark Phalan 		(u_char *) rdat.data, rdat.length);
3681159d09a2SMark Phalan 
3682159d09a2SMark Phalan 	if (r != CKR_OK) {
3683159d09a2SMark Phalan 	    pkiDebug("C_Login: %s\n", pkinit_pkcs11_code_to_text(r));
3684159d09a2SMark Phalan 	    /* Solaris Kerberos: Improved error messages */
3685159d09a2SMark Phalan 	    krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
36869e11d51cSWill Fiveash 		gettext("Failed to log into token: %s"),
3687159d09a2SMark Phalan 		pkinit_pkcs11_code_to_text(r));
3688159d09a2SMark Phalan 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
36897d2d870eSWill Fiveash 	} else {
36907d2d870eSWill Fiveash 	    /* Solaris Kerberos: only need to login once */
36917d2d870eSWill Fiveash             id_cryptoctx->p11flags |= C_LOGIN_DONE;
36927d2d870eSWill Fiveash         }
3693159d09a2SMark Phalan     }
3694488060a6SWill Fiveash     if (rdat.data) {
3695488060a6SWill Fiveash 	(void) memset(rdat.data, 0, rdat.length);
3696159d09a2SMark Phalan 	free(rdat.data);
3697488060a6SWill Fiveash     }
3698159d09a2SMark Phalan 
36999e11d51cSWill Fiveash     return (r);
3700159d09a2SMark Phalan }
3701159d09a2SMark Phalan 
37029e11d51cSWill Fiveash /*
37039e11d51cSWill Fiveash  * Solaris Kerberos: added these structs in support of prompting user for
37049e11d51cSWill Fiveash  * missing token.
37059e11d51cSWill Fiveash  */
37069e11d51cSWill Fiveash struct _token_entry {
37079e11d51cSWill Fiveash     CK_SLOT_ID slotID;
37089e11d51cSWill Fiveash     CK_SESSION_HANDLE session;
37099e11d51cSWill Fiveash     CK_TOKEN_INFO token_info;
37109e11d51cSWill Fiveash };
37119e11d51cSWill Fiveash struct _token_choices {
37129e11d51cSWill Fiveash     unsigned int numtokens;
37139e11d51cSWill Fiveash     struct _token_entry *token_array;
37149e11d51cSWill Fiveash };
37159e11d51cSWill Fiveash 
37169e11d51cSWill Fiveash 
37179e11d51cSWill Fiveash /*
37189e11d51cSWill Fiveash  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
37199e11d51cSWill Fiveash  * code.
37209e11d51cSWill Fiveash  */
3721159d09a2SMark Phalan static krb5_error_code
pkinit_prompt_token(krb5_context context,pkinit_identity_crypto_context cctx)37229e11d51cSWill Fiveash pkinit_prompt_token(krb5_context context,
3723159d09a2SMark Phalan 		    pkinit_identity_crypto_context cctx)
37249e11d51cSWill Fiveash {
37259e11d51cSWill Fiveash     char tmpbuf[4];
37269e11d51cSWill Fiveash     krb5_data reply;
37279e11d51cSWill Fiveash     char *token_prompt = gettext("If you have a smartcard insert it now. "
37289e11d51cSWill Fiveash 				 "Press enter to continue");
37299e11d51cSWill Fiveash 
37309e11d51cSWill Fiveash     reply.data = tmpbuf;
37319e11d51cSWill Fiveash     reply.length = sizeof(tmpbuf);
37329e11d51cSWill Fiveash 
37339e11d51cSWill Fiveash     /* note, don't care about the reply */
37349e11d51cSWill Fiveash     return (pkinit_prompt_user(context, cctx, &reply, token_prompt, 0));
37359e11d51cSWill Fiveash }
37369e11d51cSWill Fiveash 
37379e11d51cSWill Fiveash /*
37389e11d51cSWill Fiveash  * Solaris Kerberos: new defines for prompting support.
37399e11d51cSWill Fiveash  */
37409e11d51cSWill Fiveash #define CHOOSE_THIS_TOKEN 0
37419e11d51cSWill Fiveash #define CHOOSE_RESCAN 1
37429e11d51cSWill Fiveash #define CHOOSE_SKIP 2
37439e11d51cSWill Fiveash #define CHOOSE_SEE_NEXT 3
37449e11d51cSWill Fiveash 
37459e11d51cSWill Fiveash #define RESCAN_TOKENS -1
37469e11d51cSWill Fiveash #define SKIP_TOKENS -2
37479e11d51cSWill Fiveash 
37489e11d51cSWill Fiveash /*
37499e11d51cSWill Fiveash  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
37509e11d51cSWill Fiveash  * code.
37519e11d51cSWill Fiveash  *
37529e11d51cSWill Fiveash  * This prompts to user for various choices regarding a token to use.  Note
37539e11d51cSWill Fiveash  * that if there is no error, choice will be set to one of:
37549e11d51cSWill Fiveash  * - the token_choices->token_array entry
37559e11d51cSWill Fiveash  * - RESCAN_TOKENS
37569e11d51cSWill Fiveash  * - SKIP_TOKENS
37579e11d51cSWill Fiveash  */
37589e11d51cSWill Fiveash static int
pkinit_choose_tokens(krb5_context context,pkinit_identity_crypto_context cctx,struct _token_choices * token_choices,int * choice)37599e11d51cSWill Fiveash pkinit_choose_tokens(krb5_context context,
37609e11d51cSWill Fiveash 		     pkinit_identity_crypto_context cctx,
37619e11d51cSWill Fiveash 		     struct _token_choices *token_choices,
37629e11d51cSWill Fiveash 		     int *choice)
37639e11d51cSWill Fiveash {
37649e11d51cSWill Fiveash     krb5_error_code r;
37659e11d51cSWill Fiveash     /*
37669e11d51cSWill Fiveash      * Assuming that PAM_MAX_MSG_SIZE is a reasonable restriction. Note that -
37679e11d51cSWill Fiveash      * 2 is to account for the fact that a krb prompter to PAM conv bridge will
37689e11d51cSWill Fiveash      * add ": ".
37699e11d51cSWill Fiveash      */
37709e11d51cSWill Fiveash     char prompt[PAM_MAX_MSG_SIZE - 2];
37719e11d51cSWill Fiveash     char tmpbuf[4];
37729e11d51cSWill Fiveash     char tmplabel[sizeof (token_choices->token_array->token_info.label) + 1];
37739e11d51cSWill Fiveash     krb5_data reply;
37749e11d51cSWill Fiveash     int i, num_used, tmpchoice;
37759e11d51cSWill Fiveash 
37769e11d51cSWill Fiveash     assert(token_choices != NULL);
37779e11d51cSWill Fiveash     assert(choice != NULL);
37789e11d51cSWill Fiveash 
37799e11d51cSWill Fiveash     /* Create the menu prompt */
37809e11d51cSWill Fiveash 
37819e11d51cSWill Fiveash     /* only need to do this once before the for loop */
37829e11d51cSWill Fiveash     reply.data = tmpbuf;
37839e11d51cSWill Fiveash 
37849e11d51cSWill Fiveash     for (i = 0; i < token_choices->numtokens; i++) {
37859e11d51cSWill Fiveash 
37869e11d51cSWill Fiveash 	trim_token_label(&token_choices->token_array[i].token_info, tmplabel,
37879e11d51cSWill Fiveash 			 sizeof (tmplabel));
37889e11d51cSWill Fiveash 
37899e11d51cSWill Fiveash 	if (i == (token_choices->numtokens - 1)) {
37909e11d51cSWill Fiveash 	    /* no more smartcards/tokens */
37919e11d51cSWill Fiveash 	    if ((num_used = snprintf(prompt, sizeof (prompt),
37929e11d51cSWill Fiveash 				     "%s\n%d: %s \"%s\" %s %d\n%d: %s\n%d: %s\n",
37939e11d51cSWill Fiveash 				     /*
37949e11d51cSWill Fiveash 				      * TRANSLATION_NOTE: Translations of the
37959e11d51cSWill Fiveash 				      * following 5 strings must not exceed 450
37969e11d51cSWill Fiveash 				      * bytes total.
37979e11d51cSWill Fiveash 				      */
37989e11d51cSWill Fiveash 				     gettext("Select one of the following and press enter:"),
37999e11d51cSWill Fiveash 				     CHOOSE_THIS_TOKEN, gettext("Use smartcard"), tmplabel,
38009e11d51cSWill Fiveash                                      gettext("in slot"), token_choices->token_array[i].slotID,
38019e11d51cSWill Fiveash 				     CHOOSE_RESCAN, gettext("Rescan for newly inserted smartcard"),
38029e11d51cSWill Fiveash 				     CHOOSE_SKIP, gettext("Skip smartcard authentication")))
38039e11d51cSWill Fiveash 		>= sizeof (prompt)) {
38049e11d51cSWill Fiveash 		pkiDebug("pkinit_choose_tokens: buffer overflow num_used: %d,"
38059e11d51cSWill Fiveash 			 " sizeof prompt: %d\n", num_used, sizeof (prompt));
38069e11d51cSWill Fiveash 		krb5_set_error_message(context, EINVAL,
38079e11d51cSWill Fiveash                                gettext("In pkinit_choose_tokens: prompt size"
38089e11d51cSWill Fiveash 				      " %d exceeds prompt buffer size %d"),
38099e11d51cSWill Fiveash 			       num_used, sizeof(prompt));
38109e11d51cSWill Fiveash 		(void) snprintf(prompt, sizeof (prompt), "%s",
38119e11d51cSWill Fiveash 			        gettext("Error: PKINIT prompt message is too large for buffer, "
38129e11d51cSWill Fiveash 					"please alert the system administrator. Press enter to "
38139e11d51cSWill Fiveash 					"continue"));
38149e11d51cSWill Fiveash 		reply.length = sizeof(tmpbuf);
38159e11d51cSWill Fiveash 		if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
38169e11d51cSWill Fiveash 		    return (r);
38179e11d51cSWill Fiveash 		return (EINVAL);
38189e11d51cSWill Fiveash 	    }
38199e11d51cSWill Fiveash 	} else {
38209e11d51cSWill Fiveash 	    if ((num_used = snprintf(prompt, sizeof (prompt),
38219e11d51cSWill Fiveash 				     "%s\n%d: %s \"%s\" %s %d\n%d: %s\n%d: %s\n%d: %s\n",
38229e11d51cSWill Fiveash 				     /*
38239e11d51cSWill Fiveash 				      * TRANSLATION_NOTE: Translations of the
38249e11d51cSWill Fiveash 				      * following 6 strings must not exceed 445
38259e11d51cSWill Fiveash 				      * bytes total.
38269e11d51cSWill Fiveash 				      */
38279e11d51cSWill Fiveash 				     gettext("Select one of the following and press enter:"),
38289e11d51cSWill Fiveash 				     CHOOSE_THIS_TOKEN, gettext("Use smartcard"), tmplabel,
38299e11d51cSWill Fiveash                                      gettext("in slot"), token_choices->token_array[i].slotID,
38309e11d51cSWill Fiveash 				     CHOOSE_RESCAN, gettext("Rescan for newly inserted smartcard"),
38319e11d51cSWill Fiveash 				     CHOOSE_SKIP, gettext("Skip smartcard authentication"),
38329e11d51cSWill Fiveash 				     CHOOSE_SEE_NEXT, gettext("See next smartcard")))
38339e11d51cSWill Fiveash 		>= sizeof (prompt)) {
38349e11d51cSWill Fiveash 
38359e11d51cSWill Fiveash 		pkiDebug("pkinit_choose_tokens: buffer overflow num_used: %d,"
38369e11d51cSWill Fiveash 			 " sizeof prompt: %d\n", num_used, sizeof (prompt));
38379e11d51cSWill Fiveash 		krb5_set_error_message(context, EINVAL,
38389e11d51cSWill Fiveash 				       gettext("In pkinit_choose_tokens: prompt size"
38399e11d51cSWill Fiveash 					       " %d exceeds prompt buffer size %d"),
38409e11d51cSWill Fiveash 				       num_used, sizeof(prompt));
38419e11d51cSWill Fiveash 		(void) snprintf(prompt, sizeof (prompt), "%s",
38429e11d51cSWill Fiveash 				gettext("Error: PKINIT prompt message is too large for buffer, "
38439e11d51cSWill Fiveash 					"please alert the system administrator. Press enter to "
38449e11d51cSWill Fiveash 					"continue"));
38459e11d51cSWill Fiveash 		reply.length = sizeof(tmpbuf);
38469e11d51cSWill Fiveash 		if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
38479e11d51cSWill Fiveash 		    return (r);
38489e11d51cSWill Fiveash 		return (EINVAL);
38499e11d51cSWill Fiveash 	    }
38509e11d51cSWill Fiveash 	}
38519e11d51cSWill Fiveash 
38529e11d51cSWill Fiveash         /*
38539e11d51cSWill Fiveash 	 * reply.length needs to be reset to length of tmpbuf before calling
38549e11d51cSWill Fiveash 	 * prompter
38559e11d51cSWill Fiveash          */
38569e11d51cSWill Fiveash         reply.length = sizeof(tmpbuf);
38579e11d51cSWill Fiveash 	if ((r = pkinit_prompt_user(context, cctx, &reply, prompt, 0)) != 0 )
38589e11d51cSWill Fiveash 	    return (r);
38599e11d51cSWill Fiveash 
38609e11d51cSWill Fiveash 	if (reply.length == 0) {
38619e11d51cSWill Fiveash 	    return (EINVAL);
38629e11d51cSWill Fiveash 	} else {
38639e11d51cSWill Fiveash             char *cp = reply.data;
38649e11d51cSWill Fiveash             /* reply better be digits */
38653f8dd771SAndy Fiddaman             while (*cp != '\0') {
38669e11d51cSWill Fiveash                 if (!isdigit(*cp++))
38679e11d51cSWill Fiveash                     return (EINVAL);
38689e11d51cSWill Fiveash             }
38699e11d51cSWill Fiveash 	    errno = 0;
38709e11d51cSWill Fiveash 	    tmpchoice = (int) strtol(reply.data, (char **)NULL, 10);
38719e11d51cSWill Fiveash 	    if (errno != 0)
38729e11d51cSWill Fiveash 		return (errno);
38739e11d51cSWill Fiveash 	}
38749e11d51cSWill Fiveash 
38759e11d51cSWill Fiveash 	switch (tmpchoice) {
38769e11d51cSWill Fiveash 	case CHOOSE_THIS_TOKEN:
38779e11d51cSWill Fiveash 	    *choice = i; /* chosen entry of token_choices->token_array */
38789e11d51cSWill Fiveash 	    return (0);
38799e11d51cSWill Fiveash 	case CHOOSE_RESCAN:
38809e11d51cSWill Fiveash 	    *choice = RESCAN_TOKENS; /* rescan for new smartcard */
38819e11d51cSWill Fiveash 	    return (0);
38829e11d51cSWill Fiveash 	case CHOOSE_SKIP:
38839e11d51cSWill Fiveash 	    *choice = SKIP_TOKENS; /* skip smartcard auth */
38849e11d51cSWill Fiveash 	    return (0);
38859e11d51cSWill Fiveash 	case CHOOSE_SEE_NEXT: /* see next smartcard */
38869e11d51cSWill Fiveash 	    continue;
38879e11d51cSWill Fiveash 	default:
38889e11d51cSWill Fiveash 	    return (EINVAL);
38899e11d51cSWill Fiveash 	}
38909e11d51cSWill Fiveash     }
38919e11d51cSWill Fiveash 
38929e11d51cSWill Fiveash     return (0);
38939e11d51cSWill Fiveash }
38949e11d51cSWill Fiveash 
38959e11d51cSWill Fiveash /*
38969e11d51cSWill Fiveash  * Solaris Kerberos: this is a new function that does not exist yet in the MIT
38979e11d51cSWill Fiveash  * code.
38989e11d51cSWill Fiveash  *
38999e11d51cSWill Fiveash  * Note, this isn't the best solution to providing a function to check the
39009e11d51cSWill Fiveash  * certs in a token however I wanted to avoid rewriting a bunch of code so I
39019e11d51cSWill Fiveash  * settled for some duplication of processing.
39029e11d51cSWill Fiveash  */
39039e11d51cSWill Fiveash static krb5_error_code
check_load_certs(krb5_context context,CK_SESSION_HANDLE session,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context id_cryptoctx,krb5_principal princ,int do_matching,int load_cert)39049e11d51cSWill Fiveash check_load_certs(krb5_context context,
39059e11d51cSWill Fiveash             CK_SESSION_HANDLE session,
39069e11d51cSWill Fiveash 	    pkinit_plg_crypto_context plg_cryptoctx,
39079e11d51cSWill Fiveash 	    pkinit_req_crypto_context req_cryptoctx,
39089e11d51cSWill Fiveash             pkinit_identity_crypto_context id_cryptoctx,
39099e11d51cSWill Fiveash             krb5_principal princ,
39109e11d51cSWill Fiveash             int do_matching,
39119e11d51cSWill Fiveash             int load_cert)
39129e11d51cSWill Fiveash {
39139e11d51cSWill Fiveash     CK_OBJECT_CLASS cls;
39149e11d51cSWill Fiveash     CK_OBJECT_HANDLE obj;
39159e11d51cSWill Fiveash     CK_ATTRIBUTE attrs[4];
39169e11d51cSWill Fiveash     CK_ULONG count;
39179e11d51cSWill Fiveash     CK_CERTIFICATE_TYPE certtype;
39189e11d51cSWill Fiveash     CK_BYTE_PTR cert = NULL, cert_id = NULL;
39199e11d51cSWill Fiveash     const unsigned char *cp;
39209e11d51cSWill Fiveash     int i, r;
39219e11d51cSWill Fiveash     unsigned int nattrs;
39229e11d51cSWill Fiveash     X509 *x = NULL;
39239e11d51cSWill Fiveash 
39249e11d51cSWill Fiveash     cls = CKO_CERTIFICATE;
39259e11d51cSWill Fiveash     attrs[0].type = CKA_CLASS;
39269e11d51cSWill Fiveash     attrs[0].pValue = &cls;
39279e11d51cSWill Fiveash     attrs[0].ulValueLen = sizeof cls;
39289e11d51cSWill Fiveash 
39299e11d51cSWill Fiveash     certtype = CKC_X_509;
39309e11d51cSWill Fiveash     attrs[1].type = CKA_CERTIFICATE_TYPE;
39319e11d51cSWill Fiveash     attrs[1].pValue = &certtype;
39329e11d51cSWill Fiveash     attrs[1].ulValueLen = sizeof certtype;
39339e11d51cSWill Fiveash 
39349e11d51cSWill Fiveash     nattrs = 2;
39359e11d51cSWill Fiveash 
39369e11d51cSWill Fiveash     /* If a cert id and/or label were given, use them too */
39379e11d51cSWill Fiveash     if (id_cryptoctx->cert_id_len > 0) {
39389e11d51cSWill Fiveash 	attrs[nattrs].type = CKA_ID;
39399e11d51cSWill Fiveash 	attrs[nattrs].pValue = id_cryptoctx->cert_id;
39409e11d51cSWill Fiveash 	attrs[nattrs].ulValueLen = id_cryptoctx->cert_id_len;
39419e11d51cSWill Fiveash 	nattrs++;
39429e11d51cSWill Fiveash     }
39439e11d51cSWill Fiveash     if (id_cryptoctx->cert_label != NULL) {
39449e11d51cSWill Fiveash 	attrs[nattrs].type = CKA_LABEL;
39459e11d51cSWill Fiveash 	attrs[nattrs].pValue = id_cryptoctx->cert_label;
39469e11d51cSWill Fiveash 	attrs[nattrs].ulValueLen = strlen(id_cryptoctx->cert_label);
39479e11d51cSWill Fiveash 	nattrs++;
39489e11d51cSWill Fiveash     }
39499e11d51cSWill Fiveash 
39509e11d51cSWill Fiveash     r = id_cryptoctx->p11->C_FindObjectsInit(session, attrs, nattrs);
39519e11d51cSWill Fiveash     if (r != CKR_OK) {
39529e11d51cSWill Fiveash         pkiDebug("C_FindObjectsInit: %s\n", pkinit_pkcs11_code_to_text(r));
39539e11d51cSWill Fiveash         krb5_set_error_message(context, EINVAL,
39549e11d51cSWill Fiveash                                gettext("PKCS11 error from C_FindObjectsInit: %s"),
39559e11d51cSWill Fiveash                                pkinit_pkcs11_code_to_text(r));
39569e11d51cSWill Fiveash         r = EINVAL;
39579e11d51cSWill Fiveash         goto out;
39589e11d51cSWill Fiveash     }
39599e11d51cSWill Fiveash 
39609e11d51cSWill Fiveash     for (i = 0; ; i++) {
39619e11d51cSWill Fiveash 	if (i >= MAX_CREDS_ALLOWED) {
39629e11d51cSWill Fiveash             r = EINVAL;
39639e11d51cSWill Fiveash             goto out;
39649e11d51cSWill Fiveash         }
39659e11d51cSWill Fiveash 
39669e11d51cSWill Fiveash 	/* Look for x.509 cert */
39679e11d51cSWill Fiveash 	/* Solaris Kerberos */
39689e11d51cSWill Fiveash 	if ((r = id_cryptoctx->p11->C_FindObjects(session, &obj, 1, &count))
39699e11d51cSWill Fiveash             != CKR_OK || count == 0) {
39709e11d51cSWill Fiveash 	    id_cryptoctx->creds[i] = NULL;
39719e11d51cSWill Fiveash 	    break;
39729e11d51cSWill Fiveash 	}
39739e11d51cSWill Fiveash 
39749e11d51cSWill Fiveash 	/* Get cert and id len */
39759e11d51cSWill Fiveash 	attrs[0].type = CKA_VALUE;
39769e11d51cSWill Fiveash 	attrs[0].pValue = NULL;
39779e11d51cSWill Fiveash 	attrs[0].ulValueLen = 0;
39789e11d51cSWill Fiveash 
39799e11d51cSWill Fiveash 	attrs[1].type = CKA_ID;
39809e11d51cSWill Fiveash 	attrs[1].pValue = NULL;
39819e11d51cSWill Fiveash 	attrs[1].ulValueLen = 0;
39829e11d51cSWill Fiveash 
39839e11d51cSWill Fiveash 	if ((r = id_cryptoctx->p11->C_GetAttributeValue(session,
39849e11d51cSWill Fiveash                                                         obj,
39859e11d51cSWill Fiveash                                                         attrs,
39869e11d51cSWill Fiveash                                                         2)) != CKR_OK &&
39879e11d51cSWill Fiveash             r != CKR_BUFFER_TOO_SMALL) {
39889e11d51cSWill Fiveash             pkiDebug("C_GetAttributeValue: %s\n", pkinit_pkcs11_code_to_text(r));
39899e11d51cSWill Fiveash 	    krb5_set_error_message(context, EINVAL,
39909e11d51cSWill Fiveash 				   gettext("Error from PKCS11 C_GetAttributeValue: %s"),
39919e11d51cSWill Fiveash 				   pkinit_pkcs11_code_to_text(r));
39929e11d51cSWill Fiveash             r = EINVAL;
39939e11d51cSWill Fiveash             goto out;
39949e11d51cSWill Fiveash         }
39959e11d51cSWill Fiveash 	cert = malloc((size_t) attrs[0].ulValueLen + 1);
39969e11d51cSWill Fiveash 	if (cert == NULL) {
39979e11d51cSWill Fiveash 	    r = ENOMEM;
39989e11d51cSWill Fiveash             goto out;
39999e11d51cSWill Fiveash         }
40009e11d51cSWill Fiveash 	cert_id = malloc((size_t) attrs[1].ulValueLen + 1);
40019e11d51cSWill Fiveash 	if (cert_id == NULL) {
40029e11d51cSWill Fiveash 	    r = ENOMEM;
40039e11d51cSWill Fiveash             goto out;
40049e11d51cSWill Fiveash         }
40059e11d51cSWill Fiveash 
40069e11d51cSWill Fiveash 	/* Read the cert and id off the card */
40079e11d51cSWill Fiveash 
40089e11d51cSWill Fiveash 	attrs[0].type = CKA_VALUE;
40099e11d51cSWill Fiveash 	attrs[0].pValue = cert;
40109e11d51cSWill Fiveash 
40119e11d51cSWill Fiveash 	attrs[1].type = CKA_ID;
40129e11d51cSWill Fiveash 	attrs[1].pValue = cert_id;
40139e11d51cSWill Fiveash 
40149e11d51cSWill Fiveash 	if ((r = id_cryptoctx->p11->C_GetAttributeValue(session,
40159e11d51cSWill Fiveash 		obj, attrs, 2)) != CKR_OK) {
40169e11d51cSWill Fiveash 	    pkiDebug("C_GetAttributeValue: %s\n", pkinit_pkcs11_code_to_text(r));
40179e11d51cSWill Fiveash 	    krb5_set_error_message(context, EINVAL,
40189e11d51cSWill Fiveash 				   gettext("Error from PKCS11 C_GetAttributeValue: %s"),
40199e11d51cSWill Fiveash 				   pkinit_pkcs11_code_to_text(r));
40209e11d51cSWill Fiveash 	    r = EINVAL;
40219e11d51cSWill Fiveash             goto out;
40229e11d51cSWill Fiveash 	}
40239e11d51cSWill Fiveash 
40249e11d51cSWill Fiveash 	pkiDebug("cert %d size %d id %d idlen %d\n", i,
40259e11d51cSWill Fiveash 	    (int) attrs[0].ulValueLen, (int) cert_id[0],
40269e11d51cSWill Fiveash 	    (int) attrs[1].ulValueLen);
40279e11d51cSWill Fiveash 
40289e11d51cSWill Fiveash 	cp = (unsigned char *) cert;
40299e11d51cSWill Fiveash 	x = d2i_X509(NULL, &cp, (int) attrs[0].ulValueLen);
40309e11d51cSWill Fiveash 	if (x == NULL) {
40319e11d51cSWill Fiveash 	    r = EINVAL;
40329e11d51cSWill Fiveash             goto out;
40339e11d51cSWill Fiveash         }
40349e11d51cSWill Fiveash 
40359e11d51cSWill Fiveash 	id_cryptoctx->creds[i] = malloc(sizeof(struct _pkinit_cred_info));
40369e11d51cSWill Fiveash 	if (id_cryptoctx->creds[i] == NULL) {
40379e11d51cSWill Fiveash 	    r = ENOMEM;
40389e11d51cSWill Fiveash             goto out;
40399e11d51cSWill Fiveash         }
40409e11d51cSWill Fiveash 	id_cryptoctx->creds[i]->cert = x;
40419e11d51cSWill Fiveash 	id_cryptoctx->creds[i]->key = NULL;
40429e11d51cSWill Fiveash 	id_cryptoctx->creds[i]->cert_id = cert_id;
40439e11d51cSWill Fiveash         cert_id = NULL;
40449e11d51cSWill Fiveash 	id_cryptoctx->creds[i]->cert_id_len = attrs[1].ulValueLen;
40459e11d51cSWill Fiveash 	free(cert);
40469e11d51cSWill Fiveash         cert = NULL;
40479e11d51cSWill Fiveash     }
40489e11d51cSWill Fiveash     id_cryptoctx->p11->C_FindObjectsFinal(session);
40499e11d51cSWill Fiveash 
40509e11d51cSWill Fiveash     if (id_cryptoctx->creds[0] == NULL || id_cryptoctx->creds[0]->cert == NULL) {
40519e11d51cSWill Fiveash 	r = ENOENT;
40529e11d51cSWill Fiveash     } else if (do_matching){
40539e11d51cSWill Fiveash         /*
40549e11d51cSWill Fiveash          * Do not let pkinit_cert_matching set the primary cert in id_cryptoctx
40559e11d51cSWill Fiveash          * as this will be done later.
40569e11d51cSWill Fiveash          */
40579e11d51cSWill Fiveash         r = pkinit_cert_matching(context, plg_cryptoctx, req_cryptoctx,
40589e11d51cSWill Fiveash                                  id_cryptoctx, princ, FALSE);
40599e11d51cSWill Fiveash     }
40609e11d51cSWill Fiveash 
40619e11d51cSWill Fiveash out:
40629e11d51cSWill Fiveash     if ((r != 0 || !load_cert) &&
40639e11d51cSWill Fiveash         id_cryptoctx->creds[0] != NULL &&
40649e11d51cSWill Fiveash         id_cryptoctx->creds[0]->cert != NULL) {
40659e11d51cSWill Fiveash         /*
40669e11d51cSWill Fiveash          * If there's an error or load_cert isn't 1 free all the certs loaded
40679e11d51cSWill Fiveash          * onto id_cryptoctx.
40689e11d51cSWill Fiveash          */
40699e11d51cSWill Fiveash         (void) crypto_free_cert_info(context, plg_cryptoctx, req_cryptoctx,
40709e11d51cSWill Fiveash                                      id_cryptoctx);
40719e11d51cSWill Fiveash     }
40729e11d51cSWill Fiveash 
40739e11d51cSWill Fiveash     if (cert)
40749e11d51cSWill Fiveash         free(cert);
40759e11d51cSWill Fiveash 
40769e11d51cSWill Fiveash     if (cert_id)
40779e11d51cSWill Fiveash         free(cert_id);
4078300fdee2SAndy Fiddaman 
40799e11d51cSWill Fiveash     return (r);
40809e11d51cSWill Fiveash }
40819e11d51cSWill Fiveash 
40829e11d51cSWill Fiveash /*
40839e11d51cSWill Fiveash  * Solaris Kerberos: this function has been significantly modified to prompt
40849e11d51cSWill Fiveash  * the user in certain cases so defer to this version when resyncing MIT code.
40859e11d51cSWill Fiveash  *
40869e11d51cSWill Fiveash  * pkinit_open_session now does several things including prompting the user if
40879e11d51cSWill Fiveash  * do_matching is set which indicates the code is executing in a client
40889e11d51cSWill Fiveash  * context.  This function fills out a pkinit_identity_crypto_context with a
40899e11d51cSWill Fiveash  * set of certs and a open session if a token can be found that matches all
40909e11d51cSWill Fiveash  * supplied criteria.  If no token is found then the user is prompted one time
40919e11d51cSWill Fiveash  * to insert their token.  If there is more than one token that matches all
40929e11d51cSWill Fiveash  * client criteria the user is prompted to make a choice if in client context.
40939e11d51cSWill Fiveash  * If do_matching is false (KDC context) then the first token matching all
40949e11d51cSWill Fiveash  * server criteria is chosen.
40959e11d51cSWill Fiveash  */
40969e11d51cSWill Fiveash static krb5_error_code
pkinit_open_session(krb5_context context,pkinit_plg_crypto_context plg_cryptoctx,pkinit_req_crypto_context req_cryptoctx,pkinit_identity_crypto_context cctx,krb5_principal princ,int do_matching)40979e11d51cSWill Fiveash pkinit_open_session(krb5_context context,
40989e11d51cSWill Fiveash                     pkinit_plg_crypto_context plg_cryptoctx,
40999e11d51cSWill Fiveash                     pkinit_req_crypto_context req_cryptoctx,
41009e11d51cSWill Fiveash                     pkinit_identity_crypto_context cctx,
41019e11d51cSWill Fiveash                     krb5_principal princ,
41029e11d51cSWill Fiveash                     int do_matching)
4103159d09a2SMark Phalan {
4104159d09a2SMark Phalan     int i, r;
4105159d09a2SMark Phalan     CK_ULONG count = 0;
41069e11d51cSWill Fiveash     CK_SLOT_ID_PTR slotlist = NULL, tmpslotlist = NULL;
4107159d09a2SMark Phalan     CK_TOKEN_INFO tinfo;
41089e11d51cSWill Fiveash     krb5_boolean tokenmatch = FALSE;
41093f8dd771SAndy Fiddaman     CK_SESSION_HANDLE tmpsession = CK_INVALID_HANDLE;
41109e11d51cSWill Fiveash     struct _token_choices token_choices;
41119e11d51cSWill Fiveash     int choice = 0;
4112159d09a2SMark Phalan 
41139e11d51cSWill Fiveash     if (cctx->session != CK_INVALID_HANDLE)
4114159d09a2SMark Phalan 	return 0; /* session already open */
4115159d09a2SMark Phalan 
4116159d09a2SMark Phalan     /* Load module */
41179e11d51cSWill Fiveash     if (cctx->p11_module == NULL) {
41189e11d51cSWill Fiveash         cctx->p11_module =
41199e11d51cSWill Fiveash             pkinit_C_LoadModule(cctx->p11_module_name, &cctx->p11);
41209e11d51cSWill Fiveash         if (cctx->p11_module == NULL)
41219e11d51cSWill Fiveash             return KRB5KDC_ERR_PREAUTH_FAILED;
41229e11d51cSWill Fiveash     }
4123159d09a2SMark Phalan 
4124159d09a2SMark Phalan     /* Init */
4125159d09a2SMark Phalan     /* Solaris Kerberos: Don't fail if cryptoki is already initialized */
4126159d09a2SMark Phalan     r = cctx->p11->C_Initialize(NULL);
4127159d09a2SMark Phalan     if (r != CKR_OK && r != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
4128159d09a2SMark Phalan 	pkiDebug("C_Initialize: %s\n", pkinit_pkcs11_code_to_text(r));
41299e11d51cSWill Fiveash 	krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
41309e11d51cSWill Fiveash 			       gettext("Error from PKCS11 C_Initialize: %s"),
41319e11d51cSWill Fiveash 			       pkinit_pkcs11_code_to_text(r));
4132159d09a2SMark Phalan 	return KRB5KDC_ERR_PREAUTH_FAILED;
4133159d09a2SMark Phalan     }
4134159d09a2SMark Phalan 
41359e11d51cSWill Fiveash     (void) memset(&token_choices, 0, sizeof(token_choices));
41369e11d51cSWill Fiveash 
4137159d09a2SMark Phalan     /*
4138159d09a2SMark Phalan      * Solaris Kerberos:
4139159d09a2SMark Phalan      * If C_Initialize was already called by the process before the pkinit
4140159d09a2SMark Phalan      * module was loaded then record that fact.
4141159d09a2SMark Phalan      * "finalize_pkcs11" is used by pkinit_fini_pkcs11 to determine whether
4142300fdee2SAndy Fiddaman      * or not C_Finalize() should be called.
4143159d09a2SMark Phalan      */
4144159d09a2SMark Phalan      cctx->finalize_pkcs11 =
4145159d09a2SMark Phalan 	(r == CKR_CRYPTOKI_ALREADY_INITIALIZED ? FALSE : TRUE);
41469e11d51cSWill Fiveash     /*
41479e11d51cSWill Fiveash      * First make sure that is an applicable slot otherwise fail.
41489e11d51cSWill Fiveash      *
41499e11d51cSWill Fiveash      * Start by getting a count of all slots with or without tokens.
41509e11d51cSWill Fiveash      */
4151159d09a2SMark Phalan 
41529e11d51cSWill Fiveash     if ((r = cctx->p11->C_GetSlotList(FALSE, NULL, &count)) != CKR_OK) {
41539e11d51cSWill Fiveash 	pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
41549e11d51cSWill Fiveash 	krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
41559e11d51cSWill Fiveash 	    gettext("Error trying to get PKCS11 slot list: %s"),
41569e11d51cSWill Fiveash 	    pkinit_pkcs11_code_to_text(r));
41579e11d51cSWill Fiveash 	r = KRB5KDC_ERR_PREAUTH_FAILED;
41589e11d51cSWill Fiveash 	goto out;
41599e11d51cSWill Fiveash     }
4160e4b3f553SWill Fiveash 
4161e4b3f553SWill Fiveash     if (count == 0) {
41629e11d51cSWill Fiveash 	/* There are no slots so bail */
4163e4b3f553SWill Fiveash 	r = KRB5KDC_ERR_PREAUTH_FAILED;
4164e4b3f553SWill Fiveash 	krb5_set_error_message(context, r,
41659e11d51cSWill Fiveash 			       gettext("No PKCS11 slots found"));
41669e11d51cSWill Fiveash 	pkiDebug("pkinit_open_session: no slots, count: %d\n", count);
41679e11d51cSWill Fiveash 	goto out;
41689e11d51cSWill Fiveash     } else if (cctx->slotid != PK_NOSLOT) {
41699e11d51cSWill Fiveash 	/* See if any of the slots match the specified slotID */
41709e11d51cSWill Fiveash 	tmpslotlist = malloc(count * sizeof (CK_SLOT_ID));
41719e11d51cSWill Fiveash 	if (tmpslotlist == NULL) {
41729e11d51cSWill Fiveash 	    krb5_set_error_message(context, ENOMEM,
41739e11d51cSWill Fiveash 				   gettext("Memory allocation error:"));
41749e11d51cSWill Fiveash 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
41759e11d51cSWill Fiveash 	    goto out;
41769e11d51cSWill Fiveash 	}
41779e11d51cSWill Fiveash 	if ((r = cctx->p11->C_GetSlotList(FALSE, tmpslotlist, &count)) != CKR_OK) {
41789e11d51cSWill Fiveash 	    krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
41799e11d51cSWill Fiveash 				   gettext("Error trying to get PKCS11 slot list: %s"),
41809e11d51cSWill Fiveash 				   pkinit_pkcs11_code_to_text(r));
41819e11d51cSWill Fiveash 	    pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
41829e11d51cSWill Fiveash 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
41839e11d51cSWill Fiveash 	    goto out;
41849e11d51cSWill Fiveash 	}
41859e11d51cSWill Fiveash 
41869e11d51cSWill Fiveash 	for (i = 0; i < count && cctx->slotid != tmpslotlist[i]; i++)
41879e11d51cSWill Fiveash 	    continue;
41889e11d51cSWill Fiveash 
41899e11d51cSWill Fiveash 	if (i >= count) {
41909e11d51cSWill Fiveash 	    /* no slots match */
41919e11d51cSWill Fiveash 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
41929e11d51cSWill Fiveash 	    krb5_set_error_message(context, r,
41939e11d51cSWill Fiveash 				   gettext("Requested PKCS11 slot ID %d not found"),
41949e11d51cSWill Fiveash 				   cctx->slotid);
41959e11d51cSWill Fiveash 	    pkiDebug("open_session: no matching slot found for slotID %d\n",
41969e11d51cSWill Fiveash 		     cctx->slotid);
41979e11d51cSWill Fiveash 	    goto out;
41989e11d51cSWill Fiveash 	}
41999e11d51cSWill Fiveash     }
4200300fdee2SAndy Fiddaman 
42019e11d51cSWill Fiveash tryagain:
42029e11d51cSWill Fiveash     /* get count of slots that have tokens */
42039e11d51cSWill Fiveash     if ((r = cctx->p11->C_GetSlotList(TRUE, NULL, &count)) != CKR_OK) {
42049e11d51cSWill Fiveash 	pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
42059e11d51cSWill Fiveash 	krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
42069e11d51cSWill Fiveash 			       gettext("Error trying to get PKCS11 slot list: %s"),
42079e11d51cSWill Fiveash 			       pkinit_pkcs11_code_to_text(r));
42089e11d51cSWill Fiveash 	r = KRB5KDC_ERR_PREAUTH_FAILED;
4209e4b3f553SWill Fiveash 	goto out;
4210e4b3f553SWill Fiveash     }
4211e4b3f553SWill Fiveash 
42129e11d51cSWill Fiveash     if (count == 0) {
42139e11d51cSWill Fiveash 	/*
42149e11d51cSWill Fiveash 	 * Note, never prompt if !do_matching as this implies KDC side
42159e11d51cSWill Fiveash 	 * processing
42169e11d51cSWill Fiveash 	 */
42179e11d51cSWill Fiveash 	if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
42189e11d51cSWill Fiveash 	    /* found slot(s) but no token so prompt and try again */
42199e11d51cSWill Fiveash 	    if ((r = pkinit_prompt_token(context, cctx)) == 0) {
42209e11d51cSWill Fiveash 		cctx->p11flags |= C_PROMPTED_USER;
42219e11d51cSWill Fiveash 		goto tryagain;
42229e11d51cSWill Fiveash 	    } else {
42239e11d51cSWill Fiveash 		pkiDebug("open_session: prompt for token/smart card failed\n");
42249e11d51cSWill Fiveash 		krb5_set_error_message(context, r,
42259e11d51cSWill Fiveash 				       gettext("Prompt for token/smart card failed"));
42269e11d51cSWill Fiveash 		r = KRB5KDC_ERR_PREAUTH_FAILED;
42279e11d51cSWill Fiveash 		goto out;
42289e11d51cSWill Fiveash 	    }
42299e11d51cSWill Fiveash 
42309e11d51cSWill Fiveash 	} else {
42319e11d51cSWill Fiveash 	    /* already prompted once so bailing */
42329e11d51cSWill Fiveash 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
42339e11d51cSWill Fiveash 	    krb5_set_error_message(context, r,
42349e11d51cSWill Fiveash 				   gettext("No smart card tokens found"));
42359e11d51cSWill Fiveash 	    pkiDebug("pkinit_open_session: no token, already prompted\n");
42369e11d51cSWill Fiveash 	    goto out;
42379e11d51cSWill Fiveash 	}
42389e11d51cSWill Fiveash     }
42399e11d51cSWill Fiveash 
42409e11d51cSWill Fiveash     if (slotlist != NULL)
42419e11d51cSWill Fiveash 	free(slotlist);
4242300fdee2SAndy Fiddaman 
4243e4b3f553SWill Fiveash     slotlist = malloc(count * sizeof (CK_SLOT_ID));
4244e4b3f553SWill Fiveash     if (slotlist == NULL) {
4245e4b3f553SWill Fiveash 	krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4246e4b3f553SWill Fiveash 			       gettext("Memory allocation error"));
4247e4b3f553SWill Fiveash 	r = KRB5KDC_ERR_PREAUTH_FAILED;
4248e4b3f553SWill Fiveash 	goto out;
4249e4b3f553SWill Fiveash     }
4250e4b3f553SWill Fiveash     /*
4251e4b3f553SWill Fiveash      * Solaris Kerberos: get list of PKCS11 slotid's that have tokens.
4252e4b3f553SWill Fiveash      */
4253e4b3f553SWill Fiveash     if (cctx->p11->C_GetSlotList(TRUE, slotlist, &count) != CKR_OK) {
4254e4b3f553SWill Fiveash 	krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
4255e4b3f553SWill Fiveash 			       gettext("Error trying to get PKCS11 slot list: %s"),
4256e4b3f553SWill Fiveash 			       pkinit_pkcs11_code_to_text(r));
42579e11d51cSWill Fiveash 	pkiDebug("C_GetSlotList: %s\n", pkinit_pkcs11_code_to_text(r));
4258e4b3f553SWill Fiveash 	r = KRB5KDC_ERR_PREAUTH_FAILED;
4259e4b3f553SWill Fiveash 	goto out;
4260159d09a2SMark Phalan     }
4261159d09a2SMark Phalan 
42629e11d51cSWill Fiveash     token_choices.numtokens = 0;
42639e11d51cSWill Fiveash     token_choices.token_array = malloc(count * sizeof (*token_choices.token_array));
42649e11d51cSWill Fiveash     if (token_choices.token_array == NULL) {
42659e11d51cSWill Fiveash 	r = KRB5KDC_ERR_PREAUTH_FAILED;
42669e11d51cSWill Fiveash 	krb5_set_error_message(context, r,
42679e11d51cSWill Fiveash 			       gettext("Memory allocation error"));
42689e11d51cSWill Fiveash 	goto out;
42699e11d51cSWill Fiveash     }
42709e11d51cSWill Fiveash 
42719e11d51cSWill Fiveash     /* examine all the tokens */
4272159d09a2SMark Phalan     for (i = 0; i < count; i++) {
4273e4b3f553SWill Fiveash 	/*
4274e4b3f553SWill Fiveash 	 * Solaris Kerberos: if a slotid was specified skip slots that don't
4275e4b3f553SWill Fiveash 	 * match.
4276e4b3f553SWill Fiveash 	 */
4277e4b3f553SWill Fiveash 	if (cctx->slotid != PK_NOSLOT && cctx->slotid != slotlist[i])
4278e4b3f553SWill Fiveash 	    continue;
42799e11d51cSWill Fiveash 
4280159d09a2SMark Phalan 	/* Open session */
4281159d09a2SMark Phalan 	if ((r = cctx->p11->C_OpenSession(slotlist[i], CKF_SERIAL_SESSION,
42829e11d51cSWill Fiveash 					  NULL, NULL, &tmpsession)) != CKR_OK) {
4283159d09a2SMark Phalan 	    pkiDebug("C_OpenSession: %s\n", pkinit_pkcs11_code_to_text(r));
4284e4b3f553SWill Fiveash 	    krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
42859e11d51cSWill Fiveash 				   gettext("Error trying to open PKCS11 session: %s"),
42869e11d51cSWill Fiveash 				   pkinit_pkcs11_code_to_text(r));
4287e4b3f553SWill Fiveash 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
4288e4b3f553SWill Fiveash 	    goto out;
4289159d09a2SMark Phalan 	}
4290159d09a2SMark Phalan 
4291159d09a2SMark Phalan 	/* Get token info */
4292159d09a2SMark Phalan 	if ((r = cctx->p11->C_GetTokenInfo(slotlist[i], &tinfo)) != CKR_OK) {
4293159d09a2SMark Phalan 	    pkiDebug("C_GetTokenInfo: %s\n", pkinit_pkcs11_code_to_text(r));
4294e4b3f553SWill Fiveash 	    krb5_set_error_message(context, KRB5KDC_ERR_PREAUTH_FAILED,
42959e11d51cSWill Fiveash 				   gettext("Error trying to read PKCS11 token: %s"),
42969e11d51cSWill Fiveash 				   pkinit_pkcs11_code_to_text(r));
4297e4b3f553SWill Fiveash 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
42989e11d51cSWill Fiveash 	    cctx->p11->C_CloseSession(tmpsession);
4299e4b3f553SWill Fiveash 	    goto out;
4300159d09a2SMark Phalan 	}
430103e68e16SWill Fiveash 
430203e68e16SWill Fiveash 	if (cctx->token_label == NULL) {
43039e11d51cSWill Fiveash 	    /*
43049e11d51cSWill Fiveash              * If the token doesn't require login to examine the certs then
43059e11d51cSWill Fiveash              * let's check the certs out to see if any match the criteria if
43069e11d51cSWill Fiveash              * any.
43079e11d51cSWill Fiveash              */
43089e11d51cSWill Fiveash 	    if (!(tinfo.flags & CKF_LOGIN_REQUIRED)) {
43099e11d51cSWill Fiveash 		/*
43109e11d51cSWill Fiveash 		 * It's okay to check the certs if we don't have to login but
43119e11d51cSWill Fiveash 		 * don't load the certs onto cctx at this point, this will be
43129e11d51cSWill Fiveash 		 * done later in this function for the chosen token.
43139e11d51cSWill Fiveash 		 */
43149e11d51cSWill Fiveash 		if ((r = check_load_certs(context, tmpsession, plg_cryptoctx,
43159e11d51cSWill Fiveash 					  req_cryptoctx, cctx, princ,
43169e11d51cSWill Fiveash 					  do_matching, 0)) == 0) {
43179e11d51cSWill Fiveash 		    tokenmatch = TRUE;
43189e11d51cSWill Fiveash 		} else if (r != ENOENT){
43199e11d51cSWill Fiveash 		    r = KRB5KDC_ERR_PREAUTH_FAILED;
43209e11d51cSWill Fiveash 		    cctx->p11->C_CloseSession(tmpsession);
43219e11d51cSWill Fiveash 		    goto out;
43229e11d51cSWill Fiveash 		} else {
43239e11d51cSWill Fiveash 		    /* ignore ENOENT here */
43249e11d51cSWill Fiveash 		    r = 0;
43259e11d51cSWill Fiveash 		}
43269e11d51cSWill Fiveash 	    } else {
43279e11d51cSWill Fiveash                 tokenmatch = TRUE;
43289e11d51cSWill Fiveash             }
432903e68e16SWill Fiveash 	} else {
433003e68e16SWill Fiveash 	    /* + 1 so tokenlabelstr can be \0 terminated */
433103e68e16SWill Fiveash 	    char tokenlabelstr[sizeof (tinfo.label) + 1];
433203e68e16SWill Fiveash 
433303e68e16SWill Fiveash 	    /*
43349e11d51cSWill Fiveash 	     * Convert token label into C string with trailing white space
43359e11d51cSWill Fiveash 	     * trimmed.
433603e68e16SWill Fiveash 	     */
43379e11d51cSWill Fiveash 	    trim_token_label(&tinfo, tokenlabelstr, sizeof (tokenlabelstr));
433803e68e16SWill Fiveash 
433903e68e16SWill Fiveash 	    pkiDebug("open_session: slotid %d token found: \"%s\", "
434003e68e16SWill Fiveash 		     "cctx->token_label: \"%s\"\n",
434103e68e16SWill Fiveash 		     slotlist[i], tokenlabelstr, (char *) cctx->token_label);
43429e11d51cSWill Fiveash 
434303e68e16SWill Fiveash 	    if (!strcmp(cctx->token_label, tokenlabelstr)) {
43449e11d51cSWill Fiveash 		if (!(tinfo.flags & CKF_LOGIN_REQUIRED)) {
43459e11d51cSWill Fiveash 		    /*
43469e11d51cSWill Fiveash 		     * It's okay to check the certs if we don't have to login but
43479e11d51cSWill Fiveash 		     * don't load the certs onto cctx at this point, this will be
43489e11d51cSWill Fiveash 		     * done later in this function for the chosen token.
43499e11d51cSWill Fiveash 		     */
43509e11d51cSWill Fiveash 		    if ((r = check_load_certs(context, tmpsession, plg_cryptoctx,
43519e11d51cSWill Fiveash 					      req_cryptoctx, cctx, princ,
43529e11d51cSWill Fiveash 					      do_matching, 0)) == 0) {
43539e11d51cSWill Fiveash 			tokenmatch = TRUE;
43549e11d51cSWill Fiveash 		    } else if (r != ENOENT){
43559e11d51cSWill Fiveash 			r = KRB5KDC_ERR_PREAUTH_FAILED;
43569e11d51cSWill Fiveash 			cctx->p11->C_CloseSession(tmpsession);
43579e11d51cSWill Fiveash 			goto out;
43589e11d51cSWill Fiveash 		    } else {
43599e11d51cSWill Fiveash 			/* ignore ENOENT here */
43609e11d51cSWill Fiveash 			r = 0;
43619e11d51cSWill Fiveash 		    }
43629e11d51cSWill Fiveash 		} else {
43639e11d51cSWill Fiveash 		    tokenmatch = TRUE;
43649e11d51cSWill Fiveash 		}
436503e68e16SWill Fiveash 	    }
436603e68e16SWill Fiveash 	}
43679e11d51cSWill Fiveash 
43689e11d51cSWill Fiveash 	if (tokenmatch == TRUE) {
43699e11d51cSWill Fiveash 	    /* add the token to token_choices.token_array */
43709e11d51cSWill Fiveash 	    token_choices.token_array[token_choices.numtokens].slotID = slotlist[i];
43719e11d51cSWill Fiveash 	    token_choices.token_array[token_choices.numtokens].session = tmpsession;
43729e11d51cSWill Fiveash 	    token_choices.token_array[token_choices.numtokens].token_info = tinfo;
43739e11d51cSWill Fiveash 	    token_choices.numtokens++;
43749e11d51cSWill Fiveash             /* !do_matching implies we take the first matching token */
43759e11d51cSWill Fiveash             if (!do_matching)
43769e11d51cSWill Fiveash                 break;
43779e11d51cSWill Fiveash             else
43789e11d51cSWill Fiveash                 tokenmatch = FALSE;
43799e11d51cSWill Fiveash 	} else {
43809e11d51cSWill Fiveash 	    cctx->p11->C_CloseSession(tmpsession);
43819e11d51cSWill Fiveash 	}
4382159d09a2SMark Phalan     }
4383e4b3f553SWill Fiveash 
43849e11d51cSWill Fiveash     if (token_choices.numtokens == 0) {
43859e11d51cSWill Fiveash 	/*
43869e11d51cSWill Fiveash 	 * Solaris Kerberos: prompt for token one time if there was no token
43879e11d51cSWill Fiveash          * and do_matching is 1 (see earlier comment about do_matching).
43889e11d51cSWill Fiveash 	 */
43899e11d51cSWill Fiveash 	if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
43909e11d51cSWill Fiveash 	    if ((r = pkinit_prompt_token(context, cctx)) == 0) {
43919e11d51cSWill Fiveash                 cctx->p11flags |= C_PROMPTED_USER;
43929e11d51cSWill Fiveash 		goto tryagain;
43939e11d51cSWill Fiveash 	    } else {
43949e11d51cSWill Fiveash 		pkiDebug("open_session: prompt for token/smart card failed\n");
43959e11d51cSWill Fiveash 		krb5_set_error_message(context, r,
43969e11d51cSWill Fiveash 				       gettext("Prompt for token/smart card failed"));
43979e11d51cSWill Fiveash 		r = KRB5KDC_ERR_PREAUTH_FAILED;
43989e11d51cSWill Fiveash 		goto out;
43999e11d51cSWill Fiveash 	    }
44009e11d51cSWill Fiveash 	} else {
44019e11d51cSWill Fiveash 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
44029e11d51cSWill Fiveash 	    krb5_set_error_message(context, r,
44039e11d51cSWill Fiveash 				   gettext("No smart card tokens found"));
44049e11d51cSWill Fiveash 	    pkiDebug("open_session: no matching token found\n");
44059e11d51cSWill Fiveash 	    goto out;
44069e11d51cSWill Fiveash 	}
44079e11d51cSWill Fiveash     } else if (token_choices.numtokens == 1) {
44089e11d51cSWill Fiveash         if ((token_choices.token_array[0].token_info.flags & CKF_LOGIN_REQUIRED) &&
44099e11d51cSWill Fiveash             !(cctx->p11flags & C_PROMPTED_USER) &&
44109e11d51cSWill Fiveash             do_matching) {
44119e11d51cSWill Fiveash             if ((r = pkinit_choose_tokens(context, cctx, &token_choices, &choice)) != 0) {
44129e11d51cSWill Fiveash                 pkiDebug("pkinit_open_session: pkinit_choose_tokens failed: %d\n", r);
44139e11d51cSWill Fiveash                 r = KRB5KDC_ERR_PREAUTH_FAILED;
44149e11d51cSWill Fiveash                 krb5_set_error_message(context, r,
44159e11d51cSWill Fiveash                                        gettext("Prompt for token/smart card failed"));
44169e11d51cSWill Fiveash                 goto out;
44179e11d51cSWill Fiveash             }
44189e11d51cSWill Fiveash             if (choice == RESCAN_TOKENS) {
44199e11d51cSWill Fiveash                 /* rescan for new smartcard/token */
44209e11d51cSWill Fiveash                 for (i = 0; i < token_choices.numtokens; i++) {
44219e11d51cSWill Fiveash                     /* close all sessions */
44229e11d51cSWill Fiveash                     cctx->p11->C_CloseSession(token_choices.token_array[i].session);
44239e11d51cSWill Fiveash                 }
44249e11d51cSWill Fiveash                 free(token_choices.token_array);
44259e11d51cSWill Fiveash                 token_choices.token_array = NULL;
44269e11d51cSWill Fiveash                 token_choices.numtokens = 0;
44279e11d51cSWill Fiveash                 goto tryagain;
44289e11d51cSWill Fiveash             } else if (choice == SKIP_TOKENS) {
44299e11d51cSWill Fiveash                 /* do not use smartcard/token for auth */
44309e11d51cSWill Fiveash                 cctx->p11flags |= (C_PROMPTED_USER|C_SKIP_PKCS11_AUTH);
44319e11d51cSWill Fiveash                 r = KRB5KDC_ERR_PREAUTH_FAILED;
44329e11d51cSWill Fiveash                 goto out;
44339e11d51cSWill Fiveash             } else {
44349e11d51cSWill Fiveash                 cctx->p11flags |= C_PROMPTED_USER;
44359e11d51cSWill Fiveash             }
44369e11d51cSWill Fiveash         } else {
44379e11d51cSWill Fiveash             choice = 0; /* really the only choice is the first token_array entry */
44389e11d51cSWill Fiveash         }
44399e11d51cSWill Fiveash     } else if (!(cctx->p11flags & C_PROMPTED_USER) && do_matching) {
44409e11d51cSWill Fiveash 	/* > 1 token so present menu of token choices, let the user decide. */
44419e11d51cSWill Fiveash 	if ((r = pkinit_choose_tokens(context, cctx, &token_choices, &choice)) != 0) {
44429e11d51cSWill Fiveash 	    pkiDebug("pkinit_open_session: pkinit_choose_tokens failed: %d\n", r);
44439e11d51cSWill Fiveash 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
44449e11d51cSWill Fiveash 	    krb5_set_error_message(context, r,
44459e11d51cSWill Fiveash 				   gettext("Prompt for token/smart card failed"));
44469e11d51cSWill Fiveash 	    goto out;
44479e11d51cSWill Fiveash 	}
44489e11d51cSWill Fiveash 	if (choice == RESCAN_TOKENS) {
44499e11d51cSWill Fiveash 	    /* rescan for new smartcard/token */
44509e11d51cSWill Fiveash 	    for (i = 0; i < token_choices.numtokens; i++) {
44519e11d51cSWill Fiveash 		/* close all sessions */
44529e11d51cSWill Fiveash 		cctx->p11->C_CloseSession(token_choices.token_array[i].session);
44539e11d51cSWill Fiveash 	    }
44549e11d51cSWill Fiveash 	    free(token_choices.token_array);
44559e11d51cSWill Fiveash 	    token_choices.token_array = NULL;
44569e11d51cSWill Fiveash 	    token_choices.numtokens = 0;
44579e11d51cSWill Fiveash 	    goto tryagain;
44589e11d51cSWill Fiveash 	} else if (choice == SKIP_TOKENS) {
44599e11d51cSWill Fiveash 	    /* do not use smartcard/token for auth */
44609e11d51cSWill Fiveash             cctx->p11flags |= (C_PROMPTED_USER|C_SKIP_PKCS11_AUTH);
44619e11d51cSWill Fiveash 	    r = KRB5KDC_ERR_PREAUTH_FAILED;
44629e11d51cSWill Fiveash 	    goto out;
44639e11d51cSWill Fiveash 	} else {
44649e11d51cSWill Fiveash             cctx->p11flags |= C_PROMPTED_USER;
44659e11d51cSWill Fiveash         }
44669e11d51cSWill Fiveash     } else {
44679e11d51cSWill Fiveash         r = KRB5KDC_ERR_PREAUTH_FAILED;
44689e11d51cSWill Fiveash         goto out;
4469159d09a2SMark Phalan     }
4470e4b3f553SWill Fiveash 
44719e11d51cSWill Fiveash     cctx->slotid = token_choices.token_array[choice].slotID;
44729e11d51cSWill Fiveash     cctx->session = token_choices.token_array[choice].session;
4473e4b3f553SWill Fiveash 
4474159d09a2SMark Phalan     pkiDebug("open_session: slotid %d (%d of %d)\n", (int) cctx->slotid,
4475159d09a2SMark Phalan 	     i + 1, (int) count);
4476159d09a2SMark Phalan 
4477159d09a2SMark Phalan     /* Login if needed */
44787d2d870eSWill Fiveash     /* Solaris Kerberos: added cctx->p11flags check */
44799e11d51cSWill Fiveash     if ((token_choices.token_array[choice].token_info.flags & CKF_LOGIN_REQUIRED) &&
44809e11d51cSWill Fiveash         !(cctx->p11flags & C_LOGIN_DONE)) {
44819e11d51cSWill Fiveash         r = pkinit_login(context, cctx, &token_choices.token_array[choice].token_info);
44829e11d51cSWill Fiveash     }
44839e11d51cSWill Fiveash 
44849e11d51cSWill Fiveash     if (r == 0) {
44859e11d51cSWill Fiveash 	/* Doing this again to load the certs into cctx. */
44869e11d51cSWill Fiveash 	r = check_load_certs(context, cctx->session, plg_cryptoctx,
44879e11d51cSWill Fiveash 			     req_cryptoctx, cctx, princ, do_matching, 1);
44889e11d51cSWill Fiveash     }
4489159d09a2SMark Phalan 
4490e4b3f553SWill Fiveash out:
4491e4b3f553SWill Fiveash     if (slotlist != NULL)
4492e4b3f553SWill Fiveash 	free(slotlist);
4493e4b3f553SWill Fiveash 
44949e11d51cSWill Fiveash     if (tmpslotlist != NULL)
44959e11d51cSWill Fiveash 	free(tmpslotlist);
44969e11d51cSWill Fiveash 
44979e11d51cSWill Fiveash     if (token_choices.token_array != NULL) {
44989e11d51cSWill Fiveash 	if (r != 0) {
44999e11d51cSWill Fiveash 	    /* close all sessions if there's an error */
45009e11d51cSWill Fiveash 	    for (i = 0; i < token_choices.numtokens; i++) {
45019e11d51cSWill Fiveash 		cctx->p11->C_CloseSession(token_choices.token_array[i].session);
45029e11d51cSWill Fiveash 	    }
45039e11d51cSWill Fiveash 	    cctx->session = CK_INVALID_HANDLE;
45049e11d51cSWill Fiveash 	} else {
45059e11d51cSWill Fiveash 	    /* close sessions not chosen */
45069e11d51cSWill Fiveash 	    for (i = 0; i < token_choices.numtokens; i++) {
45079e11d51cSWill Fiveash 		if (i != choice) {
45089e11d51cSWill Fiveash 		    cctx->p11->C_CloseSession(token_choices.token_array[i].session);
45099e11d51cSWill Fiveash 		}
45109e11d51cSWill Fiveash 	    }
45119e11d51cSWill Fiveash 	}
45129e11d51cSWill Fiveash 	free(token_choices.token_array);
4513e4b3f553SWill Fiveash     }
4514e4b3f553SWill Fiveash 
45159e11d51cSWill Fiveash     return (r);
4516159d09a2SMark Phalan }
4517159d09a2SMark Phalan 
4518159d09a2SMark Phalan /*
4519159d09a2SMark Phalan  * Look for a key that's:
4520159d09a2SMark Phalan  * 1. private
4521159d09a2SMark Phalan  * 2. capable of the specified operation (usually signing or decrypting)
4522159d09a2SMark Phalan  * 3. RSA (this may be wrong but it's all we can do for now)
4523159d09a2SMark Phalan  * 4. matches the id of the cert we chose
4524159d09a2SMark Phalan  *
4525159d09a2SMark Phalan  * You must call pkinit_get_certs before calling pkinit_find_private_key
4526159d09a2SMark Phalan  * (that's because we need the ID of the private key)
4527159d09a2SMark Phalan  *
4528159d09a2SMark Phalan  * pkcs11 says the id of the key doesn't have to match that of the cert, but
4529159d09a2SMark Phalan  * I can't figure out any other way to decide which key to use.
4530159d09a2SMark Phalan  *
4531159d09a2SMark Phalan  * We should only find one key that fits all the requirements.
4532159d09a2SMark Phalan  * If there are more than one, we just take the first one.
4533159d09a2SMark Phalan  */
4534159d09a2SMark Phalan 
4535159d09a2SMark Phalan /* ARGSUSED */
4536159d09a2SMark Phalan krb5_error_code
pkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx,CK_ATTRIBUTE_TYPE usage,CK_OBJECT_HANDLE * objp)4537159d09a2SMark Phalan pkinit_find_private_key(pkinit_identity_crypto_context id_cryptoctx,
4538159d09a2SMark Phalan 			CK_ATTRIBUTE_TYPE usage,
4539159d09a2SMark Phalan 			CK_OBJECT_HANDLE *objp)
4540159d09a2SMark Phalan {
4541159d09a2SMark Phalan     CK_OBJECT_CLASS cls;
4542159d09a2SMark Phalan     CK_ATTRIBUTE attrs[4];
4543159d09a2SMark Phalan     CK_ULONG count;
4544159d09a2SMark Phalan     CK_KEY_TYPE keytype;
4545*6ff4183cSAndy Fiddaman #if OPENSSL_VERSION_NUMBER >= 0x30000000L
4546*6ff4183cSAndy Fiddaman     const RSA *rsa;
4547*6ff4183cSAndy Fiddaman #else
4548300fdee2SAndy Fiddaman     RSA *rsa;
4549*6ff4183cSAndy Fiddaman #endif
4550159d09a2SMark Phalan     unsigned int nattrs = 0;
4551159d09a2SMark Phalan     int r;
4552159d09a2SMark Phalan #ifdef PKINIT_USE_KEY_USAGE
4553159d09a2SMark Phalan     CK_BBOOL true_false;
4554159d09a2SMark Phalan #endif
4555159d09a2SMark Phalan 
4556159d09a2SMark Phalan     cls = CKO_PRIVATE_KEY;
4557159d09a2SMark Phalan     attrs[nattrs].type = CKA_CLASS;
4558159d09a2SMark Phalan     attrs[nattrs].pValue = &cls;
4559159d09a2SMark Phalan     attrs[nattrs].ulValueLen = sizeof cls;
4560159d09a2SMark Phalan     nattrs++;
4561159d09a2SMark Phalan 
4562159d09a2SMark Phalan #ifdef PKINIT_USE_KEY_USAGE
4563159d09a2SMark Phalan     /*
4564159d09a2SMark Phalan      * Some cards get confused if you try to specify a key usage,
4565159d09a2SMark Phalan      * so don't, and hope for the best. This will fail if you have
4566159d09a2SMark Phalan      * several keys with the same id and different usages but I have
4567159d09a2SMark Phalan      * not seen this on real cards.
4568159d09a2SMark Phalan      */
4569159d09a2SMark Phalan     true_false = TRUE;
4570159d09a2SMark Phalan     attrs[nattrs].type = usage;
4571159d09a2SMark Phalan     attrs[nattrs].pValue = &true_false;
4572159d09a2SMark Phalan     attrs[nattrs].ulValueLen = sizeof true_false;
4573159d09a2SMark Phalan     nattrs++;
4574159d09a2SMark Phalan #endif
4575159d09a2SMark Phalan 
4576159d09a2SMark Phalan     keytype = CKK_RSA;
4577159d09a2SMark Phalan     attrs[nattrs].type = CKA_KEY_TYPE;
4578159d09a2SMark Phalan     attrs[nattrs].pValue = &keytype;
4579159d09a2SMark Phalan     attrs[nattrs].ulValueLen = sizeof keytype;
4580159d09a2SMark Phalan     nattrs++;
4581159d09a2SMark Phalan 
4582159d09a2SMark Phalan     attrs[nattrs].type = CKA_ID;
4583159d09a2SMark Phalan     attrs[nattrs].pValue = id_cryptoctx->cert_id;
4584159d09a2SMark Phalan     attrs[nattrs].ulValueLen = id_cryptoctx->cert_id_len;
4585159d09a2SMark Phalan     nattrs++;
4586159d09a2SMark Phalan 
4587159d09a2SMark Phalan     r = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs, nattrs);
4588159d09a2SMark Phalan     if (r != CKR_OK) {
4589159d09a2SMark Phalan 	pkiDebug("krb5_pkinit_sign_data: C_FindObjectsInit: %s\n",
4590159d09a2SMark Phalan 		 pkinit_pkcs11_code_to_text(r));
4591159d09a2SMark Phalan 	return KRB5KDC_ERR_PREAUTH_FAILED;
4592159d09a2SMark Phalan     }
4593159d09a2SMark Phalan 
4594159d09a2SMark Phalan     r = id_cryptoctx->p11->C_FindObjects(id_cryptoctx->session, objp, 1, &count);
4595159d09a2SMark Phalan     id_cryptoctx->p11->C_FindObjectsFinal(id_cryptoctx->session);
4596159d09a2SMark Phalan     pkiDebug("found %d private keys (%s)\n", (int) count, pkinit_pkcs11_code_to_text(r));
4597159d09a2SMark Phalan 
4598159d09a2SMark Phalan     /*
4599159d09a2SMark Phalan      * Solaris Kerberos:
4600159d09a2SMark Phalan      * The CKA_ID may not be correctly set for the private key. For e.g. when
4601159d09a2SMark Phalan      * storing a private key in softtoken pktool(1) doesn't generate or store
4602159d09a2SMark Phalan      * a CKA_ID for the private key. Another way to identify the private key is
4603159d09a2SMark Phalan      * to look for a private key with the same RSA modulus as the public key
4604159d09a2SMark Phalan      * in the certificate.
4605159d09a2SMark Phalan      */
4606159d09a2SMark Phalan     if (r == CKR_OK && count != 1) {
4607159d09a2SMark Phalan 
4608159d09a2SMark Phalan 	EVP_PKEY *priv;
4609159d09a2SMark Phalan 	X509 *cert;
4610300fdee2SAndy Fiddaman 	const BIGNUM *rsan;
4611159d09a2SMark Phalan 	unsigned int n_len;
4612159d09a2SMark Phalan 	unsigned char *n_bytes;
4613159d09a2SMark Phalan 
4614159d09a2SMark Phalan 	cert = sk_X509_value(id_cryptoctx->my_certs, 0);
4615159d09a2SMark Phalan 	priv = X509_get_pubkey(cert);
4616159d09a2SMark Phalan 	if (priv == NULL) {
46173f8dd771SAndy Fiddaman 		pkiDebug("Failed to extract pub key from cert\n");
4618159d09a2SMark Phalan 		return KRB5KDC_ERR_PREAUTH_FAILED;
4619159d09a2SMark Phalan 	}
4620159d09a2SMark Phalan 
4621159d09a2SMark Phalan 	nattrs = 0;
4622159d09a2SMark Phalan 	cls = CKO_PRIVATE_KEY;
4623159d09a2SMark Phalan 	attrs[nattrs].type = CKA_CLASS;
4624159d09a2SMark Phalan 	attrs[nattrs].pValue = &cls;
4625159d09a2SMark Phalan 	attrs[nattrs].ulValueLen = sizeof cls;
4626159d09a2SMark Phalan 	nattrs++;
4627159d09a2SMark Phalan 
4628159d09a2SMark Phalan #ifdef PKINIT_USE_KEY_USAGE
4629159d09a2SMark Phalan 	true_false = TRUE;
4630159d09a2SMark Phalan 	attrs[nattrs].type = usage;
4631159d09a2SMark Phalan 	attrs[nattrs].pValue = &true_false;
4632159d09a2SMark Phalan 	attrs[nattrs].ulValueLen = sizeof true_false;
4633159d09a2SMark Phalan 	nattrs++;
4634159d09a2SMark Phalan #endif
4635159d09a2SMark Phalan 
4636159d09a2SMark Phalan 	keytype = CKK_RSA;
4637159d09a2SMark Phalan 	attrs[nattrs].type = CKA_KEY_TYPE;
4638159d09a2SMark Phalan 	attrs[nattrs].pValue = &keytype;
4639159d09a2SMark Phalan 	attrs[nattrs].ulValueLen = sizeof keytype;
4640159d09a2SMark Phalan 	nattrs++;
4641159d09a2SMark Phalan 
4642553e44ceSAndrew Stormont #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
4643300fdee2SAndy Fiddaman 	rsa = priv->pkey.rsa;
4644300fdee2SAndy Fiddaman 	rsan = rsa->n;
4645300fdee2SAndy Fiddaman 	n_len = BN_num_bytes(rsan);
4646300fdee2SAndy Fiddaman #else
4647300fdee2SAndy Fiddaman 	rsa = EVP_PKEY_get0_RSA(priv);
4648300fdee2SAndy Fiddaman 	RSA_get0_key(rsa, &rsan, NULL, NULL);
4649300fdee2SAndy Fiddaman 	n_len = RSA_size(rsa);
4650300fdee2SAndy Fiddaman #endif
4651159d09a2SMark Phalan 	n_bytes = (unsigned char *) malloc((size_t) n_len);
4652159d09a2SMark Phalan 	if (n_bytes == NULL) {
4653159d09a2SMark Phalan 		return (ENOMEM);
4654159d09a2SMark Phalan 	}
4655159d09a2SMark Phalan 
4656300fdee2SAndy Fiddaman 	if (BN_bn2bin(rsan, n_bytes) == 0) {
4657159d09a2SMark Phalan 		free (n_bytes);
4658300fdee2SAndy Fiddaman 		pkiDebug("zero-byte key modulus\n");
4659159d09a2SMark Phalan 		return KRB5KDC_ERR_PREAUTH_FAILED;
4660159d09a2SMark Phalan 	}
4661159d09a2SMark Phalan 
4662159d09a2SMark Phalan 	attrs[nattrs].type = CKA_MODULUS;
4663300fdee2SAndy Fiddaman 	attrs[nattrs].ulValueLen = n_len;
4664159d09a2SMark Phalan 	attrs[nattrs].pValue = n_bytes;
4665159d09a2SMark Phalan 
4666159d09a2SMark Phalan 	nattrs++;
4667159d09a2SMark Phalan 
4668159d09a2SMark Phalan 	r = id_cryptoctx->p11->C_FindObjectsInit(id_cryptoctx->session, attrs, nattrs);
4669159d09a2SMark Phalan 	free (n_bytes);
4670159d09a2SMark Phalan 	if (r != CKR_OK) {
4671159d09a2SMark Phalan 		pkiDebug("krb5_pkinit_sign_data: C_FindObjectsInit: %s\n",
4672159d09a2SMark Phalan 			pkinit_pkcs11_code_to_text(r));
4673159d09a2SMark Phalan 		return KRB5KDC_ERR_PREAUTH_FAILED;
4674159d09a2SMark Phalan 	}
4675159d09a2SMark Phalan 
4676159d09a2SMark Phalan 	r = id_cryptoctx->p11->C_FindObjects(id_cryptoctx->session, objp, 1, &count);
4677159d09a2SMark Phalan 	id_cryptoctx->p11->C_FindObjectsFinal(id_cryptoctx->session);
4678159d09a2SMark Phalan 	pkiDebug("found %d private keys (%s)\n", (int) count, pkinit_pkcs11_code_to_text(r));
4679159d09a2SMark Phalan 
4680159d09a2SMark Phalan     }
4681159d09a2SMark Phalan 
4682159d09a2SMark Phalan     if (r != CKR_OK || count < 1)
4683159d09a2SMark Phalan 	return KRB5KDC_ERR_PREAUTH_FAILED;
4684159d09a2SMark Phalan     return 0;
4685159d09a2SMark Phalan }
4686159d09a2SMark Phalan #endif
4687159d09a2SMark Phalan 
4688159d09a2SMark Phalan /* ARGSUSED */
4689159d09a2SMark Phalan static krb5_error_code
pkinit_decode_data_fs(krb5_context context,pkinit_identity_crypto_context id_cryptoctx,unsigned char * data,unsigned int data_len,unsigned char ** decoded_data,unsigned int * decoded_data_len)4690159d09a2SMark Phalan pkinit_decode_data_fs(krb5_context context,
4691159d09a2SMark Phalan 		      pkinit_identity_crypto_context id_cryptoctx,
4692159d09a2SMark Phalan 		      unsigned char *data,
4693159d09a2SMark Phalan 		      unsigned int data_len,
4694159d09a2SMark Phalan 		      unsigned char **decoded_data,
4695159d09a2SMark Phalan 		      unsigned int *decoded_data_len)
4696159d09a2SMark Phalan {
4697159d09a2SMark Phalan     if (decode_data(decoded_data, decoded_data_len, data, data_len,
4698159d09a2SMark Phalan 		id_cryptoctx->my_key, sk_X509_value(id_cryptoctx->my_certs,
4699159d09a2SMark Phalan 		id_cryptoctx->cert_index)) <= 0) {
4700159d09a2SMark Phalan 	pkiDebug("failed to decode data\n");
4701159d09a2SMark Phalan 	return KRB5KDC_ERR_PREAUTH_FAILED;
4702159d09a2SMark Phalan     }
4703159d09a2SMark Phalan     return 0;
4704159d09a2SMark Phalan }
4705159d09a2SMark Phalan 
4706159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
4707159d09a2SMark Phalan #ifdef SILLYDECRYPT
4708159d09a2SMark Phalan CK_RV
pkinit_C_Decrypt(pkinit_identity_crypto_context id_cryptoctx,CK_BYTE_PTR pEncryptedData,CK_ULONG ulEncryptedDataLen,CK_BYTE_PTR pData,CK_ULONG_PTR pulDataLen)4709159d09a2SMark Phalan pkinit_C_Decrypt(pkinit_identity_crypto_context id_cryptoctx,
4710159d09a2SMark Phalan 		 CK_BYTE_PTR pEncryptedData,
4711159d09a2SMark Phalan 		 CK_ULONG  ulEncryptedDataLen,
4712159d09a2SMark Phalan 		 CK_BYTE_PTR pData,
4713159d09a2SMark Phalan 		 CK_ULONG_PTR pulDataLen)
4714159d09a2SMark Phalan {
4715159d09a2SMark Phalan     CK_RV rv = CKR_OK;
4716159d09a2SMark Phalan 
4717159d09a2SMark Phalan     rv = id_cryptoctx->p11->C_Decrypt(id_cryptoctx->session, pEncryptedData,
4718159d09a2SMark Phalan 	ulEncryptedDataLen, pData, pulDataLen);
4719159d09a2SMark Phalan     if (rv == CKR_OK) {
4720159d09a2SMark Phalan 	pkiDebug("pData %x *pulDataLen %d\n", (int) pData, (int) *pulDataLen);
4721159d09a2SMark Phalan     }
4722159d09a2SMark Phalan     return rv;
4723159d09a2SMark Phalan }
4724159d09a2SMark Phalan #endif
4725159d09a2SMark Phalan 
4726159d09a2SMark Phalan static krb5_error_code
pkinit_decode_data_pkcs11(krb5_context context,pkinit_identity_crypto_context id_cryptoctx,unsigned char * data,unsigned int data_len,unsigned char ** decoded_data,unsigned int * decoded_data_len)4727159d09a2SMark Phalan pkinit_decode_data_pkcs11(krb5_context context,
4728159d09a2SMark Phalan 			  pkinit_identity_crypto_context id_cryptoctx,
4729159d09a2SMark Phalan 			  unsigned char *data,
4730159d09a2SMark Phalan 			  unsigned int data_len,
4731159d09a2SMark Phalan 			  unsigned char **decoded_data,
4732159d09a2SMark Phalan 			  unsigned int *decoded_data_len)
4733159d09a2SMark Phalan {
4734159d09a2SMark Phalan     CK_OBJECT_HANDLE obj;
4735159d09a2SMark Phalan     CK_ULONG len;
4736159d09a2SMark Phalan     CK_MECHANISM mech;
4737159d09a2SMark Phalan     unsigned char *cp;
4738159d09a2SMark Phalan     int r;
4739159d09a2SMark Phalan 
47409e11d51cSWill Fiveash     /*
47419e11d51cSWill Fiveash      * Solaris Kerberos: assume session is open and libpkcs11 funcs have been
47429e11d51cSWill Fiveash      * loaded.
47439e11d51cSWill Fiveash      */
47449e11d51cSWill Fiveash     assert(id_cryptoctx->p11 != NULL);
4745159d09a2SMark Phalan 
47467d2d870eSWill Fiveash     /* Solaris Kerberos: Login, if needed, to access private object */
47477d2d870eSWill Fiveash     if (!(id_cryptoctx->p11flags & C_LOGIN_DONE)) {
47487d2d870eSWill Fiveash         CK_TOKEN_INFO tinfo;
47497d2d870eSWill Fiveash 
47507d2d870eSWill Fiveash         r = id_cryptoctx->p11->C_GetTokenInfo(id_cryptoctx->slotid, &tinfo);
47517d2d870eSWill Fiveash         if (r != 0)
47527d2d870eSWill Fiveash             return r;
47537d2d870eSWill Fiveash 
47547d2d870eSWill Fiveash         r = pkinit_login(context, id_cryptoctx, &tinfo);
47557d2d870eSWill Fiveash         if (r != 0)
47567d2d870eSWill Fiveash             return r;
47577d2d870eSWill Fiveash     }
47587d2d870eSWill Fiveash 
4759159d09a2SMark Phalan     r = pkinit_find_private_key(id_cryptoctx, CKA_DECRYPT, &obj);
4760159d09a2SMark Phalan     if (r != 0)
4761159d09a2SMark Phalan 	return r;
4762159d09a2SMark Phalan 
4763159d09a2SMark Phalan     mech.mechanism = CKM_RSA_PKCS;
4764159d09a2SMark Phalan     mech.pParameter = NULL;
4765159d09a2SMark Phalan     mech.ulParameterLen = 0;
4766159d09a2SMark Phalan 
4767159d09a2SMark Phalan     if ((r = id_cryptoctx->p11->C_DecryptInit(id_cryptoctx->session, &mech,
4768159d09a2SMark Phalan 	    obj)) != CKR_OK) {
4769159d09a2SMark Phalan 	pkiDebug("C_DecryptInit: 0x%x\n", (int) r);
4770159d09a2SMark Phalan 	return KRB5KDC_ERR_PREAUTH_FAILED;
4771159d09a2SMark Phalan     }
4772159d09a2SMark Phalan     pkiDebug("data_len = %d\n", data_len);
4773159d09a2SMark Phalan     cp = (unsigned char *)malloc((size_t) data_len);
4774159d09a2SMark Phalan     if (cp == NULL)
4775159d09a2SMark Phalan 	return ENOMEM;
4776159d09a2SMark Phalan     len = data_len;
4777159d09a2SMark Phalan #ifdef SILLYDECRYPT
4778159d09a2SMark Phalan     pkiDebug("session %x edata %x edata_len %d data %x datalen @%x %d\n",
4779159d09a2SMark Phalan 	    (int) id_cryptoctx->session, (int) data, (int) data_len, (int) cp,
4780159d09a2SMark Phalan 	    (int) &len, (int) len);
4781159d09a2SMark Phalan     if ((r = pkinit_C_Decrypt(id_cryptoctx, data, (CK_ULONG) data_len,
4782159d09a2SMark Phalan 	    cp, &len)) != CKR_OK) {
4783159d09a2SMark Phalan #else
4784159d09a2SMark Phalan     if ((r = id_cryptoctx->p11->C_Decrypt(id_cryptoctx->session, data,
4785159d09a2SMark Phalan 	    (CK_ULONG) data_len, cp, &len)) != CKR_OK) {
4786159d09a2SMark Phalan #endif
4787159d09a2SMark Phalan 	pkiDebug("C_Decrypt: %s\n", pkinit_pkcs11_code_to_text(r));
4788159d09a2SMark Phalan 	if (r == CKR_BUFFER_TOO_SMALL)
4789159d09a2SMark Phalan 	    pkiDebug("decrypt %d needs %d\n", (int) data_len, (int) len);
4790159d09a2SMark Phalan 	return KRB5KDC_ERR_PREAUTH_FAILED;
4791159d09a2SMark Phalan     }
4792159d09a2SMark Phalan     pkiDebug("decrypt %d -> %d\n", (int) data_len, (int) len);
4793159d09a2SMark Phalan     *decoded_data_len = len;
4794159d09a2SMark Phalan     *decoded_data = cp;
4795159d09a2SMark Phalan 
4796159d09a2SMark Phalan     return 0;
4797159d09a2SMark Phalan }
4798159d09a2SMark Phalan #endif
4799159d09a2SMark Phalan 
4800159d09a2SMark Phalan krb5_error_code
4801159d09a2SMark Phalan pkinit_decode_data(krb5_context context,
4802159d09a2SMark Phalan 		   pkinit_identity_crypto_context id_cryptoctx,
4803159d09a2SMark Phalan 		   unsigned char *data,
4804159d09a2SMark Phalan 		   unsigned int data_len,
4805159d09a2SMark Phalan 		   unsigned char **decoded_data,
4806159d09a2SMark Phalan 		   unsigned int *decoded_data_len)
4807159d09a2SMark Phalan {
4808159d09a2SMark Phalan     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
4809159d09a2SMark Phalan 
4810159d09a2SMark Phalan     if (id_cryptoctx->pkcs11_method != 1)
4811159d09a2SMark Phalan 	retval = pkinit_decode_data_fs(context, id_cryptoctx, data, data_len,
4812159d09a2SMark Phalan 	    decoded_data, decoded_data_len);
4813159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
4814159d09a2SMark Phalan     else
4815159d09a2SMark Phalan 	retval = pkinit_decode_data_pkcs11(context, id_cryptoctx, data,
4816159d09a2SMark Phalan 	    data_len, decoded_data, decoded_data_len);
4817159d09a2SMark Phalan #endif
4818159d09a2SMark Phalan 
4819159d09a2SMark Phalan     return retval;
4820159d09a2SMark Phalan }
4821159d09a2SMark Phalan 
4822159d09a2SMark Phalan /* ARGSUSED */
4823159d09a2SMark Phalan static krb5_error_code
4824159d09a2SMark Phalan pkinit_sign_data_fs(krb5_context context,
4825159d09a2SMark Phalan 		 pkinit_identity_crypto_context id_cryptoctx,
4826159d09a2SMark Phalan 		 unsigned char *data,
4827159d09a2SMark Phalan 		 unsigned int data_len,
4828159d09a2SMark Phalan 		 unsigned char **sig,
4829159d09a2SMark Phalan 		 unsigned int *sig_len)
4830159d09a2SMark Phalan {
4831159d09a2SMark Phalan     if (create_signature(sig, sig_len, data, data_len,
4832159d09a2SMark Phalan 	    id_cryptoctx->my_key) != 0) {
4833159d09a2SMark Phalan 	    pkiDebug("failed to create the signature\n");
4834159d09a2SMark Phalan 	    return KRB5KDC_ERR_PREAUTH_FAILED;
4835159d09a2SMark Phalan     }
4836159d09a2SMark Phalan     return 0;
4837159d09a2SMark Phalan }
4838159d09a2SMark Phalan 
4839159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
4840159d09a2SMark Phalan static krb5_error_code
4841159d09a2SMark Phalan pkinit_sign_data_pkcs11(krb5_context context,
4842159d09a2SMark Phalan 			pkinit_identity_crypto_context id_cryptoctx,
4843159d09a2SMark Phalan 			unsigned char *data,
4844159d09a2SMark Phalan 			unsigned int data_len,
4845159d09a2SMark Phalan 			unsigned char **sig,
4846159d09a2SMark Phalan 			unsigned int *sig_len)
4847159d09a2SMark Phalan {
4848159d09a2SMark Phalan     CK_OBJECT_HANDLE obj;
4849159d09a2SMark Phalan     CK_ULONG len;
4850159d09a2SMark Phalan     CK_MECHANISM mech;
4851159d09a2SMark Phalan     unsigned char *cp;
4852159d09a2SMark Phalan     int r;
4853159d09a2SMark Phalan 
48549e11d51cSWill Fiveash     /*
48559e11d51cSWill Fiveash      * Solaris Kerberos: assume session is open and libpkcs11 funcs have been
48569e11d51cSWill Fiveash      * loaded.
48579e11d51cSWill Fiveash      */
48589e11d51cSWill Fiveash     assert(id_cryptoctx->p11 != NULL);
4859159d09a2SMark Phalan 
48607d2d870eSWill Fiveash     /* Solaris Kerberos: Login, if needed, to access private object */
48617d2d870eSWill Fiveash     if (!(id_cryptoctx->p11flags & C_LOGIN_DONE)) {
48627d2d870eSWill Fiveash         CK_TOKEN_INFO tinfo;
48637d2d870eSWill Fiveash 
48647d2d870eSWill Fiveash         r = id_cryptoctx->p11->C_GetTokenInfo(id_cryptoctx->slotid, &tinfo);
48657d2d870eSWill Fiveash         if (r != 0)
48667d2d870eSWill Fiveash             return r;
48677d2d870eSWill Fiveash 
48687d2d870eSWill Fiveash         r = pkinit_login(context, id_cryptoctx, &tinfo);
48697d2d870eSWill Fiveash         if (r != 0)
48707d2d870eSWill Fiveash             return r;
48717d2d870eSWill Fiveash     }
48727d2d870eSWill Fiveash 
4873159d09a2SMark Phalan     r = pkinit_find_private_key(id_cryptoctx, CKA_SIGN, &obj);
4874159d09a2SMark Phalan     if (r != 0 )
4875159d09a2SMark Phalan 	return r;
4876159d09a2SMark Phalan 
4877159d09a2SMark Phalan     mech.mechanism = id_cryptoctx->mech;
4878159d09a2SMark Phalan     mech.pParameter = NULL;
4879159d09a2SMark Phalan     mech.ulParameterLen = 0;
4880159d09a2SMark Phalan 
4881159d09a2SMark Phalan     if ((r = id_cryptoctx->p11->C_SignInit(id_cryptoctx->session, &mech,
4882159d09a2SMark Phalan 	    obj)) != CKR_OK) {
4883159d09a2SMark Phalan 	pkiDebug("C_SignInit: %s\n", pkinit_pkcs11_code_to_text(r));
4884159d09a2SMark Phalan 	return KRB5KDC_ERR_PREAUTH_FAILED;
4885159d09a2SMark Phalan     }
4886159d09a2SMark Phalan 
4887159d09a2SMark Phalan     /*
4888159d09a2SMark Phalan      * Key len would give an upper bound on sig size, but there's no way to
4889159d09a2SMark Phalan      * get that. So guess, and if it's too small, re-malloc.
4890159d09a2SMark Phalan      */
4891159d09a2SMark Phalan     len = PK_SIGLEN_GUESS;
4892159d09a2SMark Phalan     cp = (unsigned char *)malloc((size_t) len);
4893159d09a2SMark Phalan     if (cp == NULL)
4894159d09a2SMark Phalan 	return ENOMEM;
4895159d09a2SMark Phalan 
4896159d09a2SMark Phalan     r = id_cryptoctx->p11->C_Sign(id_cryptoctx->session, data,
4897159d09a2SMark Phalan 				 (CK_ULONG) data_len, cp, &len);
4898159d09a2SMark Phalan     if (r == CKR_BUFFER_TOO_SMALL || (r == CKR_OK && len >= PK_SIGLEN_GUESS)) {
4899159d09a2SMark Phalan 	free(cp);
4900159d09a2SMark Phalan 	pkiDebug("C_Sign realloc %d\n", (int) len);
4901159d09a2SMark Phalan 	cp = (unsigned char *)malloc((size_t) len);
4902159d09a2SMark Phalan 	r = id_cryptoctx->p11->C_Sign(id_cryptoctx->session, data,
4903159d09a2SMark Phalan 				     (CK_ULONG) data_len, cp, &len);
4904159d09a2SMark Phalan     }
4905159d09a2SMark Phalan     if (r != CKR_OK) {
4906159d09a2SMark Phalan 	pkiDebug("C_Sign: %s\n", pkinit_pkcs11_code_to_text(r));
4907159d09a2SMark Phalan 	return KRB5KDC_ERR_PREAUTH_FAILED;
4908159d09a2SMark Phalan     }
4909159d09a2SMark Phalan     pkiDebug("sign %d -> %d\n", (int) data_len, (int) len);
4910159d09a2SMark Phalan     *sig_len = len;
4911159d09a2SMark Phalan     *sig = cp;
4912159d09a2SMark Phalan 
4913159d09a2SMark Phalan     return 0;
4914159d09a2SMark Phalan }
4915159d09a2SMark Phalan #endif
4916159d09a2SMark Phalan 
4917159d09a2SMark Phalan krb5_error_code
4918159d09a2SMark Phalan pkinit_sign_data(krb5_context context,
4919159d09a2SMark Phalan 		 pkinit_identity_crypto_context id_cryptoctx,
4920159d09a2SMark Phalan 		 unsigned char *data,
4921159d09a2SMark Phalan 		 unsigned int data_len,
4922159d09a2SMark Phalan 		 unsigned char **sig,
4923159d09a2SMark Phalan 		 unsigned int *sig_len)
4924159d09a2SMark Phalan {
4925159d09a2SMark Phalan     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
4926159d09a2SMark Phalan 
4927159d09a2SMark Phalan     if (id_cryptoctx == NULL || id_cryptoctx->pkcs11_method != 1)
4928159d09a2SMark Phalan 	retval = pkinit_sign_data_fs(context, id_cryptoctx, data, data_len,
4929159d09a2SMark Phalan 				     sig, sig_len);
4930159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
4931159d09a2SMark Phalan     else
4932159d09a2SMark Phalan 	retval = pkinit_sign_data_pkcs11(context, id_cryptoctx, data, data_len,
4933159d09a2SMark Phalan 					 sig, sig_len);
4934159d09a2SMark Phalan #endif
4935159d09a2SMark Phalan 
4936159d09a2SMark Phalan     return retval;
4937159d09a2SMark Phalan }
4938159d09a2SMark Phalan 
4939159d09a2SMark Phalan 
4940159d09a2SMark Phalan static krb5_error_code
4941159d09a2SMark Phalan decode_data(unsigned char **out_data, unsigned int *out_data_len,
4942159d09a2SMark Phalan 	    unsigned char *data, unsigned int data_len,
4943159d09a2SMark Phalan 	    EVP_PKEY *pkey, X509 *cert)
4944159d09a2SMark Phalan {
4945159d09a2SMark Phalan     /* Solaris Kerberos */
4946159d09a2SMark Phalan     int len;
4947159d09a2SMark Phalan     unsigned char *buf = NULL;
4948159d09a2SMark Phalan     int buf_len = 0;
4949159d09a2SMark Phalan 
4950159d09a2SMark Phalan     /* Solaris Kerberos */
4951159d09a2SMark Phalan     if (out_data == NULL || out_data_len == NULL)
4952159d09a2SMark Phalan 	return EINVAL;
4953159d09a2SMark Phalan 
4954159d09a2SMark Phalan     if (cert && !X509_check_private_key(cert, pkey)) {
4955159d09a2SMark Phalan 	pkiDebug("private key does not match certificate\n");
4956159d09a2SMark Phalan 	/* Solaris Kerberos */
4957159d09a2SMark Phalan 	return EINVAL;
4958159d09a2SMark Phalan     }
4959159d09a2SMark Phalan 
4960159d09a2SMark Phalan     buf_len = EVP_PKEY_size(pkey);
4961159d09a2SMark Phalan     buf = (unsigned char *)malloc((size_t) buf_len + 10);
4962159d09a2SMark Phalan     if (buf == NULL)
4963159d09a2SMark Phalan 	return ENOMEM;
4964159d09a2SMark Phalan 
496570f9559bSTheo Schlossnagle     len = EVP_PKEY_decrypt_old(buf, data, (int)data_len, pkey);
4966159d09a2SMark Phalan     if (len <= 0) {
4967159d09a2SMark Phalan 	pkiDebug("unable to decrypt received data (len=%d)\n", data_len);
4968159d09a2SMark Phalan 	/* Solaris Kerberos */
4969159d09a2SMark Phalan 	free(buf);
4970159d09a2SMark Phalan 	return KRB5KRB_ERR_GENERIC;
4971159d09a2SMark Phalan     }
4972159d09a2SMark Phalan     *out_data = buf;
4973159d09a2SMark Phalan     *out_data_len = len;
4974159d09a2SMark Phalan 
4975159d09a2SMark Phalan     return 0;
4976159d09a2SMark Phalan }
4977159d09a2SMark Phalan 
4978159d09a2SMark Phalan static krb5_error_code
4979159d09a2SMark Phalan create_signature(unsigned char **sig, unsigned int *sig_len,
4980159d09a2SMark Phalan 		 unsigned char *data, unsigned int data_len, EVP_PKEY *pkey)
4981159d09a2SMark Phalan {
4982159d09a2SMark Phalan     krb5_error_code retval = ENOMEM;
4983300fdee2SAndy Fiddaman     EVP_MD_CTX *md_ctx;
4984159d09a2SMark Phalan 
4985159d09a2SMark Phalan     if (pkey == NULL)
4986159d09a2SMark Phalan 	/* Solaris Kerberos */
4987159d09a2SMark Phalan 	return EINVAL;
4988159d09a2SMark Phalan 
4989300fdee2SAndy Fiddaman     if ((md_ctx = EVP_MD_CTX_new()) == NULL)
4990300fdee2SAndy Fiddaman 	return EINVAL;
4991300fdee2SAndy Fiddaman 
4992300fdee2SAndy Fiddaman     EVP_VerifyInit(md_ctx, EVP_sha1());
4993300fdee2SAndy Fiddaman     EVP_SignUpdate(md_ctx, data, data_len);
4994159d09a2SMark Phalan     *sig_len = EVP_PKEY_size(pkey);
4995159d09a2SMark Phalan     if ((*sig = (unsigned char *) malloc((size_t) *sig_len)) == NULL)
4996159d09a2SMark Phalan 	goto cleanup;
4997300fdee2SAndy Fiddaman     EVP_SignFinal(md_ctx, *sig, sig_len, pkey);
4998159d09a2SMark Phalan 
4999159d09a2SMark Phalan     retval = 0;
5000159d09a2SMark Phalan 
5001159d09a2SMark Phalan   cleanup:
5002300fdee2SAndy Fiddaman     EVP_MD_CTX_free(md_ctx);
5003159d09a2SMark Phalan 
5004159d09a2SMark Phalan     return retval;
5005159d09a2SMark Phalan }
5006159d09a2SMark Phalan 
5007159d09a2SMark Phalan /*
5008159d09a2SMark Phalan  * Note:
5009159d09a2SMark Phalan  * This is not the routine the KDC uses to get its certificate.
5010159d09a2SMark Phalan  * This routine is intended to be called by the client
5011159d09a2SMark Phalan  * to obtain the KDC's certificate from some local storage
5012159d09a2SMark Phalan  * to be sent as a hint in its request to the KDC.
5013159d09a2SMark Phalan  */
5014159d09a2SMark Phalan /* ARGSUSED */
5015159d09a2SMark Phalan krb5_error_code
5016159d09a2SMark Phalan pkinit_get_kdc_cert(krb5_context context,
5017159d09a2SMark Phalan 		    pkinit_plg_crypto_context plg_cryptoctx,
5018159d09a2SMark Phalan 		    pkinit_req_crypto_context req_cryptoctx,
5019159d09a2SMark Phalan 		    pkinit_identity_crypto_context id_cryptoctx,
5020159d09a2SMark Phalan 		    krb5_principal princ)
5021159d09a2SMark Phalan {
5022159d09a2SMark Phalan    /* Solaris Kerberos */
5023159d09a2SMark Phalan     if (req_cryptoctx == NULL)
5024159d09a2SMark Phalan 	return EINVAL;
5025159d09a2SMark Phalan 
5026159d09a2SMark Phalan     req_cryptoctx->received_cert = NULL;
5027159d09a2SMark Phalan     return 0;
5028159d09a2SMark Phalan }
5029159d09a2SMark Phalan 
5030159d09a2SMark Phalan /* ARGSUSED */
5031159d09a2SMark Phalan static krb5_error_code
5032159d09a2SMark Phalan pkinit_get_certs_pkcs12(krb5_context context,
5033159d09a2SMark Phalan 			  pkinit_plg_crypto_context plg_cryptoctx,
5034159d09a2SMark Phalan 			  pkinit_req_crypto_context req_cryptoctx,
5035159d09a2SMark Phalan 			  pkinit_identity_opts *idopts,
5036159d09a2SMark Phalan 			  pkinit_identity_crypto_context id_cryptoctx,
5037159d09a2SMark Phalan 			  krb5_principal princ)
5038159d09a2SMark Phalan {
5039159d09a2SMark Phalan     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
5040159d09a2SMark Phalan     X509 *x = NULL;
5041159d09a2SMark Phalan     PKCS12 *p12 = NULL;
5042159d09a2SMark Phalan     int ret;
5043159d09a2SMark Phalan     FILE *fp;
5044159d09a2SMark Phalan     EVP_PKEY *y = NULL;
5045159d09a2SMark Phalan 
5046159d09a2SMark Phalan     if (idopts->cert_filename == NULL) {
5047159d09a2SMark Phalan 	/* Solaris Kerberos: Improved error messages */
5048159d09a2SMark Phalan 	krb5_set_error_message(context, retval,
50499e11d51cSWill Fiveash 	    gettext("Failed to get certificate location"));
5050159d09a2SMark Phalan 	pkiDebug("%s: failed to get user's cert location\n", __FUNCTION__);
5051159d09a2SMark Phalan 	goto cleanup;
5052159d09a2SMark Phalan     }
5053159d09a2SMark Phalan 
5054159d09a2SMark Phalan     if (idopts->key_filename == NULL) {
5055159d09a2SMark Phalan 	/* Solaris Kerberos: Improved error messages */
5056159d09a2SMark Phalan 	krb5_set_error_message(context, retval,
50579e11d51cSWill Fiveash 	    gettext("Failed to get private key location"));
5058159d09a2SMark Phalan 	pkiDebug("%s: failed to get user's private key location\n", __FUNCTION__);
5059159d09a2SMark Phalan 	goto cleanup;
5060159d09a2SMark Phalan     }
5061159d09a2SMark Phalan 
5062159d09a2SMark Phalan     fp = fopen(idopts->cert_filename, "rb");
5063159d09a2SMark Phalan     if (fp == NULL) {
5064159d09a2SMark Phalan 	/* Solaris Kerberos: Improved error messages */
5065159d09a2SMark Phalan 	krb5_set_error_message(context, retval,
50669e11d51cSWill Fiveash 	    gettext("Failed to open PKCS12 file '%s': %s"),
5067159d09a2SMark Phalan 	    idopts->cert_filename, error_message(errno));
5068159d09a2SMark Phalan 	pkiDebug("Failed to open PKCS12 file '%s', error %d\n",
5069159d09a2SMark Phalan 		 idopts->cert_filename, errno);
5070159d09a2SMark Phalan 	goto cleanup;
5071159d09a2SMark Phalan     }
5072159d09a2SMark Phalan 
5073159d09a2SMark Phalan     p12 = d2i_PKCS12_fp(fp, NULL);
5074159d09a2SMark Phalan     (void) fclose(fp);
5075159d09a2SMark Phalan     if (p12 == NULL) {
5076159d09a2SMark Phalan 	krb5_set_error_message(context, retval,
50779e11d51cSWill Fiveash 	    gettext("Failed to decode PKCS12 file '%s' contents"),
5078159d09a2SMark Phalan 	    idopts->cert_filename);
5079159d09a2SMark Phalan 	pkiDebug("Failed to decode PKCS12 file '%s' contents\n",
5080159d09a2SMark Phalan 		 idopts->cert_filename);
5081159d09a2SMark Phalan 	goto cleanup;
5082159d09a2SMark Phalan     }
5083159d09a2SMark Phalan     /*
5084159d09a2SMark Phalan      * Try parsing with no pass phrase first.  If that fails,
5085159d09a2SMark Phalan      * prompt for the pass phrase and try again.
5086159d09a2SMark Phalan      */
5087159d09a2SMark Phalan     ret = PKCS12_parse(p12, NULL, &y, &x, NULL);
5088159d09a2SMark Phalan     if (ret == 0) {
5089159d09a2SMark Phalan 	krb5_data rdat;
5090159d09a2SMark Phalan 	krb5_prompt kprompt;
5091159d09a2SMark Phalan 	krb5_prompt_type prompt_type;
5092159d09a2SMark Phalan 	int r = 0;
5093159d09a2SMark Phalan 	char prompt_string[128];
5094159d09a2SMark Phalan 	char prompt_reply[128];
5095159d09a2SMark Phalan 	/* Solaris Kerberos */
5096159d09a2SMark Phalan 	char *prompt_prefix = gettext("Pass phrase for");
5097159d09a2SMark Phalan 
5098159d09a2SMark Phalan 	pkiDebug("Initial PKCS12_parse with no password failed\n");
5099159d09a2SMark Phalan 
5100488060a6SWill Fiveash 	if (id_cryptoctx->PIN != NULL) {
5101488060a6SWill Fiveash 		/* Solaris Kerberos: use PIN if set */
5102488060a6SWill Fiveash 		rdat.data = id_cryptoctx->PIN;
5103488060a6SWill Fiveash 		/* note rdat.length isn't needed in this case */
5104488060a6SWill Fiveash 	} else {
5105488060a6SWill Fiveash 		(void) memset(prompt_reply, '\0', sizeof(prompt_reply));
5106488060a6SWill Fiveash 		rdat.data = prompt_reply;
5107488060a6SWill Fiveash 		rdat.length = sizeof(prompt_reply);
5108488060a6SWill Fiveash 
5109488060a6SWill Fiveash 		r = snprintf(prompt_string, sizeof(prompt_string), "%s %s",
5110488060a6SWill Fiveash 			     prompt_prefix, idopts->cert_filename);
5111488060a6SWill Fiveash 		if (r >= sizeof(prompt_string)) {
5112488060a6SWill Fiveash 		    pkiDebug("Prompt string, '%s %s', is too long!\n",
5113488060a6SWill Fiveash 			     prompt_prefix, idopts->cert_filename);
5114488060a6SWill Fiveash 		    goto cleanup;
5115488060a6SWill Fiveash 		}
5116488060a6SWill Fiveash 		kprompt.prompt = prompt_string;
5117488060a6SWill Fiveash 		kprompt.hidden = 1;
5118488060a6SWill Fiveash 		kprompt.reply = &rdat;
5119488060a6SWill Fiveash 		prompt_type = KRB5_PROMPT_TYPE_PREAUTH;
5120488060a6SWill Fiveash 
5121488060a6SWill Fiveash 		/* PROMPTER_INVOCATION */
5122488060a6SWill Fiveash 		k5int_set_prompt_types(context, &prompt_type);
5123488060a6SWill Fiveash 		r = (*id_cryptoctx->prompter)(context, id_cryptoctx->prompter_data,
5124488060a6SWill Fiveash 					      NULL, NULL, 1, &kprompt);
5125488060a6SWill Fiveash 		k5int_set_prompt_types(context, NULL);
5126159d09a2SMark Phalan 	}
5127159d09a2SMark Phalan 
5128159d09a2SMark Phalan 	ret = PKCS12_parse(p12, rdat.data, &y, &x, NULL);
5129159d09a2SMark Phalan 	if (ret == 0) {
5130159d09a2SMark Phalan 	    /* Solaris Kerberos: Improved error messages */
5131159d09a2SMark Phalan 	    krb5_set_error_message(context, retval,
51329e11d51cSWill Fiveash 	        gettext("Failed to parse PKCS12 file '%s' with password"),
5133159d09a2SMark Phalan 	        idopts->cert_filename);
5134159d09a2SMark Phalan 	    pkiDebug("Seconde PKCS12_parse with password failed\n");
5135159d09a2SMark Phalan 	    goto cleanup;
5136159d09a2SMark Phalan 	}
5137159d09a2SMark Phalan     }
5138159d09a2SMark Phalan     id_cryptoctx->creds[0] = malloc(sizeof(struct _pkinit_cred_info));
5139159d09a2SMark Phalan     if (id_cryptoctx->creds[0] == NULL)
5140159d09a2SMark Phalan 	goto cleanup;
5141159d09a2SMark Phalan     id_cryptoctx->creds[0]->cert = x;
5142159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
5143159d09a2SMark Phalan     id_cryptoctx->creds[0]->cert_id = NULL;
5144159d09a2SMark Phalan     id_cryptoctx->creds[0]->cert_id_len = 0;
5145159d09a2SMark Phalan #endif
5146159d09a2SMark Phalan     id_cryptoctx->creds[0]->key = y;
5147159d09a2SMark Phalan     id_cryptoctx->creds[1] = NULL;
5148159d09a2SMark Phalan 
5149159d09a2SMark Phalan     retval = 0;
5150159d09a2SMark Phalan 
5151159d09a2SMark Phalan cleanup:
5152159d09a2SMark Phalan     if (p12)
5153159d09a2SMark Phalan 	PKCS12_free(p12);
5154159d09a2SMark Phalan     if (retval) {
5155159d09a2SMark Phalan 	if (x != NULL)
5156159d09a2SMark Phalan 	    X509_free(x);
5157159d09a2SMark Phalan 	if (y != NULL)
5158159d09a2SMark Phalan 	    EVP_PKEY_free(y);
5159159d09a2SMark Phalan     }
5160159d09a2SMark Phalan     return retval;
5161159d09a2SMark Phalan }
5162159d09a2SMark Phalan 
5163159d09a2SMark Phalan static krb5_error_code
5164159d09a2SMark Phalan pkinit_load_fs_cert_and_key(krb5_context context,
5165159d09a2SMark Phalan 			    pkinit_identity_crypto_context id_cryptoctx,
5166159d09a2SMark Phalan 			    char *certname,
5167159d09a2SMark Phalan 			    char *keyname,
5168159d09a2SMark Phalan 			    int cindex)
5169159d09a2SMark Phalan {
5170159d09a2SMark Phalan     krb5_error_code retval;
5171159d09a2SMark Phalan     X509 *x = NULL;
5172159d09a2SMark Phalan     EVP_PKEY *y = NULL;
5173159d09a2SMark Phalan 
5174159d09a2SMark Phalan     /* load the certificate */
5175159d09a2SMark Phalan     retval = get_cert(certname, &x);
5176159d09a2SMark Phalan     if (retval != 0 || x == NULL) {
5177159d09a2SMark Phalan 	/* Solaris Kerberos: Improved error messages */
5178159d09a2SMark Phalan 	krb5_set_error_message(context, retval,
51799e11d51cSWill Fiveash 	    gettext("Failed to load user's certificate from %s: %s"),
5180159d09a2SMark Phalan 	        certname, error_message(retval));
5181159d09a2SMark Phalan 	pkiDebug("failed to load user's certificate from '%s'\n", certname);
5182159d09a2SMark Phalan 	goto cleanup;
5183159d09a2SMark Phalan     }
5184159d09a2SMark Phalan     retval = get_key(keyname, &y);
5185159d09a2SMark Phalan     if (retval != 0 || y == NULL) {
5186159d09a2SMark Phalan 	/* Solaris Kerberos: Improved error messages */
5187159d09a2SMark Phalan 	krb5_set_error_message(context, retval,
51889e11d51cSWill Fiveash 	    gettext("Failed to load user's private key from %s: %s"),
5189159d09a2SMark Phalan 	        keyname, error_message(retval));
5190159d09a2SMark Phalan 	pkiDebug("failed to load user's private key from '%s'\n", keyname);
5191159d09a2SMark Phalan 	goto cleanup;
5192159d09a2SMark Phalan     }
5193159d09a2SMark Phalan 
5194159d09a2SMark Phalan     id_cryptoctx->creds[cindex] = malloc(sizeof(struct _pkinit_cred_info));
5195159d09a2SMark Phalan     if (id_cryptoctx->creds[cindex] == NULL) {
5196159d09a2SMark Phalan 	retval = ENOMEM;
5197159d09a2SMark Phalan 	goto cleanup;
5198159d09a2SMark Phalan     }
5199159d09a2SMark Phalan     id_cryptoctx->creds[cindex]->cert = x;
5200159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
5201159d09a2SMark Phalan     id_cryptoctx->creds[cindex]->cert_id = NULL;
5202159d09a2SMark Phalan     id_cryptoctx->creds[cindex]->cert_id_len = 0;
5203159d09a2SMark Phalan #endif
5204159d09a2SMark Phalan     id_cryptoctx->creds[cindex]->key = y;
5205159d09a2SMark Phalan     id_cryptoctx->creds[cindex+1] = NULL;
5206159d09a2SMark Phalan 
5207159d09a2SMark Phalan     retval = 0;
5208159d09a2SMark Phalan 
5209159d09a2SMark Phalan cleanup:
5210159d09a2SMark Phalan     if (retval) {
5211159d09a2SMark Phalan 	if (x != NULL)
5212159d09a2SMark Phalan 	    X509_free(x);
5213159d09a2SMark Phalan 	if (y != NULL)
5214159d09a2SMark Phalan 	    EVP_PKEY_free(y);
5215159d09a2SMark Phalan     }
5216159d09a2SMark Phalan     return retval;
5217159d09a2SMark Phalan }
5218159d09a2SMark Phalan 
5219159d09a2SMark Phalan /* ARGSUSED */
5220159d09a2SMark Phalan static krb5_error_code
5221159d09a2SMark Phalan pkinit_get_certs_fs(krb5_context context,
5222159d09a2SMark Phalan 			  pkinit_plg_crypto_context plg_cryptoctx,
5223159d09a2SMark Phalan 			  pkinit_req_crypto_context req_cryptoctx,
5224159d09a2SMark Phalan 			  pkinit_identity_opts *idopts,
5225159d09a2SMark Phalan 			  pkinit_identity_crypto_context id_cryptoctx,
5226159d09a2SMark Phalan 			  krb5_principal princ)
5227159d09a2SMark Phalan {
5228159d09a2SMark Phalan     krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED;
5229159d09a2SMark Phalan 
5230159d09a2SMark Phalan     if (idopts->cert_filename == NULL) {
5231159d09a2SMark Phalan 	pkiDebug("%s: failed to get user's cert location\n", __FUNCTION__);
5232159d09a2SMark Phalan 	goto cleanup;
5233159d09a2SMark Phalan     }
5234159d09a2SMark Phalan 
5235159d09a2SMark Phalan     if (idopts->key_filename == NULL) {
5236159d09a2SMark Phalan 	pkiDebug("%s: failed to get user's private key location\n",
5237159d09a2SMark Phalan 		 __FUNCTION__);
5238159d09a2SMark Phalan 	goto cleanup;
5239159d09a2SMark Phalan     }
5240159d09a2SMark Phalan 
5241159d09a2SMark Phalan     retval = pkinit_load_fs_cert_and_key(context, id_cryptoctx,
5242159d09a2SMark Phalan 					 idopts->cert_filename,
5243159d09a2SMark Phalan 					 idopts->key_filename, 0);
5244159d09a2SMark Phalan cleanup:
5245159d09a2SMark Phalan     return retval;
5246159d09a2SMark Phalan }
5247159d09a2SMark Phalan 
5248159d09a2SMark Phalan /* ARGSUSED */
5249159d09a2SMark Phalan static krb5_error_code
5250159d09a2SMark Phalan pkinit_get_certs_dir(krb5_context context,
5251159d09a2SMark Phalan 		     pkinit_plg_crypto_context plg_cryptoctx,
5252159d09a2SMark Phalan 		     pkinit_req_crypto_context req_cryptoctx,
5253159d09a2SMark Phalan 		     pkinit_identity_opts *idopts,
5254159d09a2SMark Phalan 		     pkinit_identity_crypto_context id_cryptoctx,
5255159d09a2SMark Phalan 		     krb5_principal princ)
5256159d09a2SMark Phalan {
5257159d09a2SMark Phalan     /* Solaris Kerberos */
5258159d09a2SMark Phalan     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
5259159d09a2SMark Phalan     DIR *d = NULL;
5260159d09a2SMark Phalan     struct dirent *dentry = NULL;
5261159d09a2SMark Phalan     char certname[1024];
5262159d09a2SMark Phalan     char keyname[1024];
5263159d09a2SMark Phalan     int i = 0, len;
5264159d09a2SMark Phalan     char *dirname, *suf;
5265159d09a2SMark Phalan 
5266159d09a2SMark Phalan     /* Solaris Kerberos */
5267159d09a2SMark Phalan     if (idopts == NULL)
5268159d09a2SMark Phalan 	return EINVAL;
5269159d09a2SMark Phalan 
5270159d09a2SMark Phalan     if (idopts->cert_filename == NULL) {
5271159d09a2SMark Phalan 	pkiDebug("%s: failed to get user's certificate directory location\n",
5272159d09a2SMark Phalan 		 __FUNCTION__);
5273159d09a2SMark Phalan 	return ENOENT;
5274159d09a2SMark Phalan     }
5275159d09a2SMark Phalan 
5276159d09a2SMark Phalan     dirname = idopts->cert_filename;
5277159d09a2SMark Phalan     d = opendir(dirname);
5278159d09a2SMark Phalan     if (d == NULL) {
5279159d09a2SMark Phalan 	/* Solaris Kerberos: Improved error messages */
5280159d09a2SMark Phalan 	krb5_set_error_message(context, errno,
52819e11d51cSWill Fiveash 	    gettext("Failed to open directory \"%s\": %s"),
5282159d09a2SMark Phalan 	    dirname, error_message(errno));
5283159d09a2SMark Phalan 	return errno;
5284159d09a2SMark Phalan     }
5285159d09a2SMark Phalan 
5286159d09a2SMark Phalan     /*
5287159d09a2SMark Phalan      * We'll assume that certs are named XXX.crt and the corresponding
5288159d09a2SMark Phalan      * key is named XXX.key
5289159d09a2SMark Phalan      */
5290159d09a2SMark Phalan     while ((i < MAX_CREDS_ALLOWED) &&  (dentry = readdir(d)) != NULL) {
5291159d09a2SMark Phalan 	/* Ignore subdirectories and anything starting with a dot */
5292159d09a2SMark Phalan #ifdef DT_DIR
5293159d09a2SMark Phalan 	if (dentry->d_type == DT_DIR)
5294159d09a2SMark Phalan 	    continue;
5295159d09a2SMark Phalan #endif
5296159d09a2SMark Phalan 	if (dentry->d_name[0] == '.')
5297159d09a2SMark Phalan 	    continue;
5298159d09a2SMark Phalan 	len = strlen(dentry->d_name);
5299159d09a2SMark Phalan 	if (len < 5)
5300159d09a2SMark Phalan 	    continue;
5301159d09a2SMark Phalan 	suf = dentry->d_name + (len - 4);
5302159d09a2SMark Phalan 	if (strncmp(suf, ".crt", 4) != 0)
5303159d09a2SMark Phalan 	    continue;
5304159d09a2SMark Phalan 
5305159d09a2SMark Phalan 	/* Checked length */
5306159d09a2SMark Phalan 	if (strlen(dirname) + strlen(dentry->d_name) + 2 > sizeof(certname)) {
5307159d09a2SMark Phalan 	    pkiDebug("%s: Path too long -- directory '%s' and file '%s'\n",
5308159d09a2SMark Phalan 		     __FUNCTION__, dirname, dentry->d_name);
5309159d09a2SMark Phalan 	    continue;
5310159d09a2SMark Phalan 	}
5311159d09a2SMark Phalan 	(void) snprintf(certname, sizeof(certname), "%s/%s", dirname, dentry->d_name);
5312159d09a2SMark Phalan 	(void) snprintf(keyname, sizeof(keyname), "%s/%s", dirname, dentry->d_name);
5313159d09a2SMark Phalan 	len = strlen(keyname);
5314159d09a2SMark Phalan 	keyname[len - 3] = 'k';
5315159d09a2SMark Phalan 	keyname[len - 2] = 'e';
5316159d09a2SMark Phalan 	keyname[len - 1] = 'y';
5317159d09a2SMark Phalan 
5318159d09a2SMark Phalan 	retval = pkinit_load_fs_cert_and_key(context, id_cryptoctx,
5319159d09a2SMark Phalan 					     certname, keyname, i);
5320159d09a2SMark Phalan 	if (retval == 0) {
5321159d09a2SMark Phalan 	    pkiDebug("%s: Successfully loaded cert (and key) for %s\n",
5322159d09a2SMark Phalan 		     __FUNCTION__, dentry->d_name);
5323159d09a2SMark Phalan 	    i++;
5324159d09a2SMark Phalan 	}
5325159d09a2SMark Phalan 	else
5326159d09a2SMark Phalan 	    continue;
5327159d09a2SMark Phalan     }
5328159d09a2SMark Phalan 
5329159d09a2SMark Phalan     if (i == 0) {
5330159d09a2SMark Phalan 	/* Solaris Kerberos: Improved error messages */
5331159d09a2SMark Phalan 	krb5_set_error_message(context, ENOENT,
5332159d09a2SMark Phalan 	    gettext("No suitable cert/key pairs found in directory '%s'"),
5333159d09a2SMark Phalan 	    idopts->cert_filename);
5334159d09a2SMark Phalan 	pkiDebug("%s: No cert/key pairs found in directory '%s'\n",
5335159d09a2SMark Phalan 		 __FUNCTION__, idopts->cert_filename);
5336159d09a2SMark Phalan 	retval = ENOENT;
5337159d09a2SMark Phalan 	goto cleanup;
5338159d09a2SMark Phalan     }
5339159d09a2SMark Phalan 
5340159d09a2SMark Phalan     retval = 0;
5341159d09a2SMark Phalan 
5342159d09a2SMark Phalan   cleanup:
5343300fdee2SAndy Fiddaman     if (d)
5344159d09a2SMark Phalan 	(void) closedir(d);
5345159d09a2SMark Phalan 
5346159d09a2SMark Phalan     return retval;
5347159d09a2SMark Phalan }
5348159d09a2SMark Phalan 
5349159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
5350159d09a2SMark Phalan /* ARGSUSED */
5351159d09a2SMark Phalan static krb5_error_code
5352159d09a2SMark Phalan pkinit_get_certs_pkcs11(krb5_context context,
5353159d09a2SMark Phalan 			pkinit_plg_crypto_context plg_cryptoctx,
5354159d09a2SMark Phalan 			pkinit_req_crypto_context req_cryptoctx,
5355159d09a2SMark Phalan 			pkinit_identity_opts *idopts,
5356159d09a2SMark Phalan 			pkinit_identity_crypto_context id_cryptoctx,
53579e11d51cSWill Fiveash 			krb5_principal princ,
53589e11d51cSWill Fiveash 			int do_matching)
5359159d09a2SMark Phalan {
5360159d09a2SMark Phalan #ifdef PKINIT_USE_MECH_LIST
53619e11d51cSWill Fiveash     CK_MECHANISM_TYPE_PTR mechp = NULL;
5362159d09a2SMark Phalan     CK_MECHANISM_INFO info;
5363159d09a2SMark Phalan #endif
53649e11d51cSWill Fiveash 
53659e11d51cSWill Fiveash     if (id_cryptoctx->p11flags & C_SKIP_PKCS11_AUTH)
53669e11d51cSWill Fiveash 	return KRB5KDC_ERR_PREAUTH_FAILED;
5367159d09a2SMark Phalan 
5368159d09a2SMark Phalan     /* Copy stuff from idopts -> id_cryptoctx */
5369159d09a2SMark Phalan     if (idopts->p11_module_name != NULL) {
5370159d09a2SMark Phalan 	id_cryptoctx->p11_module_name = strdup(idopts->p11_module_name);
5371159d09a2SMark Phalan 	if (id_cryptoctx->p11_module_name == NULL)
5372159d09a2SMark Phalan 	    return ENOMEM;
5373159d09a2SMark Phalan     }
5374159d09a2SMark Phalan     if (idopts->token_label != NULL) {
5375159d09a2SMark Phalan 	id_cryptoctx->token_label = strdup(idopts->token_label);
5376159d09a2SMark Phalan 	if (id_cryptoctx->token_label == NULL)
5377159d09a2SMark Phalan 	    return ENOMEM;
5378159d09a2SMark Phalan     }
5379159d09a2SMark Phalan     if (idopts->cert_label != NULL) {
5380159d09a2SMark Phalan 	id_cryptoctx->cert_label = strdup(idopts->cert_label);
5381159d09a2SMark Phalan 	if (id_cryptoctx->cert_label == NULL)
5382159d09a2SMark Phalan 	    return ENOMEM;
5383159d09a2SMark Phalan     }
5384488060a6SWill Fiveash     if (idopts->PIN != NULL) {
5385488060a6SWill Fiveash 	id_cryptoctx->PIN = strdup(idopts->PIN);
5386488060a6SWill Fiveash 	if (id_cryptoctx->PIN == NULL)
5387488060a6SWill Fiveash 	    return ENOMEM;
5388488060a6SWill Fiveash     }
5389159d09a2SMark Phalan     /* Convert the ascii cert_id string into a binary blob */
5390159d09a2SMark Phalan     /*
5391159d09a2SMark Phalan      * Solaris Kerberos:
5392159d09a2SMark Phalan      * If the cert_id_string is empty then behave in a similar way to how
5393159d09a2SMark Phalan      * an empty certlabel is treated - i.e. don't fail now but rather continue
5394159d09a2SMark Phalan      * as though the certid wasn't specified.
5395159d09a2SMark Phalan      */
5396159d09a2SMark Phalan     if (idopts->cert_id_string != NULL && strlen(idopts->cert_id_string) != 0) {
5397159d09a2SMark Phalan 	BIGNUM *bn = NULL;
5398159d09a2SMark Phalan 	BN_hex2bn(&bn, idopts->cert_id_string);
5399159d09a2SMark Phalan 	if (bn == NULL)
5400159d09a2SMark Phalan 	    return ENOMEM;
5401159d09a2SMark Phalan 	id_cryptoctx->cert_id_len = BN_num_bytes(bn);
5402159d09a2SMark Phalan 	id_cryptoctx->cert_id = malloc((size_t) id_cryptoctx->cert_id_len);
5403159d09a2SMark Phalan 	if (id_cryptoctx->cert_id == NULL) {
5404159d09a2SMark Phalan 	    BN_free(bn);
5405159d09a2SMark Phalan 	    return ENOMEM;
5406159d09a2SMark Phalan 	}
5407159d09a2SMark Phalan 	BN_bn2bin(bn, id_cryptoctx->cert_id);
5408159d09a2SMark Phalan 	BN_free(bn);
5409159d09a2SMark Phalan     }
5410159d09a2SMark Phalan     id_cryptoctx->slotid = idopts->slotid;
5411159d09a2SMark Phalan     id_cryptoctx->pkcs11_method = 1;
5412159d09a2SMark Phalan 
5413159d09a2SMark Phalan #ifndef PKINIT_USE_MECH_LIST
5414159d09a2SMark Phalan     /*
5415159d09a2SMark Phalan      * We'd like to use CKM_SHA1_RSA_PKCS for signing if it's available, but
5416159d09a2SMark Phalan      * many cards seems to be confused about whether they are capable of
5417159d09a2SMark Phalan      * this or not. The safe thing seems to be to ignore the mechanism list,
5418159d09a2SMark Phalan      * always use CKM_RSA_PKCS and calculate the sha1 digest ourselves.
5419159d09a2SMark Phalan      */
5420159d09a2SMark Phalan 
5421159d09a2SMark Phalan     id_cryptoctx->mech = CKM_RSA_PKCS;
5422159d09a2SMark Phalan #else
5423159d09a2SMark Phalan     if ((r = id_cryptoctx->p11->C_GetMechanismList(id_cryptoctx->slotid, NULL,
5424159d09a2SMark Phalan 	    &count)) != CKR_OK || count <= 0) {
5425159d09a2SMark Phalan 	pkiDebug("C_GetMechanismList: %s\n", pkinit_pkcs11_code_to_text(r));
5426159d09a2SMark Phalan 	return KRB5KDC_ERR_PREAUTH_FAILED;
5427159d09a2SMark Phalan     }
5428159d09a2SMark Phalan     mechp = (CK_MECHANISM_TYPE_PTR) malloc(count * sizeof (CK_MECHANISM_TYPE));
5429159d09a2SMark Phalan     if (mechp == NULL)
5430159d09a2SMark Phalan 	return ENOMEM;
5431159d09a2SMark Phalan     if ((r = id_cryptoctx->p11->C_GetMechanismList(id_cryptoctx->slotid,
54329e11d51cSWill Fiveash 	    mechp, &count)) != CKR_OK) {
54339e11d51cSWill Fiveash 	free(mechp);
5434159d09a2SMark Phalan 	return KRB5KDC_ERR_PREAUTH_FAILED;
54359e11d51cSWill Fiveash     }
5436159d09a2SMark Phalan     for (i = 0; i < count; i++) {
5437159d09a2SMark Phalan 	if ((r = id_cryptoctx->p11->C_GetMechanismInfo(id_cryptoctx->slotid,
54389e11d51cSWill Fiveash 		mechp[i], &info)) != CKR_OK) {
54399e11d51cSWill Fiveash 	    free(mechp);
5440159d09a2SMark Phalan 	    return KRB5KDC_ERR_PREAUTH_FAILED;
54419e11d51cSWill Fiveash 	}
5442159d09a2SMark Phalan #ifdef DEBUG_MECHINFO
5443159d09a2SMark Phalan 	pkiDebug("mech %x flags %x\n", (int) mechp[i], (int) info.flags);
5444159d09a2SMark Phalan 	if ((info.flags & (CKF_SIGN|CKF_DECRYPT)) == (CKF_SIGN|CKF_DECRYPT))
5445159d09a2SMark Phalan 	    pkiDebug("  this mech is good for sign & decrypt\n");
5446159d09a2SMark Phalan #endif
5447159d09a2SMark Phalan 	if (mechp[i] == CKM_RSA_PKCS) {
5448159d09a2SMark Phalan 	    /* This seems backwards... */
5449159d09a2SMark Phalan 	    id_cryptoctx->mech =
5450159d09a2SMark Phalan 		(info.flags & CKF_SIGN) ? CKM_SHA1_RSA_PKCS : CKM_RSA_PKCS;
5451159d09a2SMark Phalan 	}
5452159d09a2SMark Phalan     }
5453159d09a2SMark Phalan     free(mechp);
5454159d09a2SMark Phalan 
5455159d09a2SMark Phalan     pkiDebug("got %d mechs from card\n", (int) count);
5456159d09a2SMark Phalan #endif
5457159d09a2SMark Phalan 
54589e11d51cSWill Fiveash     return (pkinit_open_session(context, plg_cryptoctx, req_cryptoctx,
54599e11d51cSWill Fiveash                                 id_cryptoctx, princ, do_matching));
5460159d09a2SMark Phalan }
5461159d09a2SMark Phalan #endif
5462159d09a2SMark Phalan 
5463159d09a2SMark Phalan /* ARGSUSED */
5464159d09a2SMark Phalan static void
5465159d09a2SMark Phalan free_cred_info(krb5_context context,
5466159d09a2SMark Phalan 	       pkinit_identity_crypto_context id_cryptoctx,
5467159d09a2SMark Phalan 	       struct _pkinit_cred_info *cred)
5468159d09a2SMark Phalan {
5469159d09a2SMark Phalan     if (cred != NULL) {
5470159d09a2SMark Phalan 	if (cred->cert != NULL)
5471159d09a2SMark Phalan 	    X509_free(cred->cert);
5472159d09a2SMark Phalan 	if (cred->key != NULL)
5473159d09a2SMark Phalan 	    EVP_PKEY_free(cred->key);
5474159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
5475159d09a2SMark Phalan 	if (cred->cert_id != NULL)
5476159d09a2SMark Phalan 	    free(cred->cert_id);
5477159d09a2SMark Phalan #endif
5478159d09a2SMark Phalan 	free(cred);
5479159d09a2SMark Phalan     }
5480159d09a2SMark Phalan }
5481159d09a2SMark Phalan 
5482159d09a2SMark Phalan /* ARGSUSED */
5483159d09a2SMark Phalan krb5_error_code
5484159d09a2SMark Phalan crypto_free_cert_info(krb5_context context,
5485159d09a2SMark Phalan 		      pkinit_plg_crypto_context plg_cryptoctx,
5486159d09a2SMark Phalan 		      pkinit_req_crypto_context req_cryptoctx,
5487159d09a2SMark Phalan 		      pkinit_identity_crypto_context id_cryptoctx)
5488159d09a2SMark Phalan {
5489159d09a2SMark Phalan     int i;
5490159d09a2SMark Phalan 
5491159d09a2SMark Phalan     if (id_cryptoctx == NULL)
5492159d09a2SMark Phalan 	return EINVAL;
5493159d09a2SMark Phalan 
5494159d09a2SMark Phalan     for (i = 0; i < MAX_CREDS_ALLOWED; i++) {
5495159d09a2SMark Phalan 	if (id_cryptoctx->creds[i] != NULL) {
5496159d09a2SMark Phalan 	    free_cred_info(context, id_cryptoctx, id_cryptoctx->creds[i]);
5497159d09a2SMark Phalan 	    id_cryptoctx->creds[i] = NULL;
5498159d09a2SMark Phalan 	}
5499159d09a2SMark Phalan     }
5500159d09a2SMark Phalan     return 0;
5501159d09a2SMark Phalan }
5502159d09a2SMark Phalan 
5503159d09a2SMark Phalan krb5_error_code
5504159d09a2SMark Phalan crypto_load_certs(krb5_context context,
5505159d09a2SMark Phalan 		  pkinit_plg_crypto_context plg_cryptoctx,
5506159d09a2SMark Phalan 		  pkinit_req_crypto_context req_cryptoctx,
5507159d09a2SMark Phalan 		  pkinit_identity_opts *idopts,
5508159d09a2SMark Phalan 		  pkinit_identity_crypto_context id_cryptoctx,
55099e11d51cSWill Fiveash 		  krb5_principal princ,
55109e11d51cSWill Fiveash 		  int do_matching)
5511159d09a2SMark Phalan {
5512159d09a2SMark Phalan     krb5_error_code retval;
5513159d09a2SMark Phalan 
5514159d09a2SMark Phalan     switch(idopts->idtype) {
5515159d09a2SMark Phalan 	case IDTYPE_FILE:
5516159d09a2SMark Phalan 	    retval = pkinit_get_certs_fs(context, plg_cryptoctx,
5517159d09a2SMark Phalan 					 req_cryptoctx, idopts,
5518159d09a2SMark Phalan 					 id_cryptoctx, princ);
5519159d09a2SMark Phalan 	    break;
5520159d09a2SMark Phalan 	case IDTYPE_DIR:
5521159d09a2SMark Phalan 	    retval = pkinit_get_certs_dir(context, plg_cryptoctx,
5522159d09a2SMark Phalan 					  req_cryptoctx, idopts,
5523159d09a2SMark Phalan 					  id_cryptoctx, princ);
5524159d09a2SMark Phalan 	    break;
5525159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
5526159d09a2SMark Phalan 	case IDTYPE_PKCS11:
5527159d09a2SMark Phalan 	    retval = pkinit_get_certs_pkcs11(context, plg_cryptoctx,
5528159d09a2SMark Phalan 					     req_cryptoctx, idopts,
55299e11d51cSWill Fiveash 					     id_cryptoctx, princ, do_matching);
5530159d09a2SMark Phalan 	    break;
5531159d09a2SMark Phalan #endif
5532159d09a2SMark Phalan 	case IDTYPE_PKCS12:
5533159d09a2SMark Phalan 	    retval = pkinit_get_certs_pkcs12(context, plg_cryptoctx,
5534159d09a2SMark Phalan 					     req_cryptoctx, idopts,
5535159d09a2SMark Phalan 					     id_cryptoctx, princ);
5536159d09a2SMark Phalan 		break;
5537159d09a2SMark Phalan 	default:
5538159d09a2SMark Phalan 	    retval = EINVAL;
5539159d09a2SMark Phalan     }
5540159d09a2SMark Phalan /* Solaris Kerberos */
5541159d09a2SMark Phalan 
5542159d09a2SMark Phalan     return retval;
5543159d09a2SMark Phalan }
5544159d09a2SMark Phalan 
5545159d09a2SMark Phalan /*
5546159d09a2SMark Phalan  * Get number of certificates available after crypto_load_certs()
5547159d09a2SMark Phalan  */
5548159d09a2SMark Phalan /* ARGSUSED */
5549159d09a2SMark Phalan krb5_error_code
5550159d09a2SMark Phalan crypto_cert_get_count(krb5_context context,
5551159d09a2SMark Phalan 		      pkinit_plg_crypto_context plg_cryptoctx,
5552159d09a2SMark Phalan 		      pkinit_req_crypto_context req_cryptoctx,
5553159d09a2SMark Phalan 		      pkinit_identity_crypto_context id_cryptoctx,
5554159d09a2SMark Phalan 		      int *cert_count)
5555159d09a2SMark Phalan {
5556159d09a2SMark Phalan     int count;
5557159d09a2SMark Phalan 
5558159d09a2SMark Phalan     if (id_cryptoctx == NULL || id_cryptoctx->creds[0] == NULL)
5559159d09a2SMark Phalan 	return EINVAL;
5560159d09a2SMark Phalan 
5561159d09a2SMark Phalan     for (count = 0;
5562159d09a2SMark Phalan 	 count <= MAX_CREDS_ALLOWED && id_cryptoctx->creds[count] != NULL;
5563159d09a2SMark Phalan 	 count++);
5564159d09a2SMark Phalan     *cert_count = count;
5565159d09a2SMark Phalan     return 0;
5566159d09a2SMark Phalan }
5567159d09a2SMark Phalan 
5568159d09a2SMark Phalan 
5569159d09a2SMark Phalan /*
5570159d09a2SMark Phalan  * Begin iteration over the certs loaded in crypto_load_certs()
5571159d09a2SMark Phalan  */
5572159d09a2SMark Phalan /* ARGSUSED */
5573159d09a2SMark Phalan krb5_error_code
5574159d09a2SMark Phalan crypto_cert_iteration_begin(krb5_context context,
5575159d09a2SMark Phalan 			    pkinit_plg_crypto_context plg_cryptoctx,
5576159d09a2SMark Phalan 			    pkinit_req_crypto_context req_cryptoctx,
5577159d09a2SMark Phalan 			    pkinit_identity_crypto_context id_cryptoctx,
5578159d09a2SMark Phalan 			    pkinit_cert_iter_handle *ih_ret)
5579159d09a2SMark Phalan {
5580159d09a2SMark Phalan     struct _pkinit_cert_iter_data *id;
5581159d09a2SMark Phalan 
5582159d09a2SMark Phalan     if (id_cryptoctx == NULL || ih_ret == NULL)
5583159d09a2SMark Phalan 	return EINVAL;
5584159d09a2SMark Phalan     if (id_cryptoctx->creds[0] == NULL)	/* No cred info available */
5585159d09a2SMark Phalan 	return ENOENT;
5586159d09a2SMark Phalan 
5587159d09a2SMark Phalan     id = calloc(1, sizeof(*id));
5588159d09a2SMark Phalan     if (id == NULL)
5589159d09a2SMark Phalan 	return ENOMEM;
5590159d09a2SMark Phalan     id->magic = ITER_MAGIC;
5591159d09a2SMark Phalan     id->plgctx = plg_cryptoctx,
5592159d09a2SMark Phalan     id->reqctx = req_cryptoctx,
5593159d09a2SMark Phalan     id->idctx = id_cryptoctx;
5594159d09a2SMark Phalan     id->index = 0;
5595159d09a2SMark Phalan     *ih_ret = (pkinit_cert_iter_handle) id;
5596159d09a2SMark Phalan     return 0;
5597159d09a2SMark Phalan }
5598159d09a2SMark Phalan 
5599159d09a2SMark Phalan /*
5600159d09a2SMark Phalan  * End iteration over the certs loaded in crypto_load_certs()
5601159d09a2SMark Phalan  */
5602159d09a2SMark Phalan /* ARGSUSED */
5603159d09a2SMark Phalan krb5_error_code
5604159d09a2SMark Phalan crypto_cert_iteration_end(krb5_context context,
5605159d09a2SMark Phalan 			  pkinit_cert_iter_handle ih)
5606159d09a2SMark Phalan {
5607159d09a2SMark Phalan     struct _pkinit_cert_iter_data *id = (struct _pkinit_cert_iter_data *)ih;
5608159d09a2SMark Phalan 
5609159d09a2SMark Phalan     if (id == NULL || id->magic != ITER_MAGIC)
5610159d09a2SMark Phalan 	return EINVAL;
5611159d09a2SMark Phalan     free(ih);
5612159d09a2SMark Phalan     return 0;
5613159d09a2SMark Phalan }
5614159d09a2SMark Phalan 
5615159d09a2SMark Phalan /*
5616159d09a2SMark Phalan  * Get next certificate handle
5617159d09a2SMark Phalan  */
5618159d09a2SMark Phalan /* ARGSUSED */
5619159d09a2SMark Phalan krb5_error_code
5620159d09a2SMark Phalan crypto_cert_iteration_next(krb5_context context,
5621159d09a2SMark Phalan 			   pkinit_cert_iter_handle ih,
5622159d09a2SMark Phalan 			   pkinit_cert_handle *ch_ret)
5623159d09a2SMark Phalan {
5624159d09a2SMark Phalan     struct _pkinit_cert_iter_data *id = (struct _pkinit_cert_iter_data *)ih;
5625159d09a2SMark Phalan     struct _pkinit_cert_data *cd;
5626159d09a2SMark Phalan     pkinit_identity_crypto_context id_cryptoctx;
5627159d09a2SMark Phalan 
5628159d09a2SMark Phalan     if (id == NULL || id->magic != ITER_MAGIC)
5629159d09a2SMark Phalan 	return EINVAL;
5630159d09a2SMark Phalan 
5631159d09a2SMark Phalan     if (ch_ret == NULL)
5632159d09a2SMark Phalan 	return EINVAL;
5633159d09a2SMark Phalan 
5634159d09a2SMark Phalan     id_cryptoctx = id->idctx;
5635159d09a2SMark Phalan     if (id_cryptoctx == NULL)
5636159d09a2SMark Phalan 	return EINVAL;
5637159d09a2SMark Phalan 
5638159d09a2SMark Phalan     if (id_cryptoctx->creds[id->index] == NULL)
5639159d09a2SMark Phalan 	return PKINIT_ITER_NO_MORE;
5640300fdee2SAndy Fiddaman 
5641159d09a2SMark Phalan     cd = calloc(1, sizeof(*cd));
5642159d09a2SMark Phalan     if (cd == NULL)
5643159d09a2SMark Phalan 	return ENOMEM;
5644159d09a2SMark Phalan 
5645159d09a2SMark Phalan     cd->magic = CERT_MAGIC;
5646159d09a2SMark Phalan     cd->plgctx = id->plgctx;
5647159d09a2SMark Phalan     cd->reqctx = id->reqctx;
5648159d09a2SMark Phalan     cd->idctx = id->idctx;
5649159d09a2SMark Phalan     cd->index = id->index;
5650159d09a2SMark Phalan     cd->cred = id_cryptoctx->creds[id->index++];
5651159d09a2SMark Phalan     *ch_ret = (pkinit_cert_handle)cd;
5652159d09a2SMark Phalan     return 0;
5653159d09a2SMark Phalan }
5654159d09a2SMark Phalan 
5655159d09a2SMark Phalan /*
5656159d09a2SMark Phalan  * Release cert handle
5657159d09a2SMark Phalan  */
5658159d09a2SMark Phalan /* ARGSUSED */
5659159d09a2SMark Phalan krb5_error_code
5660159d09a2SMark Phalan crypto_cert_release(krb5_context context,
5661159d09a2SMark Phalan 		    pkinit_cert_handle ch)
5662159d09a2SMark Phalan {
5663159d09a2SMark Phalan     struct _pkinit_cert_data *cd = (struct _pkinit_cert_data *)ch;
5664159d09a2SMark Phalan     if (cd == NULL || cd->magic != CERT_MAGIC)
5665159d09a2SMark Phalan 	return EINVAL;
5666159d09a2SMark Phalan     free(cd);
5667159d09a2SMark Phalan     return 0;
5668159d09a2SMark Phalan }
5669159d09a2SMark Phalan 
5670159d09a2SMark Phalan /*
5671159d09a2SMark Phalan  * Get certificate Key Usage and Extended Key Usage
5672159d09a2SMark Phalan  */
5673159d09a2SMark Phalan /* ARGSUSED */
5674159d09a2SMark Phalan static krb5_error_code
5675159d09a2SMark Phalan crypto_retieve_X509_key_usage(krb5_context context,
5676159d09a2SMark Phalan 			      pkinit_plg_crypto_context plgcctx,
5677159d09a2SMark Phalan 			      pkinit_req_crypto_context reqcctx,
5678159d09a2SMark Phalan 			      X509 *x,
5679159d09a2SMark Phalan 			      unsigned int *ret_ku_bits,
5680159d09a2SMark Phalan 			      unsigned int *ret_eku_bits)
5681159d09a2SMark Phalan {
5682159d09a2SMark Phalan     /* Solaris Kerberos */
5683159d09a2SMark Phalan     int i;
5684159d09a2SMark Phalan     unsigned int eku_bits = 0, ku_bits = 0;
5685159d09a2SMark Phalan     ASN1_BIT_STRING *usage = NULL;
5686159d09a2SMark Phalan 
5687159d09a2SMark Phalan     if (ret_ku_bits == NULL && ret_eku_bits == NULL)
5688159d09a2SMark Phalan 	return EINVAL;
5689159d09a2SMark Phalan 
5690159d09a2SMark Phalan     if (ret_eku_bits)
5691159d09a2SMark Phalan 	*ret_eku_bits = 0;
5692159d09a2SMark Phalan     else {
5693159d09a2SMark Phalan 	pkiDebug("%s: EKUs not requested, not checking\n", __FUNCTION__);
5694159d09a2SMark Phalan 	goto check_kus;
5695159d09a2SMark Phalan     }
5696300fdee2SAndy Fiddaman 
5697159d09a2SMark Phalan     /* Start with Extended Key usage */
5698159d09a2SMark Phalan     i = X509_get_ext_by_NID(x, NID_ext_key_usage, -1);
5699159d09a2SMark Phalan     if (i >= 0) {
5700159d09a2SMark Phalan 	EXTENDED_KEY_USAGE *eku;
5701159d09a2SMark Phalan 
5702159d09a2SMark Phalan 	eku = X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL);
5703159d09a2SMark Phalan 	if (eku) {
5704159d09a2SMark Phalan 	    for (i = 0; i < sk_ASN1_OBJECT_num(eku); i++) {
5705159d09a2SMark Phalan 		ASN1_OBJECT *certoid;
5706159d09a2SMark Phalan 		certoid = sk_ASN1_OBJECT_value(eku, i);
5707159d09a2SMark Phalan 		if ((OBJ_cmp(certoid, plgcctx->id_pkinit_KPClientAuth)) == 0)
5708159d09a2SMark Phalan 		    eku_bits |= PKINIT_EKU_PKINIT;
5709159d09a2SMark Phalan 		else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_ms_smartcard_login))) == 0)
5710159d09a2SMark Phalan 		    eku_bits |= PKINIT_EKU_MSSCLOGIN;
5711159d09a2SMark Phalan 		else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_client_auth))) == 0)
5712159d09a2SMark Phalan 		    eku_bits |= PKINIT_EKU_CLIENTAUTH;
5713159d09a2SMark Phalan 		else if ((OBJ_cmp(certoid, OBJ_nid2obj(NID_email_protect))) == 0)
5714159d09a2SMark Phalan 		    eku_bits |= PKINIT_EKU_EMAILPROTECTION;
5715159d09a2SMark Phalan 	    }
5716159d09a2SMark Phalan 	    EXTENDED_KEY_USAGE_free(eku);
5717159d09a2SMark Phalan 	}
5718159d09a2SMark Phalan     }
5719159d09a2SMark Phalan     pkiDebug("%s: returning eku 0x%08x\n", __FUNCTION__, eku_bits);
5720159d09a2SMark Phalan     *ret_eku_bits = eku_bits;
5721159d09a2SMark Phalan 
5722159d09a2SMark Phalan check_kus:
5723159d09a2SMark Phalan     /* Now the Key Usage bits */
5724159d09a2SMark Phalan     if (ret_ku_bits)
5725159d09a2SMark Phalan 	*ret_ku_bits = 0;
5726159d09a2SMark Phalan     else {
5727159d09a2SMark Phalan 	pkiDebug("%s: KUs not requested, not checking\n", __FUNCTION__);
5728159d09a2SMark Phalan 	goto out;
5729159d09a2SMark Phalan     }
5730159d09a2SMark Phalan 
5731159d09a2SMark Phalan     /* Make sure usage exists before checking bits */
5732159d09a2SMark Phalan     usage = X509_get_ext_d2i(x, NID_key_usage, NULL, NULL);
5733159d09a2SMark Phalan     if (usage) {
5734159d09a2SMark Phalan 	if (!ku_reject(x, X509v3_KU_DIGITAL_SIGNATURE))
5735159d09a2SMark Phalan 	    ku_bits |= PKINIT_KU_DIGITALSIGNATURE;
5736159d09a2SMark Phalan 	if (!ku_reject(x, X509v3_KU_KEY_ENCIPHERMENT))
5737159d09a2SMark Phalan 	    ku_bits |= PKINIT_KU_KEYENCIPHERMENT;
5738159d09a2SMark Phalan 	ASN1_BIT_STRING_free(usage);
5739159d09a2SMark Phalan     }
5740159d09a2SMark Phalan 
5741159d09a2SMark Phalan     pkiDebug("%s: returning ku 0x%08x\n", __FUNCTION__, ku_bits);
5742159d09a2SMark Phalan     *ret_ku_bits = ku_bits;
5743159d09a2SMark Phalan 
5744159d09a2SMark Phalan out:
5745159d09a2SMark Phalan     return 0;
5746159d09a2SMark Phalan }
5747159d09a2SMark Phalan 
5748159d09a2SMark Phalan /*
5749159d09a2SMark Phalan  * Return a string format of an X509_NAME in buf where
5750159d09a2SMark Phalan  * size is an in/out parameter.  On input it is the size
5751159d09a2SMark Phalan  * of the buffer, and on output it is the actual length
5752159d09a2SMark Phalan  * of the name.
5753159d09a2SMark Phalan  * If buf is NULL, returns the length req'd to hold name
5754159d09a2SMark Phalan  */
5755159d09a2SMark Phalan static char *
5756159d09a2SMark Phalan X509_NAME_oneline_ex(X509_NAME * a,
5757159d09a2SMark Phalan 		     char *buf,
5758159d09a2SMark Phalan 		     unsigned int *size,
5759159d09a2SMark Phalan 		     unsigned long flag)
5760159d09a2SMark Phalan {
5761159d09a2SMark Phalan   BIO *out = NULL;
5762159d09a2SMark Phalan 
5763159d09a2SMark Phalan   out = BIO_new(BIO_s_mem ());
5764159d09a2SMark Phalan   if (X509_NAME_print_ex(out, a, 0, flag) > 0) {
5765159d09a2SMark Phalan     if (buf != NULL && *size > (int) BIO_number_written(out)) {
5766159d09a2SMark Phalan       (void) memset(buf, 0, *size);
5767159d09a2SMark Phalan       BIO_read(out, buf, (int) BIO_number_written(out));
5768159d09a2SMark Phalan     }
5769159d09a2SMark Phalan     else {
5770159d09a2SMark Phalan       *size = BIO_number_written(out);
5771159d09a2SMark Phalan     }
5772159d09a2SMark Phalan   }
5773159d09a2SMark Phalan   BIO_free(out);
5774159d09a2SMark Phalan   return (buf);
5775159d09a2SMark Phalan }
5776159d09a2SMark Phalan 
5777159d09a2SMark Phalan /*
5778159d09a2SMark Phalan  * Get certificate information
5779159d09a2SMark Phalan  */
5780159d09a2SMark Phalan krb5_error_code
5781159d09a2SMark Phalan crypto_cert_get_matching_data(krb5_context context,
5782159d09a2SMark Phalan 			      pkinit_cert_handle ch,
5783159d09a2SMark Phalan 			      pkinit_cert_matching_data **ret_md)
5784159d09a2SMark Phalan {
5785159d09a2SMark Phalan     krb5_error_code retval;
5786159d09a2SMark Phalan     pkinit_cert_matching_data *md;
5787159d09a2SMark Phalan     krb5_principal *pkinit_sans =NULL, *upn_sans = NULL;
5788159d09a2SMark Phalan     struct _pkinit_cert_data *cd = (struct _pkinit_cert_data *)ch;
5789159d09a2SMark Phalan     int i, j;
5790159d09a2SMark Phalan     char buf[DN_BUF_LEN];
5791159d09a2SMark Phalan     unsigned int bufsize = sizeof(buf);
5792159d09a2SMark Phalan 
5793159d09a2SMark Phalan     if (cd == NULL || cd->magic != CERT_MAGIC)
5794159d09a2SMark Phalan 	return EINVAL;
5795159d09a2SMark Phalan     if (ret_md == NULL)
5796159d09a2SMark Phalan 	return EINVAL;
5797159d09a2SMark Phalan 
5798159d09a2SMark Phalan     md = calloc(1, sizeof(*md));
5799159d09a2SMark Phalan     if (md == NULL)
5800159d09a2SMark Phalan 	return ENOMEM;
5801159d09a2SMark Phalan 
5802159d09a2SMark Phalan     md->ch = ch;
5803159d09a2SMark Phalan 
5804159d09a2SMark Phalan     /* get the subject name (in rfc2253 format) */
5805159d09a2SMark Phalan     X509_NAME_oneline_ex(X509_get_subject_name(cd->cred->cert),
5806159d09a2SMark Phalan 			 buf, &bufsize, XN_FLAG_SEP_COMMA_PLUS);
5807159d09a2SMark Phalan     md->subject_dn = strdup(buf);
5808159d09a2SMark Phalan     if (md->subject_dn == NULL) {
5809159d09a2SMark Phalan 	retval = ENOMEM;
5810159d09a2SMark Phalan 	goto cleanup;
5811159d09a2SMark Phalan     }
5812159d09a2SMark Phalan 
5813159d09a2SMark Phalan     /* get the issuer name (in rfc2253 format) */
5814159d09a2SMark Phalan     X509_NAME_oneline_ex(X509_get_issuer_name(cd->cred->cert),
5815159d09a2SMark Phalan 			 buf, &bufsize, XN_FLAG_SEP_COMMA_PLUS);
5816159d09a2SMark Phalan     md->issuer_dn = strdup(buf);
5817159d09a2SMark Phalan     if (md->issuer_dn == NULL) {
5818159d09a2SMark Phalan 	retval = ENOMEM;
5819159d09a2SMark Phalan 	goto cleanup;
5820159d09a2SMark Phalan     }
5821159d09a2SMark Phalan 
5822159d09a2SMark Phalan     /* get the san data */
5823159d09a2SMark Phalan     retval = crypto_retrieve_X509_sans(context, cd->plgctx, cd->reqctx,
5824159d09a2SMark Phalan 				       cd->cred->cert, &pkinit_sans,
5825159d09a2SMark Phalan 				       &upn_sans, NULL);
5826159d09a2SMark Phalan     if (retval)
5827159d09a2SMark Phalan 	goto cleanup;
5828159d09a2SMark Phalan 
5829159d09a2SMark Phalan     j = 0;
5830159d09a2SMark Phalan     if (pkinit_sans != NULL) {
5831159d09a2SMark Phalan 	for (i = 0; pkinit_sans[i] != NULL; i++)
5832159d09a2SMark Phalan 	    j++;
5833159d09a2SMark Phalan     }
5834159d09a2SMark Phalan     if (upn_sans != NULL) {
5835159d09a2SMark Phalan 	for (i = 0; upn_sans[i] != NULL; i++)
5836159d09a2SMark Phalan 	    j++;
5837159d09a2SMark Phalan     }
5838159d09a2SMark Phalan     if (j != 0) {
5839159d09a2SMark Phalan 	md->sans = calloc((size_t)j+1, sizeof(*md->sans));
5840159d09a2SMark Phalan 	if (md->sans == NULL) {
5841159d09a2SMark Phalan 	    retval = ENOMEM;
5842159d09a2SMark Phalan 	    goto cleanup;
5843159d09a2SMark Phalan 	}
5844159d09a2SMark Phalan 	j = 0;
5845159d09a2SMark Phalan 	if (pkinit_sans != NULL) {
5846159d09a2SMark Phalan 	    for (i = 0; pkinit_sans[i] != NULL; i++)
5847159d09a2SMark Phalan 		md->sans[j++] = pkinit_sans[i];
5848159d09a2SMark Phalan 	    free(pkinit_sans);
5849159d09a2SMark Phalan 	}
5850159d09a2SMark Phalan 	if (upn_sans != NULL) {
5851159d09a2SMark Phalan 	    for (i = 0; upn_sans[i] != NULL; i++)
5852159d09a2SMark Phalan 		md->sans[j++] = upn_sans[i];
5853159d09a2SMark Phalan 	    free(upn_sans);
5854159d09a2SMark Phalan 	}
5855159d09a2SMark Phalan 	md->sans[j] = NULL;
5856159d09a2SMark Phalan     } else
5857159d09a2SMark Phalan 	md->sans = NULL;
5858159d09a2SMark Phalan 
5859159d09a2SMark Phalan     /* get the KU and EKU data */
5860159d09a2SMark Phalan 
5861159d09a2SMark Phalan     retval = crypto_retieve_X509_key_usage(context, cd->plgctx, cd->reqctx,
5862159d09a2SMark Phalan 					   cd->cred->cert,
5863159d09a2SMark Phalan 					   &md->ku_bits, &md->eku_bits);
5864159d09a2SMark Phalan     if (retval)
5865159d09a2SMark Phalan 	goto cleanup;
5866159d09a2SMark Phalan 
5867159d09a2SMark Phalan     *ret_md = md;
5868159d09a2SMark Phalan     retval = 0;
5869159d09a2SMark Phalan cleanup:
5870159d09a2SMark Phalan     if (retval) {
5871159d09a2SMark Phalan 	if (md)
5872159d09a2SMark Phalan 	    crypto_cert_free_matching_data(context, md);
5873159d09a2SMark Phalan     }
5874159d09a2SMark Phalan     return retval;
5875159d09a2SMark Phalan }
5876159d09a2SMark Phalan 
5877159d09a2SMark Phalan /*
5878159d09a2SMark Phalan  * Free certificate information
5879159d09a2SMark Phalan  */
5880159d09a2SMark Phalan krb5_error_code
5881159d09a2SMark Phalan crypto_cert_free_matching_data(krb5_context context,
5882159d09a2SMark Phalan 		      pkinit_cert_matching_data *md)
5883159d09a2SMark Phalan {
5884159d09a2SMark Phalan     krb5_principal p;
5885159d09a2SMark Phalan     int i;
5886159d09a2SMark Phalan 
5887159d09a2SMark Phalan     if (md == NULL)
5888159d09a2SMark Phalan 	return EINVAL;
5889159d09a2SMark Phalan     if (md->subject_dn)
5890159d09a2SMark Phalan 	free(md->subject_dn);
5891159d09a2SMark Phalan     if (md->issuer_dn)
5892159d09a2SMark Phalan 	free(md->issuer_dn);
5893159d09a2SMark Phalan     if (md->sans) {
5894159d09a2SMark Phalan 	for (i = 0, p = md->sans[i]; p != NULL; p = md->sans[++i])
5895159d09a2SMark Phalan 	    krb5_free_principal(context, p);
5896159d09a2SMark Phalan 	free(md->sans);
5897159d09a2SMark Phalan     }
5898159d09a2SMark Phalan     free(md);
5899159d09a2SMark Phalan     return 0;
5900159d09a2SMark Phalan }
5901159d09a2SMark Phalan 
5902159d09a2SMark Phalan /*
5903159d09a2SMark Phalan  * Make this matching certificate "the chosen one"
5904159d09a2SMark Phalan  */
5905159d09a2SMark Phalan /* ARGSUSED */
5906159d09a2SMark Phalan krb5_error_code
5907159d09a2SMark Phalan crypto_cert_select(krb5_context context,
5908159d09a2SMark Phalan 		   pkinit_cert_matching_data *md)
5909159d09a2SMark Phalan {
5910159d09a2SMark Phalan     struct _pkinit_cert_data *cd;
5911159d09a2SMark Phalan     if (md == NULL)
5912159d09a2SMark Phalan 	return EINVAL;
5913159d09a2SMark Phalan 
5914159d09a2SMark Phalan     cd = (struct _pkinit_cert_data *)md->ch;
5915159d09a2SMark Phalan     if (cd == NULL || cd->magic != CERT_MAGIC)
5916159d09a2SMark Phalan 	return EINVAL;
5917300fdee2SAndy Fiddaman 
5918300fdee2SAndy Fiddaman     /* copy the selected cert into our id_cryptoctx */
5919159d09a2SMark Phalan     if (cd->idctx->my_certs != NULL) {
5920159d09a2SMark Phalan 	sk_X509_pop_free(cd->idctx->my_certs, X509_free);
5921159d09a2SMark Phalan     }
59223f8dd771SAndy Fiddaman     cd->idctx->my_certs = sk_X509_new_null();
5923159d09a2SMark Phalan     sk_X509_push(cd->idctx->my_certs, cd->cred->cert);
5924159d09a2SMark Phalan     cd->idctx->creds[cd->index]->cert = NULL;	    /* Don't free it twice */
5925159d09a2SMark Phalan     cd->idctx->cert_index = 0;
5926159d09a2SMark Phalan 
5927159d09a2SMark Phalan     if (cd->idctx->pkcs11_method != 1) {
5928159d09a2SMark Phalan 	cd->idctx->my_key = cd->cred->key;
5929159d09a2SMark Phalan 	cd->idctx->creds[cd->index]->key = NULL;    /* Don't free it twice */
5930300fdee2SAndy Fiddaman     }
5931159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
5932159d09a2SMark Phalan     else {
5933159d09a2SMark Phalan 	cd->idctx->cert_id = cd->cred->cert_id;
5934159d09a2SMark Phalan 	cd->idctx->creds[cd->index]->cert_id = NULL; /* Don't free it twice */
5935159d09a2SMark Phalan 	cd->idctx->cert_id_len = cd->cred->cert_id_len;
5936159d09a2SMark Phalan     }
5937159d09a2SMark Phalan #endif
5938159d09a2SMark Phalan     return 0;
5939159d09a2SMark Phalan }
5940159d09a2SMark Phalan 
5941159d09a2SMark Phalan /*
5942159d09a2SMark Phalan  * Choose the default certificate as "the chosen one"
5943159d09a2SMark Phalan  */
5944159d09a2SMark Phalan krb5_error_code
5945159d09a2SMark Phalan crypto_cert_select_default(krb5_context context,
5946159d09a2SMark Phalan 			   pkinit_plg_crypto_context plg_cryptoctx,
5947159d09a2SMark Phalan 			   pkinit_req_crypto_context req_cryptoctx,
5948159d09a2SMark Phalan 			   pkinit_identity_crypto_context id_cryptoctx)
5949159d09a2SMark Phalan {
5950159d09a2SMark Phalan     krb5_error_code retval;
5951159d09a2SMark Phalan     int cert_count = 0;
5952159d09a2SMark Phalan 
5953159d09a2SMark Phalan     retval = crypto_cert_get_count(context, plg_cryptoctx, req_cryptoctx,
5954159d09a2SMark Phalan 				   id_cryptoctx, &cert_count);
5955159d09a2SMark Phalan     if (retval) {
5956159d09a2SMark Phalan 	pkiDebug("%s: crypto_cert_get_count error %d, %s\n",
5957159d09a2SMark Phalan 		 __FUNCTION__, retval, error_message(retval));
5958159d09a2SMark Phalan 	goto errout;
5959159d09a2SMark Phalan     }
5960159d09a2SMark Phalan     if (cert_count != 1) {
5961159d09a2SMark Phalan 	/* Solaris Kerberos: Improved error messages */
5962159d09a2SMark Phalan 	retval = EINVAL;
5963159d09a2SMark Phalan 	krb5_set_error_message(context, retval,
59649e11d51cSWill Fiveash 	    gettext("Failed to select default certificate: "
5965159d09a2SMark Phalan 	        "found %d certs to choose from but there must be exactly one"),
5966159d09a2SMark Phalan 	    cert_count);
5967159d09a2SMark Phalan 	pkiDebug("%s: ERROR: There are %d certs to choose from, "
5968159d09a2SMark Phalan 		 "but there must be exactly one.\n",
5969159d09a2SMark Phalan 		 __FUNCTION__, cert_count);
5970159d09a2SMark Phalan 	goto errout;
5971159d09a2SMark Phalan     }
5972300fdee2SAndy Fiddaman     /* copy the selected cert into our id_cryptoctx */
5973159d09a2SMark Phalan     if (id_cryptoctx->my_certs != NULL) {
5974159d09a2SMark Phalan 	sk_X509_pop_free(id_cryptoctx->my_certs, X509_free);
5975159d09a2SMark Phalan     }
59763f8dd771SAndy Fiddaman     id_cryptoctx->my_certs = sk_X509_new_null();
5977159d09a2SMark Phalan     sk_X509_push(id_cryptoctx->my_certs, id_cryptoctx->creds[0]->cert);
5978159d09a2SMark Phalan     id_cryptoctx->creds[0]->cert = NULL;	/* Don't free it twice */
5979159d09a2SMark Phalan     id_cryptoctx->cert_index = 0;
5980159d09a2SMark Phalan 
5981159d09a2SMark Phalan     if (id_cryptoctx->pkcs11_method != 1) {
5982159d09a2SMark Phalan 	id_cryptoctx->my_key = id_cryptoctx->creds[0]->key;
5983159d09a2SMark Phalan 	id_cryptoctx->creds[0]->key = NULL;	/* Don't free it twice */
5984300fdee2SAndy Fiddaman     }
5985159d09a2SMark Phalan #ifndef WITHOUT_PKCS11
5986159d09a2SMark Phalan     else {
5987159d09a2SMark Phalan 	id_cryptoctx->cert_id = id_cryptoctx->creds[0]->cert_id;
5988159d09a2SMark Phalan 	id_cryptoctx->creds[0]->cert_id = NULL; /* Don't free it twice */
5989159d09a2SMark Phalan 	id_cryptoctx->cert_id_len = id_cryptoctx->creds[0]->cert_id_len;
5990159d09a2SMark Phalan     }
5991159d09a2SMark Phalan #endif
5992159d09a2SMark Phalan     retval = 0;
5993159d09a2SMark Phalan errout:
5994159d09a2SMark Phalan     return retval;
5995159d09a2SMark Phalan }
5996159d09a2SMark Phalan 
5997159d09a2SMark Phalan 
5998159d09a2SMark Phalan /* ARGSUSED */
5999159d09a2SMark Phalan static krb5_error_code
6000159d09a2SMark Phalan load_cas_and_crls(krb5_context context,
6001159d09a2SMark Phalan 		  pkinit_plg_crypto_context plg_cryptoctx,
6002159d09a2SMark Phalan 		  pkinit_req_crypto_context req_cryptoctx,
6003159d09a2SMark Phalan 		  pkinit_identity_crypto_context id_cryptoctx,
6004159d09a2SMark Phalan 		  int catype,
6005159d09a2SMark Phalan 		  char *filename)
6006159d09a2SMark Phalan {
6007159d09a2SMark Phalan     STACK_OF(X509_INFO) *sk = NULL;
6008159d09a2SMark Phalan     STACK_OF(X509) *ca_certs = NULL;
6009159d09a2SMark Phalan     STACK_OF(X509_CRL) *ca_crls = NULL;
6010159d09a2SMark Phalan     BIO *in = NULL;
6011159d09a2SMark Phalan     /* Solaris Kerberos */
6012159d09a2SMark Phalan     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
6013159d09a2SMark Phalan     int i = 0;
6014159d09a2SMark Phalan 
6015159d09a2SMark Phalan     /* If there isn't already a stack in the context,
6016159d09a2SMark Phalan      * create a temporary one now */
6017159d09a2SMark Phalan     switch(catype) {
6018159d09a2SMark Phalan     case CATYPE_ANCHORS:
6019159d09a2SMark Phalan 	if (id_cryptoctx->trustedCAs != NULL)
6020159d09a2SMark Phalan 	    ca_certs = id_cryptoctx->trustedCAs;
6021159d09a2SMark Phalan 	else {
6022159d09a2SMark Phalan 	    ca_certs = sk_X509_new_null();
6023159d09a2SMark Phalan 	    if (ca_certs == NULL)
6024159d09a2SMark Phalan 		return ENOMEM;
6025159d09a2SMark Phalan 	}
6026159d09a2SMark Phalan 	break;
6027159d09a2SMark Phalan     case CATYPE_INTERMEDIATES:
6028159d09a2SMark Phalan 	if (id_cryptoctx->intermediateCAs != NULL)
6029159d09a2SMark Phalan 	    ca_certs = id_cryptoctx->intermediateCAs;
6030159d09a2SMark Phalan 	else {
6031159d09a2SMark Phalan 	    ca_certs = sk_X509_new_null();
6032159d09a2SMark Phalan 	    if (ca_certs == NULL)
6033159d09a2SMark Phalan 		return ENOMEM;
6034159d09a2SMark Phalan 	}
6035159d09a2SMark Phalan 	break;
6036159d09a2SMark Phalan     case CATYPE_CRLS:
6037159d09a2SMark Phalan 	if (id_cryptoctx->revoked != NULL)
6038159d09a2SMark Phalan 	    ca_crls = id_cryptoctx->revoked;
6039159d09a2SMark Phalan 	else {
6040159d09a2SMark Phalan 	    ca_crls = sk_X509_CRL_new_null();
6041159d09a2SMark Phalan 	    if (ca_crls == NULL)
6042159d09a2SMark Phalan 		return ENOMEM;
6043159d09a2SMark Phalan 	}
6044159d09a2SMark Phalan 	break;
6045159d09a2SMark Phalan     default:
6046159d09a2SMark Phalan 	return ENOTSUP;
6047159d09a2SMark Phalan     }
6048159d09a2SMark Phalan 
6049159d09a2SMark Phalan     if (!(in = BIO_new_file(filename, "r"))) {
6050159d09a2SMark Phalan 	retval = errno;
6051159d09a2SMark Phalan 	pkiDebug("%s: error opening file '%s': %s\n", __FUNCTION__,
6052159d09a2SMark Phalan 		 filename, error_message(errno));
6053159d09a2SMark Phalan 	goto cleanup;
6054159d09a2SMark Phalan     }
6055159d09a2SMark Phalan 
6056159d09a2SMark Phalan     /* This loads from a file, a stack of x509/crl/pkey sets */
6057159d09a2SMark Phalan     if ((sk = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL)) == NULL) {
6058159d09a2SMark Phalan 	pkiDebug("%s: error reading file '%s'\n", __FUNCTION__, filename);
6059159d09a2SMark Phalan 	retval = EIO;
6060159d09a2SMark Phalan 	goto cleanup;
6061159d09a2SMark Phalan     }
6062159d09a2SMark Phalan 
6063159d09a2SMark Phalan     /* scan over the stack created from loading the file contents,
6064159d09a2SMark Phalan      * weed out duplicates, and push new ones onto the return stack
6065159d09a2SMark Phalan      */
6066159d09a2SMark Phalan     for (i = 0; i < sk_X509_INFO_num(sk); i++) {
6067159d09a2SMark Phalan 	X509_INFO *xi = sk_X509_INFO_value(sk, i);
6068300fdee2SAndy Fiddaman 	if (xi != NULL && xi->x509 != NULL && catype != CATYPE_CRLS) {
6069159d09a2SMark Phalan 	    int j = 0, size = sk_X509_num(ca_certs), flag = 0;
6070159d09a2SMark Phalan 
6071159d09a2SMark Phalan 	    if (!size) {
6072159d09a2SMark Phalan 		sk_X509_push(ca_certs, xi->x509);
6073159d09a2SMark Phalan 		xi->x509 = NULL;
6074159d09a2SMark Phalan 		continue;
6075159d09a2SMark Phalan 	    }
6076159d09a2SMark Phalan 	    for (j = 0; j < size; j++) {
6077159d09a2SMark Phalan 		X509 *x = sk_X509_value(ca_certs, j);
6078159d09a2SMark Phalan 		flag = X509_cmp(x, xi->x509);
6079159d09a2SMark Phalan 		if (flag == 0)
6080159d09a2SMark Phalan 		    break;
6081300fdee2SAndy Fiddaman 		else
6082159d09a2SMark Phalan 		    continue;
6083159d09a2SMark Phalan 	    }
6084159d09a2SMark Phalan 	    if (flag != 0) {
6085159d09a2SMark Phalan 		sk_X509_push(ca_certs, X509_dup(xi->x509));
6086159d09a2SMark Phalan 	    }
6087159d09a2SMark Phalan 	} else if (xi != NULL && xi->crl != NULL && catype == CATYPE_CRLS) {
6088159d09a2SMark Phalan 	    int j = 0, size = sk_X509_CRL_num(ca_crls), flag = 0;
6089159d09a2SMark Phalan 	    if (!size) {
6090159d09a2SMark Phalan 		sk_X509_CRL_push(ca_crls, xi->crl);
6091159d09a2SMark Phalan 		xi->crl = NULL;
6092159d09a2SMark Phalan 		continue;
6093159d09a2SMark Phalan 	    }
6094159d09a2SMark Phalan 	    for (j = 0; j < size; j++) {
6095159d09a2SMark Phalan 		X509_CRL *x = sk_X509_CRL_value(ca_crls, j);
6096159d09a2SMark Phalan 		flag = X509_CRL_cmp(x, xi->crl);
6097159d09a2SMark Phalan 		if (flag == 0)
6098159d09a2SMark Phalan 		    break;
6099159d09a2SMark Phalan 		else
6100159d09a2SMark Phalan 		    continue;
6101159d09a2SMark Phalan 	    }
6102159d09a2SMark Phalan 	    if (flag != 0) {
610370f9559bSTheo Schlossnagle 		sk_X509_CRL_push(ca_crls, X509_CRL_dup(xi->crl));
6104159d09a2SMark Phalan 	    }
6105159d09a2SMark Phalan 	}
6106159d09a2SMark Phalan     }
6107159d09a2SMark Phalan 
6108159d09a2SMark Phalan     /* If we added something and there wasn't a stack in the
6109159d09a2SMark Phalan      * context before, add the temporary stack to the context.
6110159d09a2SMark Phalan      */
6111159d09a2SMark Phalan     switch(catype) {
6112159d09a2SMark Phalan     case CATYPE_ANCHORS:
6113159d09a2SMark Phalan 	if (sk_X509_num(ca_certs) == 0) {
6114159d09a2SMark Phalan 	    pkiDebug("no anchors in file, %s\n", filename);
6115300fdee2SAndy Fiddaman 	    if (id_cryptoctx->trustedCAs == NULL)
6116159d09a2SMark Phalan 		sk_X509_free(ca_certs);
6117159d09a2SMark Phalan 	} else {
6118159d09a2SMark Phalan 	    if (id_cryptoctx->trustedCAs == NULL)
6119159d09a2SMark Phalan 		id_cryptoctx->trustedCAs = ca_certs;
6120159d09a2SMark Phalan 	}
6121159d09a2SMark Phalan 	break;
6122159d09a2SMark Phalan     case CATYPE_INTERMEDIATES:
6123159d09a2SMark Phalan 	if (sk_X509_num(ca_certs) == 0) {
6124159d09a2SMark Phalan 	    pkiDebug("no intermediates in file, %s\n", filename);
6125300fdee2SAndy Fiddaman 	    if (id_cryptoctx->intermediateCAs == NULL)
6126159d09a2SMark Phalan 		sk_X509_free(ca_certs);
6127159d09a2SMark Phalan 	} else {
6128159d09a2SMark Phalan 	    if (id_cryptoctx->intermediateCAs == NULL)
6129159d09a2SMark Phalan 		id_cryptoctx->intermediateCAs = ca_certs;
6130159d09a2SMark Phalan 	}
6131159d09a2SMark Phalan 	break;
6132159d09a2SMark Phalan     case CATYPE_CRLS:
613370f9559bSTheo Schlossnagle 	if (sk_X509_CRL_num(ca_crls) == 0) {
6134159d09a2SMark Phalan 	    pkiDebug("no crls in file, %s\n", filename);
6135159d09a2SMark Phalan 	    if (id_cryptoctx->revoked == NULL)
6136159d09a2SMark Phalan 		sk_X509_CRL_free(ca_crls);
6137159d09a2SMark Phalan 	} else {
6138159d09a2SMark Phalan 	    if (id_cryptoctx->revoked == NULL)
6139159d09a2SMark Phalan 		id_cryptoctx->revoked = ca_crls;
6140159d09a2SMark Phalan 	}
6141159d09a2SMark Phalan 	break;
6142159d09a2SMark Phalan     default:
6143159d09a2SMark Phalan 	/* Should have been caught above! */
6144159d09a2SMark Phalan 	retval = EINVAL;
6145159d09a2SMark Phalan 	goto cleanup;
6146159d09a2SMark Phalan 	/* Solaris Kerberos: removed "break" as it's never reached */
6147159d09a2SMark Phalan     }
6148159d09a2SMark Phalan 
6149159d09a2SMark Phalan     retval = 0;
6150159d09a2SMark Phalan 
6151159d09a2SMark Phalan   cleanup:
6152159d09a2SMark Phalan     if (in != NULL)
6153159d09a2SMark Phalan 	BIO_free(in);
6154159d09a2SMark Phalan     if (sk != NULL)
6155159d09a2SMark Phalan 	sk_X509_INFO_pop_free(sk, X509_INFO_free);
6156159d09a2SMark Phalan 
6157159d09a2SMark Phalan     return retval;
6158159d09a2SMark Phalan }
6159159d09a2SMark Phalan 
6160159d09a2SMark Phalan static krb5_error_code
6161159d09a2SMark Phalan load_cas_and_crls_dir(krb5_context context,
6162159d09a2SMark Phalan 		      pkinit_plg_crypto_context plg_cryptoctx,
6163159d09a2SMark Phalan 		      pkinit_req_crypto_context req_cryptoctx,
6164159d09a2SMark Phalan 		      pkinit_identity_crypto_context id_cryptoctx,
6165159d09a2SMark Phalan 		      int catype,
6166300fdee2SAndy Fiddaman 		      char *dirname)
6167159d09a2SMark Phalan {
6168159d09a2SMark Phalan     krb5_error_code retval = EINVAL;
6169159d09a2SMark Phalan     DIR *d = NULL;
6170159d09a2SMark Phalan     struct dirent *dentry = NULL;
6171159d09a2SMark Phalan     char filename[1024];
6172159d09a2SMark Phalan 
6173159d09a2SMark Phalan     if (dirname == NULL)
6174159d09a2SMark Phalan 	return EINVAL;
6175159d09a2SMark Phalan 
6176159d09a2SMark Phalan     d = opendir(dirname);
6177300fdee2SAndy Fiddaman     if (d == NULL)
6178159d09a2SMark Phalan 	return ENOENT;
6179159d09a2SMark Phalan 
6180159d09a2SMark Phalan     while ((dentry = readdir(d))) {
6181159d09a2SMark Phalan 	if (strlen(dirname) + strlen(dentry->d_name) + 2 > sizeof(filename)) {
6182159d09a2SMark Phalan 	    pkiDebug("%s: Path too long -- directory '%s' and file '%s'\n",
6183159d09a2SMark Phalan 		     __FUNCTION__, dirname, dentry->d_name);
6184159d09a2SMark Phalan 	    goto cleanup;
6185159d09a2SMark Phalan 	}
6186159d09a2SMark Phalan 	/* Ignore subdirectories and anything starting with a dot */
6187159d09a2SMark Phalan #ifdef DT_DIR
6188159d09a2SMark Phalan 	if (dentry->d_type == DT_DIR)
6189159d09a2SMark Phalan 	    continue;
6190159d09a2SMark Phalan #endif
6191159d09a2SMark Phalan 	if (dentry->d_name[0] == '.')
6192159d09a2SMark Phalan 	    continue;
6193159d09a2SMark Phalan 	(void) snprintf(filename, sizeof(filename), "%s/%s", dirname, dentry->d_name);
6194159d09a2SMark Phalan 
6195159d09a2SMark Phalan 	retval = load_cas_and_crls(context, plg_cryptoctx, req_cryptoctx,
6196159d09a2SMark Phalan 				   id_cryptoctx, catype, filename);
6197159d09a2SMark Phalan 	if (retval)
6198159d09a2SMark Phalan 	    goto cleanup;
6199159d09a2SMark Phalan     }
6200159d09a2SMark Phalan 
6201159d09a2SMark Phalan     retval = 0;
6202159d09a2SMark Phalan 
6203159d09a2SMark Phalan   cleanup:
6204300fdee2SAndy Fiddaman     if (d != NULL)
6205159d09a2SMark Phalan 	(void) closedir(d);
6206159d09a2SMark Phalan 
6207159d09a2SMark Phalan     return retval;
6208159d09a2SMark Phalan }
6209159d09a2SMark Phalan 
6210159d09a2SMark Phalan /* ARGSUSED */
6211159d09a2SMark Phalan krb5_error_code
6212159d09a2SMark Phalan crypto_load_cas_and_crls(krb5_context context,
6213159d09a2SMark Phalan 			 pkinit_plg_crypto_context plg_cryptoctx,
6214159d09a2SMark Phalan 			 pkinit_req_crypto_context req_cryptoctx,
6215159d09a2SMark Phalan 			 pkinit_identity_opts *idopts,
6216159d09a2SMark Phalan 			 pkinit_identity_crypto_context id_cryptoctx,
6217159d09a2SMark Phalan 			 int idtype,
6218159d09a2SMark Phalan 			 int catype,
6219300fdee2SAndy Fiddaman 			 char *id)
6220159d09a2SMark Phalan {
6221159d09a2SMark Phalan     pkiDebug("%s: called with idtype %s and catype %s\n",
6222159d09a2SMark Phalan 	     __FUNCTION__, idtype2string(idtype), catype2string(catype));
6223159d09a2SMark Phalan     /* Solaris Kerberos: Removed "break"'s as they are never reached */
6224159d09a2SMark Phalan     switch (idtype) {
6225159d09a2SMark Phalan     case IDTYPE_FILE:
6226159d09a2SMark Phalan 	return load_cas_and_crls(context, plg_cryptoctx, req_cryptoctx,
6227159d09a2SMark Phalan 				 id_cryptoctx, catype, id);
6228159d09a2SMark Phalan     case IDTYPE_DIR:
6229159d09a2SMark Phalan 	return load_cas_and_crls_dir(context, plg_cryptoctx, req_cryptoctx,
6230159d09a2SMark Phalan 				     id_cryptoctx, catype, id);
6231159d09a2SMark Phalan     default:
6232159d09a2SMark Phalan 	return ENOTSUP;
6233159d09a2SMark Phalan     }
6234159d09a2SMark Phalan }
6235159d09a2SMark Phalan 
6236159d09a2SMark Phalan static krb5_error_code
6237159d09a2SMark Phalan create_identifiers_from_stack(STACK_OF(X509) *sk,
6238159d09a2SMark Phalan 			      krb5_external_principal_identifier *** ids)
6239159d09a2SMark Phalan {
6240159d09a2SMark Phalan     krb5_error_code retval = ENOMEM;
6241159d09a2SMark Phalan     int i = 0, sk_size = sk_X509_num(sk);
6242159d09a2SMark Phalan     krb5_external_principal_identifier **krb5_cas = NULL;
6243159d09a2SMark Phalan     X509 *x = NULL;
6244159d09a2SMark Phalan     X509_NAME *xn = NULL;
6245159d09a2SMark Phalan     unsigned char *p = NULL;
6246159d09a2SMark Phalan     int len = 0;
6247159d09a2SMark Phalan     PKCS7_ISSUER_AND_SERIAL *is = NULL;
6248159d09a2SMark Phalan     char buf[DN_BUF_LEN];
6249159d09a2SMark Phalan 
6250159d09a2SMark Phalan     *ids = NULL;
6251159d09a2SMark Phalan 
6252159d09a2SMark Phalan     krb5_cas =
6253159d09a2SMark Phalan 	malloc((sk_size + 1) * sizeof(krb5_external_principal_identifier *));
6254159d09a2SMark Phalan     if (krb5_cas == NULL)
6255159d09a2SMark Phalan 	return ENOMEM;
6256159d09a2SMark Phalan     krb5_cas[sk_size] = NULL;
6257159d09a2SMark Phalan 
6258159d09a2SMark Phalan     for (i = 0; i < sk_size; i++) {
6259159d09a2SMark Phalan 	krb5_cas[i] = (krb5_external_principal_identifier *)malloc(sizeof(krb5_external_principal_identifier));
6260159d09a2SMark Phalan 
6261159d09a2SMark Phalan 	x = sk_X509_value(sk, i);
6262159d09a2SMark Phalan 
6263159d09a2SMark Phalan 	X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
6264159d09a2SMark Phalan 	pkiDebug("#%d cert= %s\n", i, buf);
6265159d09a2SMark Phalan 
6266159d09a2SMark Phalan 	/* fill-in subjectName */
6267159d09a2SMark Phalan 	krb5_cas[i]->subjectName.magic = 0;
6268159d09a2SMark Phalan 	krb5_cas[i]->subjectName.length = 0;
6269159d09a2SMark Phalan 	krb5_cas[i]->subjectName.data = NULL;
6270159d09a2SMark Phalan 
6271159d09a2SMark Phalan 	xn = X509_get_subject_name(x);
6272159d09a2SMark Phalan 	len = i2d_X509_NAME(xn, NULL);
6273159d09a2SMark Phalan 	if ((p = krb5_cas[i]->subjectName.data = (unsigned char *)malloc((size_t) len)) == NULL)
6274159d09a2SMark Phalan 	    goto cleanup;
6275159d09a2SMark Phalan 	i2d_X509_NAME(xn, &p);
6276159d09a2SMark Phalan 	krb5_cas[i]->subjectName.length = len;
6277159d09a2SMark Phalan 
6278159d09a2SMark Phalan 	/* fill-in issuerAndSerialNumber */
6279159d09a2SMark Phalan 	krb5_cas[i]->issuerAndSerialNumber.length = 0;
6280159d09a2SMark Phalan 	krb5_cas[i]->issuerAndSerialNumber.magic = 0;
6281159d09a2SMark Phalan 	krb5_cas[i]->issuerAndSerialNumber.data = NULL;
6282159d09a2SMark Phalan 
6283159d09a2SMark Phalan #ifdef LONGHORN_BETA_COMPAT
6284159d09a2SMark Phalan if (longhorn == 0) { /* XXX Longhorn doesn't like this */
6285159d09a2SMark Phalan #endif
6286159d09a2SMark Phalan 	is = PKCS7_ISSUER_AND_SERIAL_new();
6287159d09a2SMark Phalan 	X509_NAME_set(&is->issuer, X509_get_issuer_name(x));
6288300fdee2SAndy Fiddaman 	ASN1_INTEGER_free(is->serial);
6289300fdee2SAndy Fiddaman 	is->serial = ASN1_INTEGER_dup(X509_get_serialNumber(x));
6290159d09a2SMark Phalan 	len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
6291159d09a2SMark Phalan 	if ((p = krb5_cas[i]->issuerAndSerialNumber.data =
6292159d09a2SMark Phalan 	     (unsigned char *)malloc((size_t) len)) == NULL)
6293159d09a2SMark Phalan 	    goto cleanup;
6294159d09a2SMark Phalan 	i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
6295159d09a2SMark Phalan 	krb5_cas[i]->issuerAndSerialNumber.length = len;
6296159d09a2SMark Phalan #ifdef LONGHORN_BETA_COMPAT
6297159d09a2SMark Phalan }
6298159d09a2SMark Phalan #endif
6299159d09a2SMark Phalan 
6300159d09a2SMark Phalan 	/* fill-in subjectKeyIdentifier */
6301159d09a2SMark Phalan 	krb5_cas[i]->subjectKeyIdentifier.length = 0;
6302159d09a2SMark Phalan 	krb5_cas[i]->subjectKeyIdentifier.magic = 0;
6303159d09a2SMark Phalan 	krb5_cas[i]->subjectKeyIdentifier.data = NULL;
6304159d09a2SMark Phalan 
6305159d09a2SMark Phalan 
6306159d09a2SMark Phalan #ifdef LONGHORN_BETA_COMPAT
6307159d09a2SMark Phalan if (longhorn == 0) {	/* XXX Longhorn doesn't like this */
6308159d09a2SMark Phalan #endif
6309159d09a2SMark Phalan 	if (X509_get_ext_by_NID(x, NID_subject_key_identifier, -1) >= 0) {
6310159d09a2SMark Phalan 	    ASN1_OCTET_STRING *ikeyid = NULL;
6311159d09a2SMark Phalan 
6312159d09a2SMark Phalan 	    if ((ikeyid = X509_get_ext_d2i(x, NID_subject_key_identifier, NULL,
6313159d09a2SMark Phalan 					   NULL))) {
6314159d09a2SMark Phalan 		len = i2d_ASN1_OCTET_STRING(ikeyid, NULL);
6315159d09a2SMark Phalan 		if ((p = krb5_cas[i]->subjectKeyIdentifier.data =
6316159d09a2SMark Phalan 			(unsigned char *)malloc((size_t) len)) == NULL)
6317159d09a2SMark Phalan 		    goto cleanup;
63183f8dd771SAndy Fiddaman 		i2d_ASN1_OCTET_STRING(ikeyid, &p);
6319159d09a2SMark Phalan 		krb5_cas[i]->subjectKeyIdentifier.length = len;
6320159d09a2SMark Phalan 	    }
6321159d09a2SMark Phalan 	    if (ikeyid != NULL)
6322159d09a2SMark Phalan 		ASN1_OCTET_STRING_free(ikeyid);
6323159d09a2SMark Phalan 	}
6324159d09a2SMark Phalan #ifdef LONGHORN_BETA_COMPAT
6325159d09a2SMark Phalan }
6326159d09a2SMark Phalan #endif
6327159d09a2SMark Phalan 	if (is != NULL) {
6328159d09a2SMark Phalan 	    if (is->issuer != NULL)
6329159d09a2SMark Phalan 		X509_NAME_free(is->issuer);
6330159d09a2SMark Phalan 	    if (is->serial != NULL)
6331159d09a2SMark Phalan 		ASN1_INTEGER_free(is->serial);
6332159d09a2SMark Phalan 	    free(is);
6333159d09a2SMark Phalan 	}
6334159d09a2SMark Phalan     }
6335159d09a2SMark Phalan 
6336159d09a2SMark Phalan     *ids = krb5_cas;
6337159d09a2SMark Phalan 
6338159d09a2SMark Phalan     retval = 0;
6339159d09a2SMark Phalan   cleanup:
6340159d09a2SMark Phalan     if (retval)
6341159d09a2SMark Phalan 	free_krb5_external_principal_identifier(&krb5_cas);
6342159d09a2SMark Phalan 
6343159d09a2SMark Phalan     return retval;
6344159d09a2SMark Phalan }
6345159d09a2SMark Phalan 
6346159d09a2SMark Phalan /* ARGSUSED */
6347159d09a2SMark Phalan static krb5_error_code
6348159d09a2SMark Phalan create_krb5_invalidCertificates(krb5_context context,
6349159d09a2SMark Phalan 				pkinit_plg_crypto_context plg_cryptoctx,
6350159d09a2SMark Phalan 				pkinit_req_crypto_context req_cryptoctx,
6351159d09a2SMark Phalan 				pkinit_identity_crypto_context id_cryptoctx,
6352159d09a2SMark Phalan 				krb5_external_principal_identifier *** ids)
6353159d09a2SMark Phalan {
6354159d09a2SMark Phalan 
6355159d09a2SMark Phalan     krb5_error_code retval = ENOMEM;
6356159d09a2SMark Phalan     STACK_OF(X509) *sk = NULL;
6357159d09a2SMark Phalan 
6358159d09a2SMark Phalan     *ids = NULL;
6359159d09a2SMark Phalan     if (req_cryptoctx->received_cert == NULL)
6360159d09a2SMark Phalan 	return KRB5KDC_ERR_PREAUTH_FAILED;
6361159d09a2SMark Phalan 
6362159d09a2SMark Phalan     sk = sk_X509_new_null();
6363300fdee2SAndy Fiddaman     if (sk == NULL)
6364159d09a2SMark Phalan 	goto cleanup;
6365159d09a2SMark Phalan     sk_X509_push(sk, req_cryptoctx->received_cert);
6366159d09a2SMark Phalan 
6367159d09a2SMark Phalan     retval = create_identifiers_from_stack(sk, ids);
6368159d09a2SMark Phalan 
6369159d09a2SMark Phalan     sk_X509_free(sk);
6370159d09a2SMark Phalan cleanup:
6371159d09a2SMark Phalan 
6372159d09a2SMark Phalan     return retval;
6373159d09a2SMark Phalan }
6374159d09a2SMark Phalan 
6375159d09a2SMark Phalan /* ARGSUSED */
6376159d09a2SMark Phalan krb5_error_code
6377159d09a2SMark Phalan create_krb5_supportedCMSTypes(krb5_context context,
6378159d09a2SMark Phalan 			      pkinit_plg_crypto_context plg_cryptoctx,
6379159d09a2SMark Phalan 			      pkinit_req_crypto_context req_cryptoctx,
6380159d09a2SMark Phalan 			      pkinit_identity_crypto_context id_cryptoctx,
6381159d09a2SMark Phalan 			      krb5_algorithm_identifier ***oids)
6382159d09a2SMark Phalan {
6383159d09a2SMark Phalan 
6384159d09a2SMark Phalan     krb5_error_code retval = ENOMEM;
6385159d09a2SMark Phalan     krb5_algorithm_identifier **loids = NULL;
6386159d09a2SMark Phalan     krb5_octet_data des3oid = {0, 8, (unsigned char *)"\x2A\x86\x48\x86\xF7\x0D\x03\x07" };
6387159d09a2SMark Phalan 
6388159d09a2SMark Phalan     *oids = NULL;
6389159d09a2SMark Phalan     loids = malloc(2 * sizeof(krb5_algorithm_identifier *));
6390159d09a2SMark Phalan     if (loids == NULL)
6391159d09a2SMark Phalan 	goto cleanup;
6392159d09a2SMark Phalan     loids[1] = NULL;
6393159d09a2SMark Phalan     loids[0] = (krb5_algorithm_identifier *)malloc(sizeof(krb5_algorithm_identifier));
6394159d09a2SMark Phalan     if (loids[0] == NULL) {
6395159d09a2SMark Phalan 	free(loids);
6396159d09a2SMark Phalan 	goto cleanup;
6397159d09a2SMark Phalan     }
6398159d09a2SMark Phalan     retval = pkinit_copy_krb5_octet_data(&loids[0]->algorithm, &des3oid);
6399159d09a2SMark Phalan     if (retval) {
6400159d09a2SMark Phalan 	free(loids[0]);
6401159d09a2SMark Phalan 	free(loids);
6402159d09a2SMark Phalan 	goto cleanup;
6403159d09a2SMark Phalan     }
6404159d09a2SMark Phalan     loids[0]->parameters.length = 0;
6405159d09a2SMark Phalan     loids[0]->parameters.data = NULL;
6406159d09a2SMark Phalan 
6407159d09a2SMark Phalan     *oids = loids;
6408159d09a2SMark Phalan     retval = 0;
6409159d09a2SMark Phalan cleanup:
6410159d09a2SMark Phalan 
6411159d09a2SMark Phalan     return retval;
6412159d09a2SMark Phalan }
6413159d09a2SMark Phalan 
6414159d09a2SMark Phalan /* ARGSUSED */
6415159d09a2SMark Phalan krb5_error_code
6416159d09a2SMark Phalan create_krb5_trustedCertifiers(krb5_context context,
6417159d09a2SMark Phalan 			      pkinit_plg_crypto_context plg_cryptoctx,
6418159d09a2SMark Phalan 			      pkinit_req_crypto_context req_cryptoctx,
6419159d09a2SMark Phalan 			      pkinit_identity_crypto_context id_cryptoctx,
6420159d09a2SMark Phalan 			      krb5_external_principal_identifier *** ids)
6421159d09a2SMark Phalan {
6422159d09a2SMark Phalan 
6423159d09a2SMark Phalan     /* Solaris Kerberos */
6424159d09a2SMark Phalan     STACK_OF(X509) *sk = id_cryptoctx->trustedCAs;
6425159d09a2SMark Phalan 
6426159d09a2SMark Phalan     *ids = NULL;
6427159d09a2SMark Phalan     if (id_cryptoctx->trustedCAs == NULL)
6428159d09a2SMark Phalan 	return KRB5KDC_ERR_PREAUTH_FAILED;
6429159d09a2SMark Phalan 
6430159d09a2SMark Phalan     return create_identifiers_from_stack(sk, ids);
6431300fdee2SAndy Fiddaman 
6432159d09a2SMark Phalan }
6433159d09a2SMark Phalan 
6434159d09a2SMark Phalan /* ARGSUSED */
6435159d09a2SMark Phalan krb5_error_code
6436159d09a2SMark Phalan create_krb5_trustedCas(krb5_context context,
6437159d09a2SMark Phalan 		       pkinit_plg_crypto_context plg_cryptoctx,
6438159d09a2SMark Phalan 		       pkinit_req_crypto_context req_cryptoctx,
6439159d09a2SMark Phalan 		       pkinit_identity_crypto_context id_cryptoctx,
6440159d09a2SMark Phalan 		       int flag,
6441159d09a2SMark Phalan 		       krb5_trusted_ca *** ids)
6442159d09a2SMark Phalan {
6443159d09a2SMark Phalan     krb5_error_code retval = ENOMEM;
6444159d09a2SMark Phalan     STACK_OF(X509) *sk = id_cryptoctx->trustedCAs;
6445159d09a2SMark Phalan     int i = 0, len = 0, sk_size = sk_X509_num(sk);
6446159d09a2SMark Phalan     krb5_trusted_ca **krb5_cas = NULL;
6447159d09a2SMark Phalan     X509 *x = NULL;
6448159d09a2SMark Phalan     char buf[DN_BUF_LEN];
6449159d09a2SMark Phalan     X509_NAME *xn = NULL;
6450159d09a2SMark Phalan     unsigned char *p = NULL;
6451159d09a2SMark Phalan     PKCS7_ISSUER_AND_SERIAL *is = NULL;
6452159d09a2SMark Phalan 
6453159d09a2SMark Phalan     *ids = NULL;
6454159d09a2SMark Phalan     if (id_cryptoctx->trustedCAs == NULL)
6455159d09a2SMark Phalan 	return KRB5KDC_ERR_PREAUTH_FAILED;
6456159d09a2SMark Phalan 
6457159d09a2SMark Phalan     krb5_cas = malloc((sk_size + 1) * sizeof(krb5_trusted_ca *));
6458159d09a2SMark Phalan     if (krb5_cas == NULL)
6459159d09a2SMark Phalan 	return ENOMEM;
6460159d09a2SMark Phalan     krb5_cas[sk_size] = NULL;
6461159d09a2SMark Phalan 
6462159d09a2SMark Phalan     for (i = 0; i < sk_size; i++) {
6463159d09a2SMark Phalan 	krb5_cas[i] = (krb5_trusted_ca *)malloc(sizeof(krb5_trusted_ca));
6464159d09a2SMark Phalan 	if (krb5_cas[i] == NULL)
6465159d09a2SMark Phalan 	    goto cleanup;
6466159d09a2SMark Phalan 	x = sk_X509_value(sk, i);
6467159d09a2SMark Phalan 
6468159d09a2SMark Phalan 	X509_NAME_oneline(X509_get_subject_name(x), buf, sizeof(buf));
6469159d09a2SMark Phalan 	pkiDebug("#%d cert= %s\n", i, buf);
6470159d09a2SMark Phalan 
6471159d09a2SMark Phalan 	switch (flag) {
6472159d09a2SMark Phalan 	    case choice_trusted_cas_principalName:
6473159d09a2SMark Phalan 		krb5_cas[i]->choice = choice_trusted_cas_principalName;
6474159d09a2SMark Phalan 		break;
6475159d09a2SMark Phalan 	    case choice_trusted_cas_caName:
6476159d09a2SMark Phalan 		krb5_cas[i]->choice = choice_trusted_cas_caName;
6477159d09a2SMark Phalan 		krb5_cas[i]->u.caName.data = NULL;
6478159d09a2SMark Phalan 		krb5_cas[i]->u.caName.length = 0;
6479159d09a2SMark Phalan 		xn = X509_get_subject_name(x);
6480159d09a2SMark Phalan 		len = i2d_X509_NAME(xn, NULL);
6481159d09a2SMark Phalan 		if ((p = krb5_cas[i]->u.caName.data =
6482159d09a2SMark Phalan 		    (unsigned char *)malloc((size_t) len)) == NULL)
6483159d09a2SMark Phalan 		    goto cleanup;
6484159d09a2SMark Phalan 		i2d_X509_NAME(xn, &p);
6485159d09a2SMark Phalan 		krb5_cas[i]->u.caName.length = len;
6486159d09a2SMark Phalan 		break;
6487159d09a2SMark Phalan 	    case choice_trusted_cas_issuerAndSerial:
6488159d09a2SMark Phalan 		krb5_cas[i]->choice = choice_trusted_cas_issuerAndSerial;
6489159d09a2SMark Phalan 		krb5_cas[i]->u.issuerAndSerial.data = NULL;
6490159d09a2SMark Phalan 		krb5_cas[i]->u.issuerAndSerial.length = 0;
6491159d09a2SMark Phalan 		is = PKCS7_ISSUER_AND_SERIAL_new();
6492159d09a2SMark Phalan 		X509_NAME_set(&is->issuer, X509_get_issuer_name(x));
6493300fdee2SAndy Fiddaman 		ASN1_INTEGER_free(is->serial);
6494300fdee2SAndy Fiddaman 		is->serial = ASN1_INTEGER_dup(X509_get_serialNumber(x));
6495159d09a2SMark Phalan 		len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
6496159d09a2SMark Phalan 		if ((p = krb5_cas[i]->u.issuerAndSerial.data =
6497159d09a2SMark Phalan 		    (unsigned char *)malloc((size_t) len)) == NULL)
6498159d09a2SMark Phalan 		    goto cleanup;
6499159d09a2SMark Phalan 		i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
6500159d09a2SMark Phalan 		krb5_cas[i]->u.issuerAndSerial.length = len;
6501159d09a2SMark Phalan 		if (is != NULL) {
6502159d09a2SMark Phalan 		    if (is->issuer != NULL)
6503159d09a2SMark Phalan 			X509_NAME_free(is->issuer);
6504159d09a2SMark Phalan 		    if (is->serial != NULL)
6505159d09a2SMark Phalan 			ASN1_INTEGER_free(is->serial);
6506159d09a2SMark Phalan 		    free(is);
6507159d09a2SMark Phalan 		}
6508159d09a2SMark Phalan 		break;
6509159d09a2SMark Phalan 	    default: break;
6510159d09a2SMark Phalan 	}
6511159d09a2SMark Phalan     }
6512159d09a2SMark Phalan     retval = 0;
6513159d09a2SMark Phalan     *ids = krb5_cas;
6514159d09a2SMark Phalan cleanup:
6515159d09a2SMark Phalan     if (retval)
6516159d09a2SMark Phalan 	free_krb5_trusted_ca(&krb5_cas);
6517159d09a2SMark Phalan 
6518159d09a2SMark Phalan     return retval;
6519159d09a2SMark Phalan }
6520159d09a2SMark Phalan 
6521159d09a2SMark Phalan /* ARGSUSED */
6522159d09a2SMark Phalan krb5_error_code
6523159d09a2SMark Phalan create_issuerAndSerial(krb5_context context,
6524159d09a2SMark Phalan 		       pkinit_plg_crypto_context plg_cryptoctx,
6525159d09a2SMark Phalan 		       pkinit_req_crypto_context req_cryptoctx,
6526159d09a2SMark Phalan 		       pkinit_identity_crypto_context id_cryptoctx,
6527159d09a2SMark Phalan 		       unsigned char **out,
6528159d09a2SMark Phalan 		       unsigned int *out_len)
6529159d09a2SMark Phalan {
6530159d09a2SMark Phalan     unsigned char *p = NULL;
6531159d09a2SMark Phalan     PKCS7_ISSUER_AND_SERIAL *is = NULL;
6532159d09a2SMark Phalan     int len = 0;
6533159d09a2SMark Phalan     krb5_error_code retval = ENOMEM;
6534159d09a2SMark Phalan     X509 *cert = req_cryptoctx->received_cert;
6535159d09a2SMark Phalan 
6536159d09a2SMark Phalan     *out = NULL;
6537159d09a2SMark Phalan     *out_len = 0;
6538159d09a2SMark Phalan     if (req_cryptoctx->received_cert == NULL)
6539159d09a2SMark Phalan 	return 0;
6540159d09a2SMark Phalan 
6541159d09a2SMark Phalan     is = PKCS7_ISSUER_AND_SERIAL_new();
6542159d09a2SMark Phalan     X509_NAME_set(&is->issuer, X509_get_issuer_name(cert));
6543300fdee2SAndy Fiddaman     ASN1_INTEGER_free(is->serial);
6544300fdee2SAndy Fiddaman     is->serial = ASN1_INTEGER_dup(X509_get_serialNumber(cert));
6545159d09a2SMark Phalan     len = i2d_PKCS7_ISSUER_AND_SERIAL(is, NULL);
6546159d09a2SMark Phalan     if ((p = *out = (unsigned char *)malloc((size_t) len)) == NULL)
6547159d09a2SMark Phalan 	goto cleanup;
6548159d09a2SMark Phalan     i2d_PKCS7_ISSUER_AND_SERIAL(is, &p);
6549159d09a2SMark Phalan     *out_len = len;
6550159d09a2SMark Phalan     retval = 0;
6551159d09a2SMark Phalan 
6552159d09a2SMark Phalan cleanup:
6553159d09a2SMark Phalan     X509_NAME_free(is->issuer);
6554159d09a2SMark Phalan     ASN1_INTEGER_free(is->serial);
6555159d09a2SMark Phalan     free(is);
6556159d09a2SMark Phalan 
6557159d09a2SMark Phalan     return retval;
6558159d09a2SMark Phalan }
6559159d09a2SMark Phalan 
6560159d09a2SMark Phalan static int
6561159d09a2SMark Phalan pkcs7_decrypt(krb5_context context,
6562159d09a2SMark Phalan 	      pkinit_identity_crypto_context id_cryptoctx,
6563159d09a2SMark Phalan 	      PKCS7 *p7,
6564159d09a2SMark Phalan 	      BIO *data)
6565159d09a2SMark Phalan {
6566159d09a2SMark Phalan     BIO *tmpmem = NULL;
6567159d09a2SMark Phalan     /* Solaris Kerberos */
6568159d09a2SMark Phalan     int i = 0;
6569159d09a2SMark Phalan     char buf[4096];
6570159d09a2SMark Phalan 
6571159d09a2SMark Phalan     if(p7 == NULL)
6572159d09a2SMark Phalan 	return 0;
6573159d09a2SMark Phalan 
6574159d09a2SMark Phalan     if(!PKCS7_type_is_enveloped(p7)) {
6575159d09a2SMark Phalan 	pkiDebug("wrong pkcs7 content type\n");
6576159d09a2SMark Phalan 	return 0;
6577159d09a2SMark Phalan     }
6578159d09a2SMark Phalan 
6579159d09a2SMark Phalan     if(!(tmpmem = pkcs7_dataDecode(context, id_cryptoctx, p7))) {
6580159d09a2SMark Phalan 	pkiDebug("unable to decrypt pkcs7 object\n");
6581159d09a2SMark Phalan 	return 0;
6582159d09a2SMark Phalan     }
6583159d09a2SMark Phalan /* Solaris Kerberos: Suppress sun studio compiler warning */
6584159d09a2SMark Phalan #pragma error_messages (off, E_END_OF_LOOP_CODE_NOT_REACHED)
6585159d09a2SMark Phalan     for(;;) {
6586159d09a2SMark Phalan 	i = BIO_read(tmpmem, buf, sizeof(buf));
6587159d09a2SMark Phalan 	if (i <= 0) break;
6588159d09a2SMark Phalan 	BIO_write(data, buf, i);
6589159d09a2SMark Phalan 	BIO_free_all(tmpmem);
6590159d09a2SMark Phalan 	return 1;
6591159d09a2SMark Phalan     }
6592159d09a2SMark Phalan #pragma error_messages (default, E_END_OF_LOOP_CODE_NOT_REACHED)
6593159d09a2SMark Phalan 
6594300fdee2SAndy Fiddaman     return 0;
6595159d09a2SMark Phalan }
6596159d09a2SMark Phalan 
6597159d09a2SMark Phalan krb5_error_code
6598159d09a2SMark Phalan pkinit_process_td_trusted_certifiers(
6599159d09a2SMark Phalan     krb5_context context,
6600159d09a2SMark Phalan     pkinit_plg_crypto_context plg_cryptoctx,
6601159d09a2SMark Phalan     pkinit_req_crypto_context req_cryptoctx,
6602159d09a2SMark Phalan     pkinit_identity_crypto_context id_cryptoctx,
6603159d09a2SMark Phalan     krb5_external_principal_identifier **krb5_trusted_certifiers,
6604159d09a2SMark Phalan     int td_type)
6605159d09a2SMark Phalan {
6606159d09a2SMark Phalan     krb5_error_code retval = ENOMEM;
6607159d09a2SMark Phalan     STACK_OF(X509_NAME) *sk_xn = NULL;
6608159d09a2SMark Phalan     X509_NAME *xn = NULL;
6609159d09a2SMark Phalan     PKCS7_ISSUER_AND_SERIAL *is = NULL;
6610159d09a2SMark Phalan     ASN1_OCTET_STRING *id = NULL;
6611159d09a2SMark Phalan     const unsigned char *p = NULL;
6612159d09a2SMark Phalan     char buf[DN_BUF_LEN];
6613159d09a2SMark Phalan     int i = 0;
6614159d09a2SMark Phalan 
6615159d09a2SMark Phalan     if (td_type == TD_TRUSTED_CERTIFIERS)
6616159d09a2SMark Phalan 	pkiDebug("received trusted certifiers\n");
6617159d09a2SMark Phalan     else
6618159d09a2SMark Phalan 	pkiDebug("received invalid certificate\n");
6619159d09a2SMark Phalan 
6620159d09a2SMark Phalan     sk_xn = sk_X509_NAME_new_null();
6621159d09a2SMark Phalan     while(krb5_trusted_certifiers[i] != NULL) {
6622159d09a2SMark Phalan 	if (krb5_trusted_certifiers[i]->subjectName.data != NULL) {
6623159d09a2SMark Phalan 	    p = krb5_trusted_certifiers[i]->subjectName.data;
6624159d09a2SMark Phalan 	    xn = d2i_X509_NAME(NULL, &p,
6625159d09a2SMark Phalan 		(int)krb5_trusted_certifiers[i]->subjectName.length);
6626159d09a2SMark Phalan 	    if (xn == NULL)
6627159d09a2SMark Phalan 		goto cleanup;
6628159d09a2SMark Phalan 	    X509_NAME_oneline(xn, buf, sizeof(buf));
6629159d09a2SMark Phalan 	    if (td_type == TD_TRUSTED_CERTIFIERS)
6630159d09a2SMark Phalan 		pkiDebug("#%d cert = %s is trusted by kdc\n", i, buf);
6631159d09a2SMark Phalan 	    else
6632159d09a2SMark Phalan 		pkiDebug("#%d cert = %s is invalid\n", i, buf);
66333f8dd771SAndy Fiddaman 	    sk_X509_NAME_push(sk_xn, xn);
6634159d09a2SMark Phalan 	}
6635159d09a2SMark Phalan 
6636159d09a2SMark Phalan 	if (krb5_trusted_certifiers[i]->issuerAndSerialNumber.data != NULL) {
6637159d09a2SMark Phalan 	    p = krb5_trusted_certifiers[i]->issuerAndSerialNumber.data;
6638159d09a2SMark Phalan 	    is = d2i_PKCS7_ISSUER_AND_SERIAL(NULL, &p,
6639159d09a2SMark Phalan 		(int)krb5_trusted_certifiers[i]->issuerAndSerialNumber.length);
6640159d09a2SMark Phalan 	    if (is == NULL)
6641159d09a2SMark Phalan 		goto cleanup;
6642159d09a2SMark Phalan 	    X509_NAME_oneline(is->issuer, buf, sizeof(buf));
6643159d09a2SMark Phalan 	    if (td_type == TD_TRUSTED_CERTIFIERS)
6644159d09a2SMark Phalan 		pkiDebug("#%d issuer = %s serial = %ld is trusted bu kdc\n", i,
6645159d09a2SMark Phalan 			 buf, ASN1_INTEGER_get(is->serial));
6646159d09a2SMark Phalan 	    else
6647159d09a2SMark Phalan 		pkiDebug("#%d issuer = %s serial = %ld is invalid\n", i, buf,
6648159d09a2SMark Phalan 			 ASN1_INTEGER_get(is->serial));
6649159d09a2SMark Phalan 	    PKCS7_ISSUER_AND_SERIAL_free(is);
6650159d09a2SMark Phalan 	}
6651159d09a2SMark Phalan 
6652159d09a2SMark Phalan 	if (krb5_trusted_certifiers[i]->subjectKeyIdentifier.data != NULL) {
6653159d09a2SMark Phalan 	    p = krb5_trusted_certifiers[i]->subjectKeyIdentifier.data;
6654159d09a2SMark Phalan 	    id = d2i_ASN1_OCTET_STRING(NULL, &p,
6655159d09a2SMark Phalan 		(int)krb5_trusted_certifiers[i]->subjectKeyIdentifier.length);
6656159d09a2SMark Phalan 	    if (id == NULL)
6657159d09a2SMark Phalan 		goto cleanup;
6658159d09a2SMark Phalan 	    /* XXX */
6659159d09a2SMark Phalan 	    ASN1_OCTET_STRING_free(id);
6660159d09a2SMark Phalan 	}
6661159d09a2SMark Phalan 	i++;
6662159d09a2SMark Phalan     }
6663159d09a2SMark Phalan     /* XXX Since we not doing anything with received trusted certifiers
6664159d09a2SMark Phalan      * return an error. this is the place where we can pick a different
6665159d09a2SMark Phalan      * client certificate based on the information in td_trusted_certifiers
6666159d09a2SMark Phalan      */
6667159d09a2SMark Phalan     retval = KRB5KDC_ERR_PREAUTH_FAILED;
6668159d09a2SMark Phalan cleanup:
6669159d09a2SMark Phalan     if (sk_xn != NULL)
6670159d09a2SMark Phalan 	sk_X509_NAME_pop_free(sk_xn, X509_NAME_free);
6671159d09a2SMark Phalan 
6672159d09a2SMark Phalan     return retval;
6673159d09a2SMark Phalan }
6674159d09a2SMark Phalan 
6675159d09a2SMark Phalan static BIO *
6676159d09a2SMark Phalan pkcs7_dataDecode(krb5_context context,
6677159d09a2SMark Phalan 		 pkinit_identity_crypto_context id_cryptoctx,
6678159d09a2SMark Phalan 		 PKCS7 *p7)
6679159d09a2SMark Phalan {
6680159d09a2SMark Phalan     int i = 0;
6681159d09a2SMark Phalan     unsigned int jj = 0, tmp_len = 0;
6682159d09a2SMark Phalan     BIO *out=NULL,*etmp=NULL,*bio=NULL;
6683159d09a2SMark Phalan     unsigned char *tmp=NULL;
6684159d09a2SMark Phalan     ASN1_OCTET_STRING *data_body=NULL;
6685159d09a2SMark Phalan     const EVP_CIPHER *evp_cipher=NULL;
6686159d09a2SMark Phalan     EVP_CIPHER_CTX *evp_ctx=NULL;
6687159d09a2SMark Phalan     X509_ALGOR *enc_alg=NULL;
6688159d09a2SMark Phalan     STACK_OF(PKCS7_RECIP_INFO) *rsk=NULL;
6689159d09a2SMark Phalan /* Solaris Kerberos: Not used */
6690159d09a2SMark Phalan #if 0
6691159d09a2SMark Phalan     X509_ALGOR *xalg=NULL;
6692159d09a2SMark Phalan #endif
6693159d09a2SMark Phalan     PKCS7_RECIP_INFO *ri=NULL;
6694159d09a2SMark Phalan     X509 *cert = sk_X509_value(id_cryptoctx->my_certs,
6695159d09a2SMark Phalan 	id_cryptoctx->cert_index);
6696159d09a2SMark Phalan 
6697159d09a2SMark Phalan     p7->state=PKCS7_S_HEADER;
6698159d09a2SMark Phalan 
6699159d09a2SMark Phalan     rsk=p7->d.enveloped->recipientinfo;
6700159d09a2SMark Phalan     enc_alg=p7->d.enveloped->enc_data->algorithm;
6701159d09a2SMark Phalan     data_body=p7->d.enveloped->enc_data->enc_data;
6702159d09a2SMark Phalan     evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm);
6703159d09a2SMark Phalan     if (evp_cipher == NULL) {
6704159d09a2SMark Phalan 	PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_UNSUPPORTED_CIPHER_TYPE);
6705159d09a2SMark Phalan 	goto cleanup;
6706159d09a2SMark Phalan     }
6707159d09a2SMark Phalan /* Solaris Kerberos: Not used */
6708159d09a2SMark Phalan #if 0
6709159d09a2SMark Phalan     xalg=p7->d.enveloped->enc_data->algorithm;
6710159d09a2SMark Phalan #endif
6711159d09a2SMark Phalan 
6712159d09a2SMark Phalan     if ((etmp=BIO_new(BIO_f_cipher())) == NULL) {
6713159d09a2SMark Phalan 	PKCS7err(PKCS7_F_PKCS7_DATADECODE,ERR_R_BIO_LIB);
6714159d09a2SMark Phalan 	goto cleanup;
6715159d09a2SMark Phalan     }
6716159d09a2SMark Phalan 
6717159d09a2SMark Phalan     /* It was encrypted, we need to decrypt the secret key
6718159d09a2SMark Phalan      * with the private key */
6719159d09a2SMark Phalan 
6720159d09a2SMark Phalan     /* Find the recipientInfo which matches the passed certificate
6721159d09a2SMark Phalan      * (if any)
6722159d09a2SMark Phalan      */
6723159d09a2SMark Phalan 
6724159d09a2SMark Phalan     if (cert) {
6725159d09a2SMark Phalan 	for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) {
6726159d09a2SMark Phalan 	    int tmp_ret = 0;
6727159d09a2SMark Phalan 	    ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
6728159d09a2SMark Phalan 	    tmp_ret = X509_NAME_cmp(ri->issuer_and_serial->issuer,
6729300fdee2SAndy Fiddaman 		X509_get_issuer_name(cert));
6730159d09a2SMark Phalan 	    if (!tmp_ret) {
6731300fdee2SAndy Fiddaman 		tmp_ret = ASN1_INTEGER_cmp(X509_get_serialNumber(cert),
6732159d09a2SMark Phalan 					     ri->issuer_and_serial->serial);
6733159d09a2SMark Phalan 		if (!tmp_ret)
6734159d09a2SMark Phalan 		    break;
6735159d09a2SMark Phalan 	    }
6736159d09a2SMark Phalan 	    ri=NULL;
6737159d09a2SMark Phalan 	}
6738159d09a2SMark Phalan 	if (ri == NULL) {
6739159d09a2SMark Phalan 	    PKCS7err(PKCS7_F_PKCS7_DATADECODE,
6740159d09a2SMark Phalan 		     PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE);
6741159d09a2SMark Phalan 	    goto cleanup;
6742159d09a2SMark Phalan 	}
6743159d09a2SMark Phalan     }
6744159d09a2SMark Phalan 
6745159d09a2SMark Phalan     /* If we haven't got a certificate try each ri in turn */
6746159d09a2SMark Phalan 
6747159d09a2SMark Phalan     if (cert == NULL) {
6748159d09a2SMark Phalan 	for (i=0; i<sk_PKCS7_RECIP_INFO_num(rsk); i++) {
6749159d09a2SMark Phalan 	    ri=sk_PKCS7_RECIP_INFO_value(rsk,i);
6750159d09a2SMark Phalan 	    jj = pkinit_decode_data(context, id_cryptoctx,
6751300fdee2SAndy Fiddaman 		(unsigned char *)ASN1_STRING_get0_data(ri->enc_key),
6752300fdee2SAndy Fiddaman 		ASN1_STRING_length(ri->enc_key),
6753159d09a2SMark Phalan 		&tmp, &tmp_len);
6754159d09a2SMark Phalan 	    if (jj) {
6755159d09a2SMark Phalan 		PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_EVP_LIB);
6756159d09a2SMark Phalan 		goto cleanup;
6757159d09a2SMark Phalan 	    }
6758159d09a2SMark Phalan 
6759159d09a2SMark Phalan 	    if (!jj && tmp_len > 0) {
6760159d09a2SMark Phalan 		jj = tmp_len;
6761159d09a2SMark Phalan 		break;
6762159d09a2SMark Phalan 	    }
6763159d09a2SMark Phalan 
6764159d09a2SMark Phalan 	    ERR_clear_error();
6765159d09a2SMark Phalan 	    ri = NULL;
6766159d09a2SMark Phalan 	}
6767159d09a2SMark Phalan 
6768159d09a2SMark Phalan 	if (ri == NULL) {
6769300fdee2SAndy Fiddaman 	    PKCS7err(PKCS7_F_PKCS7_DATADECODE,PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE);
6770159d09a2SMark Phalan 	    goto cleanup;
6771159d09a2SMark Phalan 	}
6772159d09a2SMark Phalan     }
6773159d09a2SMark Phalan     else {
6774159d09a2SMark Phalan 	jj = pkinit_decode_data(context, id_cryptoctx,
6775300fdee2SAndy Fiddaman 	    (unsigned char *)ASN1_STRING_get0_data(ri->enc_key),
6776300fdee2SAndy Fiddaman 	    ASN1_STRING_length(ri->enc_key),
6777159d09a2SMark Phalan 	    &tmp, &tmp_len);
6778159d09a2SMark Phalan 	/* Solaris Kerberos: tmp_len is unsigned. Cannot be < 0 */
6779159d09a2SMark Phalan 	if (jj || tmp_len == 0) {
6780159d09a2SMark Phalan 	    PKCS7err(PKCS7_F_PKCS7_DATADECODE, ERR_R_EVP_LIB);
6781159d09a2SMark Phalan 	    goto cleanup;
6782159d09a2SMark Phalan 	}
6783159d09a2SMark Phalan 	jj = tmp_len;
6784159d09a2SMark Phalan     }
6785159d09a2SMark Phalan 
6786159d09a2SMark Phalan     evp_ctx=NULL;
6787159d09a2SMark Phalan     BIO_get_cipher_ctx(etmp,&evp_ctx);
6788159d09a2SMark Phalan     if (EVP_CipherInit_ex(evp_ctx,evp_cipher,NULL,NULL,NULL,0) <= 0)
6789159d09a2SMark Phalan 	goto cleanup;
6790159d09a2SMark Phalan     if (EVP_CIPHER_asn1_to_param(evp_ctx,enc_alg->parameter) < 0)
6791159d09a2SMark Phalan 	goto cleanup;
6792159d09a2SMark Phalan 
6793159d09a2SMark Phalan     if (jj != EVP_CIPHER_CTX_key_length(evp_ctx)) {
6794159d09a2SMark Phalan 	/* Some S/MIME clients don't use the same key
6795159d09a2SMark Phalan 	 * and effective key length. The key length is
6796159d09a2SMark Phalan 	 * determined by the size of the decrypted RSA key.
6797159d09a2SMark Phalan 	 */
6798159d09a2SMark Phalan 	if(!EVP_CIPHER_CTX_set_key_length(evp_ctx, (int)jj)) {
6799159d09a2SMark Phalan 	    PKCS7err(PKCS7_F_PKCS7_DATADECODE,
6800300fdee2SAndy Fiddaman 		     PKCS7_R_DECRYPT_ERROR);
6801159d09a2SMark Phalan 	    goto cleanup;
6802159d09a2SMark Phalan 	}
6803159d09a2SMark Phalan     }
6804159d09a2SMark Phalan     if (EVP_CipherInit_ex(evp_ctx,NULL,NULL,tmp,NULL,0) <= 0)
6805159d09a2SMark Phalan 	goto cleanup;
6806159d09a2SMark Phalan 
6807159d09a2SMark Phalan     OPENSSL_cleanse(tmp,jj);
6808159d09a2SMark Phalan 
6809159d09a2SMark Phalan     if (out == NULL)
6810159d09a2SMark Phalan 	out=etmp;
6811159d09a2SMark Phalan     else
6812159d09a2SMark Phalan 	BIO_push(out,etmp);
6813159d09a2SMark Phalan     etmp=NULL;
6814159d09a2SMark Phalan 
6815159d09a2SMark Phalan     if (data_body->length > 0)
6816159d09a2SMark Phalan 	bio = BIO_new_mem_buf(data_body->data, data_body->length);
6817159d09a2SMark Phalan     else {
6818159d09a2SMark Phalan 	bio=BIO_new(BIO_s_mem());
6819159d09a2SMark Phalan 	BIO_set_mem_eof_return(bio,0);
6820159d09a2SMark Phalan     }
6821159d09a2SMark Phalan     BIO_push(out,bio);
6822159d09a2SMark Phalan     bio=NULL;
6823159d09a2SMark Phalan 
6824159d09a2SMark Phalan     /* Solaris Kerberos */
6825159d09a2SMark Phalan     goto out;
6826159d09a2SMark Phalan 
6827159d09a2SMark Phalan cleanup:
6828159d09a2SMark Phalan 	if (out != NULL) BIO_free_all(out);
6829159d09a2SMark Phalan 	if (etmp != NULL) BIO_free_all(etmp);
6830159d09a2SMark Phalan 	if (bio != NULL) BIO_free_all(bio);
6831159d09a2SMark Phalan 	out=NULL;
6832159d09a2SMark Phalan 
6833159d09a2SMark Phalan out:
6834159d09a2SMark Phalan     if (tmp != NULL)
6835159d09a2SMark Phalan 	free(tmp);
6836159d09a2SMark Phalan 
6837159d09a2SMark Phalan     return(out);
6838159d09a2SMark Phalan }
6839159d09a2SMark Phalan 
6840159d09a2SMark Phalan static krb5_error_code
6841159d09a2SMark Phalan der_decode_data(unsigned char *data, long data_len,
6842159d09a2SMark Phalan 		unsigned char **out, long *out_len)
6843159d09a2SMark Phalan {
6844159d09a2SMark Phalan     /* Solaris Kerberos */
6845159d09a2SMark Phalan     krb5_error_code retval = KRB5KRB_ERR_GENERIC;
6846159d09a2SMark Phalan     ASN1_OCTET_STRING *s = NULL;
6847159d09a2SMark Phalan     const unsigned char *p = data;
6848159d09a2SMark Phalan 
6849159d09a2SMark Phalan     if ((s = d2i_ASN1_BIT_STRING(NULL, &p, data_len)) == NULL)
6850159d09a2SMark Phalan 	goto cleanup;
6851159d09a2SMark Phalan     *out_len = s->length;
6852159d09a2SMark Phalan     if ((*out = (unsigned char *) malloc((size_t) *out_len + 1)) == NULL) {
6853159d09a2SMark Phalan 	retval = ENOMEM;
6854159d09a2SMark Phalan 	goto cleanup;
6855159d09a2SMark Phalan     }
6856159d09a2SMark Phalan     (void) memcpy(*out, s->data, (size_t) s->length);
6857159d09a2SMark Phalan     (*out)[s->length] = '\0';
6858159d09a2SMark Phalan 
6859159d09a2SMark Phalan     retval = 0;
6860159d09a2SMark Phalan   cleanup:
6861159d09a2SMark Phalan     if (s != NULL)
6862159d09a2SMark Phalan 	ASN1_OCTET_STRING_free(s);
6863159d09a2SMark Phalan 
6864159d09a2SMark Phalan     return retval;
6865159d09a2SMark Phalan }
6866159d09a2SMark Phalan 
6867159d09a2SMark Phalan 
6868159d09a2SMark Phalan #ifdef DEBUG_DH
6869159d09a2SMark Phalan static void
6870159d09a2SMark Phalan print_dh(DH * dh, char *msg)
6871159d09a2SMark Phalan {
6872159d09a2SMark Phalan     BIO *bio_err = NULL;
6873159d09a2SMark Phalan 
6874159d09a2SMark Phalan     bio_err = BIO_new(BIO_s_file());
6875159d09a2SMark Phalan     BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
6876159d09a2SMark Phalan 
6877159d09a2SMark Phalan     if (msg)
6878159d09a2SMark Phalan 	BIO_puts(bio_err, (const char *)msg);
6879159d09a2SMark Phalan     if (dh)
6880159d09a2SMark Phalan 	DHparams_print(bio_err, dh);
6881159d09a2SMark Phalan 
6882159d09a2SMark Phalan     BN_print(bio_err, dh->q);
6883159d09a2SMark Phalan     BIO_puts(bio_err, (const char *)"\n");
6884159d09a2SMark Phalan     BIO_free(bio_err);
6885159d09a2SMark Phalan 
6886159d09a2SMark Phalan }
6887159d09a2SMark Phalan 
6888159d09a2SMark Phalan static void
6889159d09a2SMark Phalan print_pubkey(BIGNUM * key, char *msg)
6890159d09a2SMark Phalan {
6891159d09a2SMark Phalan     BIO *bio_err = NULL;
6892159d09a2SMark Phalan 
6893159d09a2SMark Phalan     bio_err = BIO_new(BIO_s_file());
6894159d09a2SMark Phalan     BIO_set_fp(bio_err, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
6895159d09a2SMark Phalan 
6896159d09a2SMark Phalan     if (msg)
6897159d09a2SMark Phalan 	BIO_puts(bio_err, (const char *)msg);
6898159d09a2SMark Phalan     if (key)
6899159d09a2SMark Phalan 	BN_print(bio_err, key);
6900159d09a2SMark Phalan     BIO_puts(bio_err, "\n");
6901159d09a2SMark Phalan 
6902159d09a2SMark Phalan     BIO_free(bio_err);
6903159d09a2SMark Phalan 
6904159d09a2SMark Phalan }
6905159d09a2SMark Phalan #endif
6906159d09a2SMark Phalan 
6907159d09a2SMark Phalan /*
6908159d09a2SMark Phalan  * Solaris Kerberos:
6909159d09a2SMark Phalan  * Error message generation has changed so gettext() can be used
6910159d09a2SMark Phalan  */
6911159d09a2SMark Phalan #if 0
6912159d09a2SMark Phalan static char *
6913159d09a2SMark Phalan pkinit_pkcs11_code_to_text(int err)
6914159d09a2SMark Phalan {
6915159d09a2SMark Phalan     int i;
6916159d09a2SMark Phalan     static char uc[64];
6917159d09a2SMark Phalan 
6918159d09a2SMark Phalan     for (i = 0; pkcs11_errstrings[i].text != NULL; i++)
6919159d09a2SMark Phalan 	if (pkcs11_errstrings[i].code == err)
6920159d09a2SMark Phalan 	    break;
6921159d09a2SMark Phalan     if (pkcs11_errstrings[i].text != NULL)
6922159d09a2SMark Phalan 	return (pkcs11_errstrings[i].text);
6923159d09a2SMark Phalan     snprintf(uc, 64, gettext("unknown code 0x%x"), err);
6924159d09a2SMark Phalan     return (uc);
6925159d09a2SMark Phalan }
6926159d09a2SMark Phalan #endif
6927159d09a2SMark Phalan 
6928159d09a2SMark Phalan static char *
6929159d09a2SMark Phalan pkinit_pkcs11_code_to_text(int err) {
6930159d09a2SMark Phalan 	return pkcs11_error_table(err);
6931159d09a2SMark Phalan }
6932