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