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