1 /* ssl/kssl.c -*- mode: C; c-file-style: "eay" -*- */
2 /* Written by Vern Staats <staatsvr@asc.hpc.mil> for the OpenSSL project 2000.
4 /* ====================================================================
5 * Copyright (c) 2000 The OpenSSL Project. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
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
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/)"
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.
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.
33 * 6. Redistributions of any form whatsoever must retain the following
35 * "This product includes software developed by the OpenSSL Project
36 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
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 * ====================================================================
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).
59 /* ssl/kssl.c -- Routines to support (& debug) Kerberos5 auth for openssl
61 ** 19990701 VRS Started.
66 #include <openssl/ssl.h>
69 * When OpenSSL is built on Windows, we do not want to require that
70 * the Kerberos DLLs be available in order for the OpenSSL DLLs to
71 * work. Therefore, all Kerberos routines are loaded at run time
72 * and we do not link to a .LIB file.
75 #if defined(WINDOWS) || defined(WIN32)
77 * The purpose of the following pre-processor statements is to provide
78 * compatibility with different releases of MIT Kerberos for Windows.
79 * All versions up to 1.2 used macros. But macros do not allow for
80 * a binary compatible interface for DLLs. Therefore, all macros are
81 * being replaced by function calls. The following code will allow
82 * an OpenSSL DLL built on Windows to work whether or not the macro
83 * or function form of the routines are utilized.
85 #ifdef krb5_cc_get_principal
86 #define NO_DEF_KRB5_CCACHE
87 #undef krb5_cc_get_principal
89 #define krb5_cc_get_principal kssl_krb5_cc_get_principal
91 #define krb5_free_data_contents kssl_krb5_free_data_contents
92 #define krb5_free_context kssl_krb5_free_context
93 #define krb5_auth_con_free kssl_krb5_auth_con_free
94 #define krb5_free_principal kssl_krb5_free_principal
95 #define krb5_mk_req_extended kssl_krb5_mk_req_extended
96 #define krb5_get_credentials kssl_krb5_get_credentials
97 #define krb5_cc_default kssl_krb5_cc_default
98 #define krb5_sname_to_principal kssl_krb5_sname_to_principal
99 #define krb5_init_context kssl_krb5_init_context
100 #define krb5_free_ticket kssl_krb5_free_ticket
101 #define krb5_rd_req kssl_krb5_rd_req
102 #define krb5_kt_default kssl_krb5_kt_default
103 #define krb5_kt_resolve kssl_krb5_kt_resolve
104 #define krb5_auth_con_init kssl_krb5_auth_con_init
106 /* Prototypes for built in stubs */
107 void kssl_krb5_free_data_contents(krb5_context, krb5_data *);
108 void kssl_krb5_free_principal(krb5_context, krb5_principal );
109 krb5_error_code kssl_krb5_kt_resolve(krb5_context,
112 krb5_error_code kssl_krb5_kt_default(krb5_context,
114 krb5_error_code kssl_krb5_free_ticket(krb5_context, krb5_ticket *);
115 krb5_error_code kssl_krb5_rd_req(krb5_context, krb5_auth_context *,
116 krb5_const krb5_data *,
117 krb5_const_principal, krb5_keytab,
118 krb5_flags *,krb5_ticket **);
119 krb5_error_code kssl_krb5_mk_req_extended(krb5_context,
121 krb5_const krb5_flags,
125 krb5_error_code kssl_krb5_init_context(krb5_context *);
126 void kssl_krb5_free_context(krb5_context);
127 krb5_error_code kssl_krb5_cc_default(krb5_context,krb5_ccache *);
128 krb5_error_code kssl_krb5_sname_to_principal(krb5_context,
133 krb5_error_code kssl_krb5_get_credentials(krb5_context,
134 krb5_const krb5_flags,
138 krb5_error_code kssl_krb5_auth_con_init(krb5_context,
139 krb5_auth_context *);
140 krb5_error_code kssl_krb5_cc_get_principal(krb5_context context,
142 krb5_principal *principal);
143 krb5_error_code kssl_krb5_auth_con_free(krb5_context,krb5_auth_context);
145 /* Function pointers (almost all Kerberos functions are _stdcall) */
146 static void (_stdcall *p_krb5_free_data_contents)(krb5_context, krb5_data *)=NULL;
147 static void (_stdcall *p_krb5_free_principal)(krb5_context, krb5_principal )=NULL;
148 static krb5_error_code(_stdcall *p_krb5_kt_resolve)(krb5_context, krb5_const char *,
150 static krb5_error_code (_stdcall *p_krb5_kt_default)(krb5_context,
152 static krb5_error_code (_stdcall *p_krb5_free_ticket)(krb5_context,
154 static krb5_error_code (_stdcall *p_krb5_rd_req)(krb5_context,
156 krb5_const krb5_data *,
157 krb5_const_principal,
158 krb5_keytab, krb5_flags *,
159 krb5_ticket **)=NULL;
160 static krb5_error_code (_stdcall *p_krb5_mk_req_extended) (krb5_context,
162 krb5_const krb5_flags,
166 static krb5_error_code (_stdcall *p_krb5_init_context)(krb5_context *)=NULL;
167 static void (_stdcall *p_krb5_free_context)(krb5_context)=NULL;
168 static krb5_error_code (_stdcall *p_krb5_cc_default)(krb5_context,
170 static krb5_error_code (_stdcall *p_krb5_sname_to_principal)(krb5_context,
174 krb5_principal *)=NULL;
175 static krb5_error_code (_stdcall *p_krb5_get_credentials)(krb5_context,
176 krb5_const krb5_flags,
179 krb5_creds * *)=NULL;
180 static krb5_error_code (_stdcall *p_krb5_auth_con_init)(krb5_context,
181 krb5_auth_context *)=NULL;
182 static krb5_error_code (_stdcall *p_krb5_cc_get_principal)(krb5_context context,
184 krb5_principal *principal)=NULL;
185 static krb5_error_code (_stdcall *p_krb5_auth_con_free)(krb5_context,
186 krb5_auth_context)=NULL;
187 static int krb5_loaded = 0; /* only attempt to initialize func ptrs once */
189 /* Function to Load the Kerberos 5 DLL and initialize function pointers */
196 hKRB5_32 = LoadLibrary("KRB5_32");
200 (FARPROC) p_krb5_free_data_contents =
201 GetProcAddress( hKRB5_32, "krb5_free_data_contents" );
202 (FARPROC) p_krb5_free_context =
203 GetProcAddress( hKRB5_32, "krb5_free_context" );
204 (FARPROC) p_krb5_auth_con_free =
205 GetProcAddress( hKRB5_32, "krb5_auth_con_free" );
206 (FARPROC) p_krb5_free_principal =
207 GetProcAddress( hKRB5_32, "krb5_free_principal" );
208 (FARPROC) p_krb5_mk_req_extended =
209 GetProcAddress( hKRB5_32, "krb5_mk_req_extended" );
210 (FARPROC) p_krb5_get_credentials =
211 GetProcAddress( hKRB5_32, "krb5_get_credentials" );
212 (FARPROC) p_krb5_cc_get_principal =
213 GetProcAddress( hKRB5_32, "krb5_cc_get_principal" );
214 (FARPROC) p_krb5_cc_default =
215 GetProcAddress( hKRB5_32, "krb5_cc_default" );
216 (FARPROC) p_krb5_sname_to_principal =
217 GetProcAddress( hKRB5_32, "krb5_sname_to_principal" );
218 (FARPROC) p_krb5_init_context =
219 GetProcAddress( hKRB5_32, "krb5_init_context" );
220 (FARPROC) p_krb5_free_ticket =
221 GetProcAddress( hKRB5_32, "krb5_free_ticket" );
222 (FARPROC) p_krb5_rd_req =
223 GetProcAddress( hKRB5_32, "krb5_rd_req" );
224 (FARPROC) p_krb5_kt_default =
225 GetProcAddress( hKRB5_32, "krb5_kt_default" );
226 (FARPROC) p_krb5_kt_resolve =
227 GetProcAddress( hKRB5_32, "krb5_kt_resolve" );
228 (FARPROC) p_krb5_auth_con_init =
229 GetProcAddress( hKRB5_32, "krb5_auth_con_init" );
232 /* Stubs for each function to be dynamicly loaded */
234 kssl_krb5_free_data_contents(krb5_context CO, krb5_data * data)
239 if ( p_krb5_free_data_contents )
240 p_krb5_free_data_contents(CO,data);
244 kssl_krb5_mk_req_extended (krb5_context CO,
245 krb5_auth_context * pACO,
246 krb5_const krb5_flags F,
254 if ( p_krb5_mk_req_extended )
255 return(p_krb5_mk_req_extended(CO,pACO,F,pD1,pC,pD2));
257 return KRB5KRB_ERR_GENERIC;
260 kssl_krb5_auth_con_init(krb5_context CO,
261 krb5_auth_context * pACO)
266 if ( p_krb5_auth_con_init )
267 return(p_krb5_auth_con_init(CO,pACO));
269 return KRB5KRB_ERR_GENERIC;
272 kssl_krb5_auth_con_free (krb5_context CO,
273 krb5_auth_context ACO)
278 if ( p_krb5_auth_con_free )
279 return(p_krb5_auth_con_free(CO,ACO));
281 return KRB5KRB_ERR_GENERIC;
284 kssl_krb5_get_credentials(krb5_context CO,
285 krb5_const krb5_flags F,
293 if ( p_krb5_get_credentials )
294 return(p_krb5_get_credentials(CO,F,CC,pCR,ppCR));
296 return KRB5KRB_ERR_GENERIC;
299 kssl_krb5_sname_to_principal(krb5_context CO,
300 krb5_const char * pC1,
301 krb5_const char * pC2,
303 krb5_principal * pPR)
308 if ( p_krb5_sname_to_principal )
309 return(p_krb5_sname_to_principal(CO,pC1,pC2,I,pPR));
311 return KRB5KRB_ERR_GENERIC;
315 kssl_krb5_cc_default(krb5_context CO,
321 if ( p_krb5_cc_default )
322 return(p_krb5_cc_default(CO,pCC));
324 return KRB5KRB_ERR_GENERIC;
328 kssl_krb5_init_context(krb5_context * pCO)
333 if ( p_krb5_init_context )
334 return(p_krb5_init_context(pCO));
336 return KRB5KRB_ERR_GENERIC;
340 kssl_krb5_free_context(krb5_context CO)
345 if ( p_krb5_free_context )
346 p_krb5_free_context(CO);
350 kssl_krb5_free_principal(krb5_context c, krb5_principal p)
355 if ( p_krb5_free_principal )
356 p_krb5_free_principal(c,p);
360 kssl_krb5_kt_resolve(krb5_context con,
361 krb5_const char * sz,
367 if ( p_krb5_kt_resolve )
368 return(p_krb5_kt_resolve(con,sz,kt));
370 return KRB5KRB_ERR_GENERIC;
374 kssl_krb5_kt_default(krb5_context con,
380 if ( p_krb5_kt_default )
381 return(p_krb5_kt_default(con,kt));
383 return KRB5KRB_ERR_GENERIC;
387 kssl_krb5_free_ticket(krb5_context con,
393 if ( p_krb5_free_ticket )
394 return(p_krb5_free_ticket(con,kt));
396 return KRB5KRB_ERR_GENERIC;
400 kssl_krb5_rd_req(krb5_context con, krb5_auth_context * pacon,
401 krb5_const krb5_data * data,
402 krb5_const_principal princ, krb5_keytab keytab,
403 krb5_flags * flags, krb5_ticket ** pptkt)
409 return(p_krb5_rd_req(con,pacon,data,princ,keytab,flags,pptkt));
411 return KRB5KRB_ERR_GENERIC;
414 /* Structure definitions */
415 #ifndef NO_DEF_KRB5_CCACHE
417 #define krb5_x(ptr,args) ((ptr)?((*(ptr)) args):(abort(),1))
418 #define krb5_xc(ptr,args) ((ptr)?((*(ptr)) args):(abort(),(char*)0))
421 typedef krb5_pointer krb5_cc_cursor; /* cursor for sequential lookup */
423 typedef struct _krb5_ccache
426 struct _krb5_cc_ops FAR *ops;
430 typedef struct _krb5_cc_ops
434 char * (KRB5_CALLCONV *get_name) KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
435 krb5_error_code (KRB5_CALLCONV *resolve) KRB5_NPROTOTYPE((krb5_context, krb5_ccache *,
437 krb5_error_code (KRB5_CALLCONV *gen_new) KRB5_NPROTOTYPE((krb5_context, krb5_ccache *));
438 krb5_error_code (KRB5_CALLCONV *init) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
440 krb5_error_code (KRB5_CALLCONV *destroy) KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
441 krb5_error_code (KRB5_CALLCONV *close) KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
442 krb5_error_code (KRB5_CALLCONV *store) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
444 krb5_error_code (KRB5_CALLCONV *retrieve) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
445 krb5_flags, krb5_creds *,
447 krb5_error_code (KRB5_CALLCONV *get_princ) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
449 krb5_error_code (KRB5_CALLCONV *get_first) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
451 krb5_error_code (KRB5_CALLCONV *get_next) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
452 krb5_cc_cursor *, krb5_creds *));
453 krb5_error_code (KRB5_CALLCONV *end_get) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
455 krb5_error_code (KRB5_CALLCONV *remove_cred) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
456 krb5_flags, krb5_creds *));
457 krb5_error_code (KRB5_CALLCONV *set_flags) KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
460 #endif /* NO_DEF_KRB5_CCACHE */
463 kssl_krb5_cc_get_principal
464 (krb5_context context, krb5_ccache cache,
465 krb5_principal *principal)
467 if ( p_krb5_cc_get_principal )
468 return(p_krb5_cc_get_principal(context,cache,principal));
470 return(krb5_x ((cache)->ops->get_princ,(context, cache, principal)));
472 #endif /* WINDOWS || WIN32 */
475 *kstring(char *string)
477 static char *null = "[NULL]";
479 return ((string == NULL)? null: string);
484 *knumber(int len, krb5_octet *contents)
486 static char buf[MAXKNUM+1];
489 BIO_snprintf(buf, MAXKNUM, "[%d] ", len);
491 for (i=0; i < len && MAXKNUM > strlen(buf)+3; i++)
493 BIO_snprintf(&buf[strlen(buf)], 3, "%02x", contents[i]);
500 /* Set kssl_err error info when reason text is a simple string
501 ** kssl_err = struct { int reason; char text[KSSL_ERR_MAX+1]; }
504 kssl_err_set(KSSL_ERR *kssl_err, int reason, char *text)
506 if (kssl_err == NULL) return;
508 kssl_err->reason = reason;
509 BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, text);
514 /* Display contents of krb5_data struct, for debugging
517 print_krb5_data(char *label, krb5_data *kdata)
521 printf("%s[%d] ", label, kdata->length);
522 for (i=0; i < kdata->length; i++)
524 if (isprint((int) kdata->data[i]))
525 printf( "%c ", kdata->data[i]);
527 printf( "%02x", kdata->data[i]);
533 /* Display contents of krb5_authdata struct, for debugging
536 print_krb5_authdata(char *label, krb5_authdata **adata)
540 printf("%s, authdata==0\n", label);
543 printf("%s [%p]\n", label, adata);
547 printf("%s[at%d:%d] ", label, adata->ad_type, adata->length);
548 for (i=0; i < adata->length; i++)
550 printf((isprint(adata->contents[i]))? "%c ": "%02x",
559 /* Display contents of krb5_keyblock struct, for debugging
562 print_krb5_keyblock(char *label, krb5_keyblock *keyblk)
568 printf("%s, keyblk==0\n", label);
572 printf("%s\n\t[et%d:%d]: ", label, keyblk->keytype, keyblk->keyvalue->length);
573 for (i=0; i < keyblk->keyvalue->length; i++)
575 printf("%02x",(unsigned char *)(keyblk->keyvalue->contents)[i]);
579 printf("%s\n\t[et%d:%d]: ", label, keyblk->enctype, keyblk->length);
580 for (i=0; i < keyblk->length; i++)
582 printf("%02x",keyblk->contents[i]);
589 /* Given krb5 service (typically "kssl") and hostname in kssl_ctx,
590 ** Create Kerberos AP_REQ message for SSL Client.
592 ** 19990628 VRS Started.
595 kssl_cget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx,
596 /* OUT */ krb5_data *krb5_app_req, KSSL_ERR *kssl_err)
598 krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC;
599 krb5_context krb5context = NULL;
600 krb5_auth_context krb5auth_context = NULL;
601 krb5_ccache krb5ccdef = NULL;
602 krb5_creds krb5creds, *krb5credsp = NULL;
603 krb5_data krb5in_data;
605 kssl_err_set(kssl_err, 0, "");
606 memset((char *)&krb5creds, 0, sizeof(krb5creds));
610 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
611 "No kssl_ctx defined.\n");
614 else if (!kssl_ctx->service_host)
616 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
617 "kssl_ctx service_host undefined.\n");
621 if ((krb5rc = krb5_init_context(&krb5context)) != 0)
623 BIO_snprintf(kssl_err->text,KSSL_ERR_MAX,
624 "krb5_init_context() fails: %d\n", krb5rc);
625 kssl_err->reason = SSL_R_KRB5_C_INIT;
629 if ((krb5rc = krb5_sname_to_principal(krb5context,
630 kssl_ctx->service_host,
631 (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC,
632 KRB5_NT_SRV_HST, &krb5creds.server)) != 0)
634 BIO_snprintf(kssl_err->text,KSSL_ERR_MAX,
635 "krb5_sname_to_principal() fails for %s/%s\n",
636 kssl_ctx->service_host,
637 (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC);
638 kssl_err->reason = SSL_R_KRB5_C_INIT;
642 if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0)
644 kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC,
645 "krb5_cc_default fails.\n");
649 if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef,
650 &krb5creds.client)) != 0)
652 kssl_err_set(kssl_err, SSL_R_KRB5_C_CC_PRINC,
653 "krb5_cc_get_principal() fails.\n");
657 if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef,
658 &krb5creds, &krb5credsp)) != 0)
660 kssl_err_set(kssl_err, SSL_R_KRB5_C_GET_CRED,
661 "krb5_get_credentials() fails.\n");
665 krb5in_data.data = NULL;
666 krb5in_data.length = 0;
668 krb5rc = KRB5KRB_ERR_GENERIC;
669 /* caller should free data of krb5_app_req */
670 if ((krb5rc = krb5_mk_req_extended(krb5context, &krb5auth_context,
671 0, &krb5in_data, krb5credsp, krb5_app_req)) != 0)
673 kssl_err_set(kssl_err, SSL_R_KRB5_C_MK_REQ,
674 "krb5_mk_req_extended() fails.\n");
678 else if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->session))
680 kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
681 "kssl_ctx_setkey() fails.\n");
684 else if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->keyblock))
686 kssl_err_set(kssl_err, SSL_R_KRB5_C_INIT,
687 "kssl_ctx_setkey() fails.\n");
694 kssl_ctx_show(kssl_ctx);
695 #endif /* KSSL_DEBUG */
697 if (krb5creds.client) krb5_free_principal(krb5context, krb5creds.client);
698 if (krb5creds.server) krb5_free_principal(krb5context, krb5creds.server);
699 if (krb5auth_context) krb5_auth_con_free(krb5context, krb5auth_context);
700 if (krb5context) krb5_free_context(krb5context);
705 /* Given krb5 service name in KSSL_CTX *kssl_ctx (typically "kssl"),
706 ** and krb5 AP_REQ message & message length,
707 ** Return Kerberos session key and client principle
708 ** to SSL Server in KSSL_CTX *kssl_ctx.
710 ** 19990702 VRS Started.
713 kssl_sget_tkt( /* UPDATE */ KSSL_CTX *kssl_ctx,
714 /* IN */ char *msg, int msglen,
715 /* OUT */ KSSL_ERR *kssl_err )
717 krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC;
718 static krb5_context krb5context = NULL;
719 static krb5_auth_context krb5auth_context = NULL;
720 krb5_ticket *krb5ticket = NULL;
721 krb5_keytab krb5keytab = NULL;
722 krb5_principal krb5server;
723 krb5_data krb5in_data;
724 krb5_flags ap_option;
726 kssl_err_set(kssl_err, 0, "");
730 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, "No kssl_ctx defined.\n");
735 printf("in kssl_sget_tkt(%s)\n", kstring(kssl_ctx->service_name));
736 #endif /* KSSL_DEBUG */
738 if (!krb5context && (krb5rc = krb5_init_context(&krb5context)))
740 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
741 "krb5_init_context() fails.\n");
744 if (krb5auth_context &&
745 (krb5rc = krb5_auth_con_free(krb5context, krb5auth_context)))
747 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
748 "krb5_auth_con_free() fails.\n");
751 else krb5auth_context = NULL;
752 if (!krb5auth_context &&
753 (krb5rc = krb5_auth_con_init(krb5context, &krb5auth_context)))
755 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
756 "krb5_auth_con_init() fails.\n");
760 if ((krb5rc = krb5_sname_to_principal(krb5context, NULL,
761 (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC,
762 KRB5_NT_SRV_HST, &krb5server)) != 0)
764 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
765 "krb5_sname_to_principal() fails.\n");
769 /* kssl_ctx->keytab_file == NULL ==> use Kerberos default
771 if (kssl_ctx->keytab_file)
773 krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file,
777 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
778 "krb5_kt_resolve() fails.\n");
784 krb5rc = krb5_kt_default(krb5context,&krb5keytab);
787 kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
788 "krb5_kt_default() fails.\n");
793 /* Actual Kerberos5 krb5_recvauth() has initial conversation here
794 ** o check KRB5_SENDAUTH_BADAUTHVERS unless KRB5_RECVAUTH_SKIP_VERSION
795 ** o check KRB5_SENDAUTH_BADAPPLVERS
796 ** o send "0" msg if all OK
799 krb5in_data.data = msg;
800 krb5in_data.length = msglen;
801 if ((krb5rc = krb5_rd_req(krb5context, &krb5auth_context, &krb5in_data,
802 krb5server, krb5keytab, &ap_option, &krb5ticket)) != 0)
804 BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
805 "krb5_rd_req() fails with %x.\n", krb5rc);
806 kssl_err->reason = SSL_R_KRB5_S_RD_REQ;
810 krb5rc = KRB5_NO_TKT_SUPPLIED;
811 if (!krb5ticket || !krb5ticket->enc_part2 ||
812 !krb5ticket->enc_part2->client ||
813 !krb5ticket->enc_part2->client->data ||
814 !krb5ticket->enc_part2->session)
816 kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
817 "bad ticket from krb5_rd_req.\n");
819 else if (kssl_ctx_setprinc(kssl_ctx, KSSL_CLIENT,
820 &krb5ticket->enc_part2->client->realm,
821 krb5ticket->enc_part2->client->data))
823 kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
824 "kssl_ctx_setprinc() fails.\n");
826 else if (kssl_ctx_setkey(kssl_ctx, krb5ticket->enc_part2->session))
828 kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
829 "kssl_ctx_setkey() fails.\n");
835 kssl_ctx_show(kssl_ctx);
836 #endif /* KSSL_DEBUG */
838 if (krb5keytab) krb5_kt_close(krb5context, krb5keytab);
839 if (krb5ticket) krb5_free_ticket(krb5context, krb5ticket);
840 if (krb5server) krb5_free_principal(krb5context, krb5server);
845 /* Allocate & return a new kssl_ctx struct.
850 return ((KSSL_CTX *) calloc(1, sizeof(KSSL_CTX)));
854 /* Frees a kssl_ctx struct and any allocated memory it holds.
858 kssl_ctx_free(KSSL_CTX *kssl_ctx)
860 if (kssl_ctx == NULL) return kssl_ctx;
862 if (kssl_ctx->key) memset(kssl_ctx->key, 0, kssl_ctx->length);
863 if (kssl_ctx->key) free(kssl_ctx->key);
864 if (kssl_ctx->client_princ) free(kssl_ctx->client_princ);
865 if (kssl_ctx->service_host) free(kssl_ctx->service_host);
866 if (kssl_ctx->service_name) free(kssl_ctx->service_name);
867 if (kssl_ctx->keytab_file) free(kssl_ctx->keytab_file);
870 return (KSSL_CTX *) NULL;
874 /* Given a (krb5_data *) entity (and optional realm),
875 ** set the plain (char *) client_princ or service_host member
876 ** of the kssl_ctx struct.
879 kssl_ctx_setprinc(KSSL_CTX *kssl_ctx, int which,
880 krb5_data *realm, krb5_data *entity)
885 if (kssl_ctx == NULL || entity == NULL) return KSSL_CTX_ERR;
889 case KSSL_CLIENT: princ = &kssl_ctx->client_princ; break;
890 case KSSL_SERVER: princ = &kssl_ctx->service_host; break;
891 default: return KSSL_CTX_ERR; break;
893 if (*princ) free(*princ);
895 length = entity->length + ((realm)? realm->length + 2: 1);
896 if ((*princ = calloc(1, length)) == NULL)
900 strncpy(*princ, entity->data, entity->length);
903 strcat (*princ, "@");
904 (void) strncat(*princ, realm->data, realm->length);
912 /* Set one of the plain (char *) string members of the kssl_ctx struct.
913 ** Default values should be:
914 ** which == KSSL_SERVICE => "khost" (KRB5SVC)
915 ** which == KSSL_KEYTAB => "/etc/krb5.keytab" (KRB5KEYTAB)
918 kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text)
922 if (!kssl_ctx) return KSSL_CTX_ERR;
926 case KSSL_SERVICE: string = &kssl_ctx->service_name; break;
927 case KSSL_SERVER: string = &kssl_ctx->service_host; break;
928 case KSSL_CLIENT: string = &kssl_ctx->client_princ; break;
929 case KSSL_KEYTAB: string = &kssl_ctx->keytab_file; break;
930 default: return KSSL_CTX_ERR; break;
932 if (*string) free(*string);
940 if ((*string = calloc(1, strlen(text) + 1)) == NULL)
943 strcpy(*string, text);
949 /* Copy the Kerberos session key from a (krb5_keyblock *) to a kssl_ctx
950 ** struct. Clear kssl_ctx->key if Kerberos session key is NULL.
953 kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session)
955 if (!kssl_ctx) return KSSL_CTX_ERR;
959 memset(kssl_ctx->key, 0, kssl_ctx->length);
965 kssl_ctx->enctype = session->enctype;
966 kssl_ctx->length = session->length;
970 kssl_ctx->enctype = ENCTYPE_UNKNOWN;
971 kssl_ctx->length = 0;
976 (krb5_octet FAR *) calloc(1, kssl_ctx->length)) == NULL)
978 kssl_ctx->length = 0;
982 memcpy(kssl_ctx->key, session->contents, session->length);
988 /* Display contents of kssl_ctx struct
991 kssl_ctx_show(KSSL_CTX *kssl_ctx)
995 printf("kssl_ctx: ");
996 if (kssl_ctx == NULL)
1002 printf("%p\n", kssl_ctx);
1004 printf("\tservice:\t%s\n",
1005 (kssl_ctx->service_name)? kssl_ctx->service_name: "NULL");
1006 printf("\tclient:\t%s\n",
1007 (kssl_ctx->client_princ)? kssl_ctx->client_princ: "NULL");
1008 printf("\tserver:\t%s\n",
1009 (kssl_ctx->service_host)? kssl_ctx->service_host: "NULL");
1010 printf("\tkeytab:\t%s\n",
1011 (kssl_ctx->keytab_file)? kssl_ctx->keytab_file: "NULL");
1012 printf("\tkey [%d:%d]:\t",
1013 kssl_ctx->enctype, kssl_ctx->length);
1015 for (i=0; i < kssl_ctx->length && kssl_ctx->key; i++)
1017 printf("%02x", kssl_ctx->key[i]);
1023 void kssl_krb5_free_data_contents(krb5_context context, krb5_data *data)
1027 free(data->if (data->data) data);
1029 krb5_free_data_contents(NULL, data);
1033 #endif /* NO_KRB5 */