More Kerberos SSL patches from Vern Staats <staatsvr@asc.hpc.mil>.
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.
This commit is contained in:
parent
6d3dec92fb
commit
acdf4afb91
162
ssl/kssl.c
162
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);
|
||||
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;
|
||||
}
|
||||
|
||||
if (tr != (time_t)(-1))
|
||||
*atimep = mktime(&tm_time) - 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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user