*/
#include <openssl/opensslconf.h>
-#ifndef OPENSSL_NO_KRB5
+
#define _XOPEN_SOURCE /* glibc2 needs this to declare strptime() */
#include <time.h>
+#undef _XOPEN_SOURCE /* To avoid clashes with anything else... */
#include <string.h>
+#define KRB5_PRIVATE 1
+
#include <openssl/ssl.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/krb5_asn.h>
+#ifndef OPENSSL_NO_KRB5
+
+#ifndef ENOMEM
+#define ENOMEM KRB5KRB_ERR_GENERIC
+#endif
+
/*
* When OpenSSL is built on Windows, we do not want to require that
* the Kerberos DLLs be available in order for the OpenSSL DLLs to
#define krb5_rd_req kssl_krb5_rd_req
#define krb5_kt_default kssl_krb5_kt_default
#define krb5_kt_resolve kssl_krb5_kt_resolve
+/* macros in mit 1.2.2 and earlier; functions in mit 1.2.3 and greater */
+#ifndef krb5_kt_close
+#define krb5_kt_close kssl_krb5_kt_close
+#endif /* krb5_kt_close */
+#ifndef krb5_kt_get_entry
+#define krb5_kt_get_entry kssl_krb5_kt_get_entry
+#endif /* krb5_kt_get_entry */
#define krb5_auth_con_init kssl_krb5_auth_con_init
#define krb5_principal_compare kssl_krb5_principal_compare
-/* macro #define krb5_kt_get_entry kssl_krb5_kt_get_entry */
#define krb5_decrypt_tkt_part kssl_krb5_decrypt_tkt_part
#define krb5_timeofday kssl_krb5_timeofday
#define krb5_rc_default kssl_krb5_rc_default
-#define krb5_krb5_rc_initialize kssl_krb5_rc_initialize
-#define krb5_krb5_rc_get_lifespan kssl_krb5_rc_get_lifespan
-#define krb5_krb5_rc_destroy kssl_krb5_rc_destroy
+
+#ifdef krb5_rc_initialize
+#undef krb5_rc_initialize
+#endif
+#define krb5_rc_initialize kssl_krb5_rc_initialize
+
+#ifdef krb5_rc_get_lifespan
+#undef krb5_rc_get_lifespan
+#endif
+#define krb5_rc_get_lifespan kssl_krb5_rc_get_lifespan
+
+#ifdef krb5_rc_destroy
+#undef krb5_rc_destroy
+#endif
+#define krb5_rc_destroy kssl_krb5_rc_destroy
+
+#define valid_cksumtype kssl_valid_cksumtype
+#define krb5_checksum_size kssl_krb5_checksum_size
+#define krb5_kt_free_entry kssl_krb5_kt_free_entry
+#define krb5_auth_con_setrcache kssl_krb5_auth_con_setrcache
+#define krb5_auth_con_getrcache kssl_krb5_auth_con_getrcache
+#define krb5_get_server_rcache kssl_krb5_get_server_rcache
/* Prototypes for built in stubs */
void kssl_krb5_free_data_contents(krb5_context, krb5_data *);
krb5_boolean kssl_krb5_principal_compare(krb5_context, krb5_const_principal,
krb5_const_principal);
-krb5_error_code krb5_decrypt_tkt_part(krb5_context, krb5_const krb5_keyblock *,
- krb5_ticket *);
-krb5_error_code krb5_timeofday(krb5_context context, krb5_int32 *timeret);
-krb5_error_code krb5_rc_default(krb5_context context, krb5_rcache *rc);
-krb5_error_code krb5_rc_initialize(krb5_context context, krb5_rcache rc,
- krb5_deltat lifespan);
-krb5_error_code krb5_rc_get_lifespan(krb5_context context, krb5_rcache rc,
- krb5_deltat *lifespan);
-krb5_error_code krb5_rc_destroy(krb5_context context, krb5_rcache rc);
-
krb5_error_code kssl_krb5_mk_req_extended(krb5_context,
krb5_auth_context *,
krb5_const krb5_flags,
krb5_ccache cache,
krb5_principal *principal);
krb5_error_code kssl_krb5_auth_con_free(krb5_context,krb5_auth_context);
+size_t kssl_krb5_checksum_size(krb5_context context,krb5_cksumtype ctype);
+krb5_boolean kssl_valid_cksumtype(krb5_cksumtype ctype);
+krb5_error_code krb5_kt_free_entry(krb5_context,krb5_keytab_entry FAR * );
+krb5_error_code kssl_krb5_auth_con_setrcache(krb5_context,
+ krb5_auth_context,
+ krb5_rcache);
+krb5_error_code kssl_krb5_get_server_rcache(krb5_context,
+ krb5_const krb5_data *,
+ krb5_rcache *);
+krb5_error_code kssl_krb5_auth_con_getrcache(krb5_context,
+ krb5_auth_context,
+ krb5_rcache *);
/* Function pointers (almost all Kerberos functions are _stdcall) */
static void (_stdcall *p_krb5_free_data_contents)(krb5_context, krb5_data *)
krb5_principal *principal)=NULL;
static krb5_error_code (_stdcall *p_krb5_auth_con_free)
(krb5_context, krb5_auth_context)=NULL;
+static krb5_error_code (_stdcall *p_krb5_decrypt_tkt_part)
+ (krb5_context, krb5_const krb5_keyblock *,
+ krb5_ticket *)=NULL;
+static krb5_error_code (_stdcall *p_krb5_timeofday)
+ (krb5_context context, krb5_int32 *timeret)=NULL;
+static krb5_error_code (_stdcall *p_krb5_rc_default)
+ (krb5_context context, krb5_rcache *rc)=NULL;
+static krb5_error_code (_stdcall *p_krb5_rc_initialize)
+ (krb5_context context, krb5_rcache rc,
+ krb5_deltat lifespan)=NULL;
+static krb5_error_code (_stdcall *p_krb5_rc_get_lifespan)
+ (krb5_context context, krb5_rcache rc,
+ krb5_deltat *lifespan)=NULL;
+static krb5_error_code (_stdcall *p_krb5_rc_destroy)
+ (krb5_context context, krb5_rcache rc)=NULL;
+static krb5_boolean (_stdcall *p_krb5_principal_compare)
+ (krb5_context, krb5_const_principal, krb5_const_principal)=NULL;
+static size_t (_stdcall *p_krb5_checksum_size)(krb5_context context,krb5_cksumtype ctype)=NULL;
+static krb5_boolean (_stdcall *p_valid_cksumtype)(krb5_cksumtype ctype)=NULL;
+static krb5_error_code (_stdcall *p_krb5_kt_free_entry)
+ (krb5_context,krb5_keytab_entry * )=NULL;
+static krb5_error_code (_stdcall * p_krb5_auth_con_setrcache)(krb5_context,
+ krb5_auth_context,
+ krb5_rcache)=NULL;
+static krb5_error_code (_stdcall * p_krb5_get_server_rcache)(krb5_context,
+ krb5_const krb5_data *,
+ krb5_rcache *)=NULL;
+static krb5_error_code (* p_krb5_auth_con_getrcache)(krb5_context,
+ krb5_auth_context,
+ krb5_rcache *)=NULL;
+static krb5_error_code (_stdcall * p_krb5_kt_close)(krb5_context context,
+ krb5_keytab keytab)=NULL;
+static krb5_error_code (_stdcall * p_krb5_kt_get_entry)(krb5_context context,
+ krb5_keytab keytab,
+ krb5_const_principal principal, krb5_kvno vno,
+ krb5_enctype enctype, krb5_keytab_entry *entry)=NULL;
static int krb5_loaded = 0; /* only attempt to initialize func ptrs once */
/* Function to Load the Kerberos 5 DLL and initialize function pointers */
GetProcAddress( hKRB5_32, "krb5_kt_resolve" );
(FARPROC) p_krb5_auth_con_init =
GetProcAddress( hKRB5_32, "krb5_auth_con_init" );
+ (FARPROC) p_valid_cksumtype =
+ GetProcAddress( hKRB5_32, "valid_cksumtype" );
+ (FARPROC) p_krb5_checksum_size =
+ GetProcAddress( hKRB5_32, "krb5_checksum_size" );
+ (FARPROC) p_krb5_kt_free_entry =
+ GetProcAddress( hKRB5_32, "krb5_kt_free_entry" );
+ (FARPROC) p_krb5_auth_con_setrcache =
+ GetProcAddress( hKRB5_32, "krb5_auth_con_setrcache" );
+ (FARPROC) p_krb5_get_server_rcache =
+ GetProcAddress( hKRB5_32, "krb5_get_server_rcache" );
+ (FARPROC) p_krb5_auth_con_getrcache =
+ GetProcAddress( hKRB5_32, "krb5_auth_con_getrcache" );
+ (FARPROC) p_krb5_kt_close =
+ GetProcAddress( hKRB5_32, "krb5_kt_close" );
+ (FARPROC) p_krb5_kt_get_entry =
+ GetProcAddress( hKRB5_32, "krb5_kt_get_entry" );
}
/* Stubs for each function to be dynamicly loaded */
load_krb5_dll();
if ( p_krb5_principal_compare )
- return(p_krb5_principal_compare(con,princ1,princ2);
+ return(p_krb5_principal_compare(con,princ1,princ2));
else
return KRB5KRB_ERR_GENERIC;
}
load_krb5_dll();
if ( p_krb5_decrypt_tkt_part )
- return(p_krb5_decrypt_tkt_part(con,keys,ticket);
+ return(p_krb5_decrypt_tkt_part(con,keys,ticket));
else
return KRB5KRB_ERR_GENERIC;
}
load_krb5_dll();
if ( p_krb5_timeofday )
- return(p_krb5_timeofday(con,timeret);
+ return(p_krb5_timeofday(con,timeret));
else
return KRB5KRB_ERR_GENERIC;
}
load_krb5_dll();
if ( p_krb5_rc_default )
- return(p_krb5_rc_default(con,rc);
+ return(p_krb5_rc_default(con,rc));
else
return KRB5KRB_ERR_GENERIC;
}
load_krb5_dll();
if ( p_krb5_rc_initialize )
- return(p_krb5_rc_initialize(con, rc, lifespan);
+ return(p_krb5_rc_initialize(con, rc, lifespan));
else
return KRB5KRB_ERR_GENERIC;
}
load_krb5_dll();
if ( p_krb5_rc_get_lifespan )
- return(p_krb5_rc_get_lifespan(con, rc, lifespanp);
+ return(p_krb5_rc_get_lifespan(con, rc, lifespanp));
else
return KRB5KRB_ERR_GENERIC;
}
load_krb5_dll();
if ( p_krb5_rc_destroy )
- return(p_krb5_rc_destroy(con, rc);
+ return(p_krb5_rc_destroy(con, rc));
else
return KRB5KRB_ERR_GENERIC;
}
+size_t
+krb5_checksum_size(krb5_context context,krb5_cksumtype ctype)
+ {
+ if (!krb5_loaded)
+ load_krb5_dll();
+
+ if ( p_krb5_checksum_size )
+ return(p_krb5_checksum_size(context, ctype));
+ else
+ return KRB5KRB_ERR_GENERIC;
+ }
+
+krb5_boolean
+valid_cksumtype(krb5_cksumtype ctype)
+ {
+ if (!krb5_loaded)
+ load_krb5_dll();
+
+ if ( p_valid_cksumtype )
+ return(p_valid_cksumtype(ctype));
+ else
+ return KRB5KRB_ERR_GENERIC;
+ }
+
+krb5_error_code
+krb5_kt_free_entry(krb5_context con,krb5_keytab_entry * entry)
+ {
+ if (!krb5_loaded)
+ load_krb5_dll();
+
+ if ( p_krb5_kt_free_entry )
+ return(p_krb5_kt_free_entry(con,entry));
+ else
+ return KRB5KRB_ERR_GENERIC;
+ }
+
/* Structure definitions */
#ifndef NO_DEF_KRB5_CCACHE
#ifndef krb5_x
krb5_magic magic;
char *prefix;
char * (KRB5_CALLCONV *get_name)
- KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
+ (krb5_context, krb5_ccache);
krb5_error_code (KRB5_CALLCONV *resolve)
- KRB5_NPROTOTYPE((krb5_context, krb5_ccache *, const char *));
+ (krb5_context, krb5_ccache *, const char *);
krb5_error_code (KRB5_CALLCONV *gen_new)
- KRB5_NPROTOTYPE((krb5_context, krb5_ccache *));
+ (krb5_context, krb5_ccache *);
krb5_error_code (KRB5_CALLCONV *init)
- KRB5_NPROTOTYPE((krb5_context, krb5_ccache, krb5_principal));
+ (krb5_context, krb5_ccache, krb5_principal);
krb5_error_code (KRB5_CALLCONV *destroy)
- KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
+ (krb5_context, krb5_ccache);
krb5_error_code (KRB5_CALLCONV *close)
- KRB5_NPROTOTYPE((krb5_context, krb5_ccache));
+ (krb5_context, krb5_ccache);
krb5_error_code (KRB5_CALLCONV *store)
- KRB5_NPROTOTYPE((krb5_context, krb5_ccache, krb5_creds *));
+ (krb5_context, krb5_ccache, krb5_creds *);
krb5_error_code (KRB5_CALLCONV *retrieve)
- KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
- krb5_flags, krb5_creds *, krb5_creds *));
+ (krb5_context, krb5_ccache,
+ krb5_flags, krb5_creds *, krb5_creds *);
krb5_error_code (KRB5_CALLCONV *get_princ)
- KRB5_NPROTOTYPE((krb5_context, krb5_ccache, krb5_principal *));
+ (krb5_context, krb5_ccache, krb5_principal *);
krb5_error_code (KRB5_CALLCONV *get_first)
- KRB5_NPROTOTYPE((krb5_context, krb5_ccache, krb5_cc_cursor *));
+ (krb5_context, krb5_ccache, krb5_cc_cursor *);
krb5_error_code (KRB5_CALLCONV *get_next)
- KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
- krb5_cc_cursor *, krb5_creds *));
+ (krb5_context, krb5_ccache,
+ krb5_cc_cursor *, krb5_creds *);
krb5_error_code (KRB5_CALLCONV *end_get)
- KRB5_NPROTOTYPE((krb5_context, krb5_ccache, krb5_cc_cursor *));
+ (krb5_context, krb5_ccache, krb5_cc_cursor *);
krb5_error_code (KRB5_CALLCONV *remove_cred)
- KRB5_NPROTOTYPE((krb5_context, krb5_ccache,
- krb5_flags, krb5_creds *));
+ (krb5_context, krb5_ccache,
+ krb5_flags, krb5_creds *);
krb5_error_code (KRB5_CALLCONV *set_flags)
- KRB5_NPROTOTYPE((krb5_context, krb5_ccache, krb5_flags));
+ (krb5_context, krb5_ccache, krb5_flags);
} krb5_cc_ops;
#endif /* NO_DEF_KRB5_CCACHE */
return(krb5_x
((cache)->ops->get_princ,(context, cache, principal)));
}
-#else
-#endif /* OPENSSL_SYS_WINDOWS || OPENSSL_SYS_WIN32 */
-char
-*kstring(char *string)
+krb5_error_code
+kssl_krb5_auth_con_setrcache(krb5_context con, krb5_auth_context acon,
+ krb5_rcache rcache)
{
- static char *null = "[NULL]";
-
- return ((string == NULL)? null: string);
+ if ( p_krb5_auth_con_setrcache )
+ return(p_krb5_auth_con_setrcache(con,acon,rcache));
+ else
+ return KRB5KRB_ERR_GENERIC;
}
-#define MAXKNUM 255
-char
-*knumber(int len, krb5_octet *contents)
+krb5_error_code
+kssl_krb5_get_server_rcache(krb5_context con, krb5_const krb5_data * data,
+ krb5_rcache * rcache)
{
- static char buf[MAXKNUM+1];
- int i;
+ if ( p_krb5_get_server_rcache )
+ return(p_krb5_get_server_rcache(con,data,rcache));
+ else
+ return KRB5KRB_ERR_GENERIC;
+ }
- BIO_snprintf(buf, MAXKNUM, "[%d] ", len);
+krb5_error_code
+kssl_krb5_auth_con_getrcache(krb5_context con, krb5_auth_context acon,
+ krb5_rcache * prcache)
+ {
+ if ( p_krb5_auth_con_getrcache )
+ return(p_krb5_auth_con_getrcache(con,acon, prcache));
+ else
+ return KRB5KRB_ERR_GENERIC;
+ }
+
+krb5_error_code
+kssl_krb5_kt_close(krb5_context context, krb5_keytab keytab)
+ {
+ if ( p_krb5_kt_close )
+ return(p_krb5_kt_close(context,keytab));
+ else
+ return KRB5KRB_ERR_GENERIC;
+ }
- for (i=0; i < len && MAXKNUM > strlen(buf)+3; i++)
- {
- BIO_snprintf(&buf[strlen(buf)], 3, "%02x", contents[i]);
- }
+krb5_error_code
+kssl_krb5_kt_get_entry(krb5_context context, krb5_keytab keytab,
+ krb5_const_principal principal, krb5_kvno vno,
+ krb5_enctype enctype, krb5_keytab_entry *entry)
+ {
+ if ( p_krb5_kt_get_entry )
+ return(p_krb5_kt_get_entry(context,keytab,principal,vno,enctype,entry));
+ else
+ return KRB5KRB_ERR_GENERIC;
+ }
+#endif /* OPENSSL_SYS_WINDOWS || OPENSSL_SYS_WIN32 */
- return (buf);
- }
+char
+*kstring(char *string)
+ {
+ static char *null = "[NULL]";
+ return ((string == NULL)? null: string);
+ }
-/* Given KRB5 enctype (basically DES or 3DES), return
+/* Given KRB5 enctype (basically DES or 3DES),
+** return closest match openssl EVP_ encryption algorithm.
+** Return NULL for unknown or problematic (krb5_dk_encrypt) enctypes.
+** Assume ENCTYPE_*_RAW (krb5_raw_encrypt) are OK.
*/
-EVP_CIPHER *
+const EVP_CIPHER *
kssl_map_enc(krb5_enctype enctype)
{
switch (enctype)
{
+ case ENCTYPE_DES_HMAC_SHA1: /* EVP_des_cbc(); */
case ENCTYPE_DES_CBC_CRC:
case ENCTYPE_DES_CBC_MD4:
case ENCTYPE_DES_CBC_MD5:
case ENCTYPE_DES_CBC_RAW:
-#if ! defined(KRB5_MIT_OLD11)
- case ENCTYPE_DES_HMAC_SHA1:
-#endif
- return (EVP_CIPHER *) EVP_des_cbc();
+ return EVP_des_cbc();
break;
+ case ENCTYPE_DES3_CBC_SHA1: /* EVP_des_ede3_cbc(); */
case ENCTYPE_DES3_CBC_SHA:
case ENCTYPE_DES3_CBC_RAW:
-#if ! defined(KRB5_MIT_OLD11)
- case ENCTYPE_DES3_CBC_SHA1:
-#endif
- return (EVP_CIPHER *) EVP_des_ede3_cbc();
+ return EVP_des_ede3_cbc();
break;
- default: return (EVP_CIPHER *) NULL;
+ default: return NULL;
break;
}
}
/* Allocate, fill, and return cksumlens array of checksum lengths.
** This array holds just the unique elements from the krb5_cksumarray[].
** array[n] == 0 signals end of data.
+**
+** The krb5_cksumarray[] was an internal variable that has since been
+** replaced by a more general method for storing the data. It should
+** not be used. Instead we use real API calls and make a guess for
+** what the highest assigned CKSUMTYPE_ constant is. As of 1.2.2
+** it is 0x000c (CKSUMTYPE_HMAC_SHA1_DES3). So we will use 0x0010.
*/
-int *populate_cksumlens(void)
+size_t *populate_cksumlens(void)
{
- int i, j, n = krb5_max_cksum+1;
- static int *cklens = NULL;
+ int i, j, n;
+ static size_t *cklens = NULL;
+#ifdef KRB5_MIT_OLD11
+ n = krb5_max_cksum;
+#else
+ n = 0x0010;
+#endif /* KRB5_MIT_OLD11 */
+
#ifdef KRB5CHECKAUTH
- if (!cklens && !(cklens = (int *) calloc(sizeof(int), n))) return NULL;
+ if (!cklens && !(cklens = (size_t *) calloc(sizeof(int),n+1))) return NULL;
- for (i=0; i < krb5_max_cksum; i++) {
- if (!krb5_cksumarray[i]) continue; /* array has holes */
- for (j=0; j < krb5_max_cksum; j++) {
+ for (i=0; i < n; i++) {
+ if (!valid_cksumtype(i)) continue; /* array has holes */
+ for (j=0; j < n; j++) {
if (cklens[j] == 0) {
- cklens[j] = krb5_cksumarray[i]->checksum_length;
+ cklens[j] = krb5_checksum_size(NULL,i);
break; /* krb5 elem was new: add */
}
- if (cklens[j] == krb5_cksumarray[i]->checksum_length) {
+ if (cklens[j] == krb5_checksum_size(NULL,i)) {
break; /* ignore duplicate elements */
}
}
*/
unsigned char *kssl_skip_confound(krb5_enctype etype, unsigned char *a)
{
- int i, cklen, conlen;
- static int *cksumlens = NULL;
+ int i, conlen;
+ size_t cklen;
+ static size_t *cksumlens = NULL;
unsigned char *test_auth;
conlen = (etype)? 8: 0;
void
print_krb5_data(char *label, krb5_data *kdata)
{
- int i;
+ int i;
printf("%s[%d] ", label, kdata->length);
- for (i=0; i < kdata->length; i++)
+ for (i=0; i < (int)kdata->length; i++)
{
if (0 && isprint((int) kdata->data[i]))
printf( "%c ", kdata->data[i]);
printf("%s, authdata==0\n", label);
return;
}
- printf("%s [%p]\n", label, adata);
+ printf("%s [%p]\n", label, (void *)adata);
#if 0
{
int i;
void
print_krb5_keyblock(char *label, krb5_keyblock *keyblk)
{
- int i;
+ int i;
if (keyblk == NULL)
{
#ifdef KRB5_HEIMDAL
printf("%s\n\t[et%d:%d]: ", label, keyblk->keytype,
keyblk->keyvalue->length);
- for (i=0; i < keyblk->keyvalue->length; i++)
+ for (i=0; i < (int)keyblk->keyvalue->length; i++)
{
printf("%02x",(unsigned char *)(keyblk->keyvalue->contents)[i]);
}
printf("\n");
#else
printf("%s\n\t[et%d:%d]: ", label, keyblk->enctype, keyblk->length);
- for (i=0; i < keyblk->length; i++)
+ for (i=0; i < (int)keyblk->length; i++)
{
printf("%02x",keyblk->contents[i]);
}
void
print_krb5_princ(char *label, krb5_principal_data *princ)
{
- int i, j;
+ int i, ui, uj;
printf("%s principal Realm: ", label);
if (princ == NULL) return;
- for (i=0; i < princ->realm.length; i++) putchar(princ->realm.data[i]);
+ for (ui=0; ui < (int)princ->realm.length; ui++) putchar(princ->realm.data[ui]);
printf(" (nametype %d) has %d strings:\n", princ->type,princ->length);
- for (i=0; i < princ->length; i++)
+ for (i=0; i < (int)princ->length; i++)
{
printf("\t%d [%d]: ", i, princ->data[i].length);
- for (j=0; j < princ->data[i].length; j++) {
- putchar(princ->data[i].data[j]);
+ for (uj=0; uj < (int)princ->data[i].length; uj++) {
+ putchar(princ->data[i].data[uj]);
}
printf("\n");
}
}
arlen = krb5_app_req.length;
- p = krb5_app_req.data;
+ p = (unsigned char *)krb5_app_req.data;
ap_req = (KRB5_APREQBODY *) d2i_KRB5_APREQ(NULL, &p, arlen);
if (ap_req)
{
if (authenp->length &&
(authenp->data = malloc(authenp->length)))
{
- unsigned char *p = authenp->data;
+ unsigned char *adp = (unsigned char *)authenp->data;
authenp->length = i2d_KRB5_ENCDATA(
- ap_req->authenticator, &p);
+ ap_req->authenticator, &adp);
}
}
if (ap_req) KRB5_APREQ_free((KRB5_APREQ *) ap_req);
- if (krb5_app_req.length) krb5_xfree(krb5_app_req.data);
+ if (krb5_app_req.length)
+ kssl_krb5_free_data_contents(krb5context,&krb5_app_req);
}
#ifdef KRB5_HEIMDAL
if (kssl_ctx_setkey(kssl_ctx, &krb5credsp->session))
if (asn1ticket == NULL || asn1ticket->realm == NULL ||
asn1ticket->sname == NULL ||
- asn1ticket->sname->namestring == NULL ||
- asn1ticket->sname->namestring->num < 2)
+ sk_ASN1_GENERALSTRING_num(asn1ticket->sname->namestring) < 2)
{
BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
"Null field in asn1ticket.\n");
return ENOMEM; /* or KRB5KRB_ERR_GENERIC; */
}
- gstr_svc = (ASN1_GENERALSTRING*)asn1ticket->sname->namestring->data[0];
- gstr_host = (ASN1_GENERALSTRING*)asn1ticket->sname->namestring->data[1];
+ gstr_svc = sk_ASN1_GENERALSTRING_value(asn1ticket->sname->namestring, 0);
+ gstr_host = sk_ASN1_GENERALSTRING_value(asn1ticket->sname->namestring, 1);
if ((krb5rc = kssl_build_principal_2(krb5context,
&new5ticket->server,
- asn1ticket->realm->length, asn1ticket->realm->data,
- gstr_svc->length, gstr_svc->data,
- gstr_host->length, gstr_host->data)) != 0)
+ asn1ticket->realm->length, (char *)asn1ticket->realm->data,
+ gstr_svc->length, (char *)gstr_svc->data,
+ gstr_host->length, (char *)gstr_host->data)) != 0)
{
free(new5ticket);
BIO_snprintf(kssl_err->text, KSSL_ERR_MAX,
krb5_keytab krb5keytab = NULL;
krb5_keytab_entry kt_entry;
krb5_principal krb5server;
+ krb5_rcache rcache = NULL;
kssl_err_set(kssl_err, 0, "");
if (!kssl_ctx)
{
kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
- "No kssl_ctx defined.\n");
+ "No kssl_ctx defined.\n");
goto err;
}
goto err;
}
+
+ if ((krb5rc = krb5_auth_con_getrcache(krb5context, krb5auth_context,
+ &rcache)))
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
+ "krb5_auth_con_getrcache() fails.\n");
+ goto err;
+ }
+
if ((krb5rc = krb5_sname_to_principal(krb5context, NULL,
(kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC,
KRB5_NT_SRV_HST, &krb5server)) != 0)
goto err;
}
+ if (rcache == NULL)
+ {
+ if ((krb5rc = krb5_get_server_rcache(krb5context,
+ krb5_princ_component(krb5context, krb5server, 0),
+ &rcache)))
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
+ "krb5_get_server_rcache() fails.\n");
+ goto err;
+ }
+ }
+
+ if ((krb5rc = krb5_auth_con_setrcache(krb5context, krb5auth_context, rcache)))
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
+ "krb5_auth_con_setrcache() fails.\n");
+ goto err;
+ }
+
+
/* kssl_ctx->keytab_file == NULL ==> use Kerberos default
*/
if (kssl_ctx->keytab_file)
** &ap_option, &krb5ticket)) != 0) { Error }
*/
- p = indata->data;
+ p = (unsigned char *)indata->data;
if ((asn1ticket = (KRB5_TKTBODY *) d2i_KRB5_TICKET(NULL, &p,
(long) indata->length)) == NULL)
{
printf("\tcaddrs: %p, authdata: %p\n",
krb5ticket->enc_part2->caddrs,
krb5ticket->enc_part2->authorization_data);
- printf("\tcaddrs:\n");
- for (i=0; paddr[i] != NULL; i++)
- { krb5_data d;
- d.length=paddr[i]->length; d.data=paddr[i]->contents;
- print_krb5_data("\t\tIP: ", &d);
+ if (paddr)
+ {
+ printf("\tcaddrs:\n");
+ for (i=0; paddr[i] != NULL; i++)
+ {
+ krb5_data d;
+ d.length=paddr[i]->length;
+ d.data=paddr[i]->contents;
+ print_krb5_data("\t\tIP: ", &d);
+ }
}
printf("\tstart/auth/end times: %d / %d / %d\n",
krb5ticket->enc_part2->times.starttime,
"bad ticket from krb5_rd_req.\n");
}
else if (kssl_ctx_setprinc(kssl_ctx, KSSL_CLIENT,
- &krb5ticket->enc_part2->client->realm,
- krb5ticket->enc_part2->client->data))
+ &krb5ticket->enc_part2->client->realm,
+ krb5ticket->enc_part2->client->data,
+ krb5ticket->enc_part2->client->length))
{
kssl_err_set(kssl_err, SSL_R_KRB5_S_BAD_TICKET,
"kssl_ctx_setprinc() fails.\n");
{
if (kssl_ctx == NULL) return kssl_ctx;
- if (kssl_ctx->key) memset(kssl_ctx->key, 0,
+ if (kssl_ctx->key) OPENSSL_cleanse(kssl_ctx->key,
kssl_ctx->length);
if (kssl_ctx->key) free(kssl_ctx->key);
if (kssl_ctx->client_princ) free(kssl_ctx->client_princ);
}
-/* Given a (krb5_data *) entity (and optional realm),
+/* Given an array of (krb5_data *) entity (and optional realm),
** set the plain (char *) client_princ or service_host member
** of the kssl_ctx struct.
*/
krb5_error_code
kssl_ctx_setprinc(KSSL_CTX *kssl_ctx, int which,
- krb5_data *realm, krb5_data *entity)
+ krb5_data *realm, krb5_data *entity, int nentities)
{
char **princ;
int length;
+ int i;
if (kssl_ctx == NULL || entity == NULL) return KSSL_CTX_ERR;
}
if (*princ) free(*princ);
- length = entity->length + ((realm)? realm->length + 2: 1);
+ /* Add up all the entity->lengths */
+ length = 0;
+ for (i=0; i < nentities; i++)
+ {
+ length += entity[i].length;
+ }
+ /* Add in space for the '/' character(s) (if any) */
+ length += nentities-1;
+ /* Space for the ('@'+realm+NULL | NULL) */
+ length += ((realm)? realm->length + 2: 1);
+
if ((*princ = calloc(1, length)) == NULL)
return KSSL_CTX_ERR;
else
- {
- strncpy(*princ, entity->data, entity->length);
+ {
+ for (i = 0; i < nentities; i++)
+ {
+ strncat(*princ, entity[i].data, entity[i].length);
+ if (i < nentities-1)
+ {
+ strcat (*princ, "/");
+ }
+ }
if (realm)
{
strcat (*princ, "@");
if (kssl_ctx->key)
{
- memset(kssl_ctx->key, 0, kssl_ctx->length);
+ OPENSSL_cleanse(kssl_ctx->key, kssl_ctx->length);
free(kssl_ctx->key);
}
return;
}
else
- printf("%p\n", kssl_ctx);
+ printf("%p\n", (void *)kssl_ctx);
printf("\tservice:\t%s\n",
(kssl_ctx->service_name)? kssl_ctx->service_name: "NULL");
return;
}
+ int
+ kssl_keytab_is_available(KSSL_CTX *kssl_ctx)
+{
+ krb5_context krb5context = NULL;
+ krb5_keytab krb5keytab = NULL;
+ krb5_keytab_entry entry;
+ krb5_principal princ = NULL;
+ krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC;
+ int rc = 0;
+
+ if ((krb5rc = krb5_init_context(&krb5context)))
+ return(0);
+
+ /* kssl_ctx->keytab_file == NULL ==> use Kerberos default
+ */
+ if (kssl_ctx->keytab_file)
+ {
+ krb5rc = krb5_kt_resolve(krb5context, kssl_ctx->keytab_file,
+ &krb5keytab);
+ if (krb5rc)
+ goto exit;
+ }
+ else
+ {
+ krb5rc = krb5_kt_default(krb5context,&krb5keytab);
+ if (krb5rc)
+ goto exit;
+ }
+
+ /* the host key we are looking for */
+ krb5rc = krb5_sname_to_principal(krb5context, NULL,
+ kssl_ctx->service_name ? kssl_ctx->service_name: KRB5SVC,
+ KRB5_NT_SRV_HST, &princ);
+
+ krb5rc = krb5_kt_get_entry(krb5context, krb5keytab,
+ princ,
+ 0 /* IGNORE_VNO */,
+ 0 /* IGNORE_ENCTYPE */,
+ &entry);
+ if ( krb5rc == KRB5_KT_NOTFOUND ) {
+ rc = 1;
+ goto exit;
+ } else if ( krb5rc )
+ goto exit;
+
+ krb5_kt_free_entry(krb5context, &entry);
+ rc = 1;
+
+ exit:
+ if (krb5keytab) krb5_kt_close(krb5context, krb5keytab);
+ if (princ) krb5_free_principal(krb5context, princ);
+ if (krb5context) krb5_free_context(krb5context);
+ return(rc);
+}
+
+int
+kssl_tgt_is_available(KSSL_CTX *kssl_ctx)
+ {
+ krb5_error_code krb5rc = KRB5KRB_ERR_GENERIC;
+ krb5_context krb5context = NULL;
+ krb5_ccache krb5ccdef = NULL;
+ krb5_creds krb5creds, *krb5credsp = NULL;
+ int rc = 0;
+
+ memset((char *)&krb5creds, 0, sizeof(krb5creds));
+
+ if (!kssl_ctx)
+ return(0);
+
+ if (!kssl_ctx->service_host)
+ return(0);
+
+ if ((krb5rc = krb5_init_context(&krb5context)) != 0)
+ goto err;
+
+ if ((krb5rc = krb5_sname_to_principal(krb5context,
+ kssl_ctx->service_host,
+ (kssl_ctx->service_name)? kssl_ctx->service_name: KRB5SVC,
+ KRB5_NT_SRV_HST, &krb5creds.server)) != 0)
+ goto err;
+
+ if ((krb5rc = krb5_cc_default(krb5context, &krb5ccdef)) != 0)
+ goto err;
+
+ if ((krb5rc = krb5_cc_get_principal(krb5context, krb5ccdef,
+ &krb5creds.client)) != 0)
+ goto err;
+
+ if ((krb5rc = krb5_get_credentials(krb5context, 0, krb5ccdef,
+ &krb5creds, &krb5credsp)) != 0)
+ goto err;
+
+ rc = 1;
+
+ err:
+#ifdef KSSL_DEBUG
+ kssl_ctx_show(kssl_ctx);
+#endif /* KSSL_DEBUG */
+
+ if (krb5creds.client) krb5_free_principal(krb5context, krb5creds.client);
+ if (krb5creds.server) krb5_free_principal(krb5context, krb5creds.server);
+ if (krb5context) krb5_free_context(krb5context);
+ return(rc);
+ }
+
+#if !defined(OPENSSL_SYS_WINDOWS) && !defined(OPENSSL_SYS_WIN32)
void kssl_krb5_free_data_contents(krb5_context context, krb5_data *data)
{
#ifdef KRB5_HEIMDAL
data->length = 0;
- free(data->if (data->data) data);
+ if (data->data)
+ free(data->data);
#elif defined(KRB5_MIT_OLD11)
if (data->data) {
krb5_xfree(data->data);
krb5_free_data_contents(NULL, data);
#endif
}
+#endif /* !OPENSSL_SYS_WINDOWS && !OPENSSL_SYS_WIN32 */
+
+
+/* Given pointers to KerberosTime and struct tm structs, convert the
+** KerberosTime string to struct tm. Note that KerberosTime is a
+** ASN1_GENERALIZEDTIME value, constrained to GMT with no fractional
+** seconds as defined in RFC 1510.
+** Return pointer to the (partially) filled in struct tm on success,
+** return NULL on failure.
+*/
+struct tm *k_gmtime(ASN1_GENERALIZEDTIME *gtime, struct tm *k_tm)
+ {
+ char c, *p;
+
+ if (!k_tm) return NULL;
+ if (gtime == NULL || gtime->length < 14) return NULL;
+ if (gtime->data == NULL) return NULL;
+
+ p = (char *)>ime->data[14];
+
+ c = *p; *p = '\0'; p -= 2; k_tm->tm_sec = atoi(p); *(p+2) = c;
+ c = *p; *p = '\0'; p -= 2; k_tm->tm_min = atoi(p); *(p+2) = c;
+ c = *p; *p = '\0'; p -= 2; k_tm->tm_hour = atoi(p); *(p+2) = c;
+ c = *p; *p = '\0'; p -= 2; k_tm->tm_mday = atoi(p); *(p+2) = c;
+ c = *p; *p = '\0'; p -= 2; k_tm->tm_mon = atoi(p)-1; *(p+2) = c;
+ c = *p; *p = '\0'; p -= 4; k_tm->tm_year = atoi(p)-1900; *(p+4) = c;
+
+ return k_tm;
+ }
/* Helper function for kssl_validate_times().
KRB5_AUTHENTBODY *auth = NULL;
krb5_enctype enctype;
EVP_CIPHER_CTX ciph_ctx;
- EVP_CIPHER *enc = NULL;
+ const EVP_CIPHER *enc = NULL;
unsigned char iv[EVP_MAX_IV_LENGTH];
- unsigned char *p, *unenc_authent, *tbuf = NULL;
- int padl, outl, unencbufsize;
+ unsigned char *p, *unenc_authent;
+ int outl, unencbufsize;
struct tm tm_time, *tm_l, *tm_g;
- time_t now, tl, tg, tz_offset;
+ time_t now, tl, tg, tr, tz_offset;
+ EVP_CIPHER_CTX_init(&ciph_ctx);
*atimep = 0;
kssl_err_set(kssl_err, 0, "");
if (authentp == NULL || authentp->length == 0) return 0;
#ifdef KSSL_DEBUG
+ {
+ unsigned int ui;
printf("kssl_check_authent: authenticator[%d]:\n",authentp->length);
p = authentp->data;
- for (padl=0; padl < authentp->length; padl++) printf("%02x ",p[padl]);
+ for (ui=0; ui < authentp->length; ui++) printf("%02x ",p[ui]);
printf("\n");
+ }
#endif /* KSSL_DEBUG */
unencbufsize = 2 * authentp->length;
goto err;
}
- p = authentp->data;
+ p = (unsigned char *)authentp->data;
if ((dec_authent = d2i_KRB5_ENCDATA(NULL, &p,
(long) authentp->length)) == NULL)
{
}
enctype = dec_authent->etype->data[0]; /* should = kssl_ctx->enctype */
+#if !defined(KRB5_MIT_OLD11)
+ switch ( enctype ) {
+ case ENCTYPE_DES3_CBC_SHA1: /* EVP_des_ede3_cbc(); */
+ case ENCTYPE_DES3_CBC_SHA:
+ case ENCTYPE_DES3_CBC_RAW:
+ krb5rc = 0; /* Skip, can't handle derived keys */
+ goto err;
+ }
+#endif
enc = kssl_map_enc(enctype);
- memset(iv, 0, EVP_MAX_IV_LENGTH); /* per RFC 1510 */
+ memset(iv, 0, sizeof iv); /* per RFC 1510 */
- EVP_DecryptInit(&ciph_ctx, enc, kssl_ctx->key, iv);
- EVP_DecryptUpdate(&ciph_ctx, unenc_authent, &outl,
- dec_authent->cipher->data, dec_authent->cipher->length);
- if (outl > unencbufsize)
- {
- kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
- "Buffer overflow decrypting authenticator.\n");
- krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
- goto err;
- }
- EVP_DecryptFinal(&ciph_ctx, &(unenc_authent[outl]), &padl);
- outl += padl;
- if (outl > unencbufsize)
+ if (enc == NULL)
{
- kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
- "Buffer overflow decrypting authenticator.\n");
- krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ /* Disable kssl_check_authent for ENCTYPE_DES3_CBC_SHA1.
+ ** This enctype indicates the authenticator was encrypted
+ ** using key-usage derived keys which openssl cannot decrypt.
+ */
goto err;
}
- EVP_CIPHER_CTX_cleanup(&ciph_ctx);
+
+ if (!EVP_CipherInit(&ciph_ctx,enc,kssl_ctx->key,iv,0))
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
+ "EVP_CipherInit error decrypting authenticator.\n");
+ krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ goto err;
+ }
+ outl = dec_authent->cipher->length;
+ if (!EVP_Cipher(&ciph_ctx,unenc_authent,dec_authent->cipher->data,outl))
+ {
+ kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
+ "EVP_Cipher error decrypting authenticator.\n");
+ krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ goto err;
+ }
+ EVP_CIPHER_CTX_cleanup(&ciph_ctx);
#ifdef KSSL_DEBUG
printf("kssl_check_authent: decrypted authenticator[%d] =\n", outl);
krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
goto err;
}
- if ((tbuf = calloc(1, auth->ctime->length + 1)) == NULL)
- {
- kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
- "Unable to allocate atime buffer.\n");
- krb5rc = KRB5KRB_ERR_GENERIC;
- goto err;
- }
- else strncpy(tbuf, auth->ctime->data, auth->ctime->length);
-
- if (strptime(tbuf, "%Y%m%d%H%M%S", &tm_time) != NULL)
- {
- now = time(&now);
- tm_l = localtime(&now); tl = mktime(tm_l);
- tm_g = gmtime(&now); tg = mktime(tm_g);
- tz_offset = tg - tl;
- *atimep = mktime(&tm_time) - tz_offset;
- }
+ memset(&tm_time,0,sizeof(struct tm));
+ if (k_gmtime(auth->ctime, &tm_time) &&
+ ((tr = mktime(&tm_time)) != (time_t)(-1)))
+ {
+ now = time(&now);
+ tm_l = localtime(&now); tl = mktime(tm_l);
+ tm_g = gmtime(&now); tg = mktime(tm_g);
+ tz_offset = tg - tl;
+
+ *atimep = tr - tz_offset;
+ }
#ifdef KSSL_DEBUG
- printf("kssl_check_authent: client time %s = %d\n", tbuf, *atimep);
+ printf("kssl_check_authent: returns %d for client time ", *atimep);
+ if (auth && auth->ctime && auth->ctime->length && auth->ctime->data)
+ printf("%.*s\n", auth->ctime->length, auth->ctime->data);
+ else printf("NULL\n");
#endif /* KSSL_DEBUG */
err:
- if (tbuf) free(tbuf);
if (auth) KRB5_AUTHENT_free((KRB5_AUTHENT *) auth);
if (dec_authent) KRB5_ENCDATA_free(dec_authent);
if (unenc_authent) free(unenc_authent);
+ EVP_CIPHER_CTX_cleanup(&ciph_ctx);
return krb5rc;
}