From acdf4afb9147a80d894383fe86ec6de1b6dbd4d5 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Sat, 21 Jul 2001 09:43:43 +0000 Subject: [PATCH] More Kerberos SSL patches from Vern Staats . His comments are: This patch fixes the problem of modern Kerberos using "derived keys" to encrypt the authenticator by disabling the authenticator check for all derived keys enctypes. I think I've got all the bugfixes that Jeffrey and I discussed rolled into this. There were some problems with Jeffrey's code to convert the authenticator's Kerberos timestring into struct tm (e.g. Z, -1900; it helps to have an actual decryptable authenticator to play with). So I've shamelessly pushed in my code, while stealing some bits from Jeffrey. --- ssl/kssl.c | 166 +++++++++++++++++++++++++++++--------------------- ssl/s3_srvr.c | 26 ++++++-- 2 files changed, 119 insertions(+), 73 deletions(-) diff --git a/ssl/kssl.c b/ssl/kssl.c index be44ccb8a5..d9e1160550 100644 --- a/ssl/kssl.c +++ b/ssl/kssl.c @@ -750,27 +750,31 @@ char } -/* 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 * kssl_map_enc(krb5_enctype enctype) { switch (enctype) { +#if ! defined(KRB5_MIT_OLD11) + /* cannot handle derived keys */ + case ENCTYPE_DES3_CBC_SHA1: /* EVP_des_ede3_cbc(); */ + case ENCTYPE_DES_HMAC_SHA1: /* EVP_des_cbc(); */ + return (EVP_CIPHER *) NULL; + break; +#endif 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(); break; 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(); break; default: return (EVP_CIPHER *) NULL; @@ -821,11 +825,17 @@ int kssl_test_confound(unsigned char *p) */ int *populate_cksumlens(void) { - int i, j, n = 0x0010+1; + 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 = (size_t *) calloc(sizeof(int), n))) return NULL; + if (!cklens && !(cklens = (size_t *) calloc(sizeof(int),n+1))) return NULL; for (i=0; i < n; i++) { if (!valid_cksumtype(i)) continue; /* array has holes */ @@ -1812,6 +1822,35 @@ void kssl_krb5_free_data_contents(krb5_context context, krb5_data *data) } #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 *ctime, struct tm *k_tm) + { + char c, *p; + + if (!k_tm) return NULL; + if (ctime == NULL || ctime->length < 14) return NULL; + if (ctime->data == NULL) return NULL; + + p = &ctime->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(). ** We need context->clockskew, but krb5_context is an opaque struct. ** So we try to sneek the clockskew out through the replay cache. @@ -1892,8 +1931,10 @@ krb5_error_code kssl_check_authent( EVP_CIPHER_CTX ciph_ctx; EVP_CIPHER *enc = NULL; unsigned char iv[EVP_MAX_IV_LENGTH]; - unsigned char *p, *unenc_authent, *tbuf = NULL; + unsigned char *p, *unenc_authent; int padl, outl, unencbufsize; + struct tm tm_time, *tm_l, *tm_g; + time_t now, tl, tg, tr, tz_offset; *atimep = 0; kssl_err_set(kssl_err, 0, ""); @@ -1941,9 +1982,29 @@ krb5_error_code kssl_check_authent( enc = kssl_map_enc(enctype); memset(iv, 0, EVP_MAX_IV_LENGTH); /* 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 (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(&ciph_ctx, enc, kssl_ctx->key, iv)) + { + kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, + "EVP_DecryptInit 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, @@ -1951,7 +2012,13 @@ krb5_error_code kssl_check_authent( krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY; goto err; } - EVP_DecryptFinal(&ciph_ctx, &(unenc_authent[outl]), &padl); + if (!EVP_DecryptFinal(&ciph_ctx, &(unenc_authent[outl]), &padl)) + { + kssl_err_set(kssl_err, SSL_R_KRB5_S_INIT, + "EVP_DecryptFinal error decrypting authenticator.\n"); + krb5rc = KRB5KRB_AP_ERR_BAD_INTEGRITY; + goto err; + } outl += padl; if (outl > unencbufsize) { @@ -1985,64 +2052,27 @@ krb5_error_code kssl_check_authent( 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 ( auth->ctime->length >= 9 && auth->ctime->length <= 14 ) - /* tbuf == "%Y%m%d%H%M%S" */ - { - struct tm tm_time, *tm_l, *tm_g; - time_t now, tl, tg, tr, tz_offset; - int i; - char *p = tbuf; - - memset(&tm_time,0,sizeof(struct tm)); - for ( i=0; - i<4 && isdigit(*p); - i++, p++ ) - tm_time.tm_year = tm_time.tm_year*10 + (*p-'0'); - for ( i=0; - i<2 && isdigit(*p) && tm_time.tm_mon <= 1; - i++, p++ ) - tm_time.tm_mon = tm_time.tm_mon*10 + (*p-'0'); - for ( i=0; - i<2 && isdigit(*p) && tm_time.tm_mday <= 3; - i++, p++ ) - tm_time.tm_mday = tm_time.tm_mday*10 + (*p-'0'); - for ( i=0; - i<2 && isdigit(*p) && tm_time.tm_hour <= 2; - i++, p++ ) - tm_time.tm_hour = tm_time.tm_hour*10 + (*p-'0'); - for ( i=0; - i<2 && isdigit(*p) && tm_time.tm_min <= 6; - i++, p++ ) - tm_time.tm_min = tm_time.tm_min*10 + (*p-'0'); - for ( i=0; - i<2 && isdigit(*p) && tm_time.tm_sec <= 6; - i++, p++ ) - tm_time.tm_sec = tm_time.tm_sec*10 + (*p-'0'); - - now = time(&now); - tm_l = localtime(&now); tl = mktime(tm_l); - tm_g = gmtime(&now); tg = mktime(tm_g); - tz_offset = tg - tl; - tr = mktime(&tm_time); - - if (tr != (time_t)(-1)) - *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); diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 20b8cc9ac5..8d1041ce00 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -1463,7 +1463,8 @@ static int ssl3_get_client_key_exchange(SSL *s) EVP_CIPHER_CTX ciph_ctx; EVP_CIPHER *enc = NULL; unsigned char iv[EVP_MAX_IV_LENGTH]; - unsigned char pms[SSL_MAX_MASTER_KEY_LENGTH]; + unsigned char pms[SSL_MAX_MASTER_KEY_LENGTH + + EVP_MAX_IV_LENGTH + 1]; int padl, outl = sizeof(pms); krb5_timestamp authtime = 0; krb5_ticket_times ttimes; @@ -1537,16 +1538,31 @@ static int ssl3_get_client_key_exchange(SSL *s) enc = kssl_map_enc(kssl_ctx->enctype); memset(iv, 0, EVP_MAX_IV_LENGTH); /* per RFC 1510 */ - EVP_DecryptInit(&ciph_ctx,enc,kssl_ctx->key,iv); - EVP_DecryptUpdate(&ciph_ctx, pms,&outl, - enc_pms.data, enc_pms.length); + if (!EVP_DecryptInit(&ciph_ctx,enc,kssl_ctx->key,iv)) + { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DECRYPTION_FAILED); + goto err; + } + if (!EVP_DecryptUpdate(&ciph_ctx, pms,&outl, + enc_pms.data, enc_pms.length)) + { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DECRYPTION_FAILED); + goto err; + } if (outl > SSL_MAX_MASTER_KEY_LENGTH) { SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, SSL_R_DATA_LENGTH_TOO_LONG); goto err; } - EVP_DecryptFinal(&ciph_ctx,&(pms[outl]),&padl); + if (!EVP_DecryptFinal(&ciph_ctx,&(pms[outl]),&padl)) + { + SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE, + SSL_R_DECRYPTION_FAILED); + goto err; + } outl += padl; if (outl > SSL_MAX_MASTER_KEY_LENGTH) { -- 2.34.1