heimdal Add handling for PAC signatures over all encryption types

There are exceptions from the expected behaviour of 'checksum type
matches key type' that we must deal with here, or else we can't serve
DES-only servers.

Andrew Bartlett

Signed-off-by: Love Hornquist Astrand <lha@h5l.org>
This commit is contained in:
Andrew Bartlett
2010-11-02 17:08:34 +11:00
committed by Love Hornquist Astrand
parent ae948e9932
commit a42b77fb22

View File

@@ -75,6 +75,41 @@ struct krb5_pac_data {
static const char zeros[PAC_ALIGNMENT] = { 0 };
/*
* HMAC-MD5 checksum over any key (needed for the PAC routines)
*/
static krb5_error_code
HMAC_MD5_any_checksum(krb5_context context,
const krb5_keyblock *key,
const void *data,
size_t len,
unsigned usage,
Checksum *result)
{
struct key_data local_key;
krb5_error_code ret;
ret = krb5_copy_keyblock(context, key, &local_key.key);
if (ret)
return ret;
local_key.schedule = NULL;
ret = krb5_data_alloc (&result->checksum, 16);
if (ret)
return ret;
result->cksumtype = CKSUMTYPE_HMAC_MD5;
ret = HMAC_MD5_checksum(context, &local_key, data, len, usage, result);
if (ret)
krb5_data_free(&result->checksum);
krb5_free_keyblock(context, local_key.key);
return ret;
}
/*
*
*/
@@ -412,7 +447,6 @@ verify_checksum(krb5_context context,
void *ptr, size_t len,
const krb5_keyblock *key)
{
krb5_crypto crypto = NULL;
krb5_storage *sp = NULL;
uint32_t type;
krb5_error_code ret;
@@ -452,14 +486,40 @@ verify_checksum(krb5_context context,
goto out;
}
/* If the checksum is HMAC-MD5, the checksum type is not tied to
* the key type, instead the HMAC-MD5 checksum is applied blindly
* on whatever key is used for this connection, avoiding issues
* with unkeyed checksums on des-cbc-md5 and des-cbc-crc. See
* http://comments.gmane.org/gmane.comp.encryption.kerberos.devel/8743
* for the same issue in MIT, and
* http://blogs.msdn.com/b/openspecification/archive/2010/01/01/verifying-the-server-signature-in-kerberos-privilege-account-certificate.aspx
* for Microsoft's explaination */
if (cksum.cksumtype == CKSUMTYPE_HMAC_MD5) {
Checksum local_checksum;
ret = HMAC_MD5_any_checksum(context, key, ptr, len, KRB5_KU_OTHER_CKSUM, &local_checksum);
if(local_checksum.checksum.length != cksum.checksum.length ||
ct_memcmp(local_checksum.checksum.data, cksum.checksum.data, local_checksum.checksum.length)) {
ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
krb5_set_error_message(context, ret,
N_("PAC integrity check failed for hmac-md5 checksum", ""));
} else {
ret = 0;
}
krb5_data_free(&local_checksum.checksum);
} else {
krb5_crypto crypto = NULL;
ret = krb5_crypto_init(context, key, 0, &crypto);
if (ret)
goto out;
ret = krb5_verify_checksum(context, crypto, KRB5_KU_OTHER_CKSUM,
ptr, len, &cksum);
free(cksum.checksum.data);
krb5_crypto_destroy(context, crypto);
}
free(cksum.checksum.data);
krb5_storage_free(sp);
return ret;
@@ -469,14 +529,13 @@ out:
free(cksum.checksum.data);
if (sp)
krb5_storage_free(sp);
if (crypto)
krb5_crypto_destroy(context, crypto);
return ret;
}
static krb5_error_code
create_checksum(krb5_context context,
const krb5_keyblock *key,
uint32_t cksumtype,
void *data, size_t datalen,
void *sig, size_t siglen)
{
@@ -484,6 +543,17 @@ create_checksum(krb5_context context,
krb5_error_code ret;
Checksum cksum;
/* If the checksum is HMAC-MD5, the checksum type is not tied to
* the key type, instead the HMAC-MD5 checksum is applied blindly
* on whatever key is used for this connection, avoiding issues
* with unkeyed checksums on des-cbc-md5 and des-cbc-crc. See
* http://comments.gmane.org/gmane.comp.encryption.kerberos.devel/8743
* for the same issue in MIT, and
* http://blogs.msdn.com/b/openspecification/archive/2010/01/01/verifying-the-server-signature-in-kerberos-privilege-account-certificate.aspx
* for Microsoft's explaination */
if (cksumtype == CKSUMTYPE_HMAC_MD5) {
ret = HMAC_MD5_any_checksum(context, key, data, datalen, KRB5_KU_OTHER_CKSUM, &cksum);
} else {
ret = krb5_crypto_init(context, key, 0, &crypto);
if (ret)
return ret;
@@ -493,7 +563,7 @@ create_checksum(krb5_context context,
krb5_crypto_destroy(context, crypto);
if (ret)
return ret;
}
if (cksum.checksum.length != siglen) {
krb5_set_error_message(context, EINVAL, "pac checksum wrong length");
free_Checksum(&cksum);
@@ -845,8 +915,8 @@ pac_checksum(krb5_context context,
return ret;
if (krb5_checksum_is_keyed(context, cktype) == FALSE) {
krb5_set_error_message(context, EINVAL, "PAC checksum type is not keyed");
return EINVAL;
*cksumtype = CKSUMTYPE_HMAC_MD5;
*cksumsize = 16;
}
ret = krb5_checksumsize(context, cktype, cksumsize);
@@ -1026,16 +1096,14 @@ _krb5_pac_sign(krb5_context context,
}
/* sign */
ret = create_checksum(context, server_key,
ret = create_checksum(context, server_key, server_cksumtype,
d.data, d.length,
(char *)d.data + server_offset, server_size);
if (ret) {
krb5_data_free(&d);
goto out;
}
ret = create_checksum(context, priv_key,
ret = create_checksum(context, priv_key, priv_cksumtype,
(char *)d.data + server_offset, server_size,
(char *)d.data + priv_offset, priv_size);
if (ret) {