1/* ssl/kssl.c -*- mode: C; c-file-style: "eay" -*- */
2/* Written by Vern Staats <staatsvr@asc.hpc.mil> for the OpenSSL project 2000.
3 */
4/* ====================================================================
5 * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in
16 *    the documentation and/or other materials provided with the
17 *    distribution.
18 *
19 * 3. All advertising materials mentioning features or use of this
20 *    software must display the following acknowledgment:
21 *    "This product includes software developed by the OpenSSL Project
22 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
23 *
24 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
25 *    endorse or promote products derived from this software without
26 *    prior written permission. For written permission, please contact
27 *    licensing@OpenSSL.org.
28 *
29 * 5. Products derived from this software may not be called "OpenSSL"
30 *    nor may "OpenSSL" appear in their names without prior written
31 *    permission of the OpenSSL Project.
32 *
33 * 6. Redistributions of any form whatsoever must retain the following
34 *    acknowledgment:
35 *    "This product includes software developed by the OpenSSL Project
36 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
37 *
38 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
39 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
41 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
42 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
47 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
49 * OF THE POSSIBILITY OF SUCH DAMAGE.
50 * ====================================================================
51 *
52 * This product includes cryptographic software written by Eric Young
53 * (eay@cryptsoft.com).  This product includes software written by Tim
54 * Hudson (tjh@cryptsoft.com).
55 *
56 */
57
58
59/*  ssl/kssl.c  --  Routines to support (& debug) Kerberos5 auth for openssl
60**
61**  19990701	VRS 	Started.
62**  200011??	Jeffrey Altman, Richard Levitte
63**          		Generalized for Heimdal, Newer MIT, & Win32.
64**          		Integrated into main OpenSSL 0.9.7 snapshots.
65**  20010413	Simon Wilkinson, VRS
66**          		Real RFC2712 KerberosWrapper replaces AP_REQ.
67*/
68
69#include <openssl/opensslconf.h>
70
71#include <string.h>
72
73#define KRB5_PRIVATE	1
74
75#include <openssl/ssl.h>
76#include <openssl/evp.h>
77#include <openssl/objects.h>
78#include <openssl/krb5_asn.h>
79
80#ifndef OPENSSL_NO_KRB5
81
82#ifndef ENOMEM
83#define ENOMEM KRB5KRB_ERR_GENERIC
84#endif
85
86/*
87 * When OpenSSL is built on Windows, we do not want to require that
88 * the Kerberos DLLs be available in order for the OpenSSL DLLs to
89 * work.  Therefore, all Kerberos routines are loaded at run time
90 * and we do not link to a .LIB file.
91 */
92
93#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
94/*
95 * The purpose of the following pre-processor statements is to provide
96 * compatibility with different releases of MIT Kerberos for Windows.
97 * All versions up to 1.2 used macros.  But macros do not allow for
98 * a binary compatible interface for DLLs.  Therefore, all macros are
99 * being replaced by function calls.  The following code will allow
100 * an OpenSSL DLL built on Windows to work whether or not the macro
101 * or function form of the routines are utilized.
102 */
103#ifdef  krb5_cc_get_principal
104#define NO_DEF_KRB5_CCACHE
105#undef  krb5_cc_get_principal
106#endif
107#define krb5_cc_get_principal    kssl_krb5_cc_get_principal
108
109#define krb5_free_data_contents  kssl_krb5_free_data_contents
110#define krb5_free_context        kssl_krb5_free_context
111#define krb5_auth_con_free       kssl_krb5_auth_con_free
112#define krb5_free_principal      kssl_krb5_free_principal
113#define krb5_mk_req_extended     kssl_krb5_mk_req_extended
114#define krb5_get_credentials     kssl_krb5_get_credentials
115#define krb5_cc_default          kssl_krb5_cc_default
116#define krb5_sname_to_principal  kssl_krb5_sname_to_principal
117#define krb5_init_context        kssl_krb5_init_context
118#define krb5_free_ticket         kssl_krb5_free_ticket
119#define krb5_rd_req              kssl_krb5_rd_req
120#define krb5_kt_default          kssl_krb5_kt_default
121#define krb5_kt_resolve          kssl_krb5_kt_resolve
122/* macros in mit 1.2.2 and earlier; functions in mit 1.2.3 and greater */
123#ifndef krb5_kt_close
124#define krb5_kt_close            kssl_krb5_kt_close
125#endif /* krb5_kt_close */
126#ifndef krb5_kt_get_entry
127#define krb5_kt_get_entry        kssl_krb5_kt_get_entry
128#endif /* krb5_kt_get_entry */
129#define krb5_auth_con_init       kssl_krb5_auth_con_init
130
131#define krb5_principal_compare   kssl_krb5_principal_compare
132#define krb5_decrypt_tkt_part    kssl_krb5_decrypt_tkt_part
133#define krb5_timeofday           kssl_krb5_timeofday
134#define krb5_rc_default           kssl_krb5_rc_default
135
136#ifdef krb5_rc_initialize
137#undef krb5_rc_initialize
138#endif
139#define krb5_rc_initialize   kssl_krb5_rc_initialize
140
141#ifdef krb5_rc_get_lifespan
142#undef krb5_rc_get_lifespan
143#endif
144#define krb5_rc_get_lifespan kssl_krb5_rc_get_lifespan
145
146#ifdef krb5_rc_destroy
147#undef krb5_rc_destroy
148#endif
149#define krb5_rc_destroy      kssl_krb5_rc_destroy
150
151#define valid_cksumtype      kssl_valid_cksumtype
152#define krb5_checksum_size   kssl_krb5_checksum_size
153#define krb5_kt_free_entry   kssl_krb5_kt_free_entry
154#define krb5_auth_con_setrcache  kssl_krb5_auth_con_setrcache
155#define krb5_auth_con_getrcache  kssl_krb5_auth_con_getrcache
156#define krb5_get_server_rcache   kssl_krb5_get_server_rcache
157
158/* Prototypes for built in stubs */
159void kssl_krb5_free_data_contents(krb5_context, krb5_data *);
160void kssl_krb5_free_principal(krb5_context, krb5_principal );
161krb5_error_code kssl_krb5_kt_resolve(krb5_context,
162                                     krb5_const char *,
163                                     krb5_keytab *);
164krb5_error_code kssl_krb5_kt_default(krb5_context,
165                                     krb5_keytab *);
166krb5_error_code kssl_krb5_free_ticket(krb5_context, krb5_ticket *);
167krb5_error_code kssl_krb5_rd_req(krb5_context, krb5_auth_context *,
168                                 krb5_const krb5_data *,
169                                 krb5_const_principal, krb5_keytab,
170                                 krb5_flags *,krb5_ticket **);
171
172krb5_boolean kssl_krb5_principal_compare(krb5_context, krb5_const_principal,
173                                         krb5_const_principal);
174krb5_error_code kssl_krb5_mk_req_extended(krb5_context,
175                                          krb5_auth_context  *,
176                                          krb5_const krb5_flags,
177                                          krb5_data  *,
178                                          krb5_creds  *,
179                                          krb5_data  * );
180krb5_error_code kssl_krb5_init_context(krb5_context *);
181void kssl_krb5_free_context(krb5_context);
182krb5_error_code kssl_krb5_cc_default(krb5_context,krb5_ccache  *);
183krb5_error_code kssl_krb5_sname_to_principal(krb5_context,
184                                             krb5_const char  *,
185                                             krb5_const char  *,
186                                             krb5_int32,
187                                             krb5_principal  *);
188krb5_error_code kssl_krb5_get_credentials(krb5_context,
189                                          krb5_const krb5_flags,
190                                          krb5_ccache,
191                                          krb5_creds  *,
192                                          krb5_creds  *  *);
193krb5_error_code kssl_krb5_auth_con_init(krb5_context,
194                                        krb5_auth_context  *);
195krb5_error_code kssl_krb5_cc_get_principal(krb5_context context,
196                                           krb5_ccache cache,
197                                           krb5_principal *principal);
198krb5_error_code kssl_krb5_auth_con_free(krb5_context,krb5_auth_context);
199size_t kssl_krb5_checksum_size(krb5_context context,krb5_cksumtype ctype);
200krb5_boolean kssl_valid_cksumtype(krb5_cksumtype ctype);
201krb5_error_code krb5_kt_free_entry(krb5_context,krb5_keytab_entry FAR * );
202krb5_error_code kssl_krb5_auth_con_setrcache(krb5_context,
203                                             krb5_auth_context,
204                                             krb5_rcache);
205krb5_error_code kssl_krb5_get_server_rcache(krb5_context,
206                                            krb5_const krb5_data *,
207                                            krb5_rcache *);
208krb5_error_code kssl_krb5_auth_con_getrcache(krb5_context,
209                                             krb5_auth_context,
210                                             krb5_rcache *);
211
212/* Function pointers (almost all Kerberos functions are _stdcall) */
213static void (_stdcall *p_krb5_free_data_contents)(krb5_context, krb5_data *)
214	=NULL;
215static void (_stdcall *p_krb5_free_principal)(krb5_context, krb5_principal )
216	=NULL;
217static krb5_error_code(_stdcall *p_krb5_kt_resolve)
218			(krb5_context, krb5_const char *, krb5_keytab *)=NULL;
219static krb5_error_code (_stdcall *p_krb5_kt_default)(krb5_context,
220                                                     krb5_keytab *)=NULL;
221static krb5_error_code (_stdcall *p_krb5_free_ticket)(krb5_context,
222                                                      krb5_ticket *)=NULL;
223static krb5_error_code (_stdcall *p_krb5_rd_req)(krb5_context,
224                                                 krb5_auth_context *,
225                                                 krb5_const krb5_data *,
226                                                 krb5_const_principal,
227                                                 krb5_keytab, krb5_flags *,
228                                                 krb5_ticket **)=NULL;
229static krb5_error_code (_stdcall *p_krb5_mk_req_extended)
230			(krb5_context, krb5_auth_context *,
231			 krb5_const krb5_flags, krb5_data *, krb5_creds *,
232			 krb5_data * )=NULL;
233static krb5_error_code (_stdcall *p_krb5_init_context)(krb5_context *)=NULL;
234static void (_stdcall *p_krb5_free_context)(krb5_context)=NULL;
235static krb5_error_code (_stdcall *p_krb5_cc_default)(krb5_context,
236                                                     krb5_ccache  *)=NULL;
237static krb5_error_code (_stdcall *p_krb5_sname_to_principal)
238			(krb5_context, krb5_const char *, krb5_const char *,
239			 krb5_int32, krb5_principal *)=NULL;
240static krb5_error_code (_stdcall *p_krb5_get_credentials)
241			(krb5_context, krb5_const krb5_flags, krb5_ccache,
242			 krb5_creds *, krb5_creds **)=NULL;
243static krb5_error_code (_stdcall *p_krb5_auth_con_init)
244			(krb5_context, krb5_auth_context *)=NULL;
245static krb5_error_code (_stdcall *p_krb5_cc_get_principal)
246			(krb5_context context, krb5_ccache cache,
247			 krb5_principal *principal)=NULL;
248static krb5_error_code (_stdcall *p_krb5_auth_con_free)
249			(krb5_context, krb5_auth_context)=NULL;
250static krb5_error_code (_stdcall *p_krb5_decrypt_tkt_part)
251                        (krb5_context, krb5_const krb5_keyblock *,
252                                           krb5_ticket *)=NULL;
253static krb5_error_code (_stdcall *p_krb5_timeofday)
254                        (krb5_context context, krb5_int32 *timeret)=NULL;
255static krb5_error_code (_stdcall *p_krb5_rc_default)
256                        (krb5_context context, krb5_rcache *rc)=NULL;
257static krb5_error_code (_stdcall *p_krb5_rc_initialize)
258                        (krb5_context context, krb5_rcache rc,
259                                     krb5_deltat lifespan)=NULL;
260static krb5_error_code (_stdcall *p_krb5_rc_get_lifespan)
261                        (krb5_context context, krb5_rcache rc,
262                                       krb5_deltat *lifespan)=NULL;
263static krb5_error_code (_stdcall *p_krb5_rc_destroy)
264                        (krb5_context context, krb5_rcache rc)=NULL;
265static krb5_boolean (_stdcall *p_krb5_principal_compare)
266                     (krb5_context, krb5_const_principal, krb5_const_principal)=NULL;
267static size_t (_stdcall *p_krb5_checksum_size)(krb5_context context,krb5_cksumtype ctype)=NULL;
268static krb5_boolean (_stdcall *p_valid_cksumtype)(krb5_cksumtype ctype)=NULL;
269static krb5_error_code (_stdcall *p_krb5_kt_free_entry)
270                        (krb5_context,krb5_keytab_entry * )=NULL;
271static krb5_error_code (_stdcall * p_krb5_auth_con_setrcache)(krb5_context,
272                                                               krb5_auth_context,
273                                                               krb5_rcache)=NULL;
274static krb5_error_code (_stdcall * p_krb5_get_server_rcache)(krb5_context,
275                                                              krb5_const krb5_data *,
276                                                              krb5_rcache *)=NULL;
277static krb5_error_code (* p_krb5_auth_con_getrcache)(krb5_context,
278                                                      krb5_auth_context,
279                                                      krb5_rcache *)=NULL;
280static krb5_error_code (_stdcall * p_krb5_kt_close)(krb5_context context,
281                                                    krb5_keytab keytab)=NULL;
282static krb5_error_code (_stdcall * p_krb5_kt_get_entry)(krb5_context context,
283                                                        krb5_keytab keytab,
284                       krb5_const_principal principal, krb5_kvno vno,
285                       krb5_enctype enctype, krb5_keytab_entry *entry)=NULL;
286static int krb5_loaded = 0;     /* only attempt to initialize func ptrs once */
287
288/* Function to Load the Kerberos 5 DLL and initialize function pointers */
289void
290load_krb5_dll(void)
291	{
292	HANDLE hKRB5_32;
293
294	krb5_loaded++;
295	hKRB5_32 = LoadLibrary(TEXT("KRB5_32"));
296	if (!hKRB5_32)
297		return;
298
299	(FARPROC) p_krb5_free_data_contents =
300		GetProcAddress( hKRB5_32, "krb5_free_data_contents" );
301	(FARPROC) p_krb5_free_context =
302		GetProcAddress( hKRB5_32, "krb5_free_context" );
303	(FARPROC) p_krb5_auth_con_free =
304		GetProcAddress( hKRB5_32, "krb5_auth_con_free" );
305	(FARPROC) p_krb5_free_principal =
306		GetProcAddress( hKRB5_32, "krb5_free_principal" );
307	(FARPROC) p_krb5_mk_req_extended =
308		GetProcAddress( hKRB5_32, "krb5_mk_req_extended" );
309	(FARPROC) p_krb5_get_credentials =
310		GetProcAddress( hKRB5_32, "krb5_get_credentials" );
311	(FARPROC) p_krb5_cc_get_principal =
312		GetProcAddress( hKRB5_32, "krb5_cc_get_principal" );
313	(FARPROC) p_krb5_cc_default =
314		GetProcAddress( hKRB5_32, "krb5_cc_default" );
315	(FARPROC) p_krb5_sname_to_principal =
316		GetProcAddress( hKRB5_32, "krb5_sname_to_principal" );
317	(FARPROC) p_krb5_init_context =
318		GetProcAddress( hKRB5_32, "krb5_init_context" );
319	(FARPROC) p_krb5_free_ticket =
320		GetProcAddress( hKRB5_32, "krb5_free_ticket" );
321	(FARPROC) p_krb5_rd_req =
322		GetProcAddress( hKRB5_32, "krb5_rd_req" );
323	(FARPROC) p_krb5_principal_compare =
324		GetProcAddress( hKRB5_32, "krb5_principal_compare" );
325	(FARPROC) p_krb5_decrypt_tkt_part =
326		GetProcAddress( hKRB5_32, "krb5_decrypt_tkt_part" );
327	(FARPROC) p_krb5_timeofday =
328		GetProcAddress( hKRB5_32, "krb5_timeofday" );
329	(FARPROC) p_krb5_rc_default =
330		GetProcAddress( hKRB5_32, "krb5_rc_default" );
331	(FARPROC) p_krb5_rc_initialize =
332		GetProcAddress( hKRB5_32, "krb5_rc_initialize" );
333	(FARPROC) p_krb5_rc_get_lifespan =
334		GetProcAddress( hKRB5_32, "krb5_rc_get_lifespan" );
335	(FARPROC) p_krb5_rc_destroy =
336		GetProcAddress( hKRB5_32, "krb5_rc_destroy" );
337	(FARPROC) p_krb5_kt_default =
338		GetProcAddress( hKRB5_32, "krb5_kt_default" );
339	(FARPROC) p_krb5_kt_resolve =
340		GetProcAddress( hKRB5_32, "krb5_kt_resolve" );
341	(FARPROC) p_krb5_auth_con_init =
342		GetProcAddress( hKRB5_32, "krb5_auth_con_init" );
343        (FARPROC) p_valid_cksumtype =
344                GetProcAddress( hKRB5_32, "valid_cksumtype" );
345        (FARPROC) p_krb5_checksum_size =
346                GetProcAddress( hKRB5_32, "krb5_checksum_size" );
347        (FARPROC) p_krb5_kt_free_entry =
348                GetProcAddress( hKRB5_32, "krb5_kt_free_entry" );
349        (FARPROC) p_krb5_auth_con_setrcache =
350                GetProcAddress( hKRB5_32, "krb5_auth_con_setrcache" );
351        (FARPROC) p_krb5_get_server_rcache =
352                GetProcAddress( hKRB5_32, "krb5_get_server_rcache" );
353        (FARPROC) p_krb5_auth_con_getrcache =
354                GetProcAddress( hKRB5_32, "krb5_auth_con_getrcache" );
355        (FARPROC) p_krb5_kt_close =
356                GetProcAddress( hKRB5_32, "krb5_kt_close" );
357        (FARPROC) p_krb5_kt_get_entry =
358                GetProcAddress( hKRB5_32, "krb5_kt_get_entry" );
359	}
360
361/* Stubs for each function to be dynamicly loaded */
362void
363kssl_krb5_free_data_contents(krb5_context CO, krb5_data  * data)
364	{
365	if (!krb5_loaded)
366		load_krb5_dll();
367
368	if ( p_krb5_free_data_contents )
369		p_krb5_free_data_contents(CO,data);
370	}
371
372krb5_error_code
373kssl_krb5_mk_req_extended (krb5_context CO,
374                          krb5_auth_context  * pACO,
375                          krb5_const krb5_flags F,
376                          krb5_data  * pD1,
377                          krb5_creds  * pC,
378                          krb5_data  * pD2)
379	{
380	if (!krb5_loaded)
381		load_krb5_dll();
382
383	if ( p_krb5_mk_req_extended )
384		return(p_krb5_mk_req_extended(CO,pACO,F,pD1,pC,pD2));
385	else
386		return KRB5KRB_ERR_GENERIC;
387	}
388krb5_error_code
389kssl_krb5_auth_con_init(krb5_context CO,
390                       krb5_auth_context  * pACO)
391	{
392	if (!krb5_loaded)
393		load_krb5_dll();
394
395	if ( p_krb5_auth_con_init )
396		return(p_krb5_auth_con_init(CO,pACO));
397	else
398		return KRB5KRB_ERR_GENERIC;
399	}
400krb5_error_code
401kssl_krb5_auth_con_free (krb5_context CO,
402                        krb5_auth_context ACO)
403	{
404	if (!krb5_loaded)
405		load_krb5_dll();
406
407	if ( p_krb5_auth_con_free )
408		return(p_krb5_auth_con_free(CO,ACO));
409	else
410		return KRB5KRB_ERR_GENERIC;
411	}
412krb5_error_code
413kssl_krb5_get_credentials(krb5_context CO,
414                         krb5_const krb5_flags F,
415                         krb5_ccache CC,
416                         krb5_creds  * pCR,
417                         krb5_creds  ** ppCR)
418	{
419	if (!krb5_loaded)
420		load_krb5_dll();
421
422	if ( p_krb5_get_credentials )
423		return(p_krb5_get_credentials(CO,F,CC,pCR,ppCR));
424	else
425		return KRB5KRB_ERR_GENERIC;
426	}
427krb5_error_code
428kssl_krb5_sname_to_principal(krb5_context CO,
429                            krb5_const char  * pC1,
430                            krb5_const char  * pC2,
431                            krb5_int32 I,
432                            krb5_principal  * pPR)
433	{
434	if (!krb5_loaded)
435		load_krb5_dll();
436
437	if ( p_krb5_sname_to_principal )
438		return(p_krb5_sname_to_principal(CO,pC1,pC2,I,pPR));
439	else
440		return KRB5KRB_ERR_GENERIC;
441	}
442
443krb5_error_code
444kssl_krb5_cc_default(krb5_context CO,
445                    krb5_ccache  * pCC)
446	{
447	if (!krb5_loaded)
448		load_krb5_dll();
449
450	if ( p_krb5_cc_default )
451		return(p_krb5_cc_default(CO,pCC));
452	else
453		return KRB5KRB_ERR_GENERIC;
454	}
455
456krb5_error_code
457kssl_krb5_init_context(krb5_context * pCO)
458	{
459	if (!krb5_loaded)
460		load_krb5_dll();
461
462	if ( p_krb5_init_context )
463		return(p_krb5_init_context(pCO));
464	else
465		return KRB5KRB_ERR_GENERIC;
466	}
467
468void
469kssl_krb5_free_context(krb5_context CO)
470	{
471	if (!krb5_loaded)
472		load_krb5_dll();
473
474	if ( p_krb5_free_context )
475		p_krb5_free_context(CO);
476	}
477
478void
479kssl_krb5_free_principal(krb5_context c, krb5_principal p)
480	{
481	if (!krb5_loaded)
482		load_krb5_dll();
483
484	if ( p_krb5_free_principal )
485		p_krb5_free_principal(c,p);
486	}
487
488krb5_error_code
489kssl_krb5_kt_resolve(krb5_context con,
490                    krb5_const char * sz,
491                    krb5_keytab * kt)
492	{
493	if (!krb5_loaded)
494		load_krb5_dll();
495
496	if ( p_krb5_kt_resolve )
497		return(p_krb5_kt_resolve(con,sz,kt));
498	else
499		return KRB5KRB_ERR_GENERIC;
500	}
501
502krb5_error_code
503kssl_krb5_kt_default(krb5_context con,
504                    krb5_keytab * kt)
505	{
506	if (!krb5_loaded)
507		load_krb5_dll();
508
509	if ( p_krb5_kt_default )
510		return(p_krb5_kt_default(con,kt));
511	else
512		return KRB5KRB_ERR_GENERIC;
513	}
514
515krb5_error_code
516kssl_krb5_free_ticket(krb5_context con,
517                     krb5_ticket * kt)
518	{
519	if (!krb5_loaded)
520		load_krb5_dll();
521
522	if ( p_krb5_free_ticket )
523		return(p_krb5_free_ticket(con,kt));
524	else
525		return KRB5KRB_ERR_GENERIC;
526	}
527
528krb5_error_code
529kssl_krb5_rd_req(krb5_context con, krb5_auth_context * pacon,
530                krb5_const krb5_data * data,
531                krb5_const_principal princ, krb5_keytab keytab,
532                krb5_flags * flags, krb5_ticket ** pptkt)
533	{
534	if (!krb5_loaded)
535		load_krb5_dll();
536
537	if ( p_krb5_rd_req )
538		return(p_krb5_rd_req(con,pacon,data,princ,keytab,flags,pptkt));
539	else
540		return KRB5KRB_ERR_GENERIC;
541	}
542
543krb5_boolean
544krb5_principal_compare(krb5_context con, krb5_const_principal princ1,
545                krb5_const_principal princ2)
546	{
547	if (!krb5_loaded)
548		load_krb5_dll();
549
550	if ( p_krb5_principal_compare )
551		return(p_krb5_principal_compare(con,princ1,princ2));
552	else
553		return KRB5KRB_ERR_GENERIC;
554	}
555
556krb5_error_code
557krb5_decrypt_tkt_part(krb5_context con, krb5_const krb5_keyblock *keys,
558                krb5_ticket *ticket)
559	{
560	if (!krb5_loaded)
561		load_krb5_dll();
562
563	if ( p_krb5_decrypt_tkt_part )
564		return(p_krb5_decrypt_tkt_part(con,keys,ticket));
565	else
566		return KRB5KRB_ERR_GENERIC;
567	}
568
569krb5_error_code
570krb5_timeofday(krb5_context con, krb5_int32 *timeret)
571	{
572	if (!krb5_loaded)
573		load_krb5_dll();
574
575	if ( p_krb5_timeofday )
576		return(p_krb5_timeofday(con,timeret));
577	else
578		return KRB5KRB_ERR_GENERIC;
579	}
580
581krb5_error_code
582krb5_rc_default(krb5_context con, krb5_rcache *rc)
583	{
584	if (!krb5_loaded)
585		load_krb5_dll();
586
587	if ( p_krb5_rc_default )
588		return(p_krb5_rc_default(con,rc));
589	else
590		return KRB5KRB_ERR_GENERIC;
591	}
592
593krb5_error_code
594krb5_rc_initialize(krb5_context con, krb5_rcache rc, krb5_deltat lifespan)
595	{
596	if (!krb5_loaded)
597		load_krb5_dll();
598
599	if ( p_krb5_rc_initialize )
600		return(p_krb5_rc_initialize(con, rc, lifespan));
601	else
602		return KRB5KRB_ERR_GENERIC;
603	}
604
605krb5_error_code
606krb5_rc_get_lifespan(krb5_context con, krb5_rcache rc, krb5_deltat *lifespanp)
607	{
608	if (!krb5_loaded)
609		load_krb5_dll();
610
611	if ( p_krb5_rc_get_lifespan )
612		return(p_krb5_rc_get_lifespan(con, rc, lifespanp));
613	else
614		return KRB5KRB_ERR_GENERIC;
615	}
616
617krb5_error_code
618krb5_rc_destroy(krb5_context con, krb5_rcache rc)
619	{
620	if (!krb5_loaded)
621		load_krb5_dll();
622
623	if ( p_krb5_rc_destroy )
624		return(p_krb5_rc_destroy(con, rc));
625	else
626		return KRB5KRB_ERR_GENERIC;
627	}
628
629size_t
630krb5_checksum_size(krb5_context context,krb5_cksumtype ctype)
631        {
632        if (!krb5_loaded)
633                load_krb5_dll();
634
635        if ( p_krb5_checksum_size )
636                return(p_krb5_checksum_size(context, ctype));
637        else
638                return KRB5KRB_ERR_GENERIC;
639        }
640
641krb5_boolean
642valid_cksumtype(krb5_cksumtype ctype)
643        {
644        if (!krb5_loaded)
645                load_krb5_dll();
646
647        if ( p_valid_cksumtype )
648                return(p_valid_cksumtype(ctype));
649        else
650                return KRB5KRB_ERR_GENERIC;
651        }
652
653krb5_error_code
654krb5_kt_free_entry(krb5_context con,krb5_keytab_entry * entry)
655        {
656        if (!krb5_loaded)
657                load_krb5_dll();
658
659        if ( p_krb5_kt_free_entry )
660                return(p_krb5_kt_free_entry(con,entry));
661        else
662                return KRB5KRB_ERR_GENERIC;
663        }
664
665/* Structure definitions  */
666#ifndef NO_DEF_KRB5_CCACHE
667#ifndef krb5_x
668#define krb5_x(ptr,args) ((ptr)?((*(ptr)) args):(abort(),1))
669#define krb5_xc(ptr,args) ((ptr)?((*(ptr)) args):(abort(),(char*)0))
670#endif
671
672typedef	krb5_pointer	krb5_cc_cursor;	/* cursor for sequential lookup */
673
674typedef struct _krb5_ccache
675	{
676	krb5_magic magic;
677	struct _krb5_cc_ops FAR *ops;
678	krb5_pointer data;
679	} *krb5_ccache;
680
681typedef struct _krb5_cc_ops
682	{
683	krb5_magic magic;
684	char  *prefix;
685	char  * (KRB5_CALLCONV *get_name)
686		(krb5_context, krb5_ccache);
687	krb5_error_code (KRB5_CALLCONV *resolve)
688		(krb5_context, krb5_ccache  *, const char  *);
689	krb5_error_code (KRB5_CALLCONV *gen_new)
690		(krb5_context, krb5_ccache  *);
691	krb5_error_code (KRB5_CALLCONV *init)
692		(krb5_context, krb5_ccache, krb5_principal);
693	krb5_error_code (KRB5_CALLCONV *destroy)
694		(krb5_context, krb5_ccache);
695	krb5_error_code (KRB5_CALLCONV *close)
696		(krb5_context, krb5_ccache);
697	krb5_error_code (KRB5_CALLCONV *store)
698		(krb5_context, krb5_ccache, krb5_creds  *);
699	krb5_error_code (KRB5_CALLCONV *retrieve)
700		(krb5_context, krb5_ccache,
701		krb5_flags, krb5_creds  *, krb5_creds  *);
702	krb5_error_code (KRB5_CALLCONV *get_princ)
703		(krb5_context, krb5_ccache, krb5_principal  *);
704	krb5_error_code (KRB5_CALLCONV *get_first)
705		(krb5_context, krb5_ccache, krb5_cc_cursor  *);
706	krb5_error_code (KRB5_CALLCONV *get_next)
707		(krb5_context, krb5_ccache,
708		krb5_cc_cursor  *, krb5_creds  *);
709	krb5_error_code (KRB5_CALLCONV *end_get)
710		(krb5_context, krb5_ccache, krb5_cc_cursor  *);
711	krb5_error_code (KRB5_CALLCONV *remove_cred)
712		(krb5_context, krb5_ccache,
713		krb5_flags, krb5_creds  *);
714	krb5_error_code (KRB5_CALLCONV *set_flags)
715		(krb5_context, krb5_ccache, krb5_flags);
716	} krb5_cc_ops;
717#endif /* NO_DEF_KRB5_CCACHE */
718
719krb5_error_code
720kssl_krb5_cc_get_principal
721    (krb5_context context, krb5_ccache cache,
722      krb5_principal *principal)
723	{
724	if ( p_krb5_cc_get_principal )
725		return(p_krb5_cc_get_principal(context,cache,principal));
726	else
727		return(krb5_x
728			((cache)->ops->get_princ,(context, cache, principal)));
729	}
730
731krb5_error_code
732kssl_krb5_auth_con_setrcache(krb5_context con, krb5_auth_context acon,
733                             krb5_rcache rcache)
734        {
735        if ( p_krb5_auth_con_setrcache )
736                 return(p_krb5_auth_con_setrcache(con,acon,rcache));
737        else
738                 return KRB5KRB_ERR_GENERIC;
739        }
740
741krb5_error_code
742kssl_krb5_get_server_rcache(krb5_context con, krb5_const krb5_data * data,
743                            krb5_rcache * rcache)
744        {
745	if ( p_krb5_get_server_rcache )
746		return(p_krb5_get_server_rcache(con,data,rcache));
747	else
748		return KRB5KRB_ERR_GENERIC;
749        }
750
751krb5_error_code
752kssl_krb5_auth_con_getrcache(krb5_context con, krb5_auth_context acon,
753                             krb5_rcache * prcache)
754        {
755	if ( p_krb5_auth_con_getrcache )
756		return(p_krb5_auth_con_getrcache(con,acon, prcache));
757	else
758		return KRB5KRB_ERR_GENERIC;
759	}
760
761krb5_error_code
762kssl_krb5_kt_close(krb5_context context, krb5_keytab keytab)
763	{
764	if ( p_krb5_kt_close )
765		return(p_krb5_kt_close(context,keytab));
766	else
767		return KRB5KRB_ERR_GENERIC;
768	}
769
770krb5_error_code
771kssl_krb5_kt_get_entry(krb5_context context, krb5_keytab keytab,
772                       krb5_const_principal principal, krb5_kvno vno,
773                       krb5_enctype enctype, krb5_keytab_entry *entry)
774	{
775	if ( p_krb5_kt_get_entry )
776		return(p_krb5_kt_get_entry(context,keytab,principal,vno,enctype,entry));
777	else
778		return KRB5KRB_ERR_GENERIC;
779        }
780#endif  /* OPENSSL_SYS_WINDOWS || OPENSSL_SYS_WIN32 */
781
782
783/* memory allocation functions for non-temporary storage
784 * (e.g. stuff that gets saved into the kssl context) */
785static void* kssl_calloc(size_t nmemb, size_t size)
786{
787	void* p;
788
789	p=OPENSSL_malloc(nmemb*size);
790	if (p){
791		memset(p, 0, nmemb*size);
792	}
793	return p;
794}
795
796#define kssl_malloc(size) OPENSSL_malloc((size))
797#define kssl_realloc(ptr, size) OPENSSL_realloc(ptr, size)
798#define kssl_free(ptr) OPENSSL_free((ptr))
799
800
801char
802*kstring(char *string)
803        {
804        static char	*null = "[NULL]";
805
806	return ((string == NULL)? null: string);
807        }
808
809/*	Given KRB5 enctype (basically DES or 3DES),
810**	return closest match openssl EVP_ encryption algorithm.
811**	Return NULL for unknown or problematic (krb5_dk_encrypt) enctypes.
812**	Assume ENCTYPE_*_RAW (krb5_raw_encrypt) are OK.
813*/
814const EVP_CIPHER *
815kssl_map_enc(krb5_enctype enctype)
816        {
817	switch (enctype)
818		{
819	case ENCTYPE_DES_HMAC_SHA1:		/*    EVP_des_cbc();       */
820	case ENCTYPE_DES_CBC_CRC:
821	case ENCTYPE_DES_CBC_MD4:
822	case ENCTYPE_DES_CBC_MD5:
823	case ENCTYPE_DES_CBC_RAW:
824				return EVP_des_cbc();
825				break;
826	case ENCTYPE_DES3_CBC_SHA1:		/*    EVP_des_ede3_cbc();  */
827	case ENCTYPE_DES3_CBC_SHA:
828	case ENCTYPE_DES3_CBC_RAW:
829				return EVP_des_ede3_cbc();
830				break;
831	default:                return NULL;
832				break;
833		}
834	}
835
836
837/*	Return true:1 if p "looks like" the start of the real authenticator
838**	described in kssl_skip_confound() below.  The ASN.1 pattern is
839**	"62 xx 30 yy" (APPLICATION-2, SEQUENCE), where xx-yy =~ 2, and
840**	xx and yy are possibly multi-byte length fields.
841*/
842int 	kssl_test_confound(unsigned char *p)
843	{
844	int 	len = 2;
845	int 	xx = 0, yy = 0;
846
847	if (*p++ != 0x62)  return 0;
848	if (*p > 0x82)  return 0;
849	switch(*p)  {
850		case 0x82:  p++;          xx = (*p++ << 8);  xx += *p++;  break;
851		case 0x81:  p++;          xx =  *p++;  break;
852		case 0x80:  return 0;
853		default:    xx = *p++;  break;
854		}
855	if (*p++ != 0x30)  return 0;
856	if (*p > 0x82)  return 0;
857	switch(*p)  {
858		case 0x82:  p++; len+=2;  yy = (*p++ << 8);  yy += *p++;  break;
859		case 0x81:  p++; len++;   yy =  *p++;  break;
860		case 0x80:  return 0;
861		default:    yy = *p++;  break;
862		}
863
864	return (xx - len == yy)? 1: 0;
865	}
866
867/*	Allocate, fill, and return cksumlens array of checksum lengths.
868**	This array holds just the unique elements from the krb5_cksumarray[].
869**	array[n] == 0 signals end of data.
870**
871**      The krb5_cksumarray[] was an internal variable that has since been
872**      replaced by a more general method for storing the data.  It should
873**      not be used.  Instead we use real API calls and make a guess for
874**      what the highest assigned CKSUMTYPE_ constant is.  As of 1.2.2
875**      it is 0x000c (CKSUMTYPE_HMAC_SHA1_DES3).  So we will use 0x0010.
876*/
877size_t  *populate_cksumlens(void)
878	{
879	int 		i, j, n;
880	static size_t 	*cklens = NULL;
881
882#ifdef KRB5_MIT_OLD11
883	n = krb5_max_cksum;
884#else
885	n = 0x0010;
886#endif	/* KRB5_MIT_OLD11 */
887
888#ifdef KRB5CHECKAUTH
889	if (!cklens && !(cklens = (size_t *) calloc(sizeof(int),n+1)))  return NULL;
890
891	for (i=0; i < n; i++)  {
892		if (!valid_cksumtype(i))  continue;	/*  array has holes  */
893		for (j=0; j < n; j++)  {
894			if (cklens[j] == 0)  {
895				cklens[j] = krb5_checksum_size(NULL,i);
896				break;		/*  krb5 elem was new: add   */
897				}
898			if (cklens[j] == krb5_checksum_size(NULL,i))  {
899				break;		/*  ignore duplicate elements */
900				}
901			}
902		}
903#endif	/* KRB5CHECKAUTH */
904
905	return cklens;
906	}
907
908/*	Return pointer to start of real authenticator within authenticator, or
909**	return NULL on error.
910**	Decrypted authenticator looks like this:
911**		[0 or 8 byte confounder] [4-24 byte checksum] [real authent'r]
912**	This hackery wouldn't be necessary if MIT KRB5 1.0.6 had the
913**	krb5_auth_con_getcksumtype() function advertised in its krb5.h.
914*/
915unsigned char	*kssl_skip_confound(krb5_enctype etype, unsigned char *a)
916	{
917	int 		i, conlen;
918	size_t		cklen;
919	static size_t 	*cksumlens = NULL;
920	unsigned char	*test_auth;
921
922	conlen = (etype)? 8: 0;
923
924	if (!cksumlens  &&  !(cksumlens = populate_cksumlens()))  return NULL;
925	for (i=0; (cklen = cksumlens[i]) != 0; i++)
926		{
927		test_auth = a + conlen + cklen;
928		if (kssl_test_confound(test_auth))  return test_auth;
929		}
930
931	return NULL;
932	}
933
934
935/*	Set kssl_err error info when reason text is a simple string
936**		kssl_err = struct { int reason; char text[KSSL_ERR_MAX+1]; }
937*/
938void
939kssl_err_set(KSSL_ERR *kssl_err, int reason, char *text)
940        {
941	if (kssl_err == NULL)  return;
942
943	kssl_err->reason = reason;
944	BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, "%s", text);
945	return;
946        }
947
948
949/*	Display contents of krb5_data struct, for debugging
950*/
951void
952print_krb5_data(char *label, krb5_data *kdata)
953        {
954	int i;
955
956	printf("%s[%d] ", label, kdata->length);
957	for (i=0; i < (int)kdata->length; i++)
958                {
959		if (0 &&  isprint((int) kdata->data[i]))
960                        printf(	"%c ",  kdata->data[i]);
961		else
962                        printf(	"%02x ", (unsigned char) kdata->data[i]);
963		}
964	printf("\n");
965        }
966
967
968/*	Display contents of krb5_authdata struct, for debugging
969*/
970void
971print_krb5_authdata(char *label, krb5_authdata **adata)
972        {
973	if (adata == NULL)
974                {
975		printf("%s, authdata==0\n", label);
976		return;
977		}
978	printf("%s [%p]\n", label, (void *)adata);
979#if 0
980	{
981        int 	i;
982	printf("%s[at%d:%d] ", label, adata->ad_type, adata->length);
983	for (i=0; i < adata->length; i++)
984                {
985                printf((isprint(adata->contents[i]))? "%c ": "%02x",
986                        adata->contents[i]);
987		}
988	printf("\n");
989	}
990#endif
991	}
992
993
994/*	Display contents of krb5_keyblock struct, for debugging
995*/
996void
997print_krb5_keyblock(char *label, krb5_keyblock *keyblk)
998        {
999	int i;
1000
1001	if (keyblk == NULL)
1002                {
1003		printf("%s, keyblk==0\n", label);
1004		return;
1005		}
1006#ifdef KRB5_HEIMDAL
1007	printf("%s\n\t[et%d:%d]: ", label, keyblk->keytype,
1008					   keyblk->keyvalue->length);
1009	for (i=0; i < (int)keyblk->keyvalue->length; i++)
1010                {
1011		printf("%02x",(unsigned char *)(keyblk->keyvalue->contents)[i]);
1012		}
1013	printf("\n");
1014#else
1015	printf("%s\n\t[et%d:%d]: ", label, keyblk->enctype, keyblk->length);
1016	for (i=0; i < (int)keyblk->length; i++)
1017                {
1018		printf("%02x",keyblk->contents[i]);
1019		}
1020	printf("\n");
1021#endif
1022        }
1023
1024
1025/*	Display contents of krb5_principal_data struct, for debugging
1026**	(krb5_principal is typedef'd == krb5_principal_data *)
1027*/
1028void
1029print_krb5_princ(char *label, krb5_principal_data *princ)
1030        {
1031	int i, ui, uj;
1032
1033	printf("%s principal Realm: ", label);
1034	if (princ == NULL)  return;
1035	for (ui=0; ui < (int)princ->realm.length; ui++)  putchar(princ->realm.data[ui]);
1036	printf(" (nametype %d) has %d strings:\n", princ->type,princ->length);
1037	for (i=0; i < (int)princ->length; i++)
1038                {
1039		printf("\t%d [%d]: ", i, princ->data[i].length);
1040		for (uj=0; uj < (int)princ->data[i].length; uj++)  {
1041			putchar(princ->data[i].data[uj]);
1042			}
1043		printf("\n");
1044		}
1045	return;
1046        }
1047
1048
1049/*	Given krb5 service (typically "kssl") and hostname in kssl_ctx,
1050**	Return encrypted Kerberos ticket for service @ hostname.
1051**	If authenp is non-NULL, also return encrypted authenticator,
1052**	whose data should be freed by caller.
1053**	(Originally was: Create Kerberos AP_REQ message for SSL Client.)
1054**
1055**	19990628	VRS 	Started; Returns Kerberos AP_REQ message.
1056**	20010409	VRS 	Modified for RFC2712; Returns enc tkt.
1057**	20010606	VRS 	May also return optional authenticator.
1058*/
1059krb5_error_code
1060kssl_cget_tkt(	/* UPDATE */	KSSL_CTX *kssl_ctx,
1061                /* OUT    */	krb5_data **enc_ticketp,
1062                /* UPDATE */	krb5_data *authenp,
1063                /* OUT    */	KSSL_ERR *kssl_err)
1064	{
1065	krb5_error_code		krb5rc = KRB5KRB_ERR_GENERIC;
1066	krb5_context		krb5context = NULL;
1067	krb5_auth_context	krb5auth_context = NULL;
1068	krb5_ccache 		krb5ccdef = NULL;
1069	krb5_creds		krb5creds, *krb5credsp = NULL;
1070	krb5_data		krb5_app_req;
1071
1072	kssl_err_set(kssl_err, 0, "");
1073	memset((char *)&krb5creds, 0, sizeof(krb5creds));
1074
1075	if (!kssl_ctx)
1076                {
1077		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1078                        "No kssl_ctx defined.\n");
1079		goto err;
1080		}
1081	else if (!kssl_ctx->service_host)
1082                {
1083		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1084                        "kssl_ctx service_host undefined.\n");
1085		goto err;
1086		}
1087
1088	if ((krb5rc = krb5_init_context(&krb5context)) != 0)
1089                {
1090		BIO_snprintf(kssl_err->text,KSSL_ERR_MAX,
1091                        "krb5_init_context() fails: %d\n", krb5rc);
1092		kssl_err->reason = SSL_R_KRB5_C_INIT;
1093		goto err;
1094		}
1095
1096	if ((krb5rc = krb5_sname_to_principal(krb5context,
1097                kssl_ctx->service_host,
1098                (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC,
1099                KRB5_NT_SRV_HST, &krb5creds.server)) != 0)
1100                {
1101		BIO_snprintf(kssl_err->text,KSSL_ERR_MAX,
1102                        "krb5_sname_to_principal() fails for %s/%s\n",
1103                        kssl_ctx->service_host,
1104                        (kssl_ctx->service_name)? kssl_ctx->service_name:
1105						  KRB5SVC);
1106		kssl_err->reason = SSL_R_KRB5_C_INIT;
1107		goto err;
1108		}
1109
1110	if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0)
1111                {
1112		kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC,
1113                        "krb5_cc_default fails.\n");
1114		goto err;
1115		}
1116
1117	if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef,
1118                &krb5creds.client)) != 0)
1119                {
1120		kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC,
1121                        "krb5_cc_get_principal() fails.\n");
1122		goto err;
1123		}
1124
1125	if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef,
1126                &krb5creds, &krb5credsp)) != 0)
1127                {
1128		kssl_err_set(kssl_err, SSL_R_KRB5_C_GET_CRED,
1129                        "krb5_get_credentials() fails.\n");
1130		goto err;
1131		}
1132
1133	*enc_ticketp = &krb5credsp->ticket;
1134#ifdef KRB5_HEIMDAL
1135	kssl_ctx->enctype = krb5credsp->session.keytype;
1136#else
1137	kssl_ctx->enctype = krb5credsp->keyblock.enctype;
1138#endif
1139
1140	krb5rc = KRB5KRB_ERR_GENERIC;
1141	/*	caller should free data of krb5_app_req  */
1142	/*  20010406 VRS deleted for real KerberosWrapper
1143	**  20010605 VRS reinstated to offer Authenticator to KerberosWrapper
1144	*/
1145	krb5_app_req.length = 0;
1146	if (authenp)
1147                {
1148		krb5_data	krb5in_data;
1149		const unsigned char	*p;
1150		long		arlen;
1151		KRB5_APREQBODY	*ap_req;
1152
1153		authenp->length = 0;
1154		krb5in_data.data = NULL;
1155		krb5in_data.length = 0;
1156		if ((krb5rc = krb5_mk_req_extended(krb5context,
1157			&krb5auth_context, 0, &krb5in_data, krb5credsp,
1158			&krb5_app_req)) != 0)
1159			{
1160			kssl_err_set(kssl_err, SSL_R_KRB5_C_MK_REQ,
1161				"krb5_mk_req_extended() fails.\n");
1162			goto err;
1163			}
1164
1165		arlen = krb5_app_req.length;
1166		p = (unsigned char *)krb5_app_req.data;
1167		ap_req = (KRB5_APREQBODY *) d2i_KRB5_APREQ(NULL, &p, arlen);
1168		if (ap_req)
1169			{
1170			authenp->length = i2d_KRB5_ENCDATA(
1171					ap_req->authenticator, NULL);
1172			if (authenp->length  &&
1173				(authenp->data = malloc(authenp->length)))
1174				{
1175				unsigned char	*adp = (unsigned char *)authenp->data;
1176				authenp->length = i2d_KRB5_ENCDATA(
1177						ap_req->authenticator, &adp);
1178				}
1179			}
1180
1181		if (ap_req)  KRB5_APREQ_free((KRB5_APREQ *) ap_req);
1182		if (krb5_app_req.length)
1183                        kssl_krb5_free_data_contents(krb5context,&krb5_app_req);
1184		}
1185#ifdef KRB5_HEIMDAL
1186	if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->session))
1187                {
1188		kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
1189                        "kssl_ctx_setkey() fails.\n");
1190		}
1191#else
1192	if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->keyblock))
1193                {
1194		kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
1195                        "kssl_ctx_setkey() fails.\n");
1196		}
1197#endif
1198	else	krb5rc = 0;
1199
1200 err:
1201#ifdef KSSL_DEBUG
1202	kssl_ctx_show(kssl_ctx);
1203#endif	/* KSSL_DEBUG */
1204
1205	if (krb5creds.client)	krb5_free_principal(krb5context,
1206							krb5creds.client);
1207	if (krb5creds.server)	krb5_free_principal(krb5context,
1208							krb5creds.server);
1209	if (krb5auth_context)	krb5_auth_con_free(krb5context,
1210							krb5auth_context);
1211	if (krb5context)	krb5_free_context(krb5context);
1212	return (krb5rc);
1213	}
1214
1215
1216/*  Given d2i_-decoded asn1ticket, allocate and return a new krb5_ticket.
1217**  Return Kerberos error code and kssl_err struct on error.
1218**  Allocates krb5_ticket and krb5_principal; caller should free these.
1219**
1220**	20010410	VRS	Implemented krb5_decode_ticket() as
1221**				old_krb5_decode_ticket(). Missing from MIT1.0.6.
1222**	20010615	VRS 	Re-cast as openssl/asn1 d2i_*() functions.
1223**				Re-used some of the old krb5_decode_ticket()
1224**				code here.  This tkt should alloc/free just
1225**				like the real thing.
1226*/
1227krb5_error_code
1228kssl_TKT2tkt(	/* IN     */	krb5_context	krb5context,
1229		/* IN     */	KRB5_TKTBODY	*asn1ticket,
1230		/* OUT    */	krb5_ticket	**krb5ticket,
1231		/* OUT    */	KSSL_ERR *kssl_err  )
1232        {
1233        krb5_error_code			krb5rc = KRB5KRB_ERR_GENERIC;
1234	krb5_ticket 			*new5ticket = NULL;
1235	ASN1_GENERALSTRING		*gstr_svc, *gstr_host;
1236
1237	*krb5ticket = NULL;
1238
1239	if (asn1ticket == NULL  ||  asn1ticket->realm == NULL  ||
1240		asn1ticket->sname == NULL  ||
1241		sk_ASN1_GENERALSTRING_num(asn1ticket->sname->namestring) < 2)
1242		{
1243		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1244			"Null field in asn1ticket.\n");
1245		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1246		return KRB5KRB_ERR_GENERIC;
1247		}
1248
1249	if ((new5ticket = (krb5_ticket *) calloc(1, sizeof(krb5_ticket)))==NULL)
1250		{
1251		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1252			"Unable to allocate new krb5_ticket.\n");
1253		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1254		return ENOMEM;		/*  or  KRB5KRB_ERR_GENERIC;	*/
1255		}
1256
1257	gstr_svc  = sk_ASN1_GENERALSTRING_value(asn1ticket->sname->namestring, 0);
1258	gstr_host = sk_ASN1_GENERALSTRING_value(asn1ticket->sname->namestring, 1);
1259
1260	if ((krb5rc = kssl_build_principal_2(krb5context,
1261			&new5ticket->server,
1262			asn1ticket->realm->length, (char *)asn1ticket->realm->data,
1263			gstr_svc->length,  (char *)gstr_svc->data,
1264			gstr_host->length, (char *)gstr_host->data)) != 0)
1265		{
1266		free(new5ticket);
1267		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1268			"Error building ticket server principal.\n");
1269		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1270		return krb5rc;		/*  or  KRB5KRB_ERR_GENERIC;	*/
1271		}
1272
1273	krb5_princ_type(krb5context, new5ticket->server) =
1274			asn1ticket->sname->nametype->data[0];
1275	new5ticket->enc_part.enctype = asn1ticket->encdata->etype->data[0];
1276	new5ticket->enc_part.kvno = asn1ticket->encdata->kvno->data[0];
1277	new5ticket->enc_part.ciphertext.length =
1278			asn1ticket->encdata->cipher->length;
1279	if ((new5ticket->enc_part.ciphertext.data =
1280		calloc(1, asn1ticket->encdata->cipher->length)) == NULL)
1281		{
1282		free(new5ticket);
1283		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1284			"Error allocating cipher in krb5ticket.\n");
1285		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1286		return KRB5KRB_ERR_GENERIC;
1287		}
1288	else
1289		{
1290		memcpy(new5ticket->enc_part.ciphertext.data,
1291			asn1ticket->encdata->cipher->data,
1292			asn1ticket->encdata->cipher->length);
1293		}
1294
1295	*krb5ticket = new5ticket;
1296	return 0;
1297	}
1298
1299
1300/*	Given krb5 service name in KSSL_CTX *kssl_ctx (typically "kssl"),
1301**		and krb5 AP_REQ message & message length,
1302**	Return Kerberos session key and client principle
1303**		to SSL Server in KSSL_CTX *kssl_ctx.
1304**
1305**	19990702	VRS 	Started.
1306*/
1307krb5_error_code
1308kssl_sget_tkt(	/* UPDATE */	KSSL_CTX		*kssl_ctx,
1309		/* IN     */	krb5_data		*indata,
1310		/* OUT    */	krb5_ticket_times	*ttimes,
1311		/* OUT    */	KSSL_ERR		*kssl_err  )
1312        {
1313        krb5_error_code			krb5rc = KRB5KRB_ERR_GENERIC;
1314        static krb5_context		krb5context = NULL;
1315	static krb5_auth_context	krb5auth_context = NULL;
1316	krb5_ticket 			*krb5ticket = NULL;
1317	KRB5_TKTBODY 			*asn1ticket = NULL;
1318	const unsigned char		*p;
1319	krb5_keytab 			krb5keytab = NULL;
1320	krb5_keytab_entry		kt_entry;
1321	krb5_principal			krb5server;
1322        krb5_rcache                     rcache = NULL;
1323
1324	kssl_err_set(kssl_err, 0, "");
1325
1326	if (!kssl_ctx)
1327                {
1328		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1329			"No kssl_ctx defined.\n");
1330		goto err;
1331		}
1332
1333#ifdef KSSL_DEBUG
1334	printf("in kssl_sget_tkt(%s)\n", kstring(kssl_ctx->service_name));
1335#endif	/* KSSL_DEBUG */
1336
1337	if (!krb5context  &&  (krb5rc = krb5_init_context(&krb5context)))
1338                {
1339		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1340                        "krb5_init_context() fails.\n");
1341		goto err;
1342		}
1343	if (krb5auth_context  &&
1344		(krb5rc = krb5_auth_con_free(krb5context, krb5auth_context)))
1345                {
1346		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1347                        "krb5_auth_con_free() fails.\n");
1348		goto err;
1349		}
1350	else  krb5auth_context = NULL;
1351	if (!krb5auth_context  &&
1352		(krb5rc = krb5_auth_con_init(krb5context, &krb5auth_context)))
1353                {
1354		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1355                        "krb5_auth_con_init() fails.\n");
1356		goto err;
1357		}
1358
1359
1360	if ((krb5rc = krb5_auth_con_getrcache(krb5context, krb5auth_context,
1361		&rcache)))
1362		{
1363 		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1364			"krb5_auth_con_getrcache() fails.\n");
1365 		goto err;
1366		}
1367
1368	if ((krb5rc = krb5_sname_to_principal(krb5context, NULL,
1369                (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC,
1370                KRB5_NT_SRV_HST, &krb5server)) != 0)
1371                {
1372		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1373                        "krb5_sname_to_principal() fails.\n");
1374		goto err;
1375		}
1376
1377	if (rcache == NULL)
1378                {
1379                if ((krb5rc = krb5_get_server_rcache(krb5context,
1380			krb5_princ_component(krb5context, krb5server, 0),
1381			&rcache)))
1382                        {
1383		        kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1384                                "krb5_get_server_rcache() fails.\n");
1385                  	goto err;
1386                        }
1387                }
1388
1389        if ((krb5rc = krb5_auth_con_setrcache(krb5context, krb5auth_context, rcache)))
1390                {
1391                kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1392			"krb5_auth_con_setrcache() fails.\n");
1393                goto err;
1394                }
1395
1396
1397	/*	kssl_ctx->keytab_file == NULL ==> use Kerberos default
1398	*/
1399	if (kssl_ctx->keytab_file)
1400		{
1401		krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file,
1402                        &krb5keytab);
1403		if (krb5rc)
1404			{
1405			kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1406				"krb5_kt_resolve() fails.\n");
1407			goto err;
1408			}
1409		}
1410	else
1411		{
1412                krb5rc = krb5_kt_default(krb5context,&krb5keytab);
1413                if (krb5rc)
1414			{
1415			kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1416				"krb5_kt_default() fails.\n");
1417			goto err;
1418			}
1419		}
1420
1421	/*	Actual Kerberos5 krb5_recvauth() has initial conversation here
1422	**	o	check KRB5_SENDAUTH_BADAUTHVERS
1423	**		unless KRB5_RECVAUTH_SKIP_VERSION
1424	**	o	check KRB5_SENDAUTH_BADAPPLVERS
1425	**	o	send "0" msg if all OK
1426	*/
1427
1428	/*  20010411 was using AP_REQ instead of true KerberosWrapper
1429	**
1430	**  if ((krb5rc = krb5_rd_req(krb5context, &krb5auth_context,
1431	**			&krb5in_data, krb5server, krb5keytab,
1432	**			&ap_option, &krb5ticket)) != 0)  { Error }
1433	*/
1434
1435	p = (unsigned char *)indata->data;
1436	if ((asn1ticket = (KRB5_TKTBODY *) d2i_KRB5_TICKET(NULL, &p,
1437						(long) indata->length)) == NULL)
1438		{
1439		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1440			"d2i_KRB5_TICKET() ASN.1 decode failure.\n");
1441		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1442		goto err;
1443		}
1444
1445	/* Was:  krb5rc = krb5_decode_ticket(krb5in_data,&krb5ticket)) != 0) */
1446	if ((krb5rc = kssl_TKT2tkt(krb5context, asn1ticket, &krb5ticket,
1447					kssl_err)) != 0)
1448		{
1449		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1450			"Error converting ASN.1 ticket to krb5_ticket.\n");
1451		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1452		goto err;
1453		}
1454
1455	if (! krb5_principal_compare(krb5context, krb5server,
1456						  krb5ticket->server))  {
1457		krb5rc = KRB5_PRINC_NOMATCH;
1458		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1459			"server principal != ticket principal\n");
1460		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1461		goto err;
1462		}
1463	if ((krb5rc = krb5_kt_get_entry(krb5context, krb5keytab,
1464			krb5ticket->server, krb5ticket->enc_part.kvno,
1465			krb5ticket->enc_part.enctype, &kt_entry)) != 0)  {
1466		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1467			"krb5_kt_get_entry() fails with %x.\n", krb5rc);
1468		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1469		goto err;
1470		}
1471	if ((krb5rc = krb5_decrypt_tkt_part(krb5context, &kt_entry.key,
1472			krb5ticket)) != 0)  {
1473		BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1474			"krb5_decrypt_tkt_part() failed.\n");
1475		kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1476		goto err;
1477		}
1478	else  {
1479		krb5_kt_free_entry(krb5context, &kt_entry);
1480#ifdef KSSL_DEBUG
1481		{
1482		int i; krb5_address **paddr = krb5ticket->enc_part2->caddrs;
1483		printf("Decrypted ticket fields:\n");
1484		printf("\tflags: %X, transit-type: %X",
1485			krb5ticket->enc_part2->flags,
1486			krb5ticket->enc_part2->transited.tr_type);
1487		print_krb5_data("\ttransit-data: ",
1488			&(krb5ticket->enc_part2->transited.tr_contents));
1489		printf("\tcaddrs: %p, authdata: %p\n",
1490			krb5ticket->enc_part2->caddrs,
1491			krb5ticket->enc_part2->authorization_data);
1492		if (paddr)
1493			{
1494			printf("\tcaddrs:\n");
1495			for (i=0; paddr[i] != NULL; i++)
1496				{
1497				krb5_data d;
1498				d.length=paddr[i]->length;
1499				d.data=paddr[i]->contents;
1500				print_krb5_data("\t\tIP: ", &d);
1501				}
1502			}
1503		printf("\tstart/auth/end times: %d / %d / %d\n",
1504			krb5ticket->enc_part2->times.starttime,
1505			krb5ticket->enc_part2->times.authtime,
1506			krb5ticket->enc_part2->times.endtime);
1507		}
1508#endif	/* KSSL_DEBUG */
1509		}
1510
1511	krb5rc = KRB5_NO_TKT_SUPPLIED;
1512	if (!krb5ticket  ||	!krb5ticket->enc_part2  ||
1513                !krb5ticket->enc_part2->client  ||
1514                !krb5ticket->enc_part2->client->data  ||
1515                !krb5ticket->enc_part2->session)
1516                {
1517                kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
1518                        "bad ticket from krb5_rd_req.\n");
1519		}
1520	else if (kssl_ctx_setprinc(kssl_ctx, KSSL_CLIENT,
1521		 &krb5ticket->enc_part2->client->realm,
1522		 krb5ticket->enc_part2->client->data,
1523		 krb5ticket->enc_part2->client->length))
1524                {
1525		kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
1526                        "kssl_ctx_setprinc() fails.\n");
1527		}
1528	else if (kssl_ctx_setkey(kssl_ctx, krb5ticket->enc_part2->session))
1529                {
1530		kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
1531                        "kssl_ctx_setkey() fails.\n");
1532		}
1533	else if (krb5ticket->enc_part2->flags & TKT_FLG_INVALID)
1534                {
1535		krb5rc = KRB5KRB_AP_ERR_TKT_INVALID;
1536                kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
1537                        "invalid ticket from krb5_rd_req.\n");
1538		}
1539	else	krb5rc = 0;
1540
1541	kssl_ctx->enctype	= krb5ticket->enc_part.enctype;
1542	ttimes->authtime	= krb5ticket->enc_part2->times.authtime;
1543	ttimes->starttime	= krb5ticket->enc_part2->times.starttime;
1544	ttimes->endtime 	= krb5ticket->enc_part2->times.endtime;
1545	ttimes->renew_till	= krb5ticket->enc_part2->times.renew_till;
1546
1547 err:
1548#ifdef KSSL_DEBUG
1549	kssl_ctx_show(kssl_ctx);
1550#endif	/* KSSL_DEBUG */
1551
1552	if (asn1ticket) 	KRB5_TICKET_free((KRB5_TICKET *) asn1ticket);
1553        if (krb5keytab)         krb5_kt_close(krb5context, krb5keytab);
1554	if (krb5ticket) 	krb5_free_ticket(krb5context, krb5ticket);
1555	if (krb5server) 	krb5_free_principal(krb5context, krb5server);
1556	return (krb5rc);
1557        }
1558
1559
1560/*	Allocate & return a new kssl_ctx struct.
1561*/
1562KSSL_CTX	*
1563kssl_ctx_new(void)
1564        {
1565	return ((KSSL_CTX *) kssl_calloc(1, sizeof(KSSL_CTX)));
1566        }
1567
1568
1569/*	Frees a kssl_ctx struct and any allocated memory it holds.
1570**	Returns NULL.
1571*/
1572KSSL_CTX	*
1573kssl_ctx_free(KSSL_CTX *kssl_ctx)
1574        {
1575	if (kssl_ctx == NULL)  return kssl_ctx;
1576
1577	if (kssl_ctx->key)  		OPENSSL_cleanse(kssl_ctx->key,
1578							      kssl_ctx->length);
1579	if (kssl_ctx->key)  		kssl_free(kssl_ctx->key);
1580	if (kssl_ctx->client_princ) 	kssl_free(kssl_ctx->client_princ);
1581	if (kssl_ctx->service_host) 	kssl_free(kssl_ctx->service_host);
1582	if (kssl_ctx->service_name) 	kssl_free(kssl_ctx->service_name);
1583	if (kssl_ctx->keytab_file) 	kssl_free(kssl_ctx->keytab_file);
1584
1585	kssl_free(kssl_ctx);
1586	return (KSSL_CTX *) NULL;
1587        }
1588
1589
1590/*	Given an array of (krb5_data *) entity (and optional realm),
1591**	set the plain (char *) client_princ or service_host member
1592**	of the kssl_ctx struct.
1593*/
1594krb5_error_code
1595kssl_ctx_setprinc(KSSL_CTX *kssl_ctx, int which,
1596        krb5_data *realm, krb5_data *entity, int nentities)
1597        {
1598	char	**princ;
1599	int 	length;
1600	int i;
1601
1602	if (kssl_ctx == NULL  ||  entity == NULL)  return KSSL_CTX_ERR;
1603
1604	switch (which)
1605                {
1606        case KSSL_CLIENT:	princ = &kssl_ctx->client_princ;	break;
1607        case KSSL_SERVER:	princ = &kssl_ctx->service_host;	break;
1608        default:		return KSSL_CTX_ERR;			break;
1609		}
1610	if (*princ)  kssl_free(*princ);
1611
1612	/* Add up all the entity->lengths */
1613	length = 0;
1614	for (i=0; i < nentities; i++)
1615		{
1616		length += entity[i].length;
1617		}
1618	/* Add in space for the '/' character(s) (if any) */
1619	length += nentities-1;
1620	/* Space for the ('@'+realm+NULL | NULL) */
1621	length += ((realm)? realm->length + 2: 1);
1622
1623	if ((*princ = kssl_calloc(1, length)) == NULL)
1624		return KSSL_CTX_ERR;
1625	else
1626		{
1627		for (i = 0; i < nentities; i++)
1628			{
1629			strncat(*princ, entity[i].data, entity[i].length);
1630			if (i < nentities-1)
1631				{
1632				strcat (*princ, "/");
1633				}
1634			}
1635		if (realm)
1636                        {
1637			strcat (*princ, "@");
1638			(void) strncat(*princ, realm->data, realm->length);
1639			}
1640		}
1641
1642	return KSSL_CTX_OK;
1643        }
1644
1645
1646/*	Set one of the plain (char *) string members of the kssl_ctx struct.
1647**	Default values should be:
1648**		which == KSSL_SERVICE	=>	"khost" (KRB5SVC)
1649**		which == KSSL_KEYTAB	=>	"/etc/krb5.keytab" (KRB5KEYTAB)
1650*/
1651krb5_error_code
1652kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text)
1653        {
1654	char	**string;
1655
1656	if (!kssl_ctx)  return KSSL_CTX_ERR;
1657
1658	switch (which)
1659                {
1660        case KSSL_SERVICE:	string = &kssl_ctx->service_name;	break;
1661        case KSSL_SERVER:	string = &kssl_ctx->service_host;	break;
1662        case KSSL_CLIENT:	string = &kssl_ctx->client_princ;	break;
1663        case KSSL_KEYTAB:	string = &kssl_ctx->keytab_file;	break;
1664        default:		return KSSL_CTX_ERR;			break;
1665		}
1666	if (*string)  kssl_free(*string);
1667
1668	if (!text)
1669                {
1670		*string = '\0';
1671		return KSSL_CTX_OK;
1672		}
1673
1674	if ((*string = kssl_calloc(1, strlen(text) + 1)) == NULL)
1675		return KSSL_CTX_ERR;
1676	else
1677		strcpy(*string, text);
1678
1679	return KSSL_CTX_OK;
1680        }
1681
1682
1683/*	Copy the Kerberos session key from a (krb5_keyblock *) to a kssl_ctx
1684**	struct.  Clear kssl_ctx->key if Kerberos session key is NULL.
1685*/
1686krb5_error_code
1687kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session)
1688        {
1689	int 		length;
1690	krb5_enctype	enctype;
1691	krb5_octet FAR	*contents = NULL;
1692
1693	if (!kssl_ctx)  return KSSL_CTX_ERR;
1694
1695	if (kssl_ctx->key)
1696                {
1697		OPENSSL_cleanse(kssl_ctx->key, kssl_ctx->length);
1698		kssl_free(kssl_ctx->key);
1699		}
1700
1701	if (session)
1702                {
1703
1704#ifdef KRB5_HEIMDAL
1705		length = session->keyvalue->length;
1706		enctype = session->keytype;
1707		contents = session->keyvalue->contents;
1708#else
1709		length = session->length;
1710		enctype = session->enctype;
1711		contents = session->contents;
1712#endif
1713		kssl_ctx->enctype = enctype;
1714		kssl_ctx->length  = length;
1715		}
1716	else
1717                {
1718		kssl_ctx->enctype = ENCTYPE_UNKNOWN;
1719		kssl_ctx->length  = 0;
1720		return KSSL_CTX_OK;
1721		}
1722
1723	if ((kssl_ctx->key =
1724                (krb5_octet FAR *) kssl_calloc(1, kssl_ctx->length)) == NULL)
1725                {
1726		kssl_ctx->length  = 0;
1727		return KSSL_CTX_ERR;
1728		}
1729	else
1730		memcpy(kssl_ctx->key, contents, length);
1731
1732	return KSSL_CTX_OK;
1733        }
1734
1735
1736/*	Display contents of kssl_ctx struct
1737*/
1738void
1739kssl_ctx_show(KSSL_CTX *kssl_ctx)
1740        {
1741	int 	i;
1742
1743	printf("kssl_ctx: ");
1744	if (kssl_ctx == NULL)
1745                {
1746		printf("NULL\n");
1747		return;
1748		}
1749	else
1750		printf("%p\n", (void *)kssl_ctx);
1751
1752	printf("\tservice:\t%s\n",
1753                (kssl_ctx->service_name)? kssl_ctx->service_name: "NULL");
1754	printf("\tclient:\t%s\n",
1755                (kssl_ctx->client_princ)? kssl_ctx->client_princ: "NULL");
1756	printf("\tserver:\t%s\n",
1757                (kssl_ctx->service_host)? kssl_ctx->service_host: "NULL");
1758	printf("\tkeytab:\t%s\n",
1759                (kssl_ctx->keytab_file)? kssl_ctx->keytab_file: "NULL");
1760	printf("\tkey [%d:%d]:\t",
1761                kssl_ctx->enctype, kssl_ctx->length);
1762
1763	for (i=0; i < kssl_ctx->length  &&  kssl_ctx->key; i++)
1764                {
1765		printf("%02x", kssl_ctx->key[i]);
1766		}
1767	printf("\n");
1768	return;
1769        }
1770
1771    int
1772    kssl_keytab_is_available(KSSL_CTX *kssl_ctx)
1773{
1774    krb5_context		krb5context = NULL;
1775    krb5_keytab 		krb5keytab = NULL;
1776    krb5_keytab_entry           entry;
1777    krb5_principal              princ = NULL;
1778    krb5_error_code  		krb5rc = KRB5KRB_ERR_GENERIC;
1779    int rc = 0;
1780
1781    if ((krb5rc = krb5_init_context(&krb5context)))
1782        return(0);
1783
1784    /*	kssl_ctx->keytab_file == NULL ==> use Kerberos default
1785    */
1786    if (kssl_ctx->keytab_file)
1787    {
1788        krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file,
1789                                  &krb5keytab);
1790        if (krb5rc)
1791            goto exit;
1792    }
1793    else
1794    {
1795        krb5rc = krb5_kt_default(krb5context,&krb5keytab);
1796        if (krb5rc)
1797            goto exit;
1798    }
1799
1800    /* the host key we are looking for */
1801    krb5rc = krb5_sname_to_principal(krb5context, NULL,
1802                                     kssl_ctx->service_name ? kssl_ctx->service_name: KRB5SVC,
1803                                     KRB5_NT_SRV_HST, &princ);
1804
1805    if (krb5rc)
1806	goto exit;
1807
1808    krb5rc = krb5_kt_get_entry(krb5context, krb5keytab,
1809                                princ,
1810                                0 /* IGNORE_VNO */,
1811                                0 /* IGNORE_ENCTYPE */,
1812                                &entry);
1813    if ( krb5rc == KRB5_KT_NOTFOUND ) {
1814        rc = 1;
1815        goto exit;
1816    } else if ( krb5rc )
1817        goto exit;
1818
1819    krb5_kt_free_entry(krb5context, &entry);
1820    rc = 1;
1821
1822  exit:
1823    if (krb5keytab)     krb5_kt_close(krb5context, krb5keytab);
1824    if (princ)          krb5_free_principal(krb5context, princ);
1825    if (krb5context)	krb5_free_context(krb5context);
1826    return(rc);
1827}
1828
1829int
1830kssl_tgt_is_available(KSSL_CTX *kssl_ctx)
1831        {
1832        krb5_error_code		krb5rc = KRB5KRB_ERR_GENERIC;
1833        krb5_context		krb5context = NULL;
1834        krb5_ccache 		krb5ccdef = NULL;
1835        krb5_creds		krb5creds, *krb5credsp = NULL;
1836        int                     rc = 0;
1837
1838        memset((char *)&krb5creds, 0, sizeof(krb5creds));
1839
1840        if (!kssl_ctx)
1841            return(0);
1842
1843        if (!kssl_ctx->service_host)
1844            return(0);
1845
1846        if ((krb5rc = krb5_init_context(&krb5context)) != 0)
1847            goto err;
1848
1849        if ((krb5rc = krb5_sname_to_principal(krb5context,
1850                                              kssl_ctx->service_host,
1851                                              (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC,
1852                                              KRB5_NT_SRV_HST, &krb5creds.server)) != 0)
1853            goto err;
1854
1855        if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0)
1856            goto err;
1857
1858        if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef,
1859                                             &krb5creds.client)) != 0)
1860            goto err;
1861
1862        if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef,
1863                                            &krb5creds, &krb5credsp)) != 0)
1864            goto err;
1865
1866        rc = 1;
1867
1868      err:
1869#ifdef KSSL_DEBUG
1870	kssl_ctx_show(kssl_ctx);
1871#endif	/* KSSL_DEBUG */
1872
1873	if (krb5creds.client)	krb5_free_principal(krb5context, krb5creds.client);
1874	if (krb5creds.server)	krb5_free_principal(krb5context, krb5creds.server);
1875	if (krb5context)	krb5_free_context(krb5context);
1876        return(rc);
1877	}
1878
1879#if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_WIN32)
1880void kssl_krb5_free_data_contents(krb5_context context, krb5_data *data)
1881	{
1882#ifdef KRB5_HEIMDAL
1883	data->length = 0;
1884        if (data->data)
1885            free(data->data);
1886#elif defined(KRB5_MIT_OLD11)
1887	if (data->data)  {
1888		krb5_xfree(data->data);
1889		data->data = 0;
1890		}
1891#else
1892	krb5_free_data_contents(NULL, data);
1893#endif
1894	}
1895#endif /* !OPENSSL_SYS_WINDOWS && !OPENSSL_SYS_WIN32 */
1896
1897
1898/*  Given pointers to KerberosTime and struct tm structs, convert the
1899**  KerberosTime string to struct tm.  Note that KerberosTime is a
1900**  ASN1_GENERALIZEDTIME value, constrained to GMT with no fractional
1901**  seconds as defined in RFC 1510.
1902**  Return pointer to the (partially) filled in struct tm on success,
1903**  return NULL on failure.
1904*/
1905struct tm	*k_gmtime(ASN1_GENERALIZEDTIME *gtime, struct tm *k_tm)
1906	{
1907	char 		c, *p;
1908
1909	if (!k_tm)  return NULL;
1910	if (gtime == NULL  ||  gtime->length < 14)  return NULL;
1911	if (gtime->data == NULL)  return NULL;
1912
1913	p = (char *)&gtime->data[14];
1914
1915	c = *p;	 *p = '\0';  p -= 2;  k_tm->tm_sec  = atoi(p);      *(p+2) = c;
1916	c = *p;	 *p = '\0';  p -= 2;  k_tm->tm_min  = atoi(p);      *(p+2) = c;
1917	c = *p;	 *p = '\0';  p -= 2;  k_tm->tm_hour = atoi(p);      *(p+2) = c;
1918	c = *p;	 *p = '\0';  p -= 2;  k_tm->tm_mday = atoi(p);      *(p+2) = c;
1919	c = *p;	 *p = '\0';  p -= 2;  k_tm->tm_mon  = atoi(p)-1;    *(p+2) = c;
1920	c = *p;	 *p = '\0';  p -= 4;  k_tm->tm_year = atoi(p)-1900; *(p+4) = c;
1921
1922	return k_tm;
1923	}
1924
1925
1926/*  Helper function for kssl_validate_times().
1927**  We need context->clockskew, but krb5_context is an opaque struct.
1928**  So we try to sneek the clockskew out through the replay cache.
1929**	If that fails just return a likely default (300 seconds).
1930*/
1931krb5_deltat	get_rc_clockskew(krb5_context context)
1932	{
1933	krb5_rcache 	rc;
1934	krb5_deltat 	clockskew;
1935
1936	if (krb5_rc_default(context, &rc))  return KSSL_CLOCKSKEW;
1937	if (krb5_rc_initialize(context, rc, 0))  return KSSL_CLOCKSKEW;
1938	if (krb5_rc_get_lifespan(context, rc, &clockskew))  {
1939		clockskew = KSSL_CLOCKSKEW;
1940		}
1941	(void) krb5_rc_destroy(context, rc);
1942	return clockskew;
1943	}
1944
1945
1946/*  kssl_validate_times() combines (and more importantly exposes)
1947**  the MIT KRB5 internal function krb5_validate_times() and the
1948**  in_clock_skew() macro.  The authenticator client time is checked
1949**  to be within clockskew secs of the current time and the current
1950**  time is checked to be within the ticket start and expire times.
1951**  Either check may be omitted by supplying a NULL value.
1952**  Returns 0 for valid times, SSL_R_KRB5* error codes otherwise.
1953**  See Also: (Kerberos source)/krb5/lib/krb5/krb/valid_times.c
1954**  20010420 VRS
1955*/
1956krb5_error_code  kssl_validate_times(	krb5_timestamp atime,
1957					krb5_ticket_times *ttimes)
1958	{
1959	krb5_deltat 	skew;
1960	krb5_timestamp	start, now;
1961	krb5_error_code	rc;
1962	krb5_context	context;
1963
1964	if ((rc = krb5_init_context(&context)))	 return SSL_R_KRB5_S_BAD_TICKET;
1965	skew = get_rc_clockskew(context);
1966	if ((rc = krb5_timeofday(context,&now))) return SSL_R_KRB5_S_BAD_TICKET;
1967	krb5_free_context(context);
1968
1969	if (atime  &&  labs(atime - now) >= skew)  return SSL_R_KRB5_S_TKT_SKEW;
1970
1971	if (! ttimes)  return 0;
1972
1973	start = (ttimes->starttime != 0)? ttimes->starttime: ttimes->authtime;
1974	if (start - now > skew)  return SSL_R_KRB5_S_TKT_NYV;
1975	if ((now - ttimes->endtime) > skew)  return SSL_R_KRB5_S_TKT_EXPIRED;
1976
1977#ifdef KSSL_DEBUG
1978	printf("kssl_validate_times: %d |<-  | %d - %d | < %d  ->| %d\n",
1979		start, atime, now, skew, ttimes->endtime);
1980#endif	/* KSSL_DEBUG */
1981
1982	return 0;
1983	}
1984
1985
1986/*  Decode and decrypt given DER-encoded authenticator, then pass
1987**  authenticator ctime back in *atimep (or 0 if time unavailable).
1988**  Returns krb5_error_code and kssl_err on error.  A NULL
1989**  authenticator (authentp->length == 0) is not considered an error.
1990**  Note that kssl_check_authent() makes use of the KRB5 session key;
1991**  you must call kssl_sget_tkt() to get the key before calling this routine.
1992*/
1993krb5_error_code  kssl_check_authent(
1994			/* IN     */	KSSL_CTX	*kssl_ctx,
1995                        /* IN     */   	krb5_data	*authentp,
1996			/* OUT    */	krb5_timestamp	*atimep,
1997			/* OUT    */    KSSL_ERR	*kssl_err  )
1998	{
1999        krb5_error_code		krb5rc = 0;
2000	KRB5_ENCDATA		*dec_authent = NULL;
2001	KRB5_AUTHENTBODY	*auth = NULL;
2002	krb5_enctype		enctype;
2003	EVP_CIPHER_CTX		ciph_ctx;
2004	const EVP_CIPHER	*enc = NULL;
2005	unsigned char		iv[EVP_MAX_IV_LENGTH];
2006	const unsigned char	*p;
2007	unsigned char		*unenc_authent;
2008	int 			outl, unencbufsize;
2009	struct tm		tm_time, *tm_l, *tm_g;
2010	time_t			now, tl, tg, tr, tz_offset;
2011
2012	EVP_CIPHER_CTX_init(&ciph_ctx);
2013	*atimep = 0;
2014	kssl_err_set(kssl_err, 0, "");
2015
2016#ifndef KRB5CHECKAUTH
2017	authentp = NULL;
2018#else
2019#if	KRB5CHECKAUTH == 0
2020	authentp = NULL;
2021#endif
2022#endif	/* KRB5CHECKAUTH */
2023
2024	if (authentp == NULL  ||  authentp->length == 0)  return 0;
2025
2026#ifdef KSSL_DEBUG
2027        {
2028        unsigned int ui;
2029	printf("kssl_check_authent: authenticator[%d]:\n",authentp->length);
2030	p = authentp->data;
2031	for (ui=0; ui < authentp->length; ui++)  printf("%02x ",p[ui]);
2032	printf("\n");
2033        }
2034#endif	/* KSSL_DEBUG */
2035
2036	unencbufsize = 2 * authentp->length;
2037	if ((unenc_authent = calloc(1, unencbufsize)) == NULL)
2038		{
2039		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
2040			"Unable to allocate authenticator buffer.\n");
2041		krb5rc = KRB5KRB_ERR_GENERIC;
2042		goto err;
2043		}
2044
2045	p = (unsigned char *)authentp->data;
2046	if ((dec_authent = d2i_KRB5_ENCDATA(NULL, &p,
2047					(long) authentp->length)) == NULL)
2048		{
2049		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
2050                        "Error decoding authenticator.\n");
2051		krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2052		goto err;
2053		}
2054
2055	enctype = dec_authent->etype->data[0];	/* should = kssl_ctx->enctype */
2056#if !defined(KRB5_MIT_OLD11)
2057            switch ( enctype ) {
2058            case ENCTYPE_DES3_CBC_SHA1:		/*    EVP_des_ede3_cbc();  */
2059            case ENCTYPE_DES3_CBC_SHA:
2060            case ENCTYPE_DES3_CBC_RAW:
2061                krb5rc = 0;                     /* Skip, can't handle derived keys */
2062                goto err;
2063            }
2064#endif
2065	enc = kssl_map_enc(enctype);
2066	memset(iv, 0, sizeof iv);       /* per RFC 1510 */
2067
2068	if (enc == NULL)
2069		{
2070		/*  Disable kssl_check_authent for ENCTYPE_DES3_CBC_SHA1.
2071		**  This enctype indicates the authenticator was encrypted
2072		**  using key-usage derived keys which openssl cannot decrypt.
2073		*/
2074		goto err;
2075		}
2076
2077        if (!EVP_CipherInit(&ciph_ctx,enc,kssl_ctx->key,iv,0))
2078                {
2079                kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
2080                        "EVP_CipherInit error decrypting authenticator.\n");
2081                krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2082                goto err;
2083                }
2084        outl = dec_authent->cipher->length;
2085        if (!EVP_Cipher(&ciph_ctx,unenc_authent,dec_authent->cipher->data,outl))
2086                {
2087                kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
2088                        "EVP_Cipher error decrypting authenticator.\n");
2089                krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2090                goto err;
2091                }
2092        EVP_CIPHER_CTX_cleanup(&ciph_ctx);
2093
2094#ifdef KSSL_DEBUG
2095	printf("kssl_check_authent: decrypted authenticator[%d] =\n", outl);
2096	for (padl=0; padl < outl; padl++) printf("%02x ",unenc_authent[padl]);
2097	printf("\n");
2098#endif	/* KSSL_DEBUG */
2099
2100	if ((p = kssl_skip_confound(enctype, unenc_authent)) == NULL)
2101		{
2102		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
2103                        "confounded by authenticator.\n");
2104		krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2105		goto err;
2106		}
2107	outl -= p - unenc_authent;
2108
2109	if ((auth = (KRB5_AUTHENTBODY *) d2i_KRB5_AUTHENT(NULL, &p,
2110							  (long) outl))==NULL)
2111		{
2112		kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
2113                        "Error decoding authenticator body.\n");
2114		krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2115		goto err;
2116		}
2117
2118	memset(&tm_time,0,sizeof(struct tm));
2119	if (k_gmtime(auth->ctime, &tm_time)  &&
2120		((tr = mktime(&tm_time)) != (time_t)(-1)))
2121 		{
2122 		now  = time(&now);
2123 		tm_l = localtime(&now); 	tl = mktime(tm_l);
2124 		tm_g = gmtime(&now);		tg = mktime(tm_g);
2125 		tz_offset = tg - tl;
2126
2127		*atimep = tr - tz_offset;
2128 		}
2129
2130#ifdef KSSL_DEBUG
2131	printf("kssl_check_authent: returns %d for client time ", *atimep);
2132	if (auth && auth->ctime && auth->ctime->length && auth->ctime->data)
2133		printf("%.*s\n", auth->ctime->length, auth->ctime->data);
2134	else	printf("NULL\n");
2135#endif	/* KSSL_DEBUG */
2136
2137 err:
2138	if (auth)		KRB5_AUTHENT_free((KRB5_AUTHENT *) auth);
2139	if (dec_authent)	KRB5_ENCDATA_free(dec_authent);
2140	if (unenc_authent)	free(unenc_authent);
2141	EVP_CIPHER_CTX_cleanup(&ciph_ctx);
2142	return krb5rc;
2143	}
2144
2145
2146/*  Replaces krb5_build_principal_ext(), with varargs length == 2 (svc, host),
2147**  because I dont't know how to stub varargs.
2148**  Returns krb5_error_code == ENOMEM on alloc error, otherwise
2149**  passes back newly constructed principal, which should be freed by caller.
2150*/
2151krb5_error_code  kssl_build_principal_2(
2152			/* UPDATE */	krb5_context	context,
2153			/* OUT    */	krb5_principal	*princ,
2154			/* IN     */	int rlen,  const char *realm,
2155			/* IN	  */	int slen,  const char *svc,
2156			/* IN	  */	int hlen,  const char *host)
2157	{
2158	krb5_data		*p_data = NULL;
2159	krb5_principal		new_p = NULL;
2160        char			*new_r = NULL;
2161
2162	if ((p_data = (krb5_data *) calloc(2, sizeof(krb5_data))) == NULL  ||
2163	    (new_p = (krb5_principal) calloc(1, sizeof(krb5_principal_data)))
2164			== NULL)  goto err;
2165	new_p->length = 2;
2166	new_p->data = p_data;
2167
2168	if ((new_r = calloc(1, rlen + 1)) == NULL)  goto err;
2169	memcpy(new_r, realm, rlen);
2170	krb5_princ_set_realm_length(context, new_p, rlen);
2171	krb5_princ_set_realm_data(context, new_p, new_r);
2172
2173	if ((new_p->data[0].data = calloc(1, slen + 1)) == NULL)  goto err;
2174	memcpy(new_p->data[0].data, svc, slen);
2175	new_p->data[0].length = slen;
2176
2177	if ((new_p->data[1].data = calloc(1, hlen + 1)) == NULL)  goto err;
2178	memcpy(new_p->data[1].data, host, hlen);
2179	new_p->data[1].length = hlen;
2180
2181	krb5_princ_type(context, new_p) = KRB5_NT_UNKNOWN;
2182	*princ = new_p;
2183	return 0;
2184
2185 err:
2186	if (new_p  &&  new_p[0].data)	free(new_p[0].data);
2187	if (new_p  &&  new_p[1].data)	free(new_p[1].data);
2188	if (new_p)	free(new_p);
2189	if (new_r)	free(new_r);
2190	return ENOMEM;
2191	}
2192
2193
2194#else /* !OPENSSL_NO_KRB5 */
2195
2196#if defined(PEDANTIC) || defined(OPENSSL_SYS_VMS)
2197static void *dummy=&dummy;
2198#endif
2199
2200#endif	/* !OPENSSL_NO_KRB5	*/
2201
2202