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 #else /* !NO_KRB5 */
1036 static int dummy
=(int)&dummy
;
1039 #endif /* !NO_KRB5 */