Alexandre Savard | 1b09e31 | 2012-08-07 20:33:29 -0400 | [diff] [blame] | 1 | /* ssl/kssl.c -*- mode: C; c-file-style: "eay" -*- */ |
| 2 | /* Written by Vern Staats <staatsvr@asc.hpc.mil> for the OpenSSL project 2000. |
| 3 | */ |
| 4 | /* ==================================================================== |
| 5 | * Copyright (c) 2000 The OpenSSL Project. All rights reserved. |
| 6 | * |
| 7 | * Redistribution and use in source and binary forms, with or without |
| 8 | * modification, are permitted provided that the following conditions |
| 9 | * are met: |
| 10 | * |
| 11 | * 1. Redistributions of source code must retain the above copyright |
| 12 | * notice, this list of conditions and the following disclaimer. |
| 13 | * |
| 14 | * 2. Redistributions in binary form must reproduce the above copyright |
| 15 | * notice, this list of conditions and the following disclaimer in |
| 16 | * the documentation and/or other materials provided with the |
| 17 | * distribution. |
| 18 | * |
| 19 | * 3. All advertising materials mentioning features or use of this |
| 20 | * software must display the following acknowledgment: |
| 21 | * "This product includes software developed by the OpenSSL Project |
| 22 | * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" |
| 23 | * |
| 24 | * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to |
| 25 | * endorse or promote products derived from this software without |
| 26 | * prior written permission. For written permission, please contact |
| 27 | * licensing@OpenSSL.org. |
| 28 | * |
| 29 | * 5. Products derived from this software may not be called "OpenSSL" |
| 30 | * nor may "OpenSSL" appear in their names without prior written |
| 31 | * permission of the OpenSSL Project. |
| 32 | * |
| 33 | * 6. Redistributions of any form whatsoever must retain the following |
| 34 | * acknowledgment: |
| 35 | * "This product includes software developed by the OpenSSL Project |
| 36 | * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" |
| 37 | * |
| 38 | * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY |
| 39 | * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| 40 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| 41 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR |
| 42 | * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 43 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
| 44 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 45 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| 46 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| 47 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 48 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
| 49 | * OF THE POSSIBILITY OF SUCH DAMAGE. |
| 50 | * ==================================================================== |
| 51 | * |
| 52 | * This product includes cryptographic software written by Eric Young |
| 53 | * (eay@cryptsoft.com). This product includes software written by Tim |
| 54 | * Hudson (tjh@cryptsoft.com). |
| 55 | * |
| 56 | */ |
| 57 | |
| 58 | |
| 59 | /* ssl/kssl.c -- Routines to support (& debug) Kerberos5 auth for openssl |
| 60 | ** |
| 61 | ** 19990701 VRS Started. |
| 62 | ** 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 | |
Alexandre Savard | 1b09e31 | 2012-08-07 20:33:29 -0400 | [diff] [blame] | 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 | |