Further comment amendments to preserve formatting prior to source reformat
[openssl.git] / ssl / kssl.c
index 49b749b05412b713145f7dfd169c214c5de015b7..7ce81117084560148fff2d76582f1b3971c68bb6 100644 (file)
  */
 
 
-/*  ssl/kssl.c  --  Routines to support (& debug) Kerberos5 auth for openssl
-**
-**  19990701   VRS     Started.
-**  200011??   Jeffrey Altman, Richard Levitte
-**                     Generalized for Heimdal, Newer MIT, & Win32.
-**                     Integrated into main OpenSSL 0.9.7 snapshots.
-**  20010413   Simon Wilkinson, VRS
-**                     Real RFC2712 KerberosWrapper replaces AP_REQ.
-*/
+/*-
+ * ssl/kssl.c  --  Routines to support (& debug) Kerberos5 auth for openssl
+ *
+ *  19990701   VRS     Started.
+ *  200011??   Jeffrey Altman, Richard Levitte
+ *                     Generalized for Heimdal, Newer MIT, & Win32.
+ *                     Integrated into main OpenSSL 0.9.7 snapshots.
+ *  20010413   Simon Wilkinson, VRS
+ *                     Real RFC2712 KerberosWrapper replaces AP_REQ.
+ */
 
 #include <openssl/opensslconf.h>
 
-#define _XOPEN_SOURCE /* glibc2 needs this to declare strptime() */
-#include <time.h>
 #include <string.h>
 
+#define KRB5_PRIVATE   1
+
 #include <openssl/ssl.h>
 #include <openssl/evp.h>
 #include <openssl/objects.h>
 #include <openssl/krb5_asn.h>
+#include "kssl_lcl.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_principal_compare   kssl_krb5_principal_compare
 #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_rc_default          kssl_krb5_rc_default
+
+#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
@@ -275,7 +294,7 @@ load_krb5_dll(void)
        HANDLE hKRB5_32;
     
        krb5_loaded++;
-       hKRB5_32 = LoadLibrary("KRB5_32");
+       hKRB5_32 = LoadLibrary(TEXT("KRB5_32"));
        if (!hKRB5_32)
                return;
 
@@ -762,6 +781,25 @@ kssl_krb5_kt_get_entry(krb5_context context, krb5_keytab keytab,
         }
 #endif  /* OPENSSL_SYS_WINDOWS || OPENSSL_SYS_WIN32 */
 
+
+/* memory allocation functions for non-temporary storage
+ * (e.g. stuff that gets saved into the kssl context) */
+static void* kssl_calloc(size_t nmemb, size_t size)
+{
+       void* p;
+       
+       p=OPENSSL_malloc(nmemb*size);
+       if (p){
+               memset(p, 0, nmemb*size);
+       }
+       return p;
+}
+
+#define kssl_malloc(size) OPENSSL_malloc((size))
+#define kssl_realloc(ptr, size) OPENSSL_realloc(ptr, size)
+#define kssl_free(ptr) OPENSSL_free((ptr))
+
+
 char
 *kstring(char *string)
         {
@@ -770,30 +808,12 @@ char
        return ((string == NULL)? null: string);
         }
 
-#define        MAXKNUM 255
-char
-*knumber(int len, krb5_octet *contents)
-        {
-       static char     buf[MAXKNUM+1];
-       int             i;
-
-       BIO_snprintf(buf, MAXKNUM, "[%d] ", len);
-
-       for (i=0; i < len  &&  MAXKNUM > strlen(buf)+3; i++)
-                {
-                BIO_snprintf(&buf[strlen(buf)], 3, "%02x", contents[i]);
-                }
-
-       return (buf);
-       }
-
-
 /*     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 *
+ *     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.
+ */
+const EVP_CIPHER *
 kssl_map_enc(krb5_enctype enctype)
         {
        switch (enctype)
@@ -803,25 +823,25 @@ kssl_map_enc(krb5_enctype enctype)
        case ENCTYPE_DES_CBC_MD4:
        case ENCTYPE_DES_CBC_MD5:
        case ENCTYPE_DES_CBC_RAW:
-                               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:
-                               return (EVP_CIPHER *) EVP_des_ede3_cbc();
+                               return EVP_des_ede3_cbc();
                                break;
-       default:                return (EVP_CIPHER *) NULL;
+       default:                return NULL;
                                break;
                }
        }
 
 
 /*     Return true:1 if p "looks like" the start of the real authenticator
-**     described in kssl_skip_confound() below.  The ASN.1 pattern is
-**     "62 xx 30 yy" (APPLICATION-2, SEQUENCE), where xx-yy =~ 2, and
-**     xx and yy are possibly multi-byte length fields.
-*/
-int    kssl_test_confound(unsigned char *p)
+ *     described in kssl_skip_confound() below.  The ASN.1 pattern is
+ *     "62 xx 30 yy" (APPLICATION-2, SEQUENCE), where xx-yy =~ 2, and
+ *     xx and yy are possibly multi-byte length fields.
+ */
+static int     kssl_test_confound(unsigned char *p)
        {
        int     len = 2;
        int     xx = 0, yy = 0;
@@ -847,16 +867,16 @@ int       kssl_test_confound(unsigned char *p)
        }
 
 /*     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.
-*/
-size_t  *populate_cksumlens(void)
+ *     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.
+ */
+static size_t  *populate_cksumlens(void)
        {
        int             i, j, n;
        static size_t   *cklens = NULL;
@@ -887,13 +907,14 @@ size_t  *populate_cksumlens(void)
        return cklens;
        }
 
-/*     Return pointer to start of real authenticator within authenticator, or
-**     return NULL on error.
-**     Decrypted authenticator looks like this:
-**             [0 or 8 byte confounder] [4-24 byte checksum] [real authent'r]
-**     This hackery wouldn't be necessary if MIT KRB5 1.0.6 had the
-**     krb5_auth_con_getcksumtype() function advertised in its krb5.h.
-*/
+/*-
+ *     Return pointer to start of real authenticator within authenticator, or
+ *     return NULL on error.
+ *     Decrypted authenticator looks like this:
+ *             [0 or 8 byte confounder] [4-24 byte checksum] [real authent'r]
+ *     This hackery wouldn't be necessary if MIT KRB5 1.0.6 had the
+ *     krb5_auth_con_getcksumtype() function advertised in its krb5.h.
+ */
 unsigned char  *kssl_skip_confound(krb5_enctype etype, unsigned char *a)
        {
        int             i, conlen;
@@ -915,15 +936,15 @@ unsigned char     *kssl_skip_confound(krb5_enctype etype, unsigned char *a)
 
 
 /*     Set kssl_err error info when reason text is a simple string
-**             kssl_err = struct { int reason; char text[KSSL_ERR_MAX+1]; }
-*/
+ *             kssl_err = struct { int reason; char text[KSSL_ERR_MAX+1]; }
+ */
 void
 kssl_err_set(KSSL_ERR *kssl_err, int reason, char *text)
         {
        if (kssl_err == NULL)  return;
 
        kssl_err->reason = reason;
-       BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, text);
+       BIO_snprintf(kssl_err->text, KSSL_ERR_MAX, "%s", text);
        return;
         }
 
@@ -933,17 +954,17 @@ kssl_err_set(KSSL_ERR *kssl_err, int reason, char *text)
 void
 print_krb5_data(char *label, krb5_data *kdata)
         {
-       unsigned int    i;
+       int i;
 
-       printf("%s[%d] ", label, kdata->length);
-       for (i=0; i < kdata->length; i++)
+       fprintf(stderr,"%s[%d] ", label, kdata->length);
+       for (i=0; i < (int)kdata->length; i++)
                 {
                if (0 &&  isprint((int) kdata->data[i]))
-                        printf(        "%c ",  kdata->data[i]);
+                        fprintf(stderr,        "%c ",  kdata->data[i]);
                else
-                        printf(        "%02x ", (unsigned char) kdata->data[i]);
+                        fprintf(stderr,        "%02x ", (unsigned char) kdata->data[i]);
                }
-       printf("\n");
+       fprintf(stderr,"\n");
         }
 
 
@@ -954,20 +975,20 @@ print_krb5_authdata(char *label, krb5_authdata **adata)
         {
        if (adata == NULL)
                 {
-               printf("%s, authdata==0\n", label);
+               fprintf(stderr,"%s, authdata==0\n", label);
                return;
                }
-       printf("%s [%p]\n", label, adata);
+       fprintf(stderr,"%s [%p]\n", label, (void *)adata);
 #if 0
        {
         int    i;
-       printf("%s[at%d:%d] ", label, adata->ad_type, adata->length);
+       fprintf(stderr,"%s[at%d:%d] ", label, adata->ad_type, adata->length);
        for (i=0; i < adata->length; i++)
                 {
-                printf((isprint(adata->contents[i]))? "%c ": "%02x",
+                fprintf(stderr,(isprint(adata->contents[i]))? "%c ": "%02x",
                         adata->contents[i]);
                }
-       printf("\n");
+       fprintf(stderr,"\n");
        }
 #endif
        }
@@ -978,67 +999,66 @@ print_krb5_authdata(char *label, krb5_authdata **adata)
 void
 print_krb5_keyblock(char *label, krb5_keyblock *keyblk)
         {
-       unsigned int    i;
+       int i;
 
        if (keyblk == NULL)
                 {
-               printf("%s, keyblk==0\n", label);
+               fprintf(stderr,"%s, keyblk==0\n", label);
                return;
                }
 #ifdef KRB5_HEIMDAL
-       printf("%s\n\t[et%d:%d]: ", label, keyblk->keytype,
+       fprintf(stderr,"%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]);
+               fprintf(stderr,"%02x",(unsigned char *)(keyblk->keyvalue->contents)[i]);
                }
-       printf("\n");
+       fprintf(stderr,"\n");
 #else
-       printf("%s\n\t[et%d:%d]: ", label, keyblk->enctype, keyblk->length);
-       for (i=0; i < keyblk->length; i++)
+       fprintf(stderr,"%s\n\t[et%d:%d]: ", label, keyblk->enctype, keyblk->length);
+       for (i=0; i < (int)keyblk->length; i++)
                 {
-               printf("%02x",keyblk->contents[i]);
+               fprintf(stderr,"%02x",keyblk->contents[i]);
                }
-       printf("\n");
+       fprintf(stderr,"\n");
 #endif
         }
 
 
 /*     Display contents of krb5_principal_data struct, for debugging
-**     (krb5_principal is typedef'd == krb5_principal_data *)
-*/
-void
+ *     (krb5_principal is typedef'd == krb5_principal_data *)
+ */
+static void
 print_krb5_princ(char *label, krb5_principal_data *princ)
         {
-       unsigned int    ui, uj;
-        int i;
+       int i, ui, uj;
 
-       printf("%s principal Realm: ", label);
+       fprintf(stderr,"%s principal Realm: ", label);
        if (princ == NULL)  return;
-       for (ui=0; ui < 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 (ui=0; ui < (int)princ->realm.length; ui++)  putchar(princ->realm.data[ui]);
+       fprintf(stderr," (nametype %d) has %d strings:\n", princ->type,princ->length);
+       for (i=0; i < (int)princ->length; i++)
                 {
-               printf("\t%d [%d]: ", i, princ->data[i].length);
-               for (uj=0; uj < princ->data[i].length; uj++)  {
+               fprintf(stderr,"\t%d [%d]: ", i, princ->data[i].length);
+               for (uj=0; uj < (int)princ->data[i].length; uj++)  {
                        putchar(princ->data[i].data[uj]);
                        }
-               printf("\n");
+               fprintf(stderr,"\n");
                }
        return;
         }
 
 
-/*     Given krb5 service (typically "kssl") and hostname in kssl_ctx,
-**     Return encrypted Kerberos ticket for service @ hostname.
-**     If authenp is non-NULL, also return encrypted authenticator,
-**     whose data should be freed by caller.
-**     (Originally was: Create Kerberos AP_REQ message for SSL Client.)
-**
-**     19990628        VRS     Started; Returns Kerberos AP_REQ message.
-**     20010409        VRS     Modified for RFC2712; Returns enc tkt.
-**     20010606        VRS     May also return optional authenticator.
-*/
+/*-    Given krb5 service (typically "kssl") and hostname in kssl_ctx,
+ *     Return encrypted Kerberos ticket for service @ hostname.
+ *     If authenp is non-NULL, also return encrypted authenticator,
+ *     whose data should be freed by caller.
+ *     (Originally was: Create Kerberos AP_REQ message for SSL Client.)
+ *
+ *     19990628        VRS     Started; Returns Kerberos AP_REQ message.
+ *     20010409        VRS     Modified for RFC2712; Returns enc tkt.
+ *     20010606        VRS     May also return optional authenticator.
+ */
 krb5_error_code
 kssl_cget_tkt( /* UPDATE */    KSSL_CTX *kssl_ctx,
                 /* OUT    */   krb5_data **enc_ticketp,
@@ -1123,13 +1143,13 @@ kssl_cget_tkt(  /* UPDATE */    KSSL_CTX *kssl_ctx,
        krb5rc = KRB5KRB_ERR_GENERIC;
        /*      caller should free data of krb5_app_req  */
        /*  20010406 VRS deleted for real KerberosWrapper
-       **  20010605 VRS reinstated to offer Authenticator to KerberosWrapper
-       */
+        *  20010605 VRS reinstated to offer Authenticator to KerberosWrapper
+        */
        krb5_app_req.length = 0;
        if (authenp)
                 {
                krb5_data       krb5in_data;
-               unsigned char   *p;
+               const unsigned char     *p;
                long            arlen;
                KRB5_APREQBODY  *ap_req;
 
@@ -1196,18 +1216,19 @@ kssl_cget_tkt(  /* UPDATE */    KSSL_CTX *kssl_ctx,
        }
 
 
-/*  Given d2i_-decoded asn1ticket, allocate and return a new krb5_ticket.
-**  Return Kerberos error code and kssl_err struct on error.
-**  Allocates krb5_ticket and krb5_principal; caller should free these.
-**
-**     20010410        VRS     Implemented krb5_decode_ticket() as
-**                             old_krb5_decode_ticket(). Missing from MIT1.0.6.
-**     20010615        VRS     Re-cast as openssl/asn1 d2i_*() functions.
-**                             Re-used some of the old krb5_decode_ticket()
-**                             code here.  This tkt should alloc/free just
-**                             like the real thing.
-*/
-krb5_error_code
+/*-
+ *  Given d2i_-decoded asn1ticket, allocate and return a new krb5_ticket.
+ *  Return Kerberos error code and kssl_err struct on error.
+ *  Allocates krb5_ticket and krb5_principal; caller should free these.
+ *
+ *     20010410        VRS     Implemented krb5_decode_ticket() as
+ *                             old_krb5_decode_ticket(). Missing from MIT1.0.6.
+ *     20010615        VRS     Re-cast as openssl/asn1 d2i_*() functions.
+ *                             Re-used some of the old krb5_decode_ticket()
+ *                             code here.  This tkt should alloc/free just
+ *                             like the real thing.
+ */
+static krb5_error_code
 kssl_TKT2tkt(  /* IN     */    krb5_context    krb5context,
                /* IN     */    KRB5_TKTBODY    *asn1ticket,
                /* OUT    */    krb5_ticket     **krb5ticket,
@@ -1221,8 +1242,7 @@ kssl_TKT2tkt(     /* IN     */    krb5_context    krb5context,
 
        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");
@@ -1238,14 +1258,14 @@ kssl_TKT2tkt(   /* IN     */    krb5_context    krb5context,
                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,
@@ -1282,12 +1302,12 @@ kssl_TKT2tkt(   /* IN     */    krb5_context    krb5context,
 
 
 /*     Given krb5 service name in KSSL_CTX *kssl_ctx (typically "kssl"),
-**             and krb5 AP_REQ message & message length,
-**     Return Kerberos session key and client principle
-**             to SSL Server in KSSL_CTX *kssl_ctx.
-**
-**     19990702        VRS     Started.
-*/
+ *             and krb5 AP_REQ message & message length,
+ *     Return Kerberos session key and client principle
+ *             to SSL Server in KSSL_CTX *kssl_ctx.
+ *
+ *     19990702        VRS     Started.
+ */
 krb5_error_code
 kssl_sget_tkt( /* UPDATE */    KSSL_CTX                *kssl_ctx,
                /* IN     */    krb5_data               *indata,
@@ -1299,7 +1319,7 @@ kssl_sget_tkt(    /* UPDATE */    KSSL_CTX                *kssl_ctx,
        static krb5_auth_context        krb5auth_context = NULL;
        krb5_ticket                     *krb5ticket = NULL;
        KRB5_TKTBODY                    *asn1ticket = NULL;
-       unsigned char                   *p;
+       const unsigned char             *p;
        krb5_keytab                     krb5keytab = NULL;
        krb5_keytab_entry               kt_entry;
        krb5_principal                  krb5server;
@@ -1315,7 +1335,7 @@ kssl_sget_tkt(    /* UPDATE */    KSSL_CTX                *kssl_ctx,
                }
 
 #ifdef KSSL_DEBUG
-       printf("in kssl_sget_tkt(%s)\n", kstring(kssl_ctx->service_name));
+       fprintf(stderr,"in kssl_sget_tkt(%s)\n", kstring(kssl_ctx->service_name));
 #endif /* KSSL_DEBUG */
 
        if (!krb5context  &&  (krb5rc = krb5_init_context(&krb5context)))
@@ -1402,19 +1422,20 @@ kssl_sget_tkt(  /* UPDATE */    KSSL_CTX                *kssl_ctx,
                        }
                }
 
-       /*      Actual Kerberos5 krb5_recvauth() has initial conversation here
-       **      o       check KRB5_SENDAUTH_BADAUTHVERS
-       **              unless KRB5_RECVAUTH_SKIP_VERSION
-       **      o       check KRB5_SENDAUTH_BADAPPLVERS
-       **      o       send "0" msg if all OK
-       */
+       /*-     Actual Kerberos5 krb5_recvauth() has initial conversation here
+        *      o       check KRB5_SENDAUTH_BADAUTHVERS
+        *              unless KRB5_RECVAUTH_SKIP_VERSION
+        *      o       check KRB5_SENDAUTH_BADAPPLVERS
+        *      o       send "0" msg if all OK
+        */
 
-       /*  20010411 was using AP_REQ instead of true KerberosWrapper
-       **
-       **  if ((krb5rc = krb5_rd_req(krb5context, &krb5auth_context,
-       **                      &krb5in_data, krb5server, krb5keytab,
-       **                      &ap_option, &krb5ticket)) != 0)  { Error }
-       */
+       /*- 
+        * 20010411 was using AP_REQ instead of true KerberosWrapper
+        *
+        *  if ((krb5rc = krb5_rd_req(krb5context, &krb5auth_context,
+        *                      &krb5in_data, krb5server, krb5keytab,
+        *                      &ap_option, &krb5ticket)) != 0)  { Error }
+        */
 
        p = (unsigned char *)indata->data;
        if ((asn1ticket = (KRB5_TKTBODY *) d2i_KRB5_TICKET(NULL, &p,
@@ -1464,18 +1485,18 @@ kssl_sget_tkt(  /* UPDATE */    KSSL_CTX                *kssl_ctx,
 #ifdef KSSL_DEBUG
                {
                int i; krb5_address **paddr = krb5ticket->enc_part2->caddrs;
-               printf("Decrypted ticket fields:\n");
-               printf("\tflags: %X, transit-type: %X",
+               fprintf(stderr,"Decrypted ticket fields:\n");
+               fprintf(stderr,"\tflags: %X, transit-type: %X",
                        krb5ticket->enc_part2->flags,
                        krb5ticket->enc_part2->transited.tr_type);
                print_krb5_data("\ttransit-data: ",
                        &(krb5ticket->enc_part2->transited.tr_contents));
-               printf("\tcaddrs: %p, authdata: %p\n",
+               fprintf(stderr,"\tcaddrs: %p, authdata: %p\n",
                        krb5ticket->enc_part2->caddrs,
                        krb5ticket->enc_part2->authorization_data);
                if (paddr)
                        {
-                       printf("\tcaddrs:\n");
+                       fprintf(stderr,"\tcaddrs:\n");
                        for (i=0; paddr[i] != NULL; i++)
                                {
                                krb5_data d;
@@ -1484,7 +1505,7 @@ kssl_sget_tkt(    /* UPDATE */    KSSL_CTX                *kssl_ctx,
                                print_krb5_data("\t\tIP: ", &d);
                                }
                        }
-               printf("\tstart/auth/end times: %d / %d / %d\n",
+               fprintf(stderr,"\tstart/auth/end times: %d / %d / %d\n",
                        krb5ticket->enc_part2->times.starttime,
                        krb5ticket->enc_part2->times.authtime,
                        krb5ticket->enc_part2->times.endtime);
@@ -1502,8 +1523,9 @@ kssl_sget_tkt(    /* UPDATE */    KSSL_CTX                *kssl_ctx,
                         "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");
@@ -1545,41 +1567,42 @@ kssl_sget_tkt(  /* UPDATE */    KSSL_CTX                *kssl_ctx,
 KSSL_CTX       *
 kssl_ctx_new(void)
         {
-       return ((KSSL_CTX *) calloc(1, sizeof(KSSL_CTX)));
+       return ((KSSL_CTX *) kssl_calloc(1, sizeof(KSSL_CTX)));
         }
 
 
 /*     Frees a kssl_ctx struct and any allocated memory it holds.
-**     Returns NULL.
-*/
+ *     Returns NULL.
+ */
 KSSL_CTX       *
 kssl_ctx_free(KSSL_CTX *kssl_ctx)
         {
        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);
-       if (kssl_ctx->service_host)     free(kssl_ctx->service_host);
-       if (kssl_ctx->service_name)     free(kssl_ctx->service_name);
-       if (kssl_ctx->keytab_file)      free(kssl_ctx->keytab_file);
+       if (kssl_ctx->key)              kssl_free(kssl_ctx->key);
+       if (kssl_ctx->client_princ)     kssl_free(kssl_ctx->client_princ);
+       if (kssl_ctx->service_host)     kssl_free(kssl_ctx->service_host);
+       if (kssl_ctx->service_name)     kssl_free(kssl_ctx->service_name);
+       if (kssl_ctx->keytab_file)      kssl_free(kssl_ctx->keytab_file);
 
-       free(kssl_ctx);
+       kssl_free(kssl_ctx);
        return (KSSL_CTX *) NULL;
         }
 
 
-/*     Given a (krb5_data *) entity (and optional realm),
-**     set the plain (char *) client_princ or service_host member
-**     of the kssl_ctx struct.
-*/
+/*     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;
 
@@ -1589,14 +1612,31 @@ kssl_ctx_setprinc(KSSL_CTX *kssl_ctx, int which,
         case KSSL_SERVER:      princ = &kssl_ctx->service_host;        break;
         default:               return KSSL_CTX_ERR;                    break;
                }
-       if (*princ)  free(*princ);
+       if (*princ)  kssl_free(*princ);
+
+       /* 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);
 
-       length = entity->length + ((realm)? realm->length + 2: 1);
-       if ((*princ = calloc(1, length)) == NULL)
+       if ((*princ = kssl_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, "@");
@@ -1608,11 +1648,11 @@ kssl_ctx_setprinc(KSSL_CTX *kssl_ctx, int which,
         }
 
 
-/*     Set one of the plain (char *) string members of the kssl_ctx struct.
-**     Default values should be:
-**             which == KSSL_SERVICE   =>      "khost" (KRB5SVC)
-**             which == KSSL_KEYTAB    =>      "/etc/krb5.keytab" (KRB5KEYTAB)
-*/
+/*-    Set one of the plain (char *) string members of the kssl_ctx struct.
+ *     Default values should be:
+ *             which == KSSL_SERVICE   =>      "khost" (KRB5SVC)
+ *             which == KSSL_KEYTAB    =>      "/etc/krb5.keytab" (KRB5KEYTAB)
+ */
 krb5_error_code
 kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text)
         {
@@ -1628,7 +1668,7 @@ kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text)
         case KSSL_KEYTAB:      string = &kssl_ctx->keytab_file;        break;
         default:               return KSSL_CTX_ERR;                    break;
                }
-       if (*string)  free(*string);
+       if (*string)  kssl_free(*string);
 
        if (!text)
                 {
@@ -1636,7 +1676,7 @@ kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text)
                return KSSL_CTX_OK;
                }
 
-       if ((*string = calloc(1, strlen(text) + 1)) == NULL)
+       if ((*string = kssl_calloc(1, strlen(text) + 1)) == NULL)
                return KSSL_CTX_ERR;
        else
                strcpy(*string, text);
@@ -1646,8 +1686,8 @@ kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text)
 
 
 /*     Copy the Kerberos session key from a (krb5_keyblock *) to a kssl_ctx
-**     struct.  Clear kssl_ctx->key if Kerberos session key is NULL.
-*/
+ *     struct.  Clear kssl_ctx->key if Kerberos session key is NULL.
+ */
 krb5_error_code
 kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session)
         {
@@ -1659,8 +1699,8 @@ kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session)
 
        if (kssl_ctx->key)
                 {
-               memset(kssl_ctx->key, 0, kssl_ctx->length);
-               free(kssl_ctx->key);
+               OPENSSL_cleanse(kssl_ctx->key, kssl_ctx->length);
+               kssl_free(kssl_ctx->key);
                }
 
        if (session)
@@ -1686,7 +1726,7 @@ kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session)
                }
 
        if ((kssl_ctx->key =
-                (krb5_octet FAR *) calloc(1, kssl_ctx->length)) == NULL)
+                (krb5_octet FAR *) kssl_calloc(1, kssl_ctx->length)) == NULL)
                 {
                kssl_ctx->length  = 0;
                return KSSL_CTX_ERR;
@@ -1712,7 +1752,7 @@ kssl_ctx_show(KSSL_CTX *kssl_ctx)
                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");
@@ -1767,6 +1807,9 @@ kssl_ctx_show(KSSL_CTX *kssl_ctx)
                                      kssl_ctx->service_name ? kssl_ctx->service_name: KRB5SVC,
                                      KRB5_NT_SRV_HST, &princ);
 
+    if (krb5rc)
+       goto exit;
+
     krb5rc = krb5_kt_get_entry(krb5context, krb5keytab, 
                                 princ,
                                 0 /* IGNORE_VNO */,
@@ -1858,13 +1901,13 @@ void kssl_krb5_free_data_contents(krb5_context context, krb5_data *data)
 
 
 /*  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)
+ *  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.
+ */
+static struct tm *k_gmtime(ASN1_GENERALIZEDTIME *gtime, struct tm *k_tm)
        {
        char            c, *p;
 
@@ -1886,11 +1929,11 @@ struct tm       *k_gmtime(ASN1_GENERALIZEDTIME *gtime, struct tm *k_tm)
 
 
 /*  Helper function for kssl_validate_times().
-**  We need context->clockskew, but krb5_context is an opaque struct.
-**  So we try to sneek the clockskew out through the replay cache.
-**     If that fails just return a likely default (300 seconds).
-*/
-krb5_deltat    get_rc_clockskew(krb5_context context)
+ *  We need context->clockskew, but krb5_context is an opaque struct.
+ *  So we try to sneek the clockskew out through the replay cache.
+ *     If that fails just return a likely default (300 seconds).
+ */
+static krb5_deltat get_rc_clockskew(krb5_context context)
        {
        krb5_rcache     rc;
        krb5_deltat     clockskew;
@@ -1906,15 +1949,15 @@ krb5_deltat     get_rc_clockskew(krb5_context context)
 
 
 /*  kssl_validate_times() combines (and more importantly exposes)
-**  the MIT KRB5 internal function krb5_validate_times() and the
-**  in_clock_skew() macro.  The authenticator client time is checked
-**  to be within clockskew secs of the current time and the current
-**  time is checked to be within the ticket start and expire times.
-**  Either check may be omitted by supplying a NULL value.
-**  Returns 0 for valid times, SSL_R_KRB5* error codes otherwise.
-**  See Also: (Kerberos source)/krb5/lib/krb5/krb/valid_times.c
-**  20010420 VRS
-*/
+ *  the MIT KRB5 internal function krb5_validate_times() and the
+ *  in_clock_skew() macro.  The authenticator client time is checked
+ *  to be within clockskew secs of the current time and the current
+ *  time is checked to be within the ticket start and expire times.
+ *  Either check may be omitted by supplying a NULL value.
+ *  Returns 0 for valid times, SSL_R_KRB5* error codes otherwise.
+ *  See Also: (Kerberos source)/krb5/lib/krb5/krb/valid_times.c
+ *  20010420 VRS
+ */
 krb5_error_code  kssl_validate_times(  krb5_timestamp atime,
                                        krb5_ticket_times *ttimes)
        {
@@ -1937,7 +1980,7 @@ krb5_error_code  kssl_validate_times(     krb5_timestamp atime,
        if ((now - ttimes->endtime) > skew)  return SSL_R_KRB5_S_TKT_EXPIRED;
 
 #ifdef KSSL_DEBUG
-       printf("kssl_validate_times: %d |<-  | %d - %d | < %d  ->| %d\n",
+       fprintf(stderr,"kssl_validate_times: %d |<-  | %d - %d | < %d  ->| %d\n",
                start, atime, now, skew, ttimes->endtime);
 #endif /* KSSL_DEBUG */
 
@@ -1946,12 +1989,12 @@ krb5_error_code  kssl_validate_times(   krb5_timestamp atime,
 
 
 /*  Decode and decrypt given DER-encoded authenticator, then pass
-**  authenticator ctime back in *atimep (or 0 if time unavailable).
-**  Returns krb5_error_code and kssl_err on error.  A NULL 
-**  authenticator (authentp->length == 0) is not considered an error.
-**  Note that kssl_check_authent() makes use of the KRB5 session key;
-**  you must call kssl_sget_tkt() to get the key before calling this routine.
-*/
+ *  authenticator ctime back in *atimep (or 0 if time unavailable).
+ *  Returns krb5_error_code and kssl_err on error.  A NULL 
+ *  authenticator (authentp->length == 0) is not considered an error.
+ *  Note that kssl_check_authent() makes use of the KRB5 session key;
+ *  you must call kssl_sget_tkt() to get the key before calling this routine.
+ */
 krb5_error_code  kssl_check_authent(
                        /* IN     */    KSSL_CTX        *kssl_ctx,
                         /* IN     */           krb5_data       *authentp,
@@ -1963,13 +2006,15 @@ krb5_error_code  kssl_check_authent(
        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;
-       int                     padl, outl, unencbufsize;
+       const unsigned char     *p;
+       unsigned char           *unenc_authent;
+       int                     outl, unencbufsize;
        struct tm               tm_time, *tm_l, *tm_g;
        time_t                  now, tl, tg, tr, tz_offset;
 
+       EVP_CIPHER_CTX_init(&ciph_ctx);
        *atimep = 0;
        kssl_err_set(kssl_err, 0, "");
 
@@ -1986,10 +2031,10 @@ krb5_error_code  kssl_check_authent(
 #ifdef KSSL_DEBUG
         {
         unsigned int ui;
-       printf("kssl_check_authent: authenticator[%d]:\n",authentp->length);
+       fprintf(stderr,"kssl_check_authent: authenticator[%d]:\n",authentp->length);
        p = authentp->data; 
-       for (ui=0; ui < authentp->length; ui++)  printf("%02x ",p[ui]);
-       printf("\n");
+       for (ui=0; ui < authentp->length; ui++)  fprintf(stderr,"%02x ",p[ui]);
+       fprintf(stderr,"\n");
         }
 #endif /* KSSL_DEBUG */
 
@@ -2023,59 +2068,41 @@ krb5_error_code  kssl_check_authent(
             }
 #endif
        enc = kssl_map_enc(enctype);
-       memset(iv, 0, EVP_MAX_IV_LENGTH);       /* per RFC 1510 */
+       memset(iv, 0, sizeof iv);       /* per RFC 1510 */
 
        if (enc == NULL)
                {
                /*  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;
-               }
-       if (!EVP_DecryptInit_ex(&ciph_ctx, enc, NULL, kssl_ctx->key, iv))
-               {
-               kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
-                       "EVP_DecryptInit_ex error decrypting authenticator.\n");
-               krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
-               goto err;
-               }
-       if (!EVP_DecryptUpdate(&ciph_ctx, unenc_authent, &outl,
-                       dec_authent->cipher->data, dec_authent->cipher->length))
-               {
-               kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
-                       "EVP_DecryptUpdate error decrypting authenticator.\n");
-               krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
-               goto err;
-               }
-       if (outl > unencbufsize)
-               {
-               kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
-                        "Buffer overflow decrypting authenticator.\n");
-               krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+                *  This enctype indicates the authenticator was encrypted
+                *  using key-usage derived keys which openssl cannot decrypt.
+                */
                goto err;
                }
-       if (!EVP_DecryptFinal_ex(&ciph_ctx, &(unenc_authent[outl]), &padl))
-               {
-               kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT,
-                       "EVP_DecryptFinal_ex error decrypting authenticator.\n");
-               krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY;
-               goto err;
-               }
-       outl += padl;
-       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_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);
-       for (padl=0; padl < outl; padl++) printf("%02x ",unenc_authent[padl]);
-       printf("\n");
+       {
+       int padl;
+       fprintf(stderr,"kssl_check_authent: decrypted authenticator[%d] =\n", outl);
+       for (padl=0; padl < outl; padl++) fprintf(stderr,"%02x ",unenc_authent[padl]);
+       fprintf(stderr,"\n");
+       }
 #endif /* KSSL_DEBUG */
 
        if ((p = kssl_skip_confound(enctype, unenc_authent)) == NULL)
@@ -2105,29 +2132,30 @@ krb5_error_code  kssl_check_authent(
                tm_g = gmtime(&now);            tg = mktime(tm_g);
                tz_offset = tg - tl;
 
-               *atimep = tr - tz_offset;
+               *atimep = (krb5_timestamp)(tr - tz_offset);
                }
 
 #ifdef KSSL_DEBUG
-       printf("kssl_check_authent: returns %d for client time ", *atimep);
+       fprintf(stderr,"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");
+               fprintf(stderr,"%.*s\n", auth->ctime->length, auth->ctime->data);
+       else    fprintf(stderr,"NULL\n");
 #endif /* KSSL_DEBUG */
 
  err:
        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;
        }
 
 
 /*  Replaces krb5_build_principal_ext(), with varargs length == 2 (svc, host),
-**  because I dont't know how to stub varargs.
-**  Returns krb5_error_code == ENOMEM on alloc error, otherwise
-**  passes back newly constructed principal, which should be freed by caller.
-*/
+ *  because I don't know how to stub varargs.
+ *  Returns krb5_error_code == ENOMEM on alloc error, otherwise
+ *  passes back newly constructed principal, which should be freed by caller.
+ */
 krb5_error_code  kssl_build_principal_2(
                        /* UPDATE */    krb5_context    context,
                        /* OUT    */    krb5_principal  *princ,
@@ -2170,11 +2198,27 @@ krb5_error_code  kssl_build_principal_2(
        return ENOMEM;
        }
 
+void SSL_set0_kssl_ctx(SSL *s, KSSL_CTX *kctx)
+       {
+       s->kssl_ctx = kctx;
+       } 
+
+KSSL_CTX * SSL_get0_kssl_ctx(SSL *s)
+       {
+       return s->kssl_ctx;
+       }
+
+char *kssl_ctx_get0_client_princ(KSSL_CTX *kctx)
+       {
+       if (kctx)
+               return kctx->client_princ;
+       return NULL;
+       }
 
 #else /* !OPENSSL_NO_KRB5 */
 
 #if defined(PEDANTIC) || defined(OPENSSL_SYS_VMS)
-static int dummy=(int)&dummy;
+static void *dummy=&dummy;
 #endif
 
 #endif /* !OPENSSL_NO_KRB5     */