1295016Sjkim/* ssl/kssl.c */
2280304Sjkim/*
3280304Sjkim * Written by Vern Staats <staatsvr@asc.hpc.mil> for the OpenSSL project
4280304Sjkim * 2000.
5109998Smarkm */
6109998Smarkm/* ====================================================================
7109998Smarkm * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
8109998Smarkm *
9109998Smarkm * Redistribution and use in source and binary forms, with or without
10109998Smarkm * modification, are permitted provided that the following conditions
11109998Smarkm * are met:
12109998Smarkm *
13109998Smarkm * 1. Redistributions of source code must retain the above copyright
14280304Sjkim *    notice, this list of conditions and the following disclaimer.
15109998Smarkm *
16109998Smarkm * 2. Redistributions in binary form must reproduce the above copyright
17109998Smarkm *    notice, this list of conditions and the following disclaimer in
18109998Smarkm *    the documentation and/or other materials provided with the
19109998Smarkm *    distribution.
20109998Smarkm *
21109998Smarkm * 3. All advertising materials mentioning features or use of this
22109998Smarkm *    software must display the following acknowledgment:
23109998Smarkm *    "This product includes software developed by the OpenSSL Project
24109998Smarkm *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25109998Smarkm *
26109998Smarkm * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27109998Smarkm *    endorse or promote products derived from this software without
28109998Smarkm *    prior written permission. For written permission, please contact
29109998Smarkm *    licensing@OpenSSL.org.
30109998Smarkm *
31109998Smarkm * 5. Products derived from this software may not be called "OpenSSL"
32109998Smarkm *    nor may "OpenSSL" appear in their names without prior written
33109998Smarkm *    permission of the OpenSSL Project.
34109998Smarkm *
35109998Smarkm * 6. Redistributions of any form whatsoever must retain the following
36109998Smarkm *    acknowledgment:
37109998Smarkm *    "This product includes software developed by the OpenSSL Project
38109998Smarkm *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39109998Smarkm *
40109998Smarkm * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41109998Smarkm * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42109998Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43109998Smarkm * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
44109998Smarkm * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45109998Smarkm * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46109998Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47109998Smarkm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48109998Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49109998Smarkm * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50109998Smarkm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51109998Smarkm * OF THE POSSIBILITY OF SUCH DAMAGE.
52109998Smarkm * ====================================================================
53109998Smarkm *
54109998Smarkm * This product includes cryptographic software written by Eric Young
55109998Smarkm * (eay@cryptsoft.com).  This product includes software written by Tim
56109998Smarkm * Hudson (tjh@cryptsoft.com).
57109998Smarkm *
58109998Smarkm */
59109998Smarkm
60280304Sjkim/*-
61280304Sjkim * ssl/kssl.c  --  Routines to support (& debug) Kerberos5 auth for openssl
62280304Sjkim *
63280304Sjkim *  19990701    VRS     Started.
64280304Sjkim *  200011??    Jeffrey Altman, Richard Levitte
65280304Sjkim *                      Generalized for Heimdal, Newer MIT, & Win32.
66280304Sjkim *                      Integrated into main OpenSSL 0.9.7 snapshots.
67280304Sjkim *  20010413    Simon Wilkinson, VRS
68280304Sjkim *                      Real RFC2712 KerberosWrapper replaces AP_REQ.
69280304Sjkim */
70109998Smarkm
71109998Smarkm#include <openssl/opensslconf.h>
72109998Smarkm
73109998Smarkm#include <string.h>
74109998Smarkm
75280304Sjkim#define KRB5_PRIVATE    1
76160814Ssimon
77109998Smarkm#include <openssl/ssl.h>
78109998Smarkm#include <openssl/evp.h>
79109998Smarkm#include <openssl/objects.h>
80109998Smarkm#include <openssl/krb5_asn.h>
81238405Sjkim#include "kssl_lcl.h"
82109998Smarkm
83109998Smarkm#ifndef OPENSSL_NO_KRB5
84109998Smarkm
85280304Sjkim# ifndef ENOMEM
86280304Sjkim#  define ENOMEM KRB5KRB_ERR_GENERIC
87280304Sjkim# endif
88160814Ssimon
89280304Sjkim/*
90109998Smarkm * When OpenSSL is built on Windows, we do not want to require that
91109998Smarkm * the Kerberos DLLs be available in order for the OpenSSL DLLs to
92109998Smarkm * work.  Therefore, all Kerberos routines are loaded at run time
93109998Smarkm * and we do not link to a .LIB file.
94109998Smarkm */
95109998Smarkm
96280304Sjkim# if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
97280304Sjkim/*
98109998Smarkm * The purpose of the following pre-processor statements is to provide
99109998Smarkm * compatibility with different releases of MIT Kerberos for Windows.
100109998Smarkm * All versions up to 1.2 used macros.  But macros do not allow for
101109998Smarkm * a binary compatible interface for DLLs.  Therefore, all macros are
102109998Smarkm * being replaced by function calls.  The following code will allow
103109998Smarkm * an OpenSSL DLL built on Windows to work whether or not the macro
104109998Smarkm * or function form of the routines are utilized.
105109998Smarkm */
106280304Sjkim#  ifdef  krb5_cc_get_principal
107280304Sjkim#   define NO_DEF_KRB5_CCACHE
108280304Sjkim#   undef  krb5_cc_get_principal
109280304Sjkim#  endif
110280304Sjkim#  define krb5_cc_get_principal    kssl_krb5_cc_get_principal
111109998Smarkm
112280304Sjkim#  define krb5_free_data_contents  kssl_krb5_free_data_contents
113280304Sjkim#  define krb5_free_context        kssl_krb5_free_context
114280304Sjkim#  define krb5_auth_con_free       kssl_krb5_auth_con_free
115280304Sjkim#  define krb5_free_principal      kssl_krb5_free_principal
116280304Sjkim#  define krb5_mk_req_extended     kssl_krb5_mk_req_extended
117280304Sjkim#  define krb5_get_credentials     kssl_krb5_get_credentials
118280304Sjkim#  define krb5_cc_default          kssl_krb5_cc_default
119280304Sjkim#  define krb5_sname_to_principal  kssl_krb5_sname_to_principal
120280304Sjkim#  define krb5_init_context        kssl_krb5_init_context
121280304Sjkim#  define krb5_free_ticket         kssl_krb5_free_ticket
122280304Sjkim#  define krb5_rd_req              kssl_krb5_rd_req
123280304Sjkim#  define krb5_kt_default          kssl_krb5_kt_default
124280304Sjkim#  define krb5_kt_resolve          kssl_krb5_kt_resolve
125109998Smarkm/* macros in mit 1.2.2 and earlier; functions in mit 1.2.3 and greater */
126280304Sjkim#  ifndef krb5_kt_close
127280304Sjkim#   define krb5_kt_close            kssl_krb5_kt_close
128280304Sjkim#  endif                        /* krb5_kt_close */
129280304Sjkim#  ifndef krb5_kt_get_entry
130280304Sjkim#   define krb5_kt_get_entry        kssl_krb5_kt_get_entry
131280304Sjkim#  endif                        /* krb5_kt_get_entry */
132280304Sjkim#  define krb5_auth_con_init       kssl_krb5_auth_con_init
133109998Smarkm
134280304Sjkim#  define krb5_principal_compare   kssl_krb5_principal_compare
135280304Sjkim#  define krb5_decrypt_tkt_part    kssl_krb5_decrypt_tkt_part
136280304Sjkim#  define krb5_timeofday           kssl_krb5_timeofday
137280304Sjkim#  define krb5_rc_default          kssl_krb5_rc_default
138109998Smarkm
139280304Sjkim#  ifdef krb5_rc_initialize
140280304Sjkim#   undef krb5_rc_initialize
141280304Sjkim#  endif
142280304Sjkim#  define krb5_rc_initialize   kssl_krb5_rc_initialize
143109998Smarkm
144280304Sjkim#  ifdef krb5_rc_get_lifespan
145280304Sjkim#   undef krb5_rc_get_lifespan
146280304Sjkim#  endif
147280304Sjkim#  define krb5_rc_get_lifespan kssl_krb5_rc_get_lifespan
148109998Smarkm
149280304Sjkim#  ifdef krb5_rc_destroy
150280304Sjkim#   undef krb5_rc_destroy
151280304Sjkim#  endif
152280304Sjkim#  define krb5_rc_destroy      kssl_krb5_rc_destroy
153109998Smarkm
154280304Sjkim#  define valid_cksumtype      kssl_valid_cksumtype
155280304Sjkim#  define krb5_checksum_size   kssl_krb5_checksum_size
156280304Sjkim#  define krb5_kt_free_entry   kssl_krb5_kt_free_entry
157280304Sjkim#  define krb5_auth_con_setrcache  kssl_krb5_auth_con_setrcache
158280304Sjkim#  define krb5_auth_con_getrcache  kssl_krb5_auth_con_getrcache
159280304Sjkim#  define krb5_get_server_rcache   kssl_krb5_get_server_rcache
160109998Smarkm
161109998Smarkm/* Prototypes for built in stubs */
162109998Smarkmvoid kssl_krb5_free_data_contents(krb5_context, krb5_data *);
163280304Sjkimvoid kssl_krb5_free_principal(krb5_context, krb5_principal);
164109998Smarkmkrb5_error_code kssl_krb5_kt_resolve(krb5_context,
165280304Sjkim                                     krb5_const char *, krb5_keytab *);
166280304Sjkimkrb5_error_code kssl_krb5_kt_default(krb5_context, krb5_keytab *);
167109998Smarkmkrb5_error_code kssl_krb5_free_ticket(krb5_context, krb5_ticket *);
168280304Sjkimkrb5_error_code kssl_krb5_rd_req(krb5_context, krb5_auth_context *,
169109998Smarkm                                 krb5_const krb5_data *,
170280304Sjkim                                 krb5_const_principal, krb5_keytab,
171280304Sjkim                                 krb5_flags *, krb5_ticket **);
172109998Smarkm
173109998Smarkmkrb5_boolean kssl_krb5_principal_compare(krb5_context, krb5_const_principal,
174109998Smarkm                                         krb5_const_principal);
175109998Smarkmkrb5_error_code kssl_krb5_mk_req_extended(krb5_context,
176280304Sjkim                                          krb5_auth_context *,
177109998Smarkm                                          krb5_const krb5_flags,
178280304Sjkim                                          krb5_data *,
179280304Sjkim                                          krb5_creds *, krb5_data *);
180109998Smarkmkrb5_error_code kssl_krb5_init_context(krb5_context *);
181109998Smarkmvoid kssl_krb5_free_context(krb5_context);
182280304Sjkimkrb5_error_code kssl_krb5_cc_default(krb5_context, krb5_ccache *);
183109998Smarkmkrb5_error_code kssl_krb5_sname_to_principal(krb5_context,
184280304Sjkim                                             krb5_const char *,
185280304Sjkim                                             krb5_const char *,
186280304Sjkim                                             krb5_int32, krb5_principal *);
187109998Smarkmkrb5_error_code kssl_krb5_get_credentials(krb5_context,
188109998Smarkm                                          krb5_const krb5_flags,
189109998Smarkm                                          krb5_ccache,
190280304Sjkim                                          krb5_creds *, krb5_creds * *);
191280304Sjkimkrb5_error_code kssl_krb5_auth_con_init(krb5_context, krb5_auth_context *);
192280304Sjkimkrb5_error_code kssl_krb5_cc_get_principal(krb5_context context,
193109998Smarkm                                           krb5_ccache cache,
194109998Smarkm                                           krb5_principal *principal);
195280304Sjkimkrb5_error_code kssl_krb5_auth_con_free(krb5_context, krb5_auth_context);
196280304Sjkimsize_t kssl_krb5_checksum_size(krb5_context context, krb5_cksumtype ctype);
197109998Smarkmkrb5_boolean kssl_valid_cksumtype(krb5_cksumtype ctype);
198280304Sjkimkrb5_error_code krb5_kt_free_entry(krb5_context, krb5_keytab_entry FAR *);
199280304Sjkimkrb5_error_code kssl_krb5_auth_con_setrcache(krb5_context,
200280304Sjkim                                             krb5_auth_context, krb5_rcache);
201280304Sjkimkrb5_error_code kssl_krb5_get_server_rcache(krb5_context,
202109998Smarkm                                            krb5_const krb5_data *,
203109998Smarkm                                            krb5_rcache *);
204280304Sjkimkrb5_error_code kssl_krb5_auth_con_getrcache(krb5_context,
205109998Smarkm                                             krb5_auth_context,
206109998Smarkm                                             krb5_rcache *);
207109998Smarkm
208109998Smarkm/* Function pointers (almost all Kerberos functions are _stdcall) */
209280304Sjkimstatic void (_stdcall *p_krb5_free_data_contents) (krb5_context, krb5_data *)
210280304Sjkim    = NULL;
211280304Sjkimstatic void (_stdcall *p_krb5_free_principal) (krb5_context, krb5_principal)
212280304Sjkim    = NULL;
213109998Smarkmstatic krb5_error_code(_stdcall *p_krb5_kt_resolve)
214280304Sjkim (krb5_context, krb5_const char *, krb5_keytab *) = NULL;
215280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_kt_default) (krb5_context,
216280304Sjkim                                                     krb5_keytab *) = NULL;
217280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_free_ticket) (krb5_context,
218280304Sjkim                                                      krb5_ticket *) = NULL;
219280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_rd_req) (krb5_context,
220280304Sjkim                                                 krb5_auth_context *,
221109998Smarkm                                                 krb5_const krb5_data *,
222280304Sjkim                                                 krb5_const_principal,
223109998Smarkm                                                 krb5_keytab, krb5_flags *,
224280304Sjkim                                                 krb5_ticket **) = NULL;
225280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_mk_req_extended)
226280304Sjkim (krb5_context, krb5_auth_context *,
227280304Sjkim  krb5_const krb5_flags, krb5_data *, krb5_creds *, krb5_data *) = NULL;
228280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_init_context) (krb5_context *) = NULL;
229280304Sjkimstatic void (_stdcall *p_krb5_free_context) (krb5_context) = NULL;
230280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_cc_default) (krb5_context,
231280304Sjkim                                                     krb5_ccache *) = NULL;
232280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_sname_to_principal)
233280304Sjkim (krb5_context, krb5_const char *, krb5_const char *,
234280304Sjkim  krb5_int32, krb5_principal *) = NULL;
235280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_get_credentials)
236280304Sjkim (krb5_context, krb5_const krb5_flags, krb5_ccache,
237280304Sjkim  krb5_creds *, krb5_creds **) = NULL;
238280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_auth_con_init)
239280304Sjkim (krb5_context, krb5_auth_context *) = NULL;
240280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_cc_get_principal)
241280304Sjkim (krb5_context context, krb5_ccache cache, krb5_principal *principal) = NULL;
242280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_auth_con_free)
243280304Sjkim (krb5_context, krb5_auth_context) = NULL;
244280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_decrypt_tkt_part)
245280304Sjkim (krb5_context, krb5_const krb5_keyblock *, krb5_ticket *) = NULL;
246280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_timeofday)
247280304Sjkim (krb5_context context, krb5_int32 *timeret) = NULL;
248280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_rc_default)
249280304Sjkim (krb5_context context, krb5_rcache *rc) = NULL;
250280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_rc_initialize)
251280304Sjkim (krb5_context context, krb5_rcache rc, krb5_deltat lifespan) = NULL;
252280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_rc_get_lifespan)
253280304Sjkim (krb5_context context, krb5_rcache rc, krb5_deltat *lifespan) = NULL;
254280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_rc_destroy)
255280304Sjkim (krb5_context context, krb5_rcache rc) = NULL;
256280304Sjkimstatic krb5_boolean(_stdcall *p_krb5_principal_compare)
257280304Sjkim (krb5_context, krb5_const_principal, krb5_const_principal) = NULL;
258280304Sjkimstatic size_t (_stdcall *p_krb5_checksum_size) (krb5_context context,
259280304Sjkim                                                krb5_cksumtype ctype) = NULL;
260280304Sjkimstatic krb5_boolean(_stdcall *p_valid_cksumtype) (krb5_cksumtype ctype) =
261280304Sjkim    NULL;
262280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_kt_free_entry)
263280304Sjkim (krb5_context, krb5_keytab_entry *) = NULL;
264280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_auth_con_setrcache) (krb5_context,
265280304Sjkim                                                             krb5_auth_context,
266280304Sjkim                                                             krb5_rcache) =
267280304Sjkim    NULL;
268280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_get_server_rcache) (krb5_context,
269280304Sjkim                                                            krb5_const
270280304Sjkim                                                            krb5_data *,
271280304Sjkim                                                            krb5_rcache *) =
272280304Sjkim    NULL;
273280304Sjkimstatic krb5_error_code(*p_krb5_auth_con_getrcache) (krb5_context,
274280304Sjkim                                                    krb5_auth_context,
275280304Sjkim                                                    krb5_rcache *) = NULL;
276280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_kt_close) (krb5_context context,
277280304Sjkim                                                   krb5_keytab keytab) = NULL;
278280304Sjkimstatic krb5_error_code(_stdcall *p_krb5_kt_get_entry) (krb5_context context,
279280304Sjkim                                                       krb5_keytab keytab,
280280304Sjkim                                                       krb5_const_principal
281280304Sjkim                                                       principal,
282280304Sjkim                                                       krb5_kvno vno,
283280304Sjkim                                                       krb5_enctype enctype,
284280304Sjkim                                                       krb5_keytab_entry
285280304Sjkim                                                       *entry) = NULL;
286109998Smarkmstatic int krb5_loaded = 0;     /* only attempt to initialize func ptrs once */
287109998Smarkm
288109998Smarkm/* Function to Load the Kerberos 5 DLL and initialize function pointers */
289280304Sjkimvoid load_krb5_dll(void)
290280304Sjkim{
291280304Sjkim    HANDLE hKRB5_32;
292109998Smarkm
293280304Sjkim    krb5_loaded++;
294280304Sjkim    hKRB5_32 = LoadLibrary(TEXT("KRB5_32"));
295280304Sjkim    if (!hKRB5_32)
296280304Sjkim        return;
297109998Smarkm
298280304Sjkim    (FARPROC) p_krb5_free_data_contents =
299280304Sjkim        GetProcAddress(hKRB5_32, "krb5_free_data_contents");
300280304Sjkim    (FARPROC) p_krb5_free_context =
301280304Sjkim        GetProcAddress(hKRB5_32, "krb5_free_context");
302280304Sjkim    (FARPROC) p_krb5_auth_con_free =
303280304Sjkim        GetProcAddress(hKRB5_32, "krb5_auth_con_free");
304280304Sjkim    (FARPROC) p_krb5_free_principal =
305280304Sjkim        GetProcAddress(hKRB5_32, "krb5_free_principal");
306280304Sjkim    (FARPROC) p_krb5_mk_req_extended =
307280304Sjkim        GetProcAddress(hKRB5_32, "krb5_mk_req_extended");
308280304Sjkim    (FARPROC) p_krb5_get_credentials =
309280304Sjkim        GetProcAddress(hKRB5_32, "krb5_get_credentials");
310280304Sjkim    (FARPROC) p_krb5_cc_get_principal =
311280304Sjkim        GetProcAddress(hKRB5_32, "krb5_cc_get_principal");
312280304Sjkim    (FARPROC) p_krb5_cc_default = GetProcAddress(hKRB5_32, "krb5_cc_default");
313280304Sjkim    (FARPROC) p_krb5_sname_to_principal =
314280304Sjkim        GetProcAddress(hKRB5_32, "krb5_sname_to_principal");
315280304Sjkim    (FARPROC) p_krb5_init_context =
316280304Sjkim        GetProcAddress(hKRB5_32, "krb5_init_context");
317280304Sjkim    (FARPROC) p_krb5_free_ticket =
318280304Sjkim        GetProcAddress(hKRB5_32, "krb5_free_ticket");
319280304Sjkim    (FARPROC) p_krb5_rd_req = GetProcAddress(hKRB5_32, "krb5_rd_req");
320280304Sjkim    (FARPROC) p_krb5_principal_compare =
321280304Sjkim        GetProcAddress(hKRB5_32, "krb5_principal_compare");
322280304Sjkim    (FARPROC) p_krb5_decrypt_tkt_part =
323280304Sjkim        GetProcAddress(hKRB5_32, "krb5_decrypt_tkt_part");
324280304Sjkim    (FARPROC) p_krb5_timeofday = GetProcAddress(hKRB5_32, "krb5_timeofday");
325280304Sjkim    (FARPROC) p_krb5_rc_default = GetProcAddress(hKRB5_32, "krb5_rc_default");
326280304Sjkim    (FARPROC) p_krb5_rc_initialize =
327280304Sjkim        GetProcAddress(hKRB5_32, "krb5_rc_initialize");
328280304Sjkim    (FARPROC) p_krb5_rc_get_lifespan =
329280304Sjkim        GetProcAddress(hKRB5_32, "krb5_rc_get_lifespan");
330280304Sjkim    (FARPROC) p_krb5_rc_destroy = GetProcAddress(hKRB5_32, "krb5_rc_destroy");
331280304Sjkim    (FARPROC) p_krb5_kt_default = GetProcAddress(hKRB5_32, "krb5_kt_default");
332280304Sjkim    (FARPROC) p_krb5_kt_resolve = GetProcAddress(hKRB5_32, "krb5_kt_resolve");
333280304Sjkim    (FARPROC) p_krb5_auth_con_init =
334280304Sjkim        GetProcAddress(hKRB5_32, "krb5_auth_con_init");
335280304Sjkim    (FARPROC) p_valid_cksumtype = GetProcAddress(hKRB5_32, "valid_cksumtype");
336280304Sjkim    (FARPROC) p_krb5_checksum_size =
337280304Sjkim        GetProcAddress(hKRB5_32, "krb5_checksum_size");
338280304Sjkim    (FARPROC) p_krb5_kt_free_entry =
339280304Sjkim        GetProcAddress(hKRB5_32, "krb5_kt_free_entry");
340280304Sjkim    (FARPROC) p_krb5_auth_con_setrcache =
341280304Sjkim        GetProcAddress(hKRB5_32, "krb5_auth_con_setrcache");
342280304Sjkim    (FARPROC) p_krb5_get_server_rcache =
343280304Sjkim        GetProcAddress(hKRB5_32, "krb5_get_server_rcache");
344280304Sjkim    (FARPROC) p_krb5_auth_con_getrcache =
345280304Sjkim        GetProcAddress(hKRB5_32, "krb5_auth_con_getrcache");
346280304Sjkim    (FARPROC) p_krb5_kt_close = GetProcAddress(hKRB5_32, "krb5_kt_close");
347280304Sjkim    (FARPROC) p_krb5_kt_get_entry =
348280304Sjkim        GetProcAddress(hKRB5_32, "krb5_kt_get_entry");
349280304Sjkim}
350280304Sjkim
351109998Smarkm/* Stubs for each function to be dynamicly loaded */
352280304Sjkimvoid kssl_krb5_free_data_contents(krb5_context CO, krb5_data *data)
353280304Sjkim{
354280304Sjkim    if (!krb5_loaded)
355280304Sjkim        load_krb5_dll();
356109998Smarkm
357280304Sjkim    if (p_krb5_free_data_contents)
358280304Sjkim        p_krb5_free_data_contents(CO, data);
359280304Sjkim}
360109998Smarkm
361109998Smarkmkrb5_error_code
362280304Sjkimkssl_krb5_mk_req_extended(krb5_context CO,
363280304Sjkim                          krb5_auth_context *pACO,
364109998Smarkm                          krb5_const krb5_flags F,
365280304Sjkim                          krb5_data *pD1, krb5_creds *pC, krb5_data *pD2)
366280304Sjkim{
367280304Sjkim    if (!krb5_loaded)
368280304Sjkim        load_krb5_dll();
369109998Smarkm
370280304Sjkim    if (p_krb5_mk_req_extended)
371280304Sjkim        return (p_krb5_mk_req_extended(CO, pACO, F, pD1, pC, pD2));
372280304Sjkim    else
373280304Sjkim        return KRB5KRB_ERR_GENERIC;
374280304Sjkim}
375280304Sjkim
376109998Smarkmkrb5_error_code
377280304Sjkimkssl_krb5_auth_con_init(krb5_context CO, krb5_auth_context *pACO)
378280304Sjkim{
379280304Sjkim    if (!krb5_loaded)
380280304Sjkim        load_krb5_dll();
381109998Smarkm
382280304Sjkim    if (p_krb5_auth_con_init)
383280304Sjkim        return (p_krb5_auth_con_init(CO, pACO));
384280304Sjkim    else
385280304Sjkim        return KRB5KRB_ERR_GENERIC;
386280304Sjkim}
387280304Sjkim
388109998Smarkmkrb5_error_code
389280304Sjkimkssl_krb5_auth_con_free(krb5_context CO, krb5_auth_context ACO)
390280304Sjkim{
391280304Sjkim    if (!krb5_loaded)
392280304Sjkim        load_krb5_dll();
393109998Smarkm
394280304Sjkim    if (p_krb5_auth_con_free)
395280304Sjkim        return (p_krb5_auth_con_free(CO, ACO));
396280304Sjkim    else
397280304Sjkim        return KRB5KRB_ERR_GENERIC;
398280304Sjkim}
399280304Sjkim
400109998Smarkmkrb5_error_code
401109998Smarkmkssl_krb5_get_credentials(krb5_context CO,
402280304Sjkim                          krb5_const krb5_flags F,
403280304Sjkim                          krb5_ccache CC, krb5_creds *pCR, krb5_creds **ppCR)
404280304Sjkim{
405280304Sjkim    if (!krb5_loaded)
406280304Sjkim        load_krb5_dll();
407109998Smarkm
408280304Sjkim    if (p_krb5_get_credentials)
409280304Sjkim        return (p_krb5_get_credentials(CO, F, CC, pCR, ppCR));
410280304Sjkim    else
411280304Sjkim        return KRB5KRB_ERR_GENERIC;
412280304Sjkim}
413280304Sjkim
414109998Smarkmkrb5_error_code
415109998Smarkmkssl_krb5_sname_to_principal(krb5_context CO,
416280304Sjkim                             krb5_const char *pC1,
417280304Sjkim                             krb5_const char *pC2,
418280304Sjkim                             krb5_int32 I, krb5_principal *pPR)
419280304Sjkim{
420280304Sjkim    if (!krb5_loaded)
421280304Sjkim        load_krb5_dll();
422109998Smarkm
423280304Sjkim    if (p_krb5_sname_to_principal)
424280304Sjkim        return (p_krb5_sname_to_principal(CO, pC1, pC2, I, pPR));
425280304Sjkim    else
426280304Sjkim        return KRB5KRB_ERR_GENERIC;
427280304Sjkim}
428109998Smarkm
429280304Sjkimkrb5_error_code kssl_krb5_cc_default(krb5_context CO, krb5_ccache *pCC)
430280304Sjkim{
431280304Sjkim    if (!krb5_loaded)
432280304Sjkim        load_krb5_dll();
433109998Smarkm
434280304Sjkim    if (p_krb5_cc_default)
435280304Sjkim        return (p_krb5_cc_default(CO, pCC));
436280304Sjkim    else
437280304Sjkim        return KRB5KRB_ERR_GENERIC;
438280304Sjkim}
439109998Smarkm
440280304Sjkimkrb5_error_code kssl_krb5_init_context(krb5_context *pCO)
441280304Sjkim{
442280304Sjkim    if (!krb5_loaded)
443280304Sjkim        load_krb5_dll();
444109998Smarkm
445280304Sjkim    if (p_krb5_init_context)
446280304Sjkim        return (p_krb5_init_context(pCO));
447280304Sjkim    else
448280304Sjkim        return KRB5KRB_ERR_GENERIC;
449280304Sjkim}
450109998Smarkm
451280304Sjkimvoid kssl_krb5_free_context(krb5_context CO)
452280304Sjkim{
453280304Sjkim    if (!krb5_loaded)
454280304Sjkim        load_krb5_dll();
455109998Smarkm
456280304Sjkim    if (p_krb5_free_context)
457280304Sjkim        p_krb5_free_context(CO);
458280304Sjkim}
459109998Smarkm
460280304Sjkimvoid kssl_krb5_free_principal(krb5_context c, krb5_principal p)
461280304Sjkim{
462280304Sjkim    if (!krb5_loaded)
463280304Sjkim        load_krb5_dll();
464109998Smarkm
465280304Sjkim    if (p_krb5_free_principal)
466280304Sjkim        p_krb5_free_principal(c, p);
467280304Sjkim}
468109998Smarkm
469109998Smarkmkrb5_error_code
470280304Sjkimkssl_krb5_kt_resolve(krb5_context con, krb5_const char *sz, krb5_keytab *kt)
471280304Sjkim{
472280304Sjkim    if (!krb5_loaded)
473280304Sjkim        load_krb5_dll();
474109998Smarkm
475280304Sjkim    if (p_krb5_kt_resolve)
476280304Sjkim        return (p_krb5_kt_resolve(con, sz, kt));
477280304Sjkim    else
478280304Sjkim        return KRB5KRB_ERR_GENERIC;
479280304Sjkim}
480109998Smarkm
481280304Sjkimkrb5_error_code kssl_krb5_kt_default(krb5_context con, krb5_keytab *kt)
482280304Sjkim{
483280304Sjkim    if (!krb5_loaded)
484280304Sjkim        load_krb5_dll();
485109998Smarkm
486280304Sjkim    if (p_krb5_kt_default)
487280304Sjkim        return (p_krb5_kt_default(con, kt));
488280304Sjkim    else
489280304Sjkim        return KRB5KRB_ERR_GENERIC;
490280304Sjkim}
491109998Smarkm
492280304Sjkimkrb5_error_code kssl_krb5_free_ticket(krb5_context con, krb5_ticket *kt)
493280304Sjkim{
494280304Sjkim    if (!krb5_loaded)
495280304Sjkim        load_krb5_dll();
496109998Smarkm
497280304Sjkim    if (p_krb5_free_ticket)
498280304Sjkim        return (p_krb5_free_ticket(con, kt));
499280304Sjkim    else
500280304Sjkim        return KRB5KRB_ERR_GENERIC;
501280304Sjkim}
502109998Smarkm
503109998Smarkmkrb5_error_code
504280304Sjkimkssl_krb5_rd_req(krb5_context con, krb5_auth_context *pacon,
505280304Sjkim                 krb5_const krb5_data *data,
506280304Sjkim                 krb5_const_principal princ, krb5_keytab keytab,
507280304Sjkim                 krb5_flags *flags, krb5_ticket **pptkt)
508280304Sjkim{
509280304Sjkim    if (!krb5_loaded)
510280304Sjkim        load_krb5_dll();
511109998Smarkm
512280304Sjkim    if (p_krb5_rd_req)
513280304Sjkim        return (p_krb5_rd_req(con, pacon, data, princ, keytab, flags, pptkt));
514280304Sjkim    else
515280304Sjkim        return KRB5KRB_ERR_GENERIC;
516280304Sjkim}
517109998Smarkm
518109998Smarkmkrb5_boolean
519109998Smarkmkrb5_principal_compare(krb5_context con, krb5_const_principal princ1,
520280304Sjkim                       krb5_const_principal princ2)
521280304Sjkim{
522280304Sjkim    if (!krb5_loaded)
523280304Sjkim        load_krb5_dll();
524109998Smarkm
525280304Sjkim    if (p_krb5_principal_compare)
526280304Sjkim        return (p_krb5_principal_compare(con, princ1, princ2));
527280304Sjkim    else
528280304Sjkim        return KRB5KRB_ERR_GENERIC;
529280304Sjkim}
530109998Smarkm
531109998Smarkmkrb5_error_code
532109998Smarkmkrb5_decrypt_tkt_part(krb5_context con, krb5_const krb5_keyblock *keys,
533280304Sjkim                      krb5_ticket *ticket)
534280304Sjkim{
535280304Sjkim    if (!krb5_loaded)
536280304Sjkim        load_krb5_dll();
537109998Smarkm
538280304Sjkim    if (p_krb5_decrypt_tkt_part)
539280304Sjkim        return (p_krb5_decrypt_tkt_part(con, keys, ticket));
540280304Sjkim    else
541280304Sjkim        return KRB5KRB_ERR_GENERIC;
542280304Sjkim}
543109998Smarkm
544280304Sjkimkrb5_error_code krb5_timeofday(krb5_context con, krb5_int32 *timeret)
545280304Sjkim{
546280304Sjkim    if (!krb5_loaded)
547280304Sjkim        load_krb5_dll();
548109998Smarkm
549280304Sjkim    if (p_krb5_timeofday)
550280304Sjkim        return (p_krb5_timeofday(con, timeret));
551280304Sjkim    else
552280304Sjkim        return KRB5KRB_ERR_GENERIC;
553280304Sjkim}
554109998Smarkm
555280304Sjkimkrb5_error_code krb5_rc_default(krb5_context con, krb5_rcache *rc)
556280304Sjkim{
557280304Sjkim    if (!krb5_loaded)
558280304Sjkim        load_krb5_dll();
559109998Smarkm
560280304Sjkim    if (p_krb5_rc_default)
561280304Sjkim        return (p_krb5_rc_default(con, rc));
562280304Sjkim    else
563280304Sjkim        return KRB5KRB_ERR_GENERIC;
564280304Sjkim}
565109998Smarkm
566109998Smarkmkrb5_error_code
567109998Smarkmkrb5_rc_initialize(krb5_context con, krb5_rcache rc, krb5_deltat lifespan)
568280304Sjkim{
569280304Sjkim    if (!krb5_loaded)
570280304Sjkim        load_krb5_dll();
571109998Smarkm
572280304Sjkim    if (p_krb5_rc_initialize)
573280304Sjkim        return (p_krb5_rc_initialize(con, rc, lifespan));
574280304Sjkim    else
575280304Sjkim        return KRB5KRB_ERR_GENERIC;
576280304Sjkim}
577109998Smarkm
578109998Smarkmkrb5_error_code
579109998Smarkmkrb5_rc_get_lifespan(krb5_context con, krb5_rcache rc, krb5_deltat *lifespanp)
580280304Sjkim{
581280304Sjkim    if (!krb5_loaded)
582280304Sjkim        load_krb5_dll();
583109998Smarkm
584280304Sjkim    if (p_krb5_rc_get_lifespan)
585280304Sjkim        return (p_krb5_rc_get_lifespan(con, rc, lifespanp));
586280304Sjkim    else
587280304Sjkim        return KRB5KRB_ERR_GENERIC;
588280304Sjkim}
589109998Smarkm
590280304Sjkimkrb5_error_code krb5_rc_destroy(krb5_context con, krb5_rcache rc)
591280304Sjkim{
592280304Sjkim    if (!krb5_loaded)
593280304Sjkim        load_krb5_dll();
594109998Smarkm
595280304Sjkim    if (p_krb5_rc_destroy)
596280304Sjkim        return (p_krb5_rc_destroy(con, rc));
597280304Sjkim    else
598280304Sjkim        return KRB5KRB_ERR_GENERIC;
599280304Sjkim}
600109998Smarkm
601280304Sjkimsize_t krb5_checksum_size(krb5_context context, krb5_cksumtype ctype)
602280304Sjkim{
603280304Sjkim    if (!krb5_loaded)
604280304Sjkim        load_krb5_dll();
605109998Smarkm
606280304Sjkim    if (p_krb5_checksum_size)
607280304Sjkim        return (p_krb5_checksum_size(context, ctype));
608280304Sjkim    else
609280304Sjkim        return KRB5KRB_ERR_GENERIC;
610280304Sjkim}
611109998Smarkm
612280304Sjkimkrb5_boolean valid_cksumtype(krb5_cksumtype ctype)
613280304Sjkim{
614280304Sjkim    if (!krb5_loaded)
615280304Sjkim        load_krb5_dll();
616109998Smarkm
617280304Sjkim    if (p_valid_cksumtype)
618280304Sjkim        return (p_valid_cksumtype(ctype));
619280304Sjkim    else
620280304Sjkim        return KRB5KRB_ERR_GENERIC;
621280304Sjkim}
622109998Smarkm
623280304Sjkimkrb5_error_code krb5_kt_free_entry(krb5_context con, krb5_keytab_entry *entry)
624280304Sjkim{
625280304Sjkim    if (!krb5_loaded)
626280304Sjkim        load_krb5_dll();
627109998Smarkm
628280304Sjkim    if (p_krb5_kt_free_entry)
629280304Sjkim        return (p_krb5_kt_free_entry(con, entry));
630280304Sjkim    else
631280304Sjkim        return KRB5KRB_ERR_GENERIC;
632280304Sjkim}
633280304Sjkim
634109998Smarkm/* Structure definitions  */
635280304Sjkim#  ifndef NO_DEF_KRB5_CCACHE
636280304Sjkim#   ifndef krb5_x
637280304Sjkim#    define krb5_x(ptr,args) ((ptr)?((*(ptr)) args):(abort(),1))
638280304Sjkim#    define krb5_xc(ptr,args) ((ptr)?((*(ptr)) args):(abort(),(char*)0))
639280304Sjkim#   endif
640109998Smarkm
641280304Sjkimtypedef krb5_pointer krb5_cc_cursor; /* cursor for sequential lookup */
642109998Smarkm
643280304Sjkimtypedef struct _krb5_ccache {
644280304Sjkim    krb5_magic magic;
645280304Sjkim    struct _krb5_cc_ops FAR *ops;
646280304Sjkim    krb5_pointer data;
647280304Sjkim} *krb5_ccache;
648109998Smarkm
649280304Sjkimtypedef struct _krb5_cc_ops {
650280304Sjkim    krb5_magic magic;
651280304Sjkim    char *prefix;
652280304Sjkim    char *(KRB5_CALLCONV *get_name)
653280304Sjkim     (krb5_context, krb5_ccache);
654280304Sjkim     krb5_error_code(KRB5_CALLCONV *resolve)
655280304Sjkim     (krb5_context, krb5_ccache *, const char *);
656280304Sjkim     krb5_error_code(KRB5_CALLCONV *gen_new)
657280304Sjkim     (krb5_context, krb5_ccache *);
658280304Sjkim     krb5_error_code(KRB5_CALLCONV *init)
659280304Sjkim     (krb5_context, krb5_ccache, krb5_principal);
660280304Sjkim     krb5_error_code(KRB5_CALLCONV *destroy)
661280304Sjkim     (krb5_context, krb5_ccache);
662280304Sjkim     krb5_error_code(KRB5_CALLCONV *close)
663280304Sjkim     (krb5_context, krb5_ccache);
664280304Sjkim     krb5_error_code(KRB5_CALLCONV *store)
665280304Sjkim     (krb5_context, krb5_ccache, krb5_creds *);
666280304Sjkim     krb5_error_code(KRB5_CALLCONV *retrieve)
667280304Sjkim     (krb5_context, krb5_ccache, krb5_flags, krb5_creds *, krb5_creds *);
668280304Sjkim     krb5_error_code(KRB5_CALLCONV *get_princ)
669280304Sjkim     (krb5_context, krb5_ccache, krb5_principal *);
670280304Sjkim     krb5_error_code(KRB5_CALLCONV *get_first)
671280304Sjkim     (krb5_context, krb5_ccache, krb5_cc_cursor *);
672280304Sjkim     krb5_error_code(KRB5_CALLCONV *get_next)
673280304Sjkim     (krb5_context, krb5_ccache, krb5_cc_cursor *, krb5_creds *);
674280304Sjkim     krb5_error_code(KRB5_CALLCONV *end_get)
675280304Sjkim     (krb5_context, krb5_ccache, krb5_cc_cursor *);
676280304Sjkim     krb5_error_code(KRB5_CALLCONV *remove_cred)
677280304Sjkim     (krb5_context, krb5_ccache, krb5_flags, krb5_creds *);
678280304Sjkim     krb5_error_code(KRB5_CALLCONV *set_flags)
679280304Sjkim     (krb5_context, krb5_ccache, krb5_flags);
680280304Sjkim} krb5_cc_ops;
681280304Sjkim#  endif                        /* NO_DEF_KRB5_CCACHE */
682109998Smarkm
683280304Sjkimkrb5_error_code
684280304Sjkim    kssl_krb5_cc_get_principal
685280304Sjkim    (krb5_context context, krb5_ccache cache, krb5_principal *principal) {
686280304Sjkim    if (p_krb5_cc_get_principal)
687280304Sjkim        return (p_krb5_cc_get_principal(context, cache, principal));
688280304Sjkim    else
689280304Sjkim        return (krb5_x((cache)->ops->get_princ, (context, cache, principal)));
690280304Sjkim}
691109998Smarkm
692109998Smarkmkrb5_error_code
693109998Smarkmkssl_krb5_auth_con_setrcache(krb5_context con, krb5_auth_context acon,
694109998Smarkm                             krb5_rcache rcache)
695280304Sjkim{
696280304Sjkim    if (p_krb5_auth_con_setrcache)
697280304Sjkim        return (p_krb5_auth_con_setrcache(con, acon, rcache));
698280304Sjkim    else
699280304Sjkim        return KRB5KRB_ERR_GENERIC;
700280304Sjkim}
701109998Smarkm
702109998Smarkmkrb5_error_code
703280304Sjkimkssl_krb5_get_server_rcache(krb5_context con, krb5_const krb5_data *data,
704280304Sjkim                            krb5_rcache *rcache)
705280304Sjkim{
706280304Sjkim    if (p_krb5_get_server_rcache)
707280304Sjkim        return (p_krb5_get_server_rcache(con, data, rcache));
708280304Sjkim    else
709280304Sjkim        return KRB5KRB_ERR_GENERIC;
710280304Sjkim}
711109998Smarkm
712109998Smarkmkrb5_error_code
713109998Smarkmkssl_krb5_auth_con_getrcache(krb5_context con, krb5_auth_context acon,
714280304Sjkim                             krb5_rcache *prcache)
715280304Sjkim{
716280304Sjkim    if (p_krb5_auth_con_getrcache)
717280304Sjkim        return (p_krb5_auth_con_getrcache(con, acon, prcache));
718280304Sjkim    else
719280304Sjkim        return KRB5KRB_ERR_GENERIC;
720280304Sjkim}
721109998Smarkm
722280304Sjkimkrb5_error_code kssl_krb5_kt_close(krb5_context context, krb5_keytab keytab)
723280304Sjkim{
724280304Sjkim    if (p_krb5_kt_close)
725280304Sjkim        return (p_krb5_kt_close(context, keytab));
726280304Sjkim    else
727280304Sjkim        return KRB5KRB_ERR_GENERIC;
728280304Sjkim}
729280304Sjkim
730109998Smarkmkrb5_error_code
731109998Smarkmkssl_krb5_kt_get_entry(krb5_context context, krb5_keytab keytab,
732109998Smarkm                       krb5_const_principal principal, krb5_kvno vno,
733109998Smarkm                       krb5_enctype enctype, krb5_keytab_entry *entry)
734280304Sjkim{
735280304Sjkim    if (p_krb5_kt_get_entry)
736280304Sjkim        return (p_krb5_kt_get_entry
737280304Sjkim                (context, keytab, principal, vno, enctype, entry));
738280304Sjkim    else
739280304Sjkim        return KRB5KRB_ERR_GENERIC;
740280304Sjkim}
741280304Sjkim# endif                         /* OPENSSL_SYS_WINDOWS || OPENSSL_SYS_WIN32 */
742109998Smarkm
743280304Sjkim/*
744280304Sjkim * memory allocation functions for non-temporary storage (e.g. stuff that
745280304Sjkim * gets saved into the kssl context)
746280304Sjkim */
747280304Sjkimstatic void *kssl_calloc(size_t nmemb, size_t size)
748280304Sjkim{
749280304Sjkim    void *p;
750167612Ssimon
751280304Sjkim    p = OPENSSL_malloc(nmemb * size);
752280304Sjkim    if (p) {
753280304Sjkim        memset(p, 0, nmemb * size);
754280304Sjkim    }
755280304Sjkim    return p;
756167612Ssimon}
757167612Ssimon
758280304Sjkim# define kssl_malloc(size) OPENSSL_malloc((size))
759280304Sjkim# define kssl_realloc(ptr, size) OPENSSL_realloc(ptr, size)
760280304Sjkim# define kssl_free(ptr) OPENSSL_free((ptr))
761167612Ssimon
762109998Smarkmchar
763109998Smarkm*kstring(char *string)
764280304Sjkim{
765280304Sjkim    static char *null = "[NULL]";
766109998Smarkm
767280304Sjkim    return ((string == NULL) ? null : string);
768280304Sjkim}
769109998Smarkm
770280304Sjkim/*
771280304Sjkim * Given KRB5 enctype (basically DES or 3DES), return closest match openssl
772280304Sjkim * EVP_ encryption algorithm.  Return NULL for unknown or problematic
773280304Sjkim * (krb5_dk_encrypt) enctypes.  Assume ENCTYPE_*_RAW (krb5_raw_encrypt) are
774280304Sjkim * OK.
775280304Sjkim */
776280304Sjkimconst EVP_CIPHER *kssl_map_enc(krb5_enctype enctype)
777280304Sjkim{
778280304Sjkim    switch (enctype) {
779280304Sjkim    case ENCTYPE_DES_HMAC_SHA1: /* EVP_des_cbc(); */
780280304Sjkim    case ENCTYPE_DES_CBC_CRC:
781280304Sjkim    case ENCTYPE_DES_CBC_MD4:
782280304Sjkim    case ENCTYPE_DES_CBC_MD5:
783280304Sjkim    case ENCTYPE_DES_CBC_RAW:
784280304Sjkim        return EVP_des_cbc();
785280304Sjkim        break;
786280304Sjkim    case ENCTYPE_DES3_CBC_SHA1: /* EVP_des_ede3_cbc(); */
787280304Sjkim    case ENCTYPE_DES3_CBC_SHA:
788280304Sjkim    case ENCTYPE_DES3_CBC_RAW:
789280304Sjkim        return EVP_des_ede3_cbc();
790280304Sjkim        break;
791280304Sjkim    default:
792280304Sjkim        return NULL;
793280304Sjkim        break;
794280304Sjkim    }
795280304Sjkim}
796109998Smarkm
797280304Sjkim/*
798280304Sjkim * Return true:1 if p "looks like" the start of the real authenticator
799280304Sjkim * described in kssl_skip_confound() below.  The ASN.1 pattern is "62 xx 30
800280304Sjkim * yy" (APPLICATION-2, SEQUENCE), where xx-yy =~ 2, and xx and yy are
801280304Sjkim * possibly multi-byte length fields.
802280304Sjkim */
803280304Sjkimstatic int kssl_test_confound(unsigned char *p)
804280304Sjkim{
805280304Sjkim    int len = 2;
806280304Sjkim    int xx = 0, yy = 0;
807109998Smarkm
808280304Sjkim    if (*p++ != 0x62)
809280304Sjkim        return 0;
810280304Sjkim    if (*p > 0x82)
811280304Sjkim        return 0;
812280304Sjkim    switch (*p) {
813280304Sjkim    case 0x82:
814280304Sjkim        p++;
815280304Sjkim        xx = (*p++ << 8);
816280304Sjkim        xx += *p++;
817280304Sjkim        break;
818280304Sjkim    case 0x81:
819280304Sjkim        p++;
820280304Sjkim        xx = *p++;
821280304Sjkim        break;
822280304Sjkim    case 0x80:
823280304Sjkim        return 0;
824280304Sjkim    default:
825280304Sjkim        xx = *p++;
826280304Sjkim        break;
827280304Sjkim    }
828280304Sjkim    if (*p++ != 0x30)
829280304Sjkim        return 0;
830280304Sjkim    if (*p > 0x82)
831280304Sjkim        return 0;
832280304Sjkim    switch (*p) {
833280304Sjkim    case 0x82:
834280304Sjkim        p++;
835280304Sjkim        len += 2;
836280304Sjkim        yy = (*p++ << 8);
837280304Sjkim        yy += *p++;
838280304Sjkim        break;
839280304Sjkim    case 0x81:
840280304Sjkim        p++;
841280304Sjkim        len++;
842280304Sjkim        yy = *p++;
843280304Sjkim        break;
844280304Sjkim    case 0x80:
845280304Sjkim        return 0;
846280304Sjkim    default:
847280304Sjkim        yy = *p++;
848280304Sjkim        break;
849280304Sjkim    }
850109998Smarkm
851280304Sjkim    return (xx - len == yy) ? 1 : 0;
852280304Sjkim}
853109998Smarkm
854280304Sjkim/*
855280304Sjkim * Allocate, fill, and return cksumlens array of checksum lengths.  This
856280304Sjkim * array holds just the unique elements from the krb5_cksumarray[].  array[n]
857280304Sjkim * == 0 signals end of data.  The krb5_cksumarray[] was an internal variable
858280304Sjkim * that has since been replaced by a more general method for storing the
859280304Sjkim * data.  It should not be used.  Instead we use real API calls and make a
860280304Sjkim * guess for what the highest assigned CKSUMTYPE_ constant is.  As of 1.2.2
861280304Sjkim * it is 0x000c (CKSUMTYPE_HMAC_SHA1_DES3).  So we will use 0x0010.
862280304Sjkim */
863280304Sjkimstatic size_t *populate_cksumlens(void)
864280304Sjkim{
865280304Sjkim    int i, j, n;
866280304Sjkim    static size_t *cklens = NULL;
867109998Smarkm
868280304Sjkim# ifdef KRB5_MIT_OLD11
869280304Sjkim    n = krb5_max_cksum;
870280304Sjkim# else
871280304Sjkim    n = 0x0010;
872280304Sjkim# endif                         /* KRB5_MIT_OLD11 */
873109998Smarkm
874280304Sjkim# ifdef KRB5CHECKAUTH
875280304Sjkim    if (!cklens && !(cklens = (size_t *)calloc(sizeof(int), n + 1)))
876280304Sjkim        return NULL;
877109998Smarkm
878280304Sjkim    for (i = 0; i < n; i++) {
879280304Sjkim        if (!valid_cksumtype(i))
880280304Sjkim            continue;           /* array has holes */
881280304Sjkim        for (j = 0; j < n; j++) {
882280304Sjkim            if (cklens[j] == 0) {
883280304Sjkim                cklens[j] = krb5_checksum_size(NULL, i);
884280304Sjkim                break;          /* krb5 elem was new: add */
885280304Sjkim            }
886280304Sjkim            if (cklens[j] == krb5_checksum_size(NULL, i)) {
887280304Sjkim                break;          /* ignore duplicate elements */
888280304Sjkim            }
889280304Sjkim        }
890280304Sjkim    }
891280304Sjkim# endif                         /* KRB5CHECKAUTH */
892109998Smarkm
893280304Sjkim    return cklens;
894280304Sjkim}
895109998Smarkm
896280304Sjkim/*-
897280304Sjkim *      Return pointer to start of real authenticator within authenticator, or
898280304Sjkim *      return NULL on error.
899280304Sjkim *      Decrypted authenticator looks like this:
900280304Sjkim *              [0 or 8 byte confounder] [4-24 byte checksum] [real authent'r]
901280304Sjkim *      This hackery wouldn't be necessary if MIT KRB5 1.0.6 had the
902280304Sjkim *      krb5_auth_con_getcksumtype() function advertised in its krb5.h.
903280304Sjkim */
904280304Sjkimunsigned char *kssl_skip_confound(krb5_enctype etype, unsigned char *a)
905280304Sjkim{
906280304Sjkim    int i, conlen;
907280304Sjkim    size_t cklen;
908280304Sjkim    static size_t *cksumlens = NULL;
909280304Sjkim    unsigned char *test_auth;
910109998Smarkm
911280304Sjkim    conlen = (etype) ? 8 : 0;
912109998Smarkm
913280304Sjkim    if (!cksumlens && !(cksumlens = populate_cksumlens()))
914280304Sjkim        return NULL;
915280304Sjkim    for (i = 0; (cklen = cksumlens[i]) != 0; i++) {
916280304Sjkim        test_auth = a + conlen + cklen;
917280304Sjkim        if (kssl_test_confound(test_auth))
918280304Sjkim            return test_auth;
919280304Sjkim    }
920109998Smarkm
921280304Sjkim    return NULL;
922280304Sjkim}
923109998Smarkm
924280304Sjkim/*
925280304Sjkim * Set kssl_err error info when reason text is a simple string kssl_err =
926280304Sjkim * struct { int reason; char text[KSSL_ERR_MAX+1]; }
927280304Sjkim */
928280304Sjkimvoid kssl_err_set(KSSL_ERR *kssl_err, int reason, char *text)
929280304Sjkim{
930280304Sjkim    if (kssl_err == NULL)
931280304Sjkim        return;
932109998Smarkm
933280304Sjkim    kssl_err->reason = reason;
934280304Sjkim    BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, "%s", text);
935280304Sjkim    return;
936280304Sjkim}
937109998Smarkm
938280304Sjkim/*
939280304Sjkim * Display contents of krb5_data struct, for debugging
940280304Sjkim */
941280304Sjkimvoid print_krb5_data(char *label, krb5_data *kdata)
942280304Sjkim{
943280304Sjkim    int i;
944109998Smarkm
945280304Sjkim    fprintf(stderr, "%s[%d] ", label, kdata->length);
946280304Sjkim    for (i = 0; i < (int)kdata->length; i++) {
947280304Sjkim        if (0 && isprint((int)kdata->data[i]))
948280304Sjkim            fprintf(stderr, "%c ", kdata->data[i]);
949280304Sjkim        else
950280304Sjkim            fprintf(stderr, "%02x ", (unsigned char)kdata->data[i]);
951280304Sjkim    }
952280304Sjkim    fprintf(stderr, "\n");
953280304Sjkim}
954109998Smarkm
955280304Sjkim/*
956280304Sjkim * Display contents of krb5_authdata struct, for debugging
957280304Sjkim */
958280304Sjkimvoid print_krb5_authdata(char *label, krb5_authdata **adata)
959280304Sjkim{
960280304Sjkim    if (adata == NULL) {
961280304Sjkim        fprintf(stderr, "%s, authdata==0\n", label);
962280304Sjkim        return;
963280304Sjkim    }
964280304Sjkim    fprintf(stderr, "%s [%p]\n", label, (void *)adata);
965280304Sjkim# if 0
966280304Sjkim    {
967280304Sjkim        int i;
968280304Sjkim        fprintf(stderr, "%s[at%d:%d] ", label, adata->ad_type, adata->length);
969280304Sjkim        for (i = 0; i < adata->length; i++) {
970280304Sjkim            fprintf(stderr, (isprint(adata->contents[i])) ? "%c " : "%02x",
971280304Sjkim                    adata->contents[i]);
972109998Smarkm        }
973280304Sjkim        fprintf(stderr, "\n");
974280304Sjkim    }
975280304Sjkim# endif
976280304Sjkim}
977109998Smarkm
978280304Sjkim/*
979280304Sjkim * Display contents of krb5_keyblock struct, for debugging
980280304Sjkim */
981280304Sjkimvoid print_krb5_keyblock(char *label, krb5_keyblock *keyblk)
982280304Sjkim{
983280304Sjkim    int i;
984109998Smarkm
985280304Sjkim    if (keyblk == NULL) {
986280304Sjkim        fprintf(stderr, "%s, keyblk==0\n", label);
987280304Sjkim        return;
988280304Sjkim    }
989280304Sjkim# ifdef KRB5_HEIMDAL
990280304Sjkim    fprintf(stderr, "%s\n\t[et%d:%d]: ", label, keyblk->keytype,
991280304Sjkim            keyblk->keyvalue->length);
992280304Sjkim    for (i = 0; i < (int)keyblk->keyvalue->length; i++) {
993280304Sjkim        fprintf(stderr, "%02x",
994280304Sjkim                (unsigned char *)(keyblk->keyvalue->contents)[i]);
995280304Sjkim    }
996280304Sjkim    fprintf(stderr, "\n");
997280304Sjkim# else
998280304Sjkim    fprintf(stderr, "%s\n\t[et%d:%d]: ", label, keyblk->enctype,
999280304Sjkim            keyblk->length);
1000280304Sjkim    for (i = 0; i < (int)keyblk->length; i++) {
1001280304Sjkim        fprintf(stderr, "%02x", keyblk->contents[i]);
1002280304Sjkim    }
1003280304Sjkim    fprintf(stderr, "\n");
1004280304Sjkim# endif
1005280304Sjkim}
1006109998Smarkm
1007280304Sjkim/*
1008280304Sjkim * Display contents of krb5_principal_data struct, for debugging
1009280304Sjkim * (krb5_principal is typedef'd == krb5_principal_data *)
1010280304Sjkim */
1011280304Sjkimstatic void print_krb5_princ(char *label, krb5_principal_data *princ)
1012280304Sjkim{
1013280304Sjkim    int i, ui, uj;
1014109998Smarkm
1015280304Sjkim    fprintf(stderr, "%s principal Realm: ", label);
1016280304Sjkim    if (princ == NULL)
1017280304Sjkim        return;
1018280304Sjkim    for (ui = 0; ui < (int)princ->realm.length; ui++)
1019280304Sjkim        putchar(princ->realm.data[ui]);
1020280304Sjkim    fprintf(stderr, " (nametype %d) has %d strings:\n", princ->type,
1021280304Sjkim            princ->length);
1022280304Sjkim    for (i = 0; i < (int)princ->length; i++) {
1023280304Sjkim        fprintf(stderr, "\t%d [%d]: ", i, princ->data[i].length);
1024280304Sjkim        for (uj = 0; uj < (int)princ->data[i].length; uj++) {
1025280304Sjkim            putchar(princ->data[i].data[uj]);
1026109998Smarkm        }
1027280304Sjkim        fprintf(stderr, "\n");
1028280304Sjkim    }
1029280304Sjkim    return;
1030280304Sjkim}
1031109998Smarkm
1032280304Sjkim/*-     Given krb5 service (typically "kssl") and hostname in kssl_ctx,
1033280304Sjkim *      Return encrypted Kerberos ticket for service @ hostname.
1034280304Sjkim *      If authenp is non-NULL, also return encrypted authenticator,
1035280304Sjkim *      whose data should be freed by caller.
1036280304Sjkim *      (Originally was: Create Kerberos AP_REQ message for SSL Client.)
1037280304Sjkim *
1038280304Sjkim *      19990628        VRS     Started; Returns Kerberos AP_REQ message.
1039280304Sjkim *      20010409        VRS     Modified for RFC2712; Returns enc tkt.
1040280304Sjkim *      20010606        VRS     May also return optional authenticator.
1041280304Sjkim */
1042280304Sjkimkrb5_error_code kssl_cget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx,
1043280304Sjkim                              /*
1044280304Sjkim                               * OUT
1045280304Sjkim                               */ krb5_data **enc_ticketp,
1046280304Sjkim                              /*
1047280304Sjkim                               * UPDATE
1048280304Sjkim                               */ krb5_data *authenp,
1049280304Sjkim                              /*
1050280304Sjkim                               * OUT
1051280304Sjkim                               */ KSSL_ERR *kssl_err)
1052280304Sjkim{
1053280304Sjkim    krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC;
1054280304Sjkim    krb5_context krb5context = NULL;
1055280304Sjkim    krb5_auth_context krb5auth_context = NULL;
1056280304Sjkim    krb5_ccache krb5ccdef = NULL;
1057280304Sjkim    krb5_creds krb5creds, *krb5credsp = NULL;
1058280304Sjkim    krb5_data krb5_app_req;
1059109998Smarkm
1060280304Sjkim    kssl_err_set(kssl_err, 0, "");
1061280304Sjkim    memset((char *)&krb5creds, 0, sizeof(krb5creds));
1062109998Smarkm
1063280304Sjkim    if (!kssl_ctx) {
1064280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, "No kssl_ctx defined.\n");
1065280304Sjkim        goto err;
1066280304Sjkim    } else if (!kssl_ctx->service_host) {
1067280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1068280304Sjkim                     "kssl_ctx service_host undefined.\n");
1069280304Sjkim        goto err;
1070280304Sjkim    }
1071109998Smarkm
1072280304Sjkim    if ((krb5rc = krb5_init_context(&krb5context)) != 0) {
1073280304Sjkim        BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1074280304Sjkim                     "krb5_init_context() fails: %d\n", krb5rc);
1075280304Sjkim        kssl_err->reason = SSL_R_KRB5_C_INIT;
1076280304Sjkim        goto err;
1077280304Sjkim    }
1078109998Smarkm
1079280304Sjkim    if ((krb5rc = krb5_sname_to_principal(krb5context,
1080280304Sjkim                                          kssl_ctx->service_host,
1081280304Sjkim                                          (kssl_ctx->service_name) ?
1082280304Sjkim                                          kssl_ctx->service_name : KRB5SVC,
1083280304Sjkim                                          KRB5_NT_SRV_HST,
1084280304Sjkim                                          &krb5creds.server)) != 0) {
1085280304Sjkim        BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1086280304Sjkim                     "krb5_sname_to_principal() fails for %s/%s\n",
1087280304Sjkim                     kssl_ctx->service_host,
1088280304Sjkim                     (kssl_ctx->
1089280304Sjkim                      service_name) ? kssl_ctx->service_name : KRB5SVC);
1090280304Sjkim        kssl_err->reason = SSL_R_KRB5_C_INIT;
1091280304Sjkim        goto err;
1092280304Sjkim    }
1093109998Smarkm
1094280304Sjkim    if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0) {
1095280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC,
1096280304Sjkim                     "krb5_cc_default fails.\n");
1097280304Sjkim        goto err;
1098280304Sjkim    }
1099109998Smarkm
1100280304Sjkim    if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef,
1101280304Sjkim                                        &krb5creds.client)) != 0) {
1102280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC,
1103280304Sjkim                     "krb5_cc_get_principal() fails.\n");
1104280304Sjkim        goto err;
1105280304Sjkim    }
1106109998Smarkm
1107280304Sjkim    if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef,
1108280304Sjkim                                       &krb5creds, &krb5credsp)) != 0) {
1109280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_C_GET_CRED,
1110280304Sjkim                     "krb5_get_credentials() fails.\n");
1111280304Sjkim        goto err;
1112280304Sjkim    }
1113109998Smarkm
1114280304Sjkim    *enc_ticketp = &krb5credsp->ticket;
1115280304Sjkim# ifdef KRB5_HEIMDAL
1116280304Sjkim    kssl_ctx->enctype = krb5credsp->session.keytype;
1117280304Sjkim# else
1118280304Sjkim    kssl_ctx->enctype = krb5credsp->keyblock.enctype;
1119280304Sjkim# endif
1120109998Smarkm
1121280304Sjkim    krb5rc = KRB5KRB_ERR_GENERIC;
1122280304Sjkim    /*      caller should free data of krb5_app_req  */
1123280304Sjkim    /*
1124280304Sjkim     * 20010406 VRS deleted for real KerberosWrapper 20010605 VRS reinstated
1125280304Sjkim     * to offer Authenticator to KerberosWrapper
1126280304Sjkim     */
1127280304Sjkim    krb5_app_req.length = 0;
1128280304Sjkim    if (authenp) {
1129280304Sjkim        krb5_data krb5in_data;
1130280304Sjkim        const unsigned char *p;
1131280304Sjkim        long arlen;
1132280304Sjkim        KRB5_APREQBODY *ap_req;
1133109998Smarkm
1134280304Sjkim        authenp->length = 0;
1135280304Sjkim        krb5in_data.data = NULL;
1136280304Sjkim        krb5in_data.length = 0;
1137280304Sjkim        if ((krb5rc = krb5_mk_req_extended(krb5context,
1138280304Sjkim                                           &krb5auth_context, 0, &krb5in_data,
1139280304Sjkim                                           krb5credsp, &krb5_app_req)) != 0) {
1140280304Sjkim            kssl_err_set(kssl_err, SSL_R_KRB5_C_MK_REQ,
1141280304Sjkim                         "krb5_mk_req_extended() fails.\n");
1142280304Sjkim            goto err;
1143280304Sjkim        }
1144109998Smarkm
1145280304Sjkim        arlen = krb5_app_req.length;
1146280304Sjkim        p = (unsigned char *)krb5_app_req.data;
1147280304Sjkim        ap_req = (KRB5_APREQBODY *)d2i_KRB5_APREQ(NULL, &p, arlen);
1148280304Sjkim        if (ap_req) {
1149280304Sjkim            authenp->length = i2d_KRB5_ENCDATA(ap_req->authenticator, NULL);
1150280304Sjkim            if (authenp->length && (authenp->data = malloc(authenp->length))) {
1151280304Sjkim                unsigned char *adp = (unsigned char *)authenp->data;
1152280304Sjkim                authenp->length =
1153280304Sjkim                    i2d_KRB5_ENCDATA(ap_req->authenticator, &adp);
1154280304Sjkim            }
1155280304Sjkim        }
1156109998Smarkm
1157280304Sjkim        if (ap_req)
1158280304Sjkim            KRB5_APREQ_free((KRB5_APREQ *) ap_req);
1159280304Sjkim        if (krb5_app_req.length)
1160280304Sjkim            kssl_krb5_free_data_contents(krb5context, &krb5_app_req);
1161280304Sjkim    }
1162280304Sjkim# ifdef KRB5_HEIMDAL
1163280304Sjkim    if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->session)) {
1164280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
1165280304Sjkim                     "kssl_ctx_setkey() fails.\n");
1166280304Sjkim    }
1167280304Sjkim# else
1168280304Sjkim    if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->keyblock)) {
1169280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
1170280304Sjkim                     "kssl_ctx_setkey() fails.\n");
1171280304Sjkim    }
1172280304Sjkim# endif
1173280304Sjkim    else
1174280304Sjkim        krb5rc = 0;
1175109998Smarkm
1176280304Sjkim err:
1177280304Sjkim# ifdef KSSL_DEBUG
1178280304Sjkim    kssl_ctx_show(kssl_ctx);
1179280304Sjkim# endif                         /* KSSL_DEBUG */
1180109998Smarkm
1181280304Sjkim    if (krb5creds.client)
1182280304Sjkim        krb5_free_principal(krb5context, krb5creds.client);
1183280304Sjkim    if (krb5creds.server)
1184280304Sjkim        krb5_free_principal(krb5context, krb5creds.server);
1185280304Sjkim    if (krb5auth_context)
1186280304Sjkim        krb5_auth_con_free(krb5context, krb5auth_context);
1187280304Sjkim    if (krb5context)
1188280304Sjkim        krb5_free_context(krb5context);
1189280304Sjkim    return (krb5rc);
1190280304Sjkim}
1191109998Smarkm
1192280304Sjkim/*-
1193280304Sjkim *  Given d2i_-decoded asn1ticket, allocate and return a new krb5_ticket.
1194280304Sjkim *  Return Kerberos error code and kssl_err struct on error.
1195280304Sjkim *  Allocates krb5_ticket and krb5_principal; caller should free these.
1196280304Sjkim *
1197280304Sjkim *      20010410        VRS     Implemented krb5_decode_ticket() as
1198280304Sjkim *                              old_krb5_decode_ticket(). Missing from MIT1.0.6.
1199280304Sjkim *      20010615        VRS     Re-cast as openssl/asn1 d2i_*() functions.
1200280304Sjkim *                              Re-used some of the old krb5_decode_ticket()
1201280304Sjkim *                              code here.  This tkt should alloc/free just
1202280304Sjkim *                              like the real thing.
1203280304Sjkim */
1204280304Sjkimstatic krb5_error_code kssl_TKT2tkt( /* IN */ krb5_context krb5context,
1205280304Sjkim                                    /*
1206280304Sjkim                                     * IN
1207280304Sjkim                                     */ KRB5_TKTBODY *asn1ticket,
1208280304Sjkim                                    /*
1209280304Sjkim                                     * OUT
1210280304Sjkim                                     */ krb5_ticket **krb5ticket,
1211280304Sjkim                                    /*
1212280304Sjkim                                     * OUT
1213280304Sjkim                                     */ KSSL_ERR *kssl_err)
1214280304Sjkim{
1215280304Sjkim    krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC;
1216280304Sjkim    krb5_ticket *new5ticket = NULL;
1217280304Sjkim    ASN1_GENERALSTRING *gstr_svc, *gstr_host;
1218109998Smarkm
1219280304Sjkim    *krb5ticket = NULL;
1220109998Smarkm
1221280304Sjkim    if (asn1ticket == NULL || asn1ticket->realm == NULL ||
1222280304Sjkim        asn1ticket->sname == NULL ||
1223280304Sjkim        sk_ASN1_GENERALSTRING_num(asn1ticket->sname->namestring) < 2) {
1224280304Sjkim        BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1225280304Sjkim                     "Null field in asn1ticket.\n");
1226280304Sjkim        kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1227280304Sjkim        return KRB5KRB_ERR_GENERIC;
1228280304Sjkim    }
1229109998Smarkm
1230280304Sjkim    if ((new5ticket = (krb5_ticket *)calloc(1, sizeof(krb5_ticket))) == NULL) {
1231280304Sjkim        BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1232280304Sjkim                     "Unable to allocate new krb5_ticket.\n");
1233280304Sjkim        kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1234280304Sjkim        return ENOMEM;          /* or KRB5KRB_ERR_GENERIC; */
1235280304Sjkim    }
1236109998Smarkm
1237280304Sjkim    gstr_svc = sk_ASN1_GENERALSTRING_value(asn1ticket->sname->namestring, 0);
1238280304Sjkim    gstr_host = sk_ASN1_GENERALSTRING_value(asn1ticket->sname->namestring, 1);
1239109998Smarkm
1240280304Sjkim    if ((krb5rc = kssl_build_principal_2(krb5context,
1241280304Sjkim                                         &new5ticket->server,
1242280304Sjkim                                         asn1ticket->realm->length,
1243280304Sjkim                                         (char *)asn1ticket->realm->data,
1244280304Sjkim                                         gstr_svc->length,
1245280304Sjkim                                         (char *)gstr_svc->data,
1246280304Sjkim                                         gstr_host->length,
1247280304Sjkim                                         (char *)gstr_host->data)) != 0) {
1248280304Sjkim        free(new5ticket);
1249280304Sjkim        BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1250280304Sjkim                     "Error building ticket server principal.\n");
1251280304Sjkim        kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1252280304Sjkim        return krb5rc;          /* or KRB5KRB_ERR_GENERIC; */
1253280304Sjkim    }
1254109998Smarkm
1255280304Sjkim    krb5_princ_type(krb5context, new5ticket->server) =
1256280304Sjkim        asn1ticket->sname->nametype->data[0];
1257280304Sjkim    new5ticket->enc_part.enctype = asn1ticket->encdata->etype->data[0];
1258280304Sjkim    new5ticket->enc_part.kvno = asn1ticket->encdata->kvno->data[0];
1259280304Sjkim    new5ticket->enc_part.ciphertext.length =
1260280304Sjkim        asn1ticket->encdata->cipher->length;
1261280304Sjkim    if ((new5ticket->enc_part.ciphertext.data =
1262280304Sjkim         calloc(1, asn1ticket->encdata->cipher->length)) == NULL) {
1263280304Sjkim        free(new5ticket);
1264280304Sjkim        BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1265280304Sjkim                     "Error allocating cipher in krb5ticket.\n");
1266280304Sjkim        kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1267280304Sjkim        return KRB5KRB_ERR_GENERIC;
1268280304Sjkim    } else {
1269280304Sjkim        memcpy(new5ticket->enc_part.ciphertext.data,
1270280304Sjkim               asn1ticket->encdata->cipher->data,
1271280304Sjkim               asn1ticket->encdata->cipher->length);
1272280304Sjkim    }
1273109998Smarkm
1274280304Sjkim    *krb5ticket = new5ticket;
1275280304Sjkim    return 0;
1276280304Sjkim}
1277109998Smarkm
1278280304Sjkim/*-
1279280304Sjkim *      Given krb5 service name in KSSL_CTX *kssl_ctx (typically "kssl"),
1280280304Sjkim *              and krb5 AP_REQ message & message length,
1281280304Sjkim *      Return Kerberos session key and client principle
1282280304Sjkim *              to SSL Server in KSSL_CTX *kssl_ctx.
1283280304Sjkim *
1284280304Sjkim *      19990702        VRS     Started.
1285280304Sjkim */
1286280304Sjkimkrb5_error_code kssl_sget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx,
1287280304Sjkim                              /*
1288280304Sjkim                               * IN
1289280304Sjkim                               */ krb5_data *indata,
1290280304Sjkim                              /*
1291280304Sjkim                               * OUT
1292280304Sjkim                               */ krb5_ticket_times *ttimes,
1293280304Sjkim                              /*
1294280304Sjkim                               * OUT
1295280304Sjkim                               */ KSSL_ERR *kssl_err)
1296280304Sjkim{
1297280304Sjkim    krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC;
1298280304Sjkim    static krb5_context krb5context = NULL;
1299280304Sjkim    static krb5_auth_context krb5auth_context = NULL;
1300280304Sjkim    krb5_ticket *krb5ticket = NULL;
1301280304Sjkim    KRB5_TKTBODY *asn1ticket = NULL;
1302280304Sjkim    const unsigned char *p;
1303280304Sjkim    krb5_keytab krb5keytab = NULL;
1304280304Sjkim    krb5_keytab_entry kt_entry;
1305280304Sjkim    krb5_principal krb5server;
1306280304Sjkim    krb5_rcache rcache = NULL;
1307109998Smarkm
1308280304Sjkim    kssl_err_set(kssl_err, 0, "");
1309109998Smarkm
1310280304Sjkim    if (!kssl_ctx) {
1311280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, "No kssl_ctx defined.\n");
1312280304Sjkim        goto err;
1313280304Sjkim    }
1314280304Sjkim# ifdef KSSL_DEBUG
1315280304Sjkim    fprintf(stderr, "in kssl_sget_tkt(%s)\n",
1316280304Sjkim            kstring(kssl_ctx->service_name));
1317280304Sjkim# endif                         /* KSSL_DEBUG */
1318109998Smarkm
1319280304Sjkim    if (!krb5context && (krb5rc = krb5_init_context(&krb5context))) {
1320280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1321280304Sjkim                     "krb5_init_context() fails.\n");
1322280304Sjkim        goto err;
1323280304Sjkim    }
1324280304Sjkim    if (krb5auth_context &&
1325280304Sjkim        (krb5rc = krb5_auth_con_free(krb5context, krb5auth_context))) {
1326280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1327280304Sjkim                     "krb5_auth_con_free() fails.\n");
1328280304Sjkim        goto err;
1329280304Sjkim    } else
1330280304Sjkim        krb5auth_context = NULL;
1331280304Sjkim    if (!krb5auth_context &&
1332280304Sjkim        (krb5rc = krb5_auth_con_init(krb5context, &krb5auth_context))) {
1333280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1334280304Sjkim                     "krb5_auth_con_init() fails.\n");
1335280304Sjkim        goto err;
1336280304Sjkim    }
1337109998Smarkm
1338280304Sjkim    if ((krb5rc = krb5_auth_con_getrcache(krb5context, krb5auth_context,
1339280304Sjkim                                          &rcache))) {
1340280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1341280304Sjkim                     "krb5_auth_con_getrcache() fails.\n");
1342280304Sjkim        goto err;
1343280304Sjkim    }
1344109998Smarkm
1345280304Sjkim    if ((krb5rc = krb5_sname_to_principal(krb5context, NULL,
1346280304Sjkim                                          (kssl_ctx->service_name) ?
1347280304Sjkim                                          kssl_ctx->service_name : KRB5SVC,
1348280304Sjkim                                          KRB5_NT_SRV_HST,
1349280304Sjkim                                          &krb5server)) != 0) {
1350280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1351280304Sjkim                     "krb5_sname_to_principal() fails.\n");
1352280304Sjkim        goto err;
1353280304Sjkim    }
1354109998Smarkm
1355280304Sjkim    if (rcache == NULL) {
1356280304Sjkim        if ((krb5rc = krb5_get_server_rcache(krb5context,
1357280304Sjkim                                             krb5_princ_component(krb5context,
1358280304Sjkim                                                                  krb5server,
1359280304Sjkim                                                                  0),
1360280304Sjkim                                             &rcache))) {
1361280304Sjkim            kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1362280304Sjkim                         "krb5_get_server_rcache() fails.\n");
1363280304Sjkim            goto err;
1364280304Sjkim        }
1365280304Sjkim    }
1366109998Smarkm
1367280304Sjkim    if ((krb5rc =
1368280304Sjkim         krb5_auth_con_setrcache(krb5context, krb5auth_context, rcache))) {
1369280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1370280304Sjkim                     "krb5_auth_con_setrcache() fails.\n");
1371280304Sjkim        goto err;
1372280304Sjkim    }
1373109998Smarkm
1374280304Sjkim    /*
1375280304Sjkim     * kssl_ctx->keytab_file == NULL ==> use Kerberos default
1376280304Sjkim     */
1377280304Sjkim    if (kssl_ctx->keytab_file) {
1378280304Sjkim        krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file,
1379280304Sjkim                                 &krb5keytab);
1380280304Sjkim        if (krb5rc) {
1381280304Sjkim            kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1382280304Sjkim                         "krb5_kt_resolve() fails.\n");
1383280304Sjkim            goto err;
1384280304Sjkim        }
1385280304Sjkim    } else {
1386280304Sjkim        krb5rc = krb5_kt_default(krb5context, &krb5keytab);
1387280304Sjkim        if (krb5rc) {
1388280304Sjkim            kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
1389280304Sjkim                         "krb5_kt_default() fails.\n");
1390280304Sjkim            goto err;
1391280304Sjkim        }
1392280304Sjkim    }
1393109998Smarkm
1394280304Sjkim    /*-     Actual Kerberos5 krb5_recvauth() has initial conversation here
1395280304Sjkim     *      o       check KRB5_SENDAUTH_BADAUTHVERS
1396280304Sjkim     *              unless KRB5_RECVAUTH_SKIP_VERSION
1397280304Sjkim     *      o       check KRB5_SENDAUTH_BADAPPLVERS
1398280304Sjkim     *      o       send "0" msg if all OK
1399280304Sjkim     */
1400109998Smarkm
1401280304Sjkim    /*-
1402280304Sjkim     * 20010411 was using AP_REQ instead of true KerberosWrapper
1403280304Sjkim     *
1404280304Sjkim     *  if ((krb5rc = krb5_rd_req(krb5context, &krb5auth_context,
1405280304Sjkim     *                      &krb5in_data, krb5server, krb5keytab,
1406280304Sjkim     *                      &ap_option, &krb5ticket)) != 0)  { Error }
1407280304Sjkim     */
1408109998Smarkm
1409280304Sjkim    p = (unsigned char *)indata->data;
1410280304Sjkim    if ((asn1ticket = (KRB5_TKTBODY *)d2i_KRB5_TICKET(NULL, &p,
1411280304Sjkim                                                      (long)indata->length))
1412280304Sjkim        == NULL) {
1413280304Sjkim        BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1414280304Sjkim                     "d2i_KRB5_TICKET() ASN.1 decode failure.\n");
1415280304Sjkim        kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1416280304Sjkim        goto err;
1417280304Sjkim    }
1418109998Smarkm
1419280304Sjkim    /*
1420280304Sjkim     * Was: krb5rc = krb5_decode_ticket(krb5in_data,&krb5ticket)) != 0)
1421280304Sjkim     */
1422280304Sjkim    if ((krb5rc = kssl_TKT2tkt(krb5context, asn1ticket, &krb5ticket,
1423280304Sjkim                               kssl_err)) != 0) {
1424280304Sjkim        BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1425280304Sjkim                     "Error converting ASN.1 ticket to krb5_ticket.\n");
1426280304Sjkim        kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1427280304Sjkim        goto err;
1428280304Sjkim    }
1429109998Smarkm
1430280304Sjkim    if (!krb5_principal_compare(krb5context, krb5server, krb5ticket->server)) {
1431280304Sjkim        krb5rc = KRB5_PRINC_NOMATCH;
1432280304Sjkim        BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1433280304Sjkim                     "server principal != ticket principal\n");
1434280304Sjkim        kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1435280304Sjkim        goto err;
1436280304Sjkim    }
1437280304Sjkim    if ((krb5rc = krb5_kt_get_entry(krb5context, krb5keytab,
1438280304Sjkim                                    krb5ticket->server,
1439280304Sjkim                                    krb5ticket->enc_part.kvno,
1440280304Sjkim                                    krb5ticket->enc_part.enctype,
1441280304Sjkim                                    &kt_entry)) != 0) {
1442280304Sjkim        BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1443280304Sjkim                     "krb5_kt_get_entry() fails with %x.\n", krb5rc);
1444280304Sjkim        kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1445280304Sjkim        goto err;
1446280304Sjkim    }
1447280304Sjkim    if ((krb5rc = krb5_decrypt_tkt_part(krb5context, &kt_entry.key,
1448280304Sjkim                                        krb5ticket)) != 0) {
1449280304Sjkim        BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
1450280304Sjkim                     "krb5_decrypt_tkt_part() failed.\n");
1451280304Sjkim        kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
1452280304Sjkim        goto err;
1453280304Sjkim    } else {
1454280304Sjkim        krb5_kt_free_entry(krb5context, &kt_entry);
1455280304Sjkim# ifdef KSSL_DEBUG
1456280304Sjkim        {
1457280304Sjkim            int i;
1458280304Sjkim            krb5_address **paddr = krb5ticket->enc_part2->caddrs;
1459280304Sjkim            fprintf(stderr, "Decrypted ticket fields:\n");
1460280304Sjkim            fprintf(stderr, "\tflags: %X, transit-type: %X",
1461280304Sjkim                    krb5ticket->enc_part2->flags,
1462280304Sjkim                    krb5ticket->enc_part2->transited.tr_type);
1463280304Sjkim            print_krb5_data("\ttransit-data: ",
1464280304Sjkim                            &(krb5ticket->enc_part2->transited.tr_contents));
1465280304Sjkim            fprintf(stderr, "\tcaddrs: %p, authdata: %p\n",
1466280304Sjkim                    krb5ticket->enc_part2->caddrs,
1467280304Sjkim                    krb5ticket->enc_part2->authorization_data);
1468280304Sjkim            if (paddr) {
1469280304Sjkim                fprintf(stderr, "\tcaddrs:\n");
1470280304Sjkim                for (i = 0; paddr[i] != NULL; i++) {
1471280304Sjkim                    krb5_data d;
1472280304Sjkim                    d.length = paddr[i]->length;
1473280304Sjkim                    d.data = paddr[i]->contents;
1474280304Sjkim                    print_krb5_data("\t\tIP: ", &d);
1475109998Smarkm                }
1476280304Sjkim            }
1477280304Sjkim            fprintf(stderr, "\tstart/auth/end times: %d / %d / %d\n",
1478280304Sjkim                    krb5ticket->enc_part2->times.starttime,
1479280304Sjkim                    krb5ticket->enc_part2->times.authtime,
1480280304Sjkim                    krb5ticket->enc_part2->times.endtime);
1481280304Sjkim        }
1482280304Sjkim# endif                         /* KSSL_DEBUG */
1483280304Sjkim    }
1484109998Smarkm
1485280304Sjkim    krb5rc = KRB5_NO_TKT_SUPPLIED;
1486280304Sjkim    if (!krb5ticket || !krb5ticket->enc_part2 ||
1487280304Sjkim        !krb5ticket->enc_part2->client ||
1488280304Sjkim        !krb5ticket->enc_part2->client->data ||
1489280304Sjkim        !krb5ticket->enc_part2->session) {
1490280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
1491280304Sjkim                     "bad ticket from krb5_rd_req.\n");
1492280304Sjkim    } else if (kssl_ctx_setprinc(kssl_ctx, KSSL_CLIENT,
1493280304Sjkim                                 &krb5ticket->enc_part2->client->realm,
1494280304Sjkim                                 krb5ticket->enc_part2->client->data,
1495280304Sjkim                                 krb5ticket->enc_part2->client->length)) {
1496280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
1497280304Sjkim                     "kssl_ctx_setprinc() fails.\n");
1498280304Sjkim    } else if (kssl_ctx_setkey(kssl_ctx, krb5ticket->enc_part2->session)) {
1499280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
1500280304Sjkim                     "kssl_ctx_setkey() fails.\n");
1501280304Sjkim    } else if (krb5ticket->enc_part2->flags & TKT_FLG_INVALID) {
1502280304Sjkim        krb5rc = KRB5KRB_AP_ERR_TKT_INVALID;
1503280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
1504280304Sjkim                     "invalid ticket from krb5_rd_req.\n");
1505280304Sjkim    } else
1506280304Sjkim        krb5rc = 0;
1507109998Smarkm
1508280304Sjkim    kssl_ctx->enctype = krb5ticket->enc_part.enctype;
1509280304Sjkim    ttimes->authtime = krb5ticket->enc_part2->times.authtime;
1510280304Sjkim    ttimes->starttime = krb5ticket->enc_part2->times.starttime;
1511280304Sjkim    ttimes->endtime = krb5ticket->enc_part2->times.endtime;
1512280304Sjkim    ttimes->renew_till = krb5ticket->enc_part2->times.renew_till;
1513109998Smarkm
1514109998Smarkm err:
1515280304Sjkim# ifdef KSSL_DEBUG
1516280304Sjkim    kssl_ctx_show(kssl_ctx);
1517280304Sjkim# endif                         /* KSSL_DEBUG */
1518109998Smarkm
1519280304Sjkim    if (asn1ticket)
1520280304Sjkim        KRB5_TICKET_free((KRB5_TICKET *) asn1ticket);
1521280304Sjkim    if (krb5keytab)
1522280304Sjkim        krb5_kt_close(krb5context, krb5keytab);
1523280304Sjkim    if (krb5ticket)
1524280304Sjkim        krb5_free_ticket(krb5context, krb5ticket);
1525280304Sjkim    if (krb5server)
1526280304Sjkim        krb5_free_principal(krb5context, krb5server);
1527280304Sjkim    return (krb5rc);
1528280304Sjkim}
1529109998Smarkm
1530280304Sjkim/*
1531280304Sjkim * Allocate & return a new kssl_ctx struct.
1532280304Sjkim */
1533280304SjkimKSSL_CTX *kssl_ctx_new(void)
1534280304Sjkim{
1535280304Sjkim    return ((KSSL_CTX *)kssl_calloc(1, sizeof(KSSL_CTX)));
1536280304Sjkim}
1537109998Smarkm
1538280304Sjkim/*
1539280304Sjkim * Frees a kssl_ctx struct and any allocated memory it holds.  Returns NULL.
1540280304Sjkim */
1541280304SjkimKSSL_CTX *kssl_ctx_free(KSSL_CTX *kssl_ctx)
1542280304Sjkim{
1543280304Sjkim    if (kssl_ctx == NULL)
1544280304Sjkim        return kssl_ctx;
1545109998Smarkm
1546280304Sjkim    if (kssl_ctx->key)
1547280304Sjkim        OPENSSL_cleanse(kssl_ctx->key, kssl_ctx->length);
1548280304Sjkim    if (kssl_ctx->key)
1549280304Sjkim        kssl_free(kssl_ctx->key);
1550280304Sjkim    if (kssl_ctx->client_princ)
1551280304Sjkim        kssl_free(kssl_ctx->client_princ);
1552280304Sjkim    if (kssl_ctx->service_host)
1553280304Sjkim        kssl_free(kssl_ctx->service_host);
1554280304Sjkim    if (kssl_ctx->service_name)
1555280304Sjkim        kssl_free(kssl_ctx->service_name);
1556280304Sjkim    if (kssl_ctx->keytab_file)
1557280304Sjkim        kssl_free(kssl_ctx->keytab_file);
1558109998Smarkm
1559280304Sjkim    kssl_free(kssl_ctx);
1560280304Sjkim    return (KSSL_CTX *)NULL;
1561280304Sjkim}
1562109998Smarkm
1563280304Sjkim/*
1564280304Sjkim * Given an array of (krb5_data *) entity (and optional realm), set the plain
1565280304Sjkim * (char *) client_princ or service_host member of the kssl_ctx struct.
1566280304Sjkim */
1567109998Smarkmkrb5_error_code
1568109998Smarkmkssl_ctx_setprinc(KSSL_CTX *kssl_ctx, int which,
1569280304Sjkim                  krb5_data *realm, krb5_data *entity, int nentities)
1570280304Sjkim{
1571280304Sjkim    char **princ;
1572280304Sjkim    int length;
1573280304Sjkim    int i;
1574109998Smarkm
1575280304Sjkim    if (kssl_ctx == NULL || entity == NULL)
1576280304Sjkim        return KSSL_CTX_ERR;
1577109998Smarkm
1578280304Sjkim    switch (which) {
1579280304Sjkim    case KSSL_CLIENT:
1580280304Sjkim        princ = &kssl_ctx->client_princ;
1581280304Sjkim        break;
1582280304Sjkim    case KSSL_SERVER:
1583280304Sjkim        princ = &kssl_ctx->service_host;
1584280304Sjkim        break;
1585280304Sjkim    default:
1586280304Sjkim        return KSSL_CTX_ERR;
1587280304Sjkim        break;
1588280304Sjkim    }
1589280304Sjkim    if (*princ)
1590280304Sjkim        kssl_free(*princ);
1591109998Smarkm
1592280304Sjkim    /* Add up all the entity->lengths */
1593280304Sjkim    length = 0;
1594280304Sjkim    for (i = 0; i < nentities; i++) {
1595280304Sjkim        length += entity[i].length;
1596280304Sjkim    }
1597280304Sjkim    /* Add in space for the '/' character(s) (if any) */
1598280304Sjkim    length += nentities - 1;
1599280304Sjkim    /* Space for the ('@'+realm+NULL | NULL) */
1600280304Sjkim    length += ((realm) ? realm->length + 2 : 1);
1601120631Snectar
1602280304Sjkim    if ((*princ = kssl_calloc(1, length)) == NULL)
1603280304Sjkim        return KSSL_CTX_ERR;
1604280304Sjkim    else {
1605280304Sjkim        for (i = 0; i < nentities; i++) {
1606280304Sjkim            strncat(*princ, entity[i].data, entity[i].length);
1607280304Sjkim            if (i < nentities - 1) {
1608280304Sjkim                strcat(*princ, "/");
1609280304Sjkim            }
1610109998Smarkm        }
1611280304Sjkim        if (realm) {
1612280304Sjkim            strcat(*princ, "@");
1613280304Sjkim            (void)strncat(*princ, realm->data, realm->length);
1614280304Sjkim        }
1615280304Sjkim    }
1616109998Smarkm
1617280304Sjkim    return KSSL_CTX_OK;
1618280304Sjkim}
1619109998Smarkm
1620280304Sjkim/*-     Set one of the plain (char *) string members of the kssl_ctx struct.
1621280304Sjkim *      Default values should be:
1622280304Sjkim *              which == KSSL_SERVICE   =>      "khost" (KRB5SVC)
1623280304Sjkim *              which == KSSL_KEYTAB    =>      "/etc/krb5.keytab" (KRB5KEYTAB)
1624280304Sjkim */
1625280304Sjkimkrb5_error_code kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text)
1626280304Sjkim{
1627280304Sjkim    char **string;
1628109998Smarkm
1629280304Sjkim    if (!kssl_ctx)
1630280304Sjkim        return KSSL_CTX_ERR;
1631109998Smarkm
1632280304Sjkim    switch (which) {
1633280304Sjkim    case KSSL_SERVICE:
1634280304Sjkim        string = &kssl_ctx->service_name;
1635280304Sjkim        break;
1636280304Sjkim    case KSSL_SERVER:
1637280304Sjkim        string = &kssl_ctx->service_host;
1638280304Sjkim        break;
1639280304Sjkim    case KSSL_CLIENT:
1640280304Sjkim        string = &kssl_ctx->client_princ;
1641280304Sjkim        break;
1642280304Sjkim    case KSSL_KEYTAB:
1643280304Sjkim        string = &kssl_ctx->keytab_file;
1644280304Sjkim        break;
1645280304Sjkim    default:
1646280304Sjkim        return KSSL_CTX_ERR;
1647280304Sjkim        break;
1648280304Sjkim    }
1649280304Sjkim    if (*string)
1650280304Sjkim        kssl_free(*string);
1651109998Smarkm
1652280304Sjkim    if (!text) {
1653280304Sjkim        *string = '\0';
1654280304Sjkim        return KSSL_CTX_OK;
1655280304Sjkim    }
1656109998Smarkm
1657280304Sjkim    if ((*string = kssl_calloc(1, strlen(text) + 1)) == NULL)
1658280304Sjkim        return KSSL_CTX_ERR;
1659280304Sjkim    else
1660280304Sjkim        strcpy(*string, text);
1661109998Smarkm
1662280304Sjkim    return KSSL_CTX_OK;
1663280304Sjkim}
1664109998Smarkm
1665280304Sjkim/*
1666280304Sjkim * Copy the Kerberos session key from a (krb5_keyblock *) to a kssl_ctx
1667280304Sjkim * struct.  Clear kssl_ctx->key if Kerberos session key is NULL.
1668280304Sjkim */
1669280304Sjkimkrb5_error_code kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session)
1670280304Sjkim{
1671280304Sjkim    int length;
1672280304Sjkim    krb5_enctype enctype;
1673280304Sjkim    krb5_octet FAR *contents = NULL;
1674109998Smarkm
1675280304Sjkim    if (!kssl_ctx)
1676280304Sjkim        return KSSL_CTX_ERR;
1677109998Smarkm
1678280304Sjkim    if (kssl_ctx->key) {
1679280304Sjkim        OPENSSL_cleanse(kssl_ctx->key, kssl_ctx->length);
1680280304Sjkim        kssl_free(kssl_ctx->key);
1681280304Sjkim    }
1682109998Smarkm
1683280304Sjkim    if (session) {
1684109998Smarkm
1685280304Sjkim# ifdef KRB5_HEIMDAL
1686280304Sjkim        length = session->keyvalue->length;
1687280304Sjkim        enctype = session->keytype;
1688280304Sjkim        contents = session->keyvalue->contents;
1689280304Sjkim# else
1690280304Sjkim        length = session->length;
1691280304Sjkim        enctype = session->enctype;
1692280304Sjkim        contents = session->contents;
1693280304Sjkim# endif
1694280304Sjkim        kssl_ctx->enctype = enctype;
1695280304Sjkim        kssl_ctx->length = length;
1696280304Sjkim    } else {
1697280304Sjkim        kssl_ctx->enctype = ENCTYPE_UNKNOWN;
1698280304Sjkim        kssl_ctx->length = 0;
1699280304Sjkim        return KSSL_CTX_OK;
1700280304Sjkim    }
1701109998Smarkm
1702280304Sjkim    if ((kssl_ctx->key =
1703280304Sjkim         (krb5_octet FAR *)kssl_calloc(1, kssl_ctx->length)) == NULL) {
1704280304Sjkim        kssl_ctx->length = 0;
1705280304Sjkim        return KSSL_CTX_ERR;
1706280304Sjkim    } else
1707280304Sjkim        memcpy(kssl_ctx->key, contents, length);
1708109998Smarkm
1709280304Sjkim    return KSSL_CTX_OK;
1710280304Sjkim}
1711109998Smarkm
1712280304Sjkim/*
1713280304Sjkim * Display contents of kssl_ctx struct
1714280304Sjkim */
1715280304Sjkimvoid kssl_ctx_show(KSSL_CTX *kssl_ctx)
1716280304Sjkim{
1717280304Sjkim    int i;
1718109998Smarkm
1719280304Sjkim    printf("kssl_ctx: ");
1720280304Sjkim    if (kssl_ctx == NULL) {
1721280304Sjkim        printf("NULL\n");
1722280304Sjkim        return;
1723280304Sjkim    } else
1724280304Sjkim        printf("%p\n", (void *)kssl_ctx);
1725109998Smarkm
1726280304Sjkim    printf("\tservice:\t%s\n",
1727280304Sjkim           (kssl_ctx->service_name) ? kssl_ctx->service_name : "NULL");
1728280304Sjkim    printf("\tclient:\t%s\n",
1729280304Sjkim           (kssl_ctx->client_princ) ? kssl_ctx->client_princ : "NULL");
1730280304Sjkim    printf("\tserver:\t%s\n",
1731280304Sjkim           (kssl_ctx->service_host) ? kssl_ctx->service_host : "NULL");
1732280304Sjkim    printf("\tkeytab:\t%s\n",
1733280304Sjkim           (kssl_ctx->keytab_file) ? kssl_ctx->keytab_file : "NULL");
1734280304Sjkim    printf("\tkey [%d:%d]:\t", kssl_ctx->enctype, kssl_ctx->length);
1735109998Smarkm
1736280304Sjkim    for (i = 0; i < kssl_ctx->length && kssl_ctx->key; i++) {
1737280304Sjkim        printf("%02x", kssl_ctx->key[i]);
1738280304Sjkim    }
1739280304Sjkim    printf("\n");
1740280304Sjkim    return;
1741280304Sjkim}
1742109998Smarkm
1743280304Sjkimint kssl_keytab_is_available(KSSL_CTX *kssl_ctx)
1744109998Smarkm{
1745280304Sjkim    krb5_context krb5context = NULL;
1746280304Sjkim    krb5_keytab krb5keytab = NULL;
1747280304Sjkim    krb5_keytab_entry entry;
1748280304Sjkim    krb5_principal princ = NULL;
1749280304Sjkim    krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC;
1750109998Smarkm    int rc = 0;
1751109998Smarkm
1752109998Smarkm    if ((krb5rc = krb5_init_context(&krb5context)))
1753280304Sjkim        return (0);
1754109998Smarkm
1755280304Sjkim    /*
1756280304Sjkim     * kssl_ctx->keytab_file == NULL ==> use Kerberos default
1757280304Sjkim     */
1758280304Sjkim    if (kssl_ctx->keytab_file) {
1759109998Smarkm        krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file,
1760280304Sjkim                                 &krb5keytab);
1761109998Smarkm        if (krb5rc)
1762109998Smarkm            goto exit;
1763280304Sjkim    } else {
1764280304Sjkim        krb5rc = krb5_kt_default(krb5context, &krb5keytab);
1765109998Smarkm        if (krb5rc)
1766109998Smarkm            goto exit;
1767109998Smarkm    }
1768109998Smarkm
1769109998Smarkm    /* the host key we are looking for */
1770280304Sjkim    krb5rc = krb5_sname_to_principal(krb5context, NULL,
1771280304Sjkim                                     kssl_ctx->
1772280304Sjkim                                     service_name ? kssl_ctx->service_name :
1773280304Sjkim                                     KRB5SVC, KRB5_NT_SRV_HST, &princ);
1774109998Smarkm
1775206046Ssimon    if (krb5rc)
1776280304Sjkim        goto exit;
1777206046Ssimon
1778280304Sjkim    krb5rc = krb5_kt_get_entry(krb5context, krb5keytab, princ,
1779280304Sjkim                               /* IGNORE_VNO */
1780280304Sjkim                               0,
1781280304Sjkim                               /* IGNORE_ENCTYPE */
1782280304Sjkim                               0, &entry);
1783280304Sjkim    if (krb5rc == KRB5_KT_NOTFOUND) {
1784109998Smarkm        rc = 1;
1785109998Smarkm        goto exit;
1786280304Sjkim    } else if (krb5rc)
1787109998Smarkm        goto exit;
1788280304Sjkim
1789109998Smarkm    krb5_kt_free_entry(krb5context, &entry);
1790109998Smarkm    rc = 1;
1791109998Smarkm
1792280304Sjkim exit:
1793280304Sjkim    if (krb5keytab)
1794280304Sjkim        krb5_kt_close(krb5context, krb5keytab);
1795280304Sjkim    if (princ)
1796280304Sjkim        krb5_free_principal(krb5context, princ);
1797280304Sjkim    if (krb5context)
1798280304Sjkim        krb5_free_context(krb5context);
1799280304Sjkim    return (rc);
1800109998Smarkm}
1801109998Smarkm
1802280304Sjkimint kssl_tgt_is_available(KSSL_CTX *kssl_ctx)
1803280304Sjkim{
1804280304Sjkim    krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC;
1805280304Sjkim    krb5_context krb5context = NULL;
1806280304Sjkim    krb5_ccache krb5ccdef = NULL;
1807280304Sjkim    krb5_creds krb5creds, *krb5credsp = NULL;
1808280304Sjkim    int rc = 0;
1809109998Smarkm
1810280304Sjkim    memset((char *)&krb5creds, 0, sizeof(krb5creds));
1811109998Smarkm
1812280304Sjkim    if (!kssl_ctx)
1813280304Sjkim        return (0);
1814109998Smarkm
1815280304Sjkim    if (!kssl_ctx->service_host)
1816280304Sjkim        return (0);
1817109998Smarkm
1818280304Sjkim    if ((krb5rc = krb5_init_context(&krb5context)) != 0)
1819280304Sjkim        goto err;
1820109998Smarkm
1821280304Sjkim    if ((krb5rc = krb5_sname_to_principal(krb5context,
1822280304Sjkim                                          kssl_ctx->service_host,
1823280304Sjkim                                          (kssl_ctx->service_name) ?
1824280304Sjkim                                          kssl_ctx->service_name : KRB5SVC,
1825280304Sjkim                                          KRB5_NT_SRV_HST,
1826280304Sjkim                                          &krb5creds.server)) != 0)
1827280304Sjkim        goto err;
1828109998Smarkm
1829280304Sjkim    if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0)
1830280304Sjkim        goto err;
1831109998Smarkm
1832280304Sjkim    if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef,
1833280304Sjkim                                        &krb5creds.client)) != 0)
1834280304Sjkim        goto err;
1835109998Smarkm
1836280304Sjkim    if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef,
1837280304Sjkim                                       &krb5creds, &krb5credsp)) != 0)
1838280304Sjkim        goto err;
1839109998Smarkm
1840280304Sjkim    rc = 1;
1841109998Smarkm
1842280304Sjkim err:
1843280304Sjkim# ifdef KSSL_DEBUG
1844280304Sjkim    kssl_ctx_show(kssl_ctx);
1845280304Sjkim# endif                         /* KSSL_DEBUG */
1846109998Smarkm
1847280304Sjkim    if (krb5creds.client)
1848280304Sjkim        krb5_free_principal(krb5context, krb5creds.client);
1849280304Sjkim    if (krb5creds.server)
1850280304Sjkim        krb5_free_principal(krb5context, krb5creds.server);
1851280304Sjkim    if (krb5context)
1852280304Sjkim        krb5_free_context(krb5context);
1853280304Sjkim    return (rc);
1854280304Sjkim}
1855109998Smarkm
1856280304Sjkim# if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_WIN32)
1857109998Smarkmvoid kssl_krb5_free_data_contents(krb5_context context, krb5_data *data)
1858280304Sjkim{
1859280304Sjkim#  ifdef KRB5_HEIMDAL
1860280304Sjkim    data->length = 0;
1861280304Sjkim    if (data->data)
1862280304Sjkim        free(data->data);
1863280304Sjkim#  elif defined(KRB5_MIT_OLD11)
1864280304Sjkim    if (data->data) {
1865280304Sjkim        krb5_xfree(data->data);
1866280304Sjkim        data->data = 0;
1867280304Sjkim    }
1868280304Sjkim#  else
1869280304Sjkim    krb5_free_data_contents(NULL, data);
1870280304Sjkim#  endif
1871280304Sjkim}
1872280304Sjkim# endif
1873280304Sjkim/* !OPENSSL_SYS_WINDOWS && !OPENSSL_SYS_WIN32 */
1874109998Smarkm
1875280304Sjkim/*
1876280304Sjkim * Given pointers to KerberosTime and struct tm structs, convert the
1877280304Sjkim * KerberosTime string to struct tm.  Note that KerberosTime is a
1878280304Sjkim * ASN1_GENERALIZEDTIME value, constrained to GMT with no fractional seconds
1879280304Sjkim * as defined in RFC 1510.  Return pointer to the (partially) filled in
1880280304Sjkim * struct tm on success, return NULL on failure.
1881280304Sjkim */
1882238405Sjkimstatic struct tm *k_gmtime(ASN1_GENERALIZEDTIME *gtime, struct tm *k_tm)
1883280304Sjkim{
1884280304Sjkim    char c, *p;
1885109998Smarkm
1886280304Sjkim    if (!k_tm)
1887280304Sjkim        return NULL;
1888280304Sjkim    if (gtime == NULL || gtime->length < 14)
1889280304Sjkim        return NULL;
1890280304Sjkim    if (gtime->data == NULL)
1891280304Sjkim        return NULL;
1892109998Smarkm
1893280304Sjkim    p = (char *)&gtime->data[14];
1894109998Smarkm
1895280304Sjkim    c = *p;
1896280304Sjkim    *p = '\0';
1897280304Sjkim    p -= 2;
1898280304Sjkim    k_tm->tm_sec = atoi(p);
1899280304Sjkim    *(p + 2) = c;
1900280304Sjkim    c = *p;
1901280304Sjkim    *p = '\0';
1902280304Sjkim    p -= 2;
1903280304Sjkim    k_tm->tm_min = atoi(p);
1904280304Sjkim    *(p + 2) = c;
1905280304Sjkim    c = *p;
1906280304Sjkim    *p = '\0';
1907280304Sjkim    p -= 2;
1908280304Sjkim    k_tm->tm_hour = atoi(p);
1909280304Sjkim    *(p + 2) = c;
1910280304Sjkim    c = *p;
1911280304Sjkim    *p = '\0';
1912280304Sjkim    p -= 2;
1913280304Sjkim    k_tm->tm_mday = atoi(p);
1914280304Sjkim    *(p + 2) = c;
1915280304Sjkim    c = *p;
1916280304Sjkim    *p = '\0';
1917280304Sjkim    p -= 2;
1918280304Sjkim    k_tm->tm_mon = atoi(p) - 1;
1919280304Sjkim    *(p + 2) = c;
1920280304Sjkim    c = *p;
1921280304Sjkim    *p = '\0';
1922280304Sjkim    p -= 4;
1923280304Sjkim    k_tm->tm_year = atoi(p) - 1900;
1924280304Sjkim    *(p + 4) = c;
1925109998Smarkm
1926280304Sjkim    return k_tm;
1927280304Sjkim}
1928109998Smarkm
1929280304Sjkim/*
1930280304Sjkim * Helper function for kssl_validate_times().  We need context->clockskew,
1931280304Sjkim * but krb5_context is an opaque struct.  So we try to sneek the clockskew
1932280304Sjkim * out through the replay cache.  If that fails just return a likely default
1933280304Sjkim * (300 seconds).
1934280304Sjkim */
1935238405Sjkimstatic krb5_deltat get_rc_clockskew(krb5_context context)
1936280304Sjkim{
1937280304Sjkim    krb5_rcache rc;
1938280304Sjkim    krb5_deltat clockskew;
1939109998Smarkm
1940280304Sjkim    if (krb5_rc_default(context, &rc))
1941280304Sjkim        return KSSL_CLOCKSKEW;
1942280304Sjkim    if (krb5_rc_initialize(context, rc, 0))
1943280304Sjkim        return KSSL_CLOCKSKEW;
1944280304Sjkim    if (krb5_rc_get_lifespan(context, rc, &clockskew)) {
1945280304Sjkim        clockskew = KSSL_CLOCKSKEW;
1946280304Sjkim    }
1947280304Sjkim    (void)krb5_rc_destroy(context, rc);
1948280304Sjkim    return clockskew;
1949280304Sjkim}
1950109998Smarkm
1951280304Sjkim/*
1952280304Sjkim * kssl_validate_times() combines (and more importantly exposes) the MIT KRB5
1953280304Sjkim * internal function krb5_validate_times() and the in_clock_skew() macro.
1954280304Sjkim * The authenticator client time is checked to be within clockskew secs of
1955280304Sjkim * the current time and the current time is checked to be within the ticket
1956280304Sjkim * start and expire times.  Either check may be omitted by supplying a NULL
1957280304Sjkim * value.  Returns 0 for valid times, SSL_R_KRB5* error codes otherwise.  See
1958280304Sjkim * Also: (Kerberos source)/krb5/lib/krb5/krb/valid_times.c 20010420 VRS
1959280304Sjkim */
1960280304Sjkimkrb5_error_code kssl_validate_times(krb5_timestamp atime,
1961280304Sjkim                                    krb5_ticket_times *ttimes)
1962280304Sjkim{
1963280304Sjkim    krb5_deltat skew;
1964280304Sjkim    krb5_timestamp start, now;
1965280304Sjkim    krb5_error_code rc;
1966280304Sjkim    krb5_context context;
1967109998Smarkm
1968280304Sjkim    if ((rc = krb5_init_context(&context)))
1969280304Sjkim        return SSL_R_KRB5_S_BAD_TICKET;
1970280304Sjkim    skew = get_rc_clockskew(context);
1971280304Sjkim    if ((rc = krb5_timeofday(context, &now)))
1972280304Sjkim        return SSL_R_KRB5_S_BAD_TICKET;
1973280304Sjkim    krb5_free_context(context);
1974109998Smarkm
1975280304Sjkim    if (atime && labs(atime - now) >= skew)
1976280304Sjkim        return SSL_R_KRB5_S_TKT_SKEW;
1977109998Smarkm
1978280304Sjkim    if (!ttimes)
1979280304Sjkim        return 0;
1980109998Smarkm
1981280304Sjkim    start = (ttimes->starttime != 0) ? ttimes->starttime : ttimes->authtime;
1982280304Sjkim    if (start - now > skew)
1983280304Sjkim        return SSL_R_KRB5_S_TKT_NYV;
1984280304Sjkim    if ((now - ttimes->endtime) > skew)
1985280304Sjkim        return SSL_R_KRB5_S_TKT_EXPIRED;
1986109998Smarkm
1987280304Sjkim# ifdef KSSL_DEBUG
1988280304Sjkim    fprintf(stderr, "kssl_validate_times: %d |<-  | %d - %d | < %d  ->| %d\n",
1989280304Sjkim            start, atime, now, skew, ttimes->endtime);
1990280304Sjkim# endif                         /* KSSL_DEBUG */
1991109998Smarkm
1992280304Sjkim    return 0;
1993280304Sjkim}
1994109998Smarkm
1995280304Sjkim/*
1996280304Sjkim * Decode and decrypt given DER-encoded authenticator, then pass
1997280304Sjkim * authenticator ctime back in *atimep (or 0 if time unavailable).  Returns
1998280304Sjkim * krb5_error_code and kssl_err on error.  A NULL authenticator
1999280304Sjkim * (authentp->length == 0) is not considered an error.  Note that
2000280304Sjkim * kssl_check_authent() makes use of the KRB5 session key; you must call
2001280304Sjkim * kssl_sget_tkt() to get the key before calling this routine.
2002280304Sjkim */
2003280304Sjkimkrb5_error_code kssl_check_authent(
2004280304Sjkim                                      /*
2005280304Sjkim                                       * IN
2006280304Sjkim                                       */ KSSL_CTX *kssl_ctx,
2007280304Sjkim                                      /*
2008280304Sjkim                                       * IN
2009280304Sjkim                                       */ krb5_data *authentp,
2010280304Sjkim                                      /*
2011280304Sjkim                                       * OUT
2012280304Sjkim                                       */ krb5_timestamp *atimep,
2013280304Sjkim                                      /*
2014280304Sjkim                                       * OUT
2015280304Sjkim                                       */ KSSL_ERR *kssl_err)
2016280304Sjkim{
2017280304Sjkim    krb5_error_code krb5rc = 0;
2018280304Sjkim    KRB5_ENCDATA *dec_authent = NULL;
2019280304Sjkim    KRB5_AUTHENTBODY *auth = NULL;
2020280304Sjkim    krb5_enctype enctype;
2021280304Sjkim    EVP_CIPHER_CTX ciph_ctx;
2022280304Sjkim    const EVP_CIPHER *enc = NULL;
2023280304Sjkim    unsigned char iv[EVP_MAX_IV_LENGTH];
2024280304Sjkim    const unsigned char *p;
2025280304Sjkim    unsigned char *unenc_authent;
2026280304Sjkim    int outl, unencbufsize;
2027280304Sjkim    struct tm tm_time, *tm_l, *tm_g;
2028280304Sjkim    time_t now, tl, tg, tr, tz_offset;
2029109998Smarkm
2030280304Sjkim    EVP_CIPHER_CTX_init(&ciph_ctx);
2031280304Sjkim    *atimep = 0;
2032280304Sjkim    kssl_err_set(kssl_err, 0, "");
2033109998Smarkm
2034280304Sjkim# ifndef KRB5CHECKAUTH
2035280304Sjkim    authentp = NULL;
2036280304Sjkim# else
2037280304Sjkim#  if     KRB5CHECKAUTH == 0
2038280304Sjkim    authentp = NULL;
2039280304Sjkim#  endif
2040280304Sjkim# endif                         /* KRB5CHECKAUTH */
2041109998Smarkm
2042280304Sjkim    if (authentp == NULL || authentp->length == 0)
2043280304Sjkim        return 0;
2044109998Smarkm
2045280304Sjkim# ifdef KSSL_DEBUG
2046280304Sjkim    {
2047109998Smarkm        unsigned int ui;
2048280304Sjkim        fprintf(stderr, "kssl_check_authent: authenticator[%d]:\n",
2049280304Sjkim                authentp->length);
2050280304Sjkim        p = authentp->data;
2051280304Sjkim        for (ui = 0; ui < authentp->length; ui++)
2052280304Sjkim            fprintf(stderr, "%02x ", p[ui]);
2053280304Sjkim        fprintf(stderr, "\n");
2054280304Sjkim    }
2055280304Sjkim# endif                         /* KSSL_DEBUG */
2056109998Smarkm
2057280304Sjkim    unencbufsize = 2 * authentp->length;
2058280304Sjkim    if ((unenc_authent = calloc(1, unencbufsize)) == NULL) {
2059280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
2060280304Sjkim                     "Unable to allocate authenticator buffer.\n");
2061280304Sjkim        krb5rc = KRB5KRB_ERR_GENERIC;
2062280304Sjkim        goto err;
2063280304Sjkim    }
2064109998Smarkm
2065280304Sjkim    p = (unsigned char *)authentp->data;
2066280304Sjkim    if ((dec_authent = d2i_KRB5_ENCDATA(NULL, &p,
2067280304Sjkim                                        (long)authentp->length)) == NULL) {
2068280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
2069280304Sjkim                     "Error decoding authenticator.\n");
2070280304Sjkim        krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2071280304Sjkim        goto err;
2072280304Sjkim    }
2073109998Smarkm
2074280304Sjkim    enctype = dec_authent->etype->data[0]; /* should = kssl_ctx->enctype */
2075280304Sjkim# if !defined(KRB5_MIT_OLD11)
2076280304Sjkim    switch (enctype) {
2077280304Sjkim    case ENCTYPE_DES3_CBC_SHA1: /* EVP_des_ede3_cbc(); */
2078280304Sjkim    case ENCTYPE_DES3_CBC_SHA:
2079280304Sjkim    case ENCTYPE_DES3_CBC_RAW:
2080280304Sjkim        krb5rc = 0;             /* Skip, can't handle derived keys */
2081280304Sjkim        goto err;
2082280304Sjkim    }
2083280304Sjkim# endif
2084280304Sjkim    enc = kssl_map_enc(enctype);
2085280304Sjkim    memset(iv, 0, sizeof iv);   /* per RFC 1510 */
2086109998Smarkm
2087280304Sjkim    if (enc == NULL) {
2088280304Sjkim        /*
2089280304Sjkim         * Disable kssl_check_authent for ENCTYPE_DES3_CBC_SHA1.  This
2090280304Sjkim         * enctype indicates the authenticator was encrypted using key-usage
2091280304Sjkim         * derived keys which openssl cannot decrypt.
2092280304Sjkim         */
2093280304Sjkim        goto err;
2094280304Sjkim    }
2095109998Smarkm
2096280304Sjkim    if (!EVP_CipherInit(&ciph_ctx, enc, kssl_ctx->key, iv, 0)) {
2097280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
2098280304Sjkim                     "EVP_CipherInit error decrypting authenticator.\n");
2099280304Sjkim        krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2100280304Sjkim        goto err;
2101280304Sjkim    }
2102280304Sjkim    outl = dec_authent->cipher->length;
2103280304Sjkim    if (!EVP_Cipher
2104280304Sjkim        (&ciph_ctx, unenc_authent, dec_authent->cipher->data, outl)) {
2105280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
2106280304Sjkim                     "EVP_Cipher error decrypting authenticator.\n");
2107280304Sjkim        krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2108280304Sjkim        goto err;
2109280304Sjkim    }
2110280304Sjkim    EVP_CIPHER_CTX_cleanup(&ciph_ctx);
2111109998Smarkm
2112280304Sjkim# ifdef KSSL_DEBUG
2113280304Sjkim    {
2114280304Sjkim        int padl;
2115280304Sjkim        fprintf(stderr, "kssl_check_authent: decrypted authenticator[%d] =\n",
2116280304Sjkim                outl);
2117280304Sjkim        for (padl = 0; padl < outl; padl++)
2118280304Sjkim            fprintf(stderr, "%02x ", unenc_authent[padl]);
2119280304Sjkim        fprintf(stderr, "\n");
2120280304Sjkim    }
2121280304Sjkim# endif                         /* KSSL_DEBUG */
2122109998Smarkm
2123280304Sjkim    if ((p = kssl_skip_confound(enctype, unenc_authent)) == NULL) {
2124280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
2125280304Sjkim                     "confounded by authenticator.\n");
2126280304Sjkim        krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2127280304Sjkim        goto err;
2128280304Sjkim    }
2129280304Sjkim    outl -= p - unenc_authent;
2130109998Smarkm
2131280304Sjkim    if ((auth = (KRB5_AUTHENTBODY *)d2i_KRB5_AUTHENT(NULL, &p,
2132280304Sjkim                                                     (long)outl)) == NULL) {
2133280304Sjkim        kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
2134280304Sjkim                     "Error decoding authenticator body.\n");
2135280304Sjkim        krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
2136280304Sjkim        goto err;
2137280304Sjkim    }
2138109998Smarkm
2139280304Sjkim    memset(&tm_time, 0, sizeof(struct tm));
2140280304Sjkim    if (k_gmtime(auth->ctime, &tm_time) &&
2141280304Sjkim        ((tr = mktime(&tm_time)) != (time_t)(-1))) {
2142280304Sjkim        now = time(&now);
2143280304Sjkim        tm_l = localtime(&now);
2144280304Sjkim        tl = mktime(tm_l);
2145280304Sjkim        tm_g = gmtime(&now);
2146280304Sjkim        tg = mktime(tm_g);
2147280304Sjkim        tz_offset = tg - tl;
2148109998Smarkm
2149280304Sjkim        *atimep = (krb5_timestamp)(tr - tz_offset);
2150280304Sjkim    }
2151280304Sjkim# ifdef KSSL_DEBUG
2152280304Sjkim    fprintf(stderr, "kssl_check_authent: returns %d for client time ",
2153280304Sjkim            *atimep);
2154280304Sjkim    if (auth && auth->ctime && auth->ctime->length && auth->ctime->data)
2155280304Sjkim        fprintf(stderr, "%.*s\n", auth->ctime->length, auth->ctime->data);
2156280304Sjkim    else
2157280304Sjkim        fprintf(stderr, "NULL\n");
2158280304Sjkim# endif                         /* KSSL_DEBUG */
2159109998Smarkm
2160109998Smarkm err:
2161280304Sjkim    if (auth)
2162280304Sjkim        KRB5_AUTHENT_free((KRB5_AUTHENT *) auth);
2163280304Sjkim    if (dec_authent)
2164280304Sjkim        KRB5_ENCDATA_free(dec_authent);
2165280304Sjkim    if (unenc_authent)
2166280304Sjkim        free(unenc_authent);
2167280304Sjkim    EVP_CIPHER_CTX_cleanup(&ciph_ctx);
2168280304Sjkim    return krb5rc;
2169280304Sjkim}
2170109998Smarkm
2171280304Sjkim/*
2172280304Sjkim * Replaces krb5_build_principal_ext(), with varargs length == 2 (svc, host),
2173280304Sjkim * because I don't know how to stub varargs.  Returns krb5_error_code ==
2174280304Sjkim * ENOMEM on alloc error, otherwise passes back newly constructed principal,
2175280304Sjkim * which should be freed by caller.
2176280304Sjkim */
2177280304Sjkimkrb5_error_code kssl_build_principal_2(
2178280304Sjkim                                          /*
2179280304Sjkim                                           * UPDATE
2180280304Sjkim                                           */ krb5_context context,
2181280304Sjkim                                          /*
2182280304Sjkim                                           * OUT
2183280304Sjkim                                           */ krb5_principal *princ,
2184280304Sjkim                                          /*
2185280304Sjkim                                           * IN
2186280304Sjkim                                           */ int rlen, const char *realm,
2187280304Sjkim                                          /*
2188280304Sjkim                                           * IN
2189280304Sjkim                                           */ int slen, const char *svc,
2190280304Sjkim                                          /*
2191280304Sjkim                                           * IN
2192280304Sjkim                                           */ int hlen, const char *host)
2193280304Sjkim{
2194280304Sjkim    krb5_data *p_data = NULL;
2195280304Sjkim    krb5_principal new_p = NULL;
2196280304Sjkim    char *new_r = NULL;
2197109998Smarkm
2198280304Sjkim    if ((p_data = (krb5_data *)calloc(2, sizeof(krb5_data))) == NULL ||
2199280304Sjkim        (new_p = (krb5_principal)calloc(1, sizeof(krb5_principal_data)))
2200280304Sjkim        == NULL)
2201280304Sjkim        goto err;
2202280304Sjkim    new_p->length = 2;
2203280304Sjkim    new_p->data = p_data;
2204109998Smarkm
2205280304Sjkim    if ((new_r = calloc(1, rlen + 1)) == NULL)
2206280304Sjkim        goto err;
2207280304Sjkim    memcpy(new_r, realm, rlen);
2208280304Sjkim    krb5_princ_set_realm_length(context, new_p, rlen);
2209280304Sjkim    krb5_princ_set_realm_data(context, new_p, new_r);
2210109998Smarkm
2211280304Sjkim    if ((new_p->data[0].data = calloc(1, slen + 1)) == NULL)
2212280304Sjkim        goto err;
2213280304Sjkim    memcpy(new_p->data[0].data, svc, slen);
2214280304Sjkim    new_p->data[0].length = slen;
2215109998Smarkm
2216280304Sjkim    if ((new_p->data[1].data = calloc(1, hlen + 1)) == NULL)
2217280304Sjkim        goto err;
2218280304Sjkim    memcpy(new_p->data[1].data, host, hlen);
2219280304Sjkim    new_p->data[1].length = hlen;
2220109998Smarkm
2221280304Sjkim    krb5_princ_type(context, new_p) = KRB5_NT_UNKNOWN;
2222280304Sjkim    *princ = new_p;
2223280304Sjkim    return 0;
2224109998Smarkm
2225109998Smarkm err:
2226280304Sjkim    if (new_p && new_p[0].data)
2227280304Sjkim        free(new_p[0].data);
2228280304Sjkim    if (new_p && new_p[1].data)
2229280304Sjkim        free(new_p[1].data);
2230280304Sjkim    if (new_p)
2231280304Sjkim        free(new_p);
2232280304Sjkim    if (new_r)
2233280304Sjkim        free(new_r);
2234280304Sjkim    return ENOMEM;
2235280304Sjkim}
2236109998Smarkm
2237238405Sjkimvoid SSL_set0_kssl_ctx(SSL *s, KSSL_CTX *kctx)
2238280304Sjkim{
2239280304Sjkim    s->kssl_ctx = kctx;
2240280304Sjkim}
2241109998Smarkm
2242280304SjkimKSSL_CTX *SSL_get0_kssl_ctx(SSL *s)
2243280304Sjkim{
2244280304Sjkim    return s->kssl_ctx;
2245280304Sjkim}
2246238405Sjkim
2247238405Sjkimchar *kssl_ctx_get0_client_princ(KSSL_CTX *kctx)
2248280304Sjkim{
2249280304Sjkim    if (kctx)
2250280304Sjkim        return kctx->client_princ;
2251280304Sjkim    return NULL;
2252280304Sjkim}
2253238405Sjkim
2254280304Sjkim#else                           /* !OPENSSL_NO_KRB5 */
2255109998Smarkm
2256280304Sjkim# if defined(PEDANTIC) || defined(OPENSSL_SYS_VMS)
2257280304Sjkimstatic void *dummy = &dummy;
2258280304Sjkim# endif
2259109998Smarkm
2260280304Sjkim#endif                          /* !OPENSSL_NO_KRB5 */
2261