]> git.ipfire.org Git - thirdparty/openssl.git/blame - ssl/kssl.c
Use new-style system-id macros everywhere possible. I hope I haven't
[thirdparty/openssl.git] / ssl / kssl.c
CommitLineData
43fcc1b0
RL
1/* ssl/kssl.c -*- mode: C; c-file-style: "eay" -*- */
2/* Written by Vern Staats <staatsvr@asc.hpc.mil> for the OpenSSL project 2000.
3 */
4/* ====================================================================
5 * Copyright (c) 2000 The OpenSSL Project. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * 3. All advertising materials mentioning features or use of this
20 * software must display the following acknowledgment:
21 * "This product includes software developed by the OpenSSL Project
22 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
23 *
24 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
25 * endorse or promote products derived from this software without
26 * prior written permission. For written permission, please contact
27 * licensing@OpenSSL.org.
28 *
29 * 5. Products derived from this software may not be called "OpenSSL"
30 * nor may "OpenSSL" appear in their names without prior written
31 * permission of the OpenSSL Project.
32 *
33 * 6. Redistributions of any form whatsoever must retain the following
34 * acknowledgment:
35 * "This product includes software developed by the OpenSSL Project
36 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
37 *
38 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
39 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
41 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
42 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
47 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
49 * OF THE POSSIBILITY OF SUCH DAMAGE.
50 * ====================================================================
51 *
52 * This product includes cryptographic software written by Eric Young
53 * (eay@cryptsoft.com). This product includes software written by Tim
54 * Hudson (tjh@cryptsoft.com).
55 *
56 */
57
58
59/* ssl/kssl.c -- Routines to support (& debug) Kerberos5 auth for openssl
60**
61** 19990701 VRS Started.
62*/
63
7bd51947 64#include <openssl/opensslconf.h>
bc36ee62 65#ifndef OPENSSL_NO_KRB5
43fcc1b0
RL
66#include <string.h>
67#include <openssl/ssl.h>
68
f9b3bff6
RL
69/*
70 * When OpenSSL is built on Windows, we do not want to require that
71 * the Kerberos DLLs be available in order for the OpenSSL DLLs to
72 * work. Therefore, all Kerberos routines are loaded at run time
73 * and we do not link to a .LIB file.
74 */
75
bc36ee62 76#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
f9b3bff6
RL
77/*
78 * The purpose of the following pre-processor statements is to provide
79 * compatibility with different releases of MIT Kerberos for Windows.
80 * All versions up to 1.2 used macros. But macros do not allow for
81 * a binary compatible interface for DLLs. Therefore, all macros are
82 * being replaced by function calls. The following code will allow
83 * an OpenSSL DLL built on Windows to work whether or not the macro
84 * or function form of the routines are utilized.
85 */
86#ifdef krb5_cc_get_principal
87#define NO_DEF_KRB5_CCACHE
88#undef krb5_cc_get_principal
89#endif
90#define krb5_cc_get_principal kssl_krb5_cc_get_principal
91
92#define krb5_free_data_contents kssl_krb5_free_data_contents
93#define krb5_free_context kssl_krb5_free_context
94#define krb5_auth_con_free kssl_krb5_auth_con_free
95#define krb5_free_principal kssl_krb5_free_principal
96#define krb5_mk_req_extended kssl_krb5_mk_req_extended
97#define krb5_get_credentials kssl_krb5_get_credentials
98#define krb5_cc_default kssl_krb5_cc_default
99#define krb5_sname_to_principal kssl_krb5_sname_to_principal
100#define krb5_init_context kssl_krb5_init_context
101#define krb5_free_ticket kssl_krb5_free_ticket
102#define krb5_rd_req kssl_krb5_rd_req
103#define krb5_kt_default kssl_krb5_kt_default
104#define krb5_kt_resolve kssl_krb5_kt_resolve
105#define krb5_auth_con_init kssl_krb5_auth_con_init
106
107/* Prototypes for built in stubs */
108void kssl_krb5_free_data_contents(krb5_context, krb5_data *);
109void kssl_krb5_free_principal(krb5_context, krb5_principal );
110krb5_error_code kssl_krb5_kt_resolve(krb5_context,
111 krb5_const char *,
112 krb5_keytab *);
113krb5_error_code kssl_krb5_kt_default(krb5_context,
114 krb5_keytab *);
115krb5_error_code kssl_krb5_free_ticket(krb5_context, krb5_ticket *);
116krb5_error_code kssl_krb5_rd_req(krb5_context, krb5_auth_context *,
117 krb5_const krb5_data *,
118 krb5_const_principal, krb5_keytab,
119 krb5_flags *,krb5_ticket **);
120krb5_error_code kssl_krb5_mk_req_extended(krb5_context,
121 krb5_auth_context *,
122 krb5_const krb5_flags,
123 krb5_data *,
124 krb5_creds *,
125 krb5_data * );
126krb5_error_code kssl_krb5_init_context(krb5_context *);
127void kssl_krb5_free_context(krb5_context);
128krb5_error_code kssl_krb5_cc_default(krb5_context,krb5_ccache *);
129krb5_error_code kssl_krb5_sname_to_principal(krb5_context,
130 krb5_const char *,
131 krb5_const char *,
132 krb5_int32,
133 krb5_principal *);
134krb5_error_code kssl_krb5_get_credentials(krb5_context,
135 krb5_const krb5_flags,
136 krb5_ccache,
137 krb5_creds *,
138 krb5_creds * *);
139krb5_error_code kssl_krb5_auth_con_init(krb5_context,
140 krb5_auth_context *);
141krb5_error_code kssl_krb5_cc_get_principal(krb5_context context,
142 krb5_ccache cache,
143 krb5_principal *principal);
144krb5_error_code kssl_krb5_auth_con_free(krb5_context,krb5_auth_context);
145
146/* Function pointers (almost all Kerberos functions are _stdcall) */
147static void (_stdcall *p_krb5_free_data_contents)(krb5_context, krb5_data *)=NULL;
148static void (_stdcall *p_krb5_free_principal)(krb5_context, krb5_principal )=NULL;
149static krb5_error_code(_stdcall *p_krb5_kt_resolve)(krb5_context, krb5_const char *,
150 krb5_keytab *)=NULL;
151static krb5_error_code (_stdcall *p_krb5_kt_default)(krb5_context,
152 krb5_keytab *)=NULL;
153static krb5_error_code (_stdcall *p_krb5_free_ticket)(krb5_context,
154 krb5_ticket *)=NULL;
155static krb5_error_code (_stdcall *p_krb5_rd_req)(krb5_context,
156 krb5_auth_context *,
157 krb5_const krb5_data *,
158 krb5_const_principal,
159 krb5_keytab, krb5_flags *,
160 krb5_ticket **)=NULL;
161static krb5_error_code (_stdcall *p_krb5_mk_req_extended) (krb5_context,
162 krb5_auth_context *,
163 krb5_const krb5_flags,
164 krb5_data *,
165 krb5_creds *,
166 krb5_data * )=NULL;
167static krb5_error_code (_stdcall *p_krb5_init_context)(krb5_context *)=NULL;
168static void (_stdcall *p_krb5_free_context)(krb5_context)=NULL;
169static krb5_error_code (_stdcall *p_krb5_cc_default)(krb5_context,
170 krb5_ccache *)=NULL;
171static krb5_error_code (_stdcall *p_krb5_sname_to_principal)(krb5_context,
172 krb5_const char *,
173 krb5_const char *,
174 krb5_int32,
175 krb5_principal *)=NULL;
176static krb5_error_code (_stdcall *p_krb5_get_credentials)(krb5_context,
177 krb5_const krb5_flags,
178 krb5_ccache,
179 krb5_creds *,
180 krb5_creds * *)=NULL;
181static krb5_error_code (_stdcall *p_krb5_auth_con_init)(krb5_context,
182 krb5_auth_context *)=NULL;
183static krb5_error_code (_stdcall *p_krb5_cc_get_principal)(krb5_context context,
184 krb5_ccache cache,
185 krb5_principal *principal)=NULL;
186static krb5_error_code (_stdcall *p_krb5_auth_con_free)(krb5_context,
187 krb5_auth_context)=NULL;
188static int krb5_loaded = 0; /* only attempt to initialize func ptrs once */
189
190/* Function to Load the Kerberos 5 DLL and initialize function pointers */
191void
192load_krb5_dll(void)
193 {
194 HANDLE hKRB5_32;
195
196 krb5_loaded++;
197 hKRB5_32 = LoadLibrary("KRB5_32");
198 if (!hKRB5_32)
199 return;
200
201 (FARPROC) p_krb5_free_data_contents =
202 GetProcAddress( hKRB5_32, "krb5_free_data_contents" );
203 (FARPROC) p_krb5_free_context =
204 GetProcAddress( hKRB5_32, "krb5_free_context" );
205 (FARPROC) p_krb5_auth_con_free =
206 GetProcAddress( hKRB5_32, "krb5_auth_con_free" );
207 (FARPROC) p_krb5_free_principal =
208 GetProcAddress( hKRB5_32, "krb5_free_principal" );
209 (FARPROC) p_krb5_mk_req_extended =
210 GetProcAddress( hKRB5_32, "krb5_mk_req_extended" );
211 (FARPROC) p_krb5_get_credentials =
212 GetProcAddress( hKRB5_32, "krb5_get_credentials" );
213 (FARPROC) p_krb5_cc_get_principal =
214 GetProcAddress( hKRB5_32, "krb5_cc_get_principal" );
215 (FARPROC) p_krb5_cc_default =
216 GetProcAddress( hKRB5_32, "krb5_cc_default" );
217 (FARPROC) p_krb5_sname_to_principal =
218 GetProcAddress( hKRB5_32, "krb5_sname_to_principal" );
219 (FARPROC) p_krb5_init_context =
220 GetProcAddress( hKRB5_32, "krb5_init_context" );
221 (FARPROC) p_krb5_free_ticket =
222 GetProcAddress( hKRB5_32, "krb5_free_ticket" );
223 (FARPROC) p_krb5_rd_req =
224 GetProcAddress( hKRB5_32, "krb5_rd_req" );
225 (FARPROC) p_krb5_kt_default =
226 GetProcAddress( hKRB5_32, "krb5_kt_default" );
227 (FARPROC) p_krb5_kt_resolve =
228 GetProcAddress( hKRB5_32, "krb5_kt_resolve" );
229 (FARPROC) p_krb5_auth_con_init =
230 GetProcAddress( hKRB5_32, "krb5_auth_con_init" );
231 }
232
233/* Stubs for each function to be dynamicly loaded */
234void
235kssl_krb5_free_data_contents(krb5_context CO, krb5_data * data)
236 {
237 if (!krb5_loaded)
238 load_krb5_dll();
239
240 if ( p_krb5_free_data_contents )
241 p_krb5_free_data_contents(CO,data);
242 }
243
244krb5_error_code
245kssl_krb5_mk_req_extended (krb5_context CO,
246 krb5_auth_context * pACO,
247 krb5_const krb5_flags F,
248 krb5_data * pD1,
249 krb5_creds * pC,
250 krb5_data * pD2)
251 {
252 if (!krb5_loaded)
253 load_krb5_dll();
254
255 if ( p_krb5_mk_req_extended )
256 return(p_krb5_mk_req_extended(CO,pACO,F,pD1,pC,pD2));
257 else
258 return KRB5KRB_ERR_GENERIC;
259 }
260krb5_error_code
261kssl_krb5_auth_con_init(krb5_context CO,
262 krb5_auth_context * pACO)
263 {
264 if (!krb5_loaded)
265 load_krb5_dll();
266
267 if ( p_krb5_auth_con_init )
268 return(p_krb5_auth_con_init(CO,pACO));
269 else
270 return KRB5KRB_ERR_GENERIC;
271 }
272krb5_error_code
273kssl_krb5_auth_con_free (krb5_context CO,
274 krb5_auth_context ACO)
275 {
276 if (!krb5_loaded)
277 load_krb5_dll();
278
279 if ( p_krb5_auth_con_free )
280 return(p_krb5_auth_con_free(CO,ACO));
281 else
282 return KRB5KRB_ERR_GENERIC;
283 }
284krb5_error_code
285kssl_krb5_get_credentials(krb5_context CO,
286 krb5_const krb5_flags F,
287 krb5_ccache CC,
288 krb5_creds * pCR,
289 krb5_creds ** ppCR)
290 {
291 if (!krb5_loaded)
292 load_krb5_dll();
293
294 if ( p_krb5_get_credentials )
295 return(p_krb5_get_credentials(CO,F,CC,pCR,ppCR));
296 else
297 return KRB5KRB_ERR_GENERIC;
298 }
299krb5_error_code
300kssl_krb5_sname_to_principal(krb5_context CO,
301 krb5_const char * pC1,
302 krb5_const char * pC2,
303 krb5_int32 I,
304 krb5_principal * pPR)
305 {
306 if (!krb5_loaded)
307 load_krb5_dll();
308
309 if ( p_krb5_sname_to_principal )
310 return(p_krb5_sname_to_principal(CO,pC1,pC2,I,pPR));
311 else
312 return KRB5KRB_ERR_GENERIC;
313 }
314
315krb5_error_code
316kssl_krb5_cc_default(krb5_context CO,
317 krb5_ccache * pCC)
318 {
319 if (!krb5_loaded)
320 load_krb5_dll();
321
322 if ( p_krb5_cc_default )
323 return(p_krb5_cc_default(CO,pCC));
324 else
325 return KRB5KRB_ERR_GENERIC;
326 }
327
328krb5_error_code
329kssl_krb5_init_context(krb5_context * pCO)
330 {
331 if (!krb5_loaded)
332 load_krb5_dll();
333
334 if ( p_krb5_init_context )
335 return(p_krb5_init_context(pCO));
336 else
337 return KRB5KRB_ERR_GENERIC;
338 }
339
340void
341kssl_krb5_free_context(krb5_context CO)
342 {
343 if (!krb5_loaded)
344 load_krb5_dll();
345
346 if ( p_krb5_free_context )
347 p_krb5_free_context(CO);
348 }
349
350void
351kssl_krb5_free_principal(krb5_context c, krb5_principal p)
352 {
353 if (!krb5_loaded)
354 load_krb5_dll();
355
356 if ( p_krb5_free_principal )
357 p_krb5_free_principal(c,p);
358 }
359
360krb5_error_code
361kssl_krb5_kt_resolve(krb5_context con,
362 krb5_const char * sz,
363 krb5_keytab * kt)
364 {
365 if (!krb5_loaded)
366 load_krb5_dll();
367
368 if ( p_krb5_kt_resolve )
369 return(p_krb5_kt_resolve(con,sz,kt));
370 else
371 return KRB5KRB_ERR_GENERIC;
372 }
373
374krb5_error_code
375kssl_krb5_kt_default(krb5_context con,
376 krb5_keytab * kt)
377 {
378 if (!krb5_loaded)
379 load_krb5_dll();
380
381 if ( p_krb5_kt_default )
382 return(p_krb5_kt_default(con,kt));
383 else
384 return KRB5KRB_ERR_GENERIC;
385 }
386
387krb5_error_code
388kssl_krb5_free_ticket(krb5_context con,
389 krb5_ticket * kt)
390 {
391 if (!krb5_loaded)
392 load_krb5_dll();
393
394 if ( p_krb5_free_ticket )
395 return(p_krb5_free_ticket(con,kt));
396 else
397 return KRB5KRB_ERR_GENERIC;
398 }
399
400krb5_error_code
401kssl_krb5_rd_req(krb5_context con, krb5_auth_context * pacon,
402 krb5_const krb5_data * data,
403 krb5_const_principal princ, krb5_keytab keytab,
404 krb5_flags * flags, krb5_ticket ** pptkt)
405 {
406 if (!krb5_loaded)
407 load_krb5_dll();
408
409 if ( p_krb5_rd_req )
410 return(p_krb5_rd_req(con,pacon,data,princ,keytab,flags,pptkt));
411 else
412 return KRB5KRB_ERR_GENERIC;
413 }
414
415/* Structure definitions */
416#ifndef NO_DEF_KRB5_CCACHE
417#ifndef krb5_x
418#define krb5_x(ptr,args) ((ptr)?((*(ptr)) args):(abort(),1))
419#define krb5_xc(ptr,args) ((ptr)?((*(ptr)) args):(abort(),(char*)0))
420#endif
421
422typedef krb5_pointer krb5_cc_cursor; /* cursor for sequential lookup */
423
424typedef struct _krb5_ccache
425 {
426 krb5_magic magic;
427 struct _krb5_cc_ops FAR *ops;
428 krb5_pointer data;
429 } *krb5_ccache;
430
431typedef struct _krb5_cc_ops
432 {
433 krb5_magic magic;
434 char *prefix;
435 char * (KRB5_CALLCONV *get_name) KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
436 krb5_error_code (KRB5_CALLCONV *resolve) KRB5_NPROTOTYPE((krb5_context, krb5_ccache *,
437 const char *));
438 krb5_error_code (KRB5_CALLCONV *gen_new) KRB5_NPROTOTYPE((krb5_context, krb5_ccache *));
439 krb5_error_code (KRB5_CALLCONV *init) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
440 krb5_principal));
441 krb5_error_code (KRB5_CALLCONV *destroy) KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
442 krb5_error_code (KRB5_CALLCONV *close) KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
443 krb5_error_code (KRB5_CALLCONV *store) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
444 krb5_creds *));
445 krb5_error_code (KRB5_CALLCONV *retrieve) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
446 krb5_flags, krb5_creds *,
447 krb5_creds *));
448 krb5_error_code (KRB5_CALLCONV *get_princ) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
449 krb5_principal *));
450 krb5_error_code (KRB5_CALLCONV *get_first) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
451 krb5_cc_cursor *));
452 krb5_error_code (KRB5_CALLCONV *get_next) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
453 krb5_cc_cursor *, krb5_creds *));
454 krb5_error_code (KRB5_CALLCONV *end_get) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
455 krb5_cc_cursor *));
456 krb5_error_code (KRB5_CALLCONV *remove_cred) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
457 krb5_flags, krb5_creds *));
458 krb5_error_code (KRB5_CALLCONV *set_flags) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
459 krb5_flags));
460 } krb5_cc_ops;
461#endif /* NO_DEF_KRB5_CCACHE */
462
463krb5_error_code
464kssl_krb5_cc_get_principal
465 (krb5_context context, krb5_ccache cache,
466 krb5_principal *principal)
467 {
468 if ( p_krb5_cc_get_principal )
469 return(p_krb5_cc_get_principal(context,cache,principal));
470 else
471 return(krb5_x ((cache)->ops->get_princ,(context, cache, principal)));
472 }
bc36ee62 473#endif /* OPENSSL_SYS_WINDOWS || OPENSSL_SYS_WIN32 */
f9b3bff6 474
43fcc1b0
RL
475char
476*kstring(char *string)
477 {
478 static char *null = "[NULL]";
479
480 return ((string == NULL)? null: string);
481 }
482
483#define MAXKNUM 255
484char
485*knumber(int len, krb5_octet *contents)
486 {
487 static char buf[MAXKNUM+1];
488 int i;
489
490 BIO_snprintf(buf, MAXKNUM, "[%d] ", len);
491
492 for (i=0; i < len && MAXKNUM > strlen(buf)+3; i++)
493 {
494 BIO_snprintf(&buf[strlen(buf)], 3, "%02x", contents[i]);
495 }
496
497 return (buf);
f9b3bff6 498 }
43fcc1b0
RL
499
500
501/* Set kssl_err error info when reason text is a simple string
502** kssl_err = struct { int reason; char text[KSSL_ERR_MAX+1]; }
503*/
504void
505kssl_err_set(KSSL_ERR *kssl_err, int reason, char *text)
506 {
507 if (kssl_err == NULL) return;
508
509 kssl_err->reason = reason;
510 BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, text);
511 return;
512 }
513
514
515/* Display contents of krb5_data struct, for debugging
516*/
517void
518print_krb5_data(char *label, krb5_data *kdata)
519 {
520 int i;
521
522 printf("%s[%d] ", label, kdata->length);
523 for (i=0; i < kdata->length; i++)
524 {
525 if (isprint((int) kdata->data[i]))
526 printf( "%c ", kdata->data[i]);
527 else
528 printf( "%02x", kdata->data[i]);
529 }
530 printf("\n");
531 }
532
533
534/* Display contents of krb5_authdata struct, for debugging
535*/
536void
537print_krb5_authdata(char *label, krb5_authdata **adata)
538 {
539 if (adata == NULL)
540 {
541 printf("%s, authdata==0\n", label);
542 return;
543 }
544 printf("%s [%p]\n", label, adata);
545#if 0
546 {
547 int i;
548 printf("%s[at%d:%d] ", label, adata->ad_type, adata->length);
549 for (i=0; i < adata->length; i++)
550 {
551 printf((isprint(adata->contents[i]))? "%c ": "%02x",
552 adata->contents[i]);
553 }
554 printf("\n");
555 }
556#endif
f9b3bff6 557 }
43fcc1b0
RL
558
559
560/* Display contents of krb5_keyblock struct, for debugging
561*/
562void
563print_krb5_keyblock(char *label, krb5_keyblock *keyblk)
564 {
565 int i;
566
567 if (keyblk == NULL)
568 {
569 printf("%s, keyblk==0\n", label);
570 return;
571 }
f9b3bff6
RL
572#ifdef KRB5_HEIMDAL
573 printf("%s\n\t[et%d:%d]: ", label, keyblk->keytype, keyblk->keyvalue->length);
574 for (i=0; i < keyblk->keyvalue->length; i++)
575 {
576 printf("%02x",(unsigned char *)(keyblk->keyvalue->contents)[i]);
577 }
578 printf("\n");
579#else
43fcc1b0
RL
580 printf("%s\n\t[et%d:%d]: ", label, keyblk->enctype, keyblk->length);
581 for (i=0; i < keyblk->length; i++)
582 {
583 printf("%02x",keyblk->contents[i]);
584 }
585 printf("\n");
f9b3bff6 586#endif
43fcc1b0
RL
587 }
588
589
590/* Given krb5 service (typically "kssl") and hostname in kssl_ctx,
591** Create Kerberos AP_REQ message for SSL Client.
592**
593** 19990628 VRS Started.
594*/
595krb5_error_code
596kssl_cget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx,
597 /* OUT */ krb5_data *krb5_app_req, KSSL_ERR *kssl_err)
f9b3bff6 598 {
43fcc1b0
RL
599 krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC;
600 krb5_context krb5context = NULL;
601 krb5_auth_context krb5auth_context = NULL;
602 krb5_ccache krb5ccdef = NULL;
603 krb5_creds krb5creds, *krb5credsp = NULL;
604 krb5_data krb5in_data;
605
606 kssl_err_set(kssl_err, 0, "");
607 memset((char *)&krb5creds, 0, sizeof(krb5creds));
608
609 if (!kssl_ctx)
610 {
611 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
612 "No kssl_ctx defined.\n");
613 goto err;
614 }
615 else if (!kssl_ctx->service_host)
616 {
617 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
618 "kssl_ctx service_host undefined.\n");
619 goto err;
620 }
621
622 if ((krb5rc = krb5_init_context(&krb5context)) != 0)
623 {
624 BIO_snprintf(kssl_err->text,KSSL_ERR_MAX,
625 "krb5_init_context() fails: %d\n", krb5rc);
626 kssl_err->reason = SSL_R_KRB5_C_INIT;
627 goto err;
628 }
629
630 if ((krb5rc = krb5_sname_to_principal(krb5context,
631 kssl_ctx->service_host,
632 (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC,
633 KRB5_NT_SRV_HST, &krb5creds.server)) != 0)
634 {
635 BIO_snprintf(kssl_err->text,KSSL_ERR_MAX,
636 "krb5_sname_to_principal() fails for %s/%s\n",
637 kssl_ctx->service_host,
638 (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC);
639 kssl_err->reason = SSL_R_KRB5_C_INIT;
640 goto err;
641 }
642
643 if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0)
644 {
645 kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC,
646 "krb5_cc_default fails.\n");
647 goto err;
648 }
649
650 if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef,
651 &krb5creds.client)) != 0)
652 {
653 kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC,
654 "krb5_cc_get_principal() fails.\n");
655 goto err;
656 }
657
658 if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef,
659 &krb5creds, &krb5credsp)) != 0)
660 {
661 kssl_err_set(kssl_err, SSL_R_KRB5_C_GET_CRED,
662 "krb5_get_credentials() fails.\n");
663 goto err;
664 }
665
666 krb5in_data.data = NULL;
667 krb5in_data.length = 0;
668
669 krb5rc = KRB5KRB_ERR_GENERIC;
670 /* caller should free data of krb5_app_req */
671 if ((krb5rc = krb5_mk_req_extended(krb5context, &krb5auth_context,
672 0, &krb5in_data, krb5credsp, krb5_app_req)) != 0)
673 {
674 kssl_err_set(kssl_err, SSL_R_KRB5_C_MK_REQ,
675 "krb5_mk_req_extended() fails.\n");
676 goto err;
677 }
f9b3bff6
RL
678#ifdef KRB5_HEIMDAL
679 else if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->session))
680 {
681 kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
682 "kssl_ctx_setkey() fails.\n");
683 }
684#else
43fcc1b0
RL
685 else if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->keyblock))
686 {
687 kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
688 "kssl_ctx_setkey() fails.\n");
689 }
f9b3bff6 690#endif
43fcc1b0
RL
691 else krb5rc = 0;
692
693 err:
694#ifdef KSSL_DEBUG
695 kssl_ctx_show(kssl_ctx);
696#endif /* KSSL_DEBUG */
697
698 if (krb5creds.client) krb5_free_principal(krb5context, krb5creds.client);
699 if (krb5creds.server) krb5_free_principal(krb5context, krb5creds.server);
700 if (krb5auth_context) krb5_auth_con_free(krb5context, krb5auth_context);
701 if (krb5context) krb5_free_context(krb5context);
702 return (krb5rc);
f9b3bff6 703 }
43fcc1b0
RL
704
705
706/* Given krb5 service name in KSSL_CTX *kssl_ctx (typically "kssl"),
707** and krb5 AP_REQ message & message length,
708** Return Kerberos session key and client principle
709** to SSL Server in KSSL_CTX *kssl_ctx.
710**
711** 19990702 VRS Started.
712*/
713krb5_error_code
714kssl_sget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx,
715 /* IN */ char *msg, int msglen,
716 /* OUT */ KSSL_ERR *kssl_err )
717 {
718 krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC;
719 static krb5_context krb5context = NULL;
720 static krb5_auth_context krb5auth_context = NULL;
721 krb5_ticket *krb5ticket = NULL;
722 krb5_keytab krb5keytab = NULL;
723 krb5_principal krb5server;
724 krb5_data krb5in_data;
725 krb5_flags ap_option;
726
727 kssl_err_set(kssl_err, 0, "");
728
729 if (!kssl_ctx)
730 {
731 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, "No kssl_ctx defined.\n");
732 goto err;
733 }
734
735#ifdef KSSL_DEBUG
736 printf("in kssl_sget_tkt(%s)\n", kstring(kssl_ctx->service_name));
737#endif /* KSSL_DEBUG */
738
739 if (!krb5context && (krb5rc = krb5_init_context(&krb5context)))
740 {
741 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
742 "krb5_init_context() fails.\n");
743 goto err;
744 }
745 if (krb5auth_context &&
746 (krb5rc = krb5_auth_con_free(krb5context, krb5auth_context)))
747 {
748 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
749 "krb5_auth_con_free() fails.\n");
750 goto err;
751 }
752 else krb5auth_context = NULL;
753 if (!krb5auth_context &&
754 (krb5rc = krb5_auth_con_init(krb5context, &krb5auth_context)))
755 {
756 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
757 "krb5_auth_con_init() fails.\n");
758 goto err;
759 }
760
761 if ((krb5rc = krb5_sname_to_principal(krb5context, NULL,
762 (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC,
763 KRB5_NT_SRV_HST, &krb5server)) != 0)
764 {
765 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
766 "krb5_sname_to_principal() fails.\n");
767 goto err;
768 }
769
f9b3bff6 770 /* kssl_ctx->keytab_file == NULL ==> use Kerberos default
43fcc1b0 771 */
f9b3bff6
RL
772 if (kssl_ctx->keytab_file)
773 {
774 krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file,
775 &krb5keytab);
3e7a6396 776 if (krb5rc)
f9b3bff6
RL
777 {
778 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
779 "krb5_kt_resolve() fails.\n");
780 goto err;
781 }
782 }
783 else
784 {
785 krb5rc = krb5_kt_default(krb5context,&krb5keytab);
786 if (krb5rc)
787 {
788 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
789 "krb5_kt_default() fails.\n");
790 goto err;
791 }
792 }
43fcc1b0
RL
793
794 /* Actual Kerberos5 krb5_recvauth() has initial conversation here
795 ** o check KRB5_SENDAUTH_BADAUTHVERS unless KRB5_RECVAUTH_SKIP_VERSION
796 ** o check KRB5_SENDAUTH_BADAPPLVERS
797 ** o send "0" msg if all OK
798 */
799
800 krb5in_data.data = msg;
801 krb5in_data.length = msglen;
802 if ((krb5rc = krb5_rd_req(krb5context, &krb5auth_context, &krb5in_data,
f9b3bff6 803 krb5server, krb5keytab, &ap_option, &krb5ticket)) != 0)
43fcc1b0
RL
804 {
805 BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
806 "krb5_rd_req() fails with %x.\n", krb5rc);
807 kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
808 goto err;
809 }
810
811 krb5rc = KRB5_NO_TKT_SUPPLIED;
812 if (!krb5ticket || !krb5ticket->enc_part2 ||
813 !krb5ticket->enc_part2->client ||
814 !krb5ticket->enc_part2->client->data ||
815 !krb5ticket->enc_part2->session)
816 {
817 kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
818 "bad ticket from krb5_rd_req.\n");
819 }
820 else if (kssl_ctx_setprinc(kssl_ctx, KSSL_CLIENT,
821 &krb5ticket->enc_part2->client->realm,
822 krb5ticket->enc_part2->client->data))
823 {
824 kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
825 "kssl_ctx_setprinc() fails.\n");
826 }
827 else if (kssl_ctx_setkey(kssl_ctx, krb5ticket->enc_part2->session))
828 {
829 kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
830 "kssl_ctx_setkey() fails.\n");
831 }
832 else krb5rc = 0;
833
834 err:
835#ifdef KSSL_DEBUG
836 kssl_ctx_show(kssl_ctx);
837#endif /* KSSL_DEBUG */
838
f9b3bff6 839 if (krb5keytab) krb5_kt_close(krb5context, krb5keytab);
43fcc1b0
RL
840 if (krb5ticket) krb5_free_ticket(krb5context, krb5ticket);
841 if (krb5server) krb5_free_principal(krb5context, krb5server);
842 return (krb5rc);
843 }
844
845
846/* Allocate & return a new kssl_ctx struct.
847*/
848KSSL_CTX *
849kssl_ctx_new(void)
850 {
851 return ((KSSL_CTX *) calloc(1, sizeof(KSSL_CTX)));
852 }
853
854
855/* Frees a kssl_ctx struct and any allocated memory it holds.
856** Returns NULL.
857*/
858KSSL_CTX *
859kssl_ctx_free(KSSL_CTX *kssl_ctx)
860 {
861 if (kssl_ctx == NULL) return kssl_ctx;
862
863 if (kssl_ctx->key) memset(kssl_ctx->key, 0, kssl_ctx->length);
864 if (kssl_ctx->key) free(kssl_ctx->key);
865 if (kssl_ctx->client_princ) free(kssl_ctx->client_princ);
866 if (kssl_ctx->service_host) free(kssl_ctx->service_host);
867 if (kssl_ctx->service_name) free(kssl_ctx->service_name);
868 if (kssl_ctx->keytab_file) free(kssl_ctx->keytab_file);
869
870 free(kssl_ctx);
871 return (KSSL_CTX *) NULL;
872 }
873
874
875/* Given a (krb5_data *) entity (and optional realm),
876** set the plain (char *) client_princ or service_host member
877** of the kssl_ctx struct.
878*/
879krb5_error_code
880kssl_ctx_setprinc(KSSL_CTX *kssl_ctx, int which,
881 krb5_data *realm, krb5_data *entity)
882 {
883 char **princ;
884 int length;
885
886 if (kssl_ctx == NULL || entity == NULL) return KSSL_CTX_ERR;
887
888 switch (which)
889 {
890 case KSSL_CLIENT: princ = &kssl_ctx->client_princ; break;
891 case KSSL_SERVER: princ = &kssl_ctx->service_host; break;
892 default: return KSSL_CTX_ERR; break;
893 }
894 if (*princ) free(*princ);
895
896 length = entity->length + ((realm)? realm->length + 2: 1);
f9b3bff6
RL
897 if ((*princ = calloc(1, length)) == NULL)
898 return KSSL_CTX_ERR;
43fcc1b0
RL
899 else
900 {
901 strncpy(*princ, entity->data, entity->length);
902 if (realm)
903 {
904 strcat (*princ, "@");
905 (void) strncat(*princ, realm->data, realm->length);
906 }
907 }
908
909 return KSSL_CTX_OK;
910 }
911
912
913/* Set one of the plain (char *) string members of the kssl_ctx struct.
914** Default values should be:
f9b3bff6
RL
915** which == KSSL_SERVICE => "khost" (KRB5SVC)
916** which == KSSL_KEYTAB => "/etc/krb5.keytab" (KRB5KEYTAB)
43fcc1b0
RL
917*/
918krb5_error_code
919kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text)
920 {
921 char **string;
922
923 if (!kssl_ctx) return KSSL_CTX_ERR;
924
925 switch (which)
926 {
927 case KSSL_SERVICE: string = &kssl_ctx->service_name; break;
928 case KSSL_SERVER: string = &kssl_ctx->service_host; break;
929 case KSSL_CLIENT: string = &kssl_ctx->client_princ; break;
930 case KSSL_KEYTAB: string = &kssl_ctx->keytab_file; break;
931 default: return KSSL_CTX_ERR; break;
932 }
933 if (*string) free(*string);
934
935 if (!text)
936 {
937 *string = '\0';
938 return KSSL_CTX_OK;
939 }
940
f9b3bff6
RL
941 if ((*string = calloc(1, strlen(text) + 1)) == NULL)
942 return KSSL_CTX_ERR;
943 else
944 strcpy(*string, text);
43fcc1b0
RL
945
946 return KSSL_CTX_OK;
947 }
948
949
950/* Copy the Kerberos session key from a (krb5_keyblock *) to a kssl_ctx
951** struct. Clear kssl_ctx->key if Kerberos session key is NULL.
952*/
953krb5_error_code
954kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session)
955 {
956 if (!kssl_ctx) return KSSL_CTX_ERR;
957
958 if (kssl_ctx->key)
959 {
960 memset(kssl_ctx->key, 0, kssl_ctx->length);
961 free(kssl_ctx->key);
962 }
963
964 if (session)
965 {
966 kssl_ctx->enctype = session->enctype;
967 kssl_ctx->length = session->length;
968 }
969 else
970 {
971 kssl_ctx->enctype = ENCTYPE_UNKNOWN;
972 kssl_ctx->length = 0;
973 return KSSL_CTX_OK;
974 }
975
976 if ((kssl_ctx->key =
977 (krb5_octet FAR *) calloc(1, kssl_ctx->length)) == NULL)
978 {
979 kssl_ctx->length = 0;
980 return KSSL_CTX_ERR;
981 }
f9b3bff6
RL
982 else
983 memcpy(kssl_ctx->key, session->contents, session->length);
43fcc1b0
RL
984
985 return KSSL_CTX_OK;
986 }
987
988
989/* Display contents of kssl_ctx struct
990*/
991void
992kssl_ctx_show(KSSL_CTX *kssl_ctx)
993 {
994 int i;
995
996 printf("kssl_ctx: ");
997 if (kssl_ctx == NULL)
998 {
999 printf("NULL\n");
1000 return;
1001 }
f9b3bff6
RL
1002 else
1003 printf("%p\n", kssl_ctx);
43fcc1b0
RL
1004
1005 printf("\tservice:\t%s\n",
1006 (kssl_ctx->service_name)? kssl_ctx->service_name: "NULL");
1007 printf("\tclient:\t%s\n",
1008 (kssl_ctx->client_princ)? kssl_ctx->client_princ: "NULL");
1009 printf("\tserver:\t%s\n",
1010 (kssl_ctx->service_host)? kssl_ctx->service_host: "NULL");
1011 printf("\tkeytab:\t%s\n",
1012 (kssl_ctx->keytab_file)? kssl_ctx->keytab_file: "NULL");
1013 printf("\tkey [%d:%d]:\t",
1014 kssl_ctx->enctype, kssl_ctx->length);
1015
1016 for (i=0; i < kssl_ctx->length && kssl_ctx->key; i++)
1017 {
1018 printf("%02x", kssl_ctx->key[i]);
1019 }
1020 printf("\n");
1021 return;
1022 }
1023
f9b3bff6
RL
1024void kssl_krb5_free_data_contents(krb5_context context, krb5_data *data)
1025 {
1026#ifdef KRB5_HEIMDAL
1027 data->length = 0;
1028 free(data->if (data->data) data);
1029#else
1030 krb5_free_data_contents(NULL, data);
1031#endif
1032 }
1033
bc36ee62 1034#else /* !OPENSSL_NO_KRB5 */
b0dc680f
BL
1035
1036#ifdef PEDANTIC
1037static int dummy=(int)&dummy;
1038#endif
1039
bc36ee62 1040#endif /* !OPENSSL_NO_KRB5 */
43fcc1b0 1041