diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 53680d487..e9a5b79e7 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -1106,11 +1106,33 @@ get_pa_etype_info(krb5_context context, * */ -extern int _krb5_AES_string_to_default_iterator; +extern int _krb5_AES_SHA1_string_to_default_iterator; +extern int _krb5_AES_SHA2_string_to_default_iterator; + +static krb5_error_code +make_s2kparams(int value, size_t len, krb5_data **ps2kparams) +{ + krb5_data *s2kparams; + krb5_error_code ret; + + ALLOC(s2kparams); + if (s2kparams == NULL) + return ENOMEM; + ret = krb5_data_alloc(s2kparams, len); + if (ret) { + free(s2kparams); + return ret; + } + _krb5_put_int(s2kparams->data, value, len); + *ps2kparams = s2kparams; + return 0; +} static krb5_error_code make_etype_info2_entry(ETYPE_INFO2_ENTRY *ent, Key *key) { + krb5_error_code ret; + ent->etype = key->key.keytype; if(key->salt) { ALLOC(ent->salt); @@ -1132,44 +1154,28 @@ make_etype_info2_entry(ETYPE_INFO2_ENTRY *ent, Key *key) switch (key->key.keytype) { case ETYPE_AES128_CTS_HMAC_SHA1_96: case ETYPE_AES256_CTS_HMAC_SHA1_96: - ALLOC(ent->s2kparams); - if (ent->s2kparams == NULL) - return ENOMEM; - ent->s2kparams->length = 4; - ent->s2kparams->data = malloc(ent->s2kparams->length); - if (ent->s2kparams->data == NULL) { - free(ent->s2kparams); - ent->s2kparams = NULL; - return ENOMEM; - } - _krb5_put_int(ent->s2kparams->data, - _krb5_AES_string_to_default_iterator, - ent->s2kparams->length); + ret = make_s2kparams(_krb5_AES_SHA1_string_to_default_iterator, + 4, &ent->s2kparams); + break; + case KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128: + case KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192: + ret = make_s2kparams(_krb5_AES_SHA2_string_to_default_iterator, + 4, &ent->s2kparams); break; case ETYPE_DES_CBC_CRC: case ETYPE_DES_CBC_MD4: case ETYPE_DES_CBC_MD5: /* Check if this was a AFS3 salted key */ - if(key->salt && key->salt->type == hdb_afs3_salt){ - ALLOC(ent->s2kparams); - if (ent->s2kparams == NULL) - return ENOMEM; - ent->s2kparams->length = 1; - ent->s2kparams->data = malloc(ent->s2kparams->length); - if (ent->s2kparams->data == NULL) { - free(ent->s2kparams); - ent->s2kparams = NULL; - return ENOMEM; - } - _krb5_put_int(ent->s2kparams->data, - 1, - ent->s2kparams->length); - } + if(key->salt && key->salt->type == hdb_afs3_salt) + ret = make_s2kparams(1, 1, &ent->s2kparams); + else + ret = 0; break; default: + ret = 0; break; } - return 0; + return ret; } /* diff --git a/lib/asn1/krb5.asn1 b/lib/asn1/krb5.asn1 index 2e3a29519..12986ea4e 100644 --- a/lib/asn1/krb5.asn1 +++ b/lib/asn1/krb5.asn1 @@ -233,6 +233,8 @@ CKSUMTYPE ::= INTEGER { CKSUMTYPE_SHA1(14), CKSUMTYPE_HMAC_SHA1_96_AES_128(15), CKSUMTYPE_HMAC_SHA1_96_AES_256(16), + CKSUMTYPE_HMAC_SHA256_128_AES128(19), + CKSUMTYPE_HMAC_SHA384_192_AES256(20), CKSUMTYPE_GSSAPI(0x8003), CKSUMTYPE_HMAC_MD5(-138), -- unofficial microsoft number CKSUMTYPE_HMAC_MD5_ENC(-1138) -- even more unofficial @@ -252,6 +254,8 @@ ENCTYPE ::= INTEGER { KRB5_ENCTYPE_DES3_CBC_SHA1(16), -- with key derivation KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96(17), KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96(18), + KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128(19), + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192(20), KRB5_ENCTYPE_ARCFOUR_HMAC_MD5(23), KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56(24), KRB5_ENCTYPE_ENCTYPE_PK_CROSS(48), diff --git a/lib/gssapi/krb5/init_sec_context.c b/lib/gssapi/krb5/init_sec_context.c index 0b7028006..aee797a77 100644 --- a/lib/gssapi/krb5/init_sec_context.c +++ b/lib/gssapi/krb5/init_sec_context.c @@ -423,16 +423,10 @@ init_auth /* * This is hideous glue for (NFS) clients that wants to limit the * available enctypes to what it can support (encryption in - * kernel). If there is no enctypes selected for this credential, - * reset it to the default set of enctypes. + * kernel). */ - { - krb5_enctype *enctypes = NULL; - - if (cred && cred->enctypes) - enctypes = cred->enctypes; - krb5_set_default_in_tkt_etypes(context, enctypes); - } + if (cred && cred->enctypes) + krb5_set_default_in_tkt_etypes(context, cred->enctypes); ret = gsskrb5_get_creds(minor_status, context, ctx->ccache, ctx, name, time_req, time_rec); diff --git a/lib/hcrypto/evp.h b/lib/hcrypto/evp.h index 22e8f4d04..a0369db72 100644 --- a/lib/hcrypto/evp.h +++ b/lib/hcrypto/evp.h @@ -98,6 +98,7 @@ #define EVP_sha256 hc_EVP_sha256 #define EVP_sha384 hc_EVP_sha384 #define EVP_sha512 hc_EVP_sha512 +#define PKCS5_PBKDF2_HMAC hc_PKCS5_PBKDF2_HMAC #define PKCS5_PBKDF2_HMAC_SHA1 hc_PKCS5_PBKDF2_HMAC_SHA1 #define EVP_BytesToKey hc_EVP_BytesToKey #define EVP_get_cipherbyname hc_EVP_get_cipherbyname @@ -333,6 +334,9 @@ int EVP_CipherFinal_ex(EVP_CIPHER_CTX *, void *, int *); int EVP_Cipher(EVP_CIPHER_CTX *,void *,const void *,size_t); +int PKCS5_PBKDF2_HMAC(const void *, size_t, const void *, size_t, + unsigned long, const EVP_MD *, size_t, void *); + int PKCS5_PBKDF2_HMAC_SHA1(const void *, size_t, const void *, size_t, unsigned long, size_t, void *); diff --git a/lib/hcrypto/libhcrypto-exports.def b/lib/hcrypto/libhcrypto-exports.def index 366270f6c..ab692b4e5 100644 --- a/lib/hcrypto/libhcrypto-exports.def +++ b/lib/hcrypto/libhcrypto-exports.def @@ -276,6 +276,7 @@ EXPORTS hc_OpenSSL_add_all_algorithms_conf hc_OpenSSL_add_all_algorithms_noconf hc_PKCS12_key_gen + hc_PKCS5_PBKDF2_HMAC hc_PKCS5_PBKDF2_HMAC_SHA1 hc_RAND_add hc_RAND_bytes diff --git a/lib/hcrypto/pkcs5.c b/lib/hcrypto/pkcs5.c index 5b5d0cc70..dff3ccea3 100644 --- a/lib/hcrypto/pkcs5.c +++ b/lib/hcrypto/pkcs5.c @@ -49,6 +49,7 @@ * @param salt Salt * @param salt_len Length of salt. * @param iter iteration counter. + * @param md the digest function. * @param keylen the output key length. * @param key the output key. * @@ -58,21 +59,23 @@ */ int -PKCS5_PBKDF2_HMAC_SHA1(const void * password, size_t password_len, - const void * salt, size_t salt_len, - unsigned long iter, - size_t keylen, void *key) +PKCS5_PBKDF2_HMAC(const void * password, size_t password_len, + const void * salt, size_t salt_len, + unsigned long iter, + const EVP_MD *md, + size_t keylen, void *key) { size_t datalen, leftofkey, checksumsize; char *data, *tmpcksum; uint32_t keypart; - const EVP_MD *md; unsigned long i; int j; char *p; unsigned int hmacsize; - md = EVP_sha1(); + if (md == NULL) + return 0; + checksumsize = EVP_MD_size(md); datalen = salt_len + 4; @@ -122,3 +125,28 @@ PKCS5_PBKDF2_HMAC_SHA1(const void * password, size_t password_len, return 1; } + +/** + * As descriped in PKCS5, convert a password, salt, and iteration counter into a crypto key. + * + * @param password Password. + * @param password_len Length of password. + * @param salt Salt + * @param salt_len Length of salt. + * @param iter iteration counter. + * @param keylen the output key length. + * @param key the output key. + * + * @return 1 on success, non 1 on failure. + * + * @ingroup hcrypto_misc + */ +int +PKCS5_PBKDF2_HMAC_SHA1(const void * password, size_t password_len, + const void * salt, size_t salt_len, + unsigned long iter, + size_t keylen, void *key) +{ + return PKCS5_PBKDF2_HMAC(password, password_len, salt, salt_len, iter, + EVP_sha1(), keylen, key); +} diff --git a/lib/hcrypto/test_pkcs5.c b/lib/hcrypto/test_pkcs5.c index ece3461ca..3641a6efa 100644 --- a/lib/hcrypto/test_pkcs5.c +++ b/lib/hcrypto/test_pkcs5.c @@ -107,24 +107,24 @@ test_pkcs5_pbe2(const struct tests *t) unsigned char key[32]; int ret, error = 0; - ret = PKCS5_PBKDF2_HMAC_SHA1(t->password, strlen(t->password), - t->salt, strlen(t->salt), - t->iterations, - 16, key); + ret = PKCS5_PBKDF2_HMAC(t->password, strlen(t->password), + t->salt, strlen(t->salt), + t->iterations, EVP_sha1(), + 16, key); if (ret != 1) - errx(1, "PKCS5_PBKDF2_HMAC_SHA1: %d", ret); + errx(1, "PKCS5_PBKDF2_HMAC: %d", ret); if (memcmp(t->pbkdf2_128, key, 16) != 0) { printf("incorrect 128 key\n"); error++; } - ret = PKCS5_PBKDF2_HMAC_SHA1(t->password, strlen(t->password), - t->salt, strlen(t->salt), - t->iterations, - 32, key); + ret = PKCS5_PBKDF2_HMAC(t->password, strlen(t->password), + t->salt, strlen(t->salt), + t->iterations, EVP_sha1(), + 32, key); if (ret != 1) - errx(1, "PKCS5_PBKDF2_HMAC_SHA1: %d", ret); + errx(1, "PKCS5_PBKDF2_HMAC: %d", ret); if (memcmp(t->pbkdf2_256, key, 32) != 0) { printf("incorrect 256 key\n"); diff --git a/lib/hcrypto/undef.h b/lib/hcrypto/undef.h index fd22e3436..512b8c3f0 100644 --- a/lib/hcrypto/undef.h +++ b/lib/hcrypto/undef.h @@ -133,6 +133,7 @@ #undef EVP_sha256 #undef EVP_sha384 #undef EVP_sha512 +#undef PKCS5_PBKDF2_HMAC #undef PKCS5_PBKDF2_HMAC_SHA1 #undef EVP_BytesToKey #undef EVP_get_cipherbyname diff --git a/lib/hcrypto/version-script.map b/lib/hcrypto/version-script.map index e94048baf..5b9d34a45 100644 --- a/lib/hcrypto/version-script.map +++ b/lib/hcrypto/version-script.map @@ -261,6 +261,7 @@ HEIMDAL_CRYPTO_1.0 { hc_OpenSSL_add_all_algorithms_conf; hc_OpenSSL_add_all_algorithms_noconf; hc_PKCS12_key_gen; + hc_PKCS5_PBKDF2_HMAC; hc_PKCS5_PBKDF2_HMAC_SHA1; hc_RAND_add; hc_RAND_bytes; diff --git a/lib/hdb/keys.c b/lib/hdb/keys.c index 881329ac0..7c24093f8 100644 --- a/lib/hdb/keys.c +++ b/lib/hdb/keys.c @@ -1,4 +1,3 @@ - /* * Copyright (c) 1997 - 2011 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). @@ -34,6 +33,21 @@ #include "hdb_locl.h" +struct hx509_certs_data; +struct krb5_pk_identity; +struct krb5_pk_cert; +struct ContentInfo; +struct AlgorithmIdentifier; +struct _krb5_krb_auth_data; +typedef struct krb5_pk_init_ctx_data *krb5_pk_init_ctx; +struct krb5_dh_moduli; +struct _krb5_key_data; +struct _krb5_encryption_type; +struct _krb5_key_type; +#include +#include +#include + /* * free all the memory used by (len, keys) */ @@ -168,9 +182,11 @@ parse_key_set(krb5_context context, const char *key, /* if no salt was specified make up default salt */ if(salt->saltvalue.data == NULL) { - if(salt->salttype == KRB5_PW_SALT) + if(salt->salttype == KRB5_PW_SALT) { ret = krb5_get_pw_salt(context, principal, salt); - else if(salt->salttype == KRB5_AFS3_SALT) { + if (ret) + return ret; + } else if(salt->salttype == KRB5_AFS3_SALT) { krb5_const_realm realm = krb5_principal_get_realm(context, principal); salt->saltvalue.data = strdup(realm); if(salt->saltvalue.data == NULL) { @@ -571,6 +587,41 @@ glob_rules_keys(krb5_context context, krb5_const_principal principal) return NULL; } +/* + * NIST guidance in Section 5.1 of [SP800-132] requires that a portion + * of the salt of at least 128 bits shall be randomly generated. + */ +static krb5_error_code +add_random_to_salt(krb5_context context, krb5_salt *in, krb5_salt *out) +{ + krb5_error_code ret; + char *p; + unsigned char random[16]; + char *s; + int slen; + + krb5_generate_random_block(random, sizeof(random)); + + slen = rk_base64_encode(random, sizeof(random), &s); + if (slen < 0) + return ENOMEM; + + ret = krb5_data_alloc(&out->saltvalue, slen + in->saltvalue.length); + if (ret) { + free(s); + return ret; + } + + p = out->saltvalue.data; + memcpy(p, s, slen); + memcpy(&p[slen], in->saltvalue.data, in->saltvalue.length); + + out->salttype = in->salttype; + free(s); + + return 0; +} + /* * Generate the `key_set' from the [kadmin]default_keys statement. If * `no_salt' is set, salt is not important (and will not be set) since @@ -642,6 +693,9 @@ hdb_generate_key_set(krb5_context context, krb5_principal principal, } for (i = 0; i < num_enctypes; i++) { + krb5_salt *saltp = no_salt ? NULL : &salt; + krb5_salt rsalt; + /* find duplicates */ for (j = 0; j < *nkeyset; j++) { @@ -660,14 +714,27 @@ hdb_generate_key_set(krb5_context context, krb5_principal principal, } } /* not a duplicate, lets add it */ - if (j == *nkeyset) { + if (j < *nkeyset) + continue; + + memset(&rsalt, 0, sizeof(rsalt)); + + /* prepend salt with randomness if required */ + if (!no_salt && + _krb5_enctype_requires_random_salt(context, enctypes[i])) { + saltp = &rsalt; + ret = add_random_to_salt(context, &salt, &rsalt); + } + + if (ret == 0) ret = add_enctype_to_key_set(&key_set, nkeyset, enctypes[i], - no_salt ? NULL : &salt); - if (ret) { - free(enctypes); - krb5_free_salt(context, salt); - goto out; - } + saltp); + krb5_free_salt(context, rsalt); + + if (ret) { + free(enctypes); + krb5_free_salt(context, salt); + goto out; } } free(enctypes); @@ -718,17 +785,17 @@ hdb_generate_key_set_password(krb5_context context, for (i = 0; i < (*num_keys); i++) { krb5_salt salt; + Key *key = &(*keys)[i]; - salt.salttype = (*keys)[i].salt->type; - salt.saltvalue.length = (*keys)[i].salt->salt.length; - salt.saltvalue.data = (*keys)[i].salt->salt.data; + salt.salttype = key->salt->type; + salt.saltvalue.length = key->salt->salt.length; + salt.saltvalue.data = key->salt->salt.data; ret = krb5_string_to_key_salt (context, - (*keys)[i].key.keytype, + key->key.keytype, password, salt, - &(*keys)[i].key); - + &key->key); if(ret) break; } diff --git a/lib/hdb/mkey.c b/lib/hdb/mkey.c index 6ccb0b0b0..ebfcb76f5 100644 --- a/lib/hdb/mkey.c +++ b/lib/hdb/mkey.c @@ -374,7 +374,7 @@ _hdb_set_master_key_usage(krb5_context context, HDB *db, unsigned int key_usage) } hdb_master_key -_hdb_find_master_key(uint32_t *mkvno, hdb_master_key mkey) +_hdb_find_master_key(int *mkvno, hdb_master_key mkey) { hdb_master_key ret = NULL; while(mkey) { diff --git a/lib/krb5/Makefile.am b/lib/krb5/Makefile.am index c462d9372..9431614f9 100644 --- a/lib/krb5/Makefile.am +++ b/lib/krb5/Makefile.am @@ -26,6 +26,7 @@ TESTS = \ derived-key-test \ n-fold-test \ parse-name-test \ + pseudo-random-test \ store-test \ string-to-key-test \ test_acl \ @@ -133,7 +134,8 @@ dist_libkrb5_la_SOURCES = \ creds.c \ crypto.c \ crypto.h \ - crypto-aes.c \ + crypto-aes-sha1.c \ + crypto-aes-sha2.c \ crypto-algs.c \ crypto-arcfour.c \ crypto-des.c \ @@ -215,10 +217,12 @@ dist_libkrb5_la_SOURCES = \ recvauth.c \ replay.c \ salt.c \ - salt-aes.c \ + salt-aes-sha1.c \ + salt-aes-sha2.c \ salt-arcfour.c \ salt-des.c \ salt-des3.c \ + sp800-108-kdf.c \ scache.c \ send_to_kdc.c \ sendauth.c \ @@ -274,7 +278,8 @@ librfc3961_la_SOURCES = \ crc.c \ crypto.c \ crypto.h \ - crypto-aes.c \ + crypto-aes-sha1.c \ + crypto-aes-sha2.c \ crypto-algs.c \ crypto-arcfour.c \ crypto-des.c \ @@ -291,10 +296,12 @@ librfc3961_la_SOURCES = \ keyblock.c \ n-fold.c \ salt.c \ - salt-aes.c \ + salt-aes-sha1.c \ + salt-aes-sha2.c \ salt-arcfour.c \ salt-des.c \ salt-des3.c \ + sp800-108-kdf.c \ store-int.c \ warn.c diff --git a/lib/krb5/NTMakefile b/lib/krb5/NTMakefile index 8c5064b11..710cbe899 100644 --- a/lib/krb5/NTMakefile +++ b/lib/krb5/NTMakefile @@ -56,7 +56,8 @@ libkrb5_OBJS = \ $(OBJ)\crc.obj \ $(OBJ)\creds.obj \ $(OBJ)\crypto.obj \ - $(OBJ)\crypto-aes.obj \ + $(OBJ)\crypto-aes-sha1.obj \ + $(OBJ)\crypto-aes-sha2.obj \ $(OBJ)\crypto-algs.obj \ $(OBJ)\crypto-arcfour.obj \ $(OBJ)\crypto-des-common.obj \ @@ -133,7 +134,8 @@ libkrb5_OBJS = \ $(OBJ)\read_message.obj \ $(OBJ)\recvauth.obj \ $(OBJ)\replay.obj \ - $(OBJ)\salt-aes.obj \ + $(OBJ)\salt-aes-sha1.obj \ + $(OBJ)\salt-aes-sha2.obj \ $(OBJ)\salt-arcfour.obj \ $(OBJ)\salt-des.obj \ $(OBJ)\salt-des3.obj \ @@ -143,6 +145,7 @@ libkrb5_OBJS = \ $(OBJ)\sendauth.obj \ $(OBJ)\set_default_realm.obj \ $(OBJ)\sock_principal.obj \ + $(OBJ)\sp800-108-kdf.obj \ $(OBJ)\store.obj \ $(OBJ)\store-int.obj \ $(OBJ)\store_emem.obj \ @@ -206,7 +209,8 @@ dist_libkrb5_la_SOURCES = \ creds.c \ crypto.c \ crypto.h \ - crypto-aes.c \ + crypto-aes-sha1.c \ + crypto-aes-sha2.c \ crypto-algs.c \ crypto-arcfour.c \ crypto-des.c \ @@ -285,7 +289,8 @@ dist_libkrb5_la_SOURCES = \ recvauth.c \ replay.c \ salt.c \ - salt-aes.c \ + salt-aes-sha1.c \ + salt-aes-sha2.c \ salt-arcfour.c \ salt-des.c \ salt-des3.c \ @@ -294,6 +299,7 @@ dist_libkrb5_la_SOURCES = \ sendauth.c \ set_default_realm.c \ sock_principal.c \ + sp800-108-kdf.c \ store.c \ store-int.c \ store-int.h \ @@ -368,7 +374,8 @@ clean:: librfc3961_OBJS=\ $(OBJ)\crc.obj \ $(OBJ)\crypto.obj \ - $(OBJ)\crypto-aes.obj \ + $(OBJ)\crypto-aes-sha1.obj \ + $(OBJ)\crypto-aes-sha2.obj \ $(OBJ)\crypto-algs.obj \ $(OBJ)\crypto-arcfour.obj \ $(OBJ)\crypto-des.obj \ @@ -384,10 +391,12 @@ librfc3961_OBJS=\ $(OBJ)\keyblock.obj \ $(OBJ)\n-fold.obj \ $(OBJ)\salt.obj \ - $(OBJ)\salt-aes.obj \ + $(OBJ)\salt-aes-sha1.obj \ + $(OBJ)\salt-aes-sha2.obj \ $(OBJ)\salt-arcfour.obj \ $(OBJ)\salt-des.obj \ $(OBJ)\salt-des3.obj \ + $(OBJ)\sp800-108-kdf.obj \ $(OBJ)\store-int.obj \ $(OBJ)\warn.obj @@ -428,6 +437,7 @@ test_binaries = \ $(OBJ)\krbhst-test.exe \ $(OBJ)\n-fold-test.exe \ $(OBJ)\parse-name-test.exe \ + $(OBJ)\pseudo-random-test.exe \ $(OBJ)\store-test.exe \ $(OBJ)\string-to-key-test.exe \ $(OBJ)\test_acl.exe \ @@ -467,6 +477,7 @@ test-run: -krbhst-test.exe -n-fold-test.exe -parse-name-test.exe + -pseudo-random-test.exe -store-test.exe -string-to-key-test.exe -test_acl.exe diff --git a/lib/krb5/aes-test.c b/lib/krb5/aes-test.c index da66af04d..7bca78ab6 100644 --- a/lib/krb5/aes-test.c +++ b/lib/krb5/aes-test.c @@ -57,6 +57,29 @@ struct { char *pbkdf2; char *key; } keys[] = { + { + "password", + "\x10\xDF\x9D\xD7\x83\xE5\xBC\x8A\xCE\xA1\x73\x0E\x74\x35\x5F\x61" + "ATHENA.MIT.EDUraeburn", + 37, + 32768, + KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128, + 16, + NULL, + "\x08\x9B\xCA\x48\xB1\x05\xEA\x6E\xA7\x7C\xA5\xD2\xF3\x9D\xC5\xE7" + }, + { + "password", + "\x10\xDF\x9D\xD7\x83\xE5\xBC\x8A\xCE\xA1\x73\x0E\x74\x35\x5F\x61" + "ATHENA.MIT.EDUraeburn", + 37, + 32768, + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192, + 32, + NULL, + "\x45\xBD\x80\x6D\xBF\x6A\x83\x3A\x9C\xFF\xC1\xC9\x45\x89\xA2\x22" + "\x36\x7A\x79\xBC\x21\xC4\x13\x71\x89\x06\xE9\xF5\x78\xA7\x84\x67" + }, { "password", "ATHENA.MIT.EDUraeburn", -1, 1, @@ -156,7 +179,6 @@ struct { "\x1a\x8b\x4d\x28\x26\x01\xdb\x3b\x36\xbe\x92\x46\x91\x5e\xc8\x2a", "\xd7\x8c\x5c\x9c\xb8\x72\xa8\xc9\xda\xd4\x69\x7f\x0b\xb5\xb2\xd2" "\x14\x96\xc8\x2b\xeb\x2c\xae\xda\x21\x12\xfc\xee\xa0\x57\x40\x1b" - }, { "\xf0\x9d\x84\x9e" /* g-clef */, "EXAMPLE.COMpianist", -1, @@ -221,10 +243,10 @@ string_to_key_test(krb5_context context) if (keys[i].keylen > sizeof(keyout)) abort(); - PKCS5_PBKDF2_HMAC_SHA1(password.data, password.length, - salt.saltvalue.data, salt.saltvalue.length, - keys[i].iterations, - keys[i].keylen, keyout); + PKCS5_PBKDF2_HMAC(password.data, password.length, + salt.saltvalue.data, salt.saltvalue.length, + keys[i].iterations, EVP_sha1(), + keys[i].keylen, keyout); if (memcmp(keyout, keys[i].pbkdf2, keys[i].keylen) != 0) { krb5_warnx(context, "%d: pbkdf2", i); @@ -477,9 +499,10 @@ static int krb_checksum_iov(krb5_context context, krb5_crypto crypto, unsigned usage, - krb5_data *plain) + krb5_data *plain, + krb5_data *verify) { - krb5_crypto_iov iov[4]; + krb5_crypto_iov iov[3]; int ret; char *p; size_t len; @@ -488,8 +511,12 @@ krb_checksum_iov(krb5_context context, len = plain->length; iov[0].flags = KRB5_CRYPTO_TYPE_CHECKSUM; - krb5_crypto_length(context, crypto, iov[0].flags, &iov[0].data.length); - iov[0].data.data = emalloc(iov[0].data.length); + if (verify) { + iov[0].data = *verify; + } else { + krb5_crypto_length(context, crypto, iov[0].flags, &iov[0].data.length); + iov[0].data.data = emalloc(iov[0].data.length); + } iov[1].flags = KRB5_CRYPTO_TYPE_DATA; iov[1].data.length = len; @@ -499,16 +526,19 @@ krb_checksum_iov(krb5_context context, krb5_crypto_length(context, crypto, iov[0].flags, &iov[2].data.length); iov[2].data.data = malloc(iov[2].data.length); - ret = krb5_create_checksum_iov(context, crypto, usage, - iov, sizeof(iov)/sizeof(iov[0]), NULL); - if (ret) - krb5_err(context, 1, ret, "krb5_create_checksum_iov failed"); + if (verify == NULL) { + ret = krb5_create_checksum_iov(context, crypto, usage, + iov, sizeof(iov)/sizeof(iov[0]), NULL); + if (ret) + krb5_err(context, 1, ret, "krb5_create_checksum_iov failed"); + } ret = krb5_verify_checksum_iov(context, crypto, usage, iov, sizeof(iov)/sizeof(iov[0]), NULL); if (ret) krb5_err(context, 1, ret, "krb5_verify_checksum_iov"); - free(iov[0].data.data); + if (verify == NULL) + free(iov[0].data.data); free(iov[2].data.data); return 0; @@ -558,7 +588,6 @@ krb_enc_mit(krb5_context context, return 0; } - struct { krb5_enctype enctype; unsigned usage; @@ -568,6 +597,8 @@ struct { void* edata; size_t plen; void *pdata; + size_t clen; /* checksum length */ + void *cdata; /* checksum data */ } krbencs[] = { { ETYPE_AES256_CTS_HMAC_SHA1_96, @@ -580,11 +611,133 @@ struct { "\xa9\xec\x1c\x5c\x21\xfb\x6e\xef\x1a\x7a\xc8\xc1\xcc\x5a\x95\x24" "\x6f\x9f\xf4\xd5\xbe\x5d\x59\x97\x44\xd8\x47\xcd", 16, - "\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74\x2e\x0a" + "\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74\x2e\x0a", + 0, + NULL + }, + { + KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128, + 2, + 16, + "\x37\x05\xD9\x60\x80\xC1\x77\x28\xA0\xE8\x00\xEA\xB6\xE0\xD2\x3C", + 32, + "\xEF\x85\xFB\x89\x0B\xB8\x47\x2F\x4D\xAB\x20\x39\x4D\xCA\x78\x1D" + "\xAD\x87\x7E\xDA\x39\xD5\x0C\x87\x0C\x0D\x5A\x0A\x8E\x48\xC7\x18", + 0, + "", + 0, + NULL + }, + { + KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128, + 2, + 16, + "\x37\x05\xD9\x60\x80\xC1\x77\x28\xA0\xE8\x00\xEA\xB6\xE0\xD2\x3C", + 38, + "\x84\xD7\xF3\x07\x54\xED\x98\x7B\xAB\x0B\xF3\x50\x6B\xEB\x09\xCF" + "\xB5\x54\x02\xCE\xF7\xE6\x87\x7C\xE9\x9E\x24\x7E\x52\xD1\x6E\xD4" + "\x42\x1D\xFD\xF8\x97\x6C", + 6, + "\x00\x01\x02\x03\x04\x05", + 0, + NULL + }, + { + KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128, + 2, + 16, + "\x37\x05\xD9\x60\x80\xC1\x77\x28\xA0\xE8\x00\xEA\xB6\xE0\xD2\x3C", + 48, + "\x35\x17\xD6\x40\xF5\x0D\xDC\x8A\xD3\x62\x87\x22\xB3\x56\x9D\x2A" + "\xE0\x74\x93\xFA\x82\x63\x25\x40\x80\xEA\x65\xC1\x00\x8E\x8F\xC2" + "\x95\xFB\x48\x52\xE7\xD8\x3E\x1E\x7C\x48\xC3\x7E\xEB\xE6\xB0\xD3", + 16, + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F", + 0, + NULL + }, + { + KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128, + 2, + 16, + "\x37\x05\xD9\x60\x80\xC1\x77\x28\xA0\xE8\x00\xEA\xB6\xE0\xD2\x3C", + 53, + "\x72\x0F\x73\xB1\x8D\x98\x59\xCD\x6C\xCB\x43\x46\x11\x5C\xD3\x36" + "\xC7\x0F\x58\xED\xC0\xC4\x43\x7C\x55\x73\x54\x4C\x31\xC8\x13\xBC" + "\xE1\xE6\xD0\x72\xC1\x86\xB3\x9A\x41\x3C\x2F\x92\xCA\x9B\x83\x34" + "\xA2\x87\xFF\xCB\xFC", + 21, + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x14", + 16, + "\xD7\x83\x67\x18\x66\x43\xD6\x7B\x41\x1C\xBA\x91\x39\xFC\x1D\xEE" + }, + { + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192, + 2, + 32, + "\x6D\x40\x4D\x37\xFA\xF7\x9F\x9D\xF0\xD3\x35\x68\xD3\x20\x66\x98" + "\x00\xEB\x48\x36\x47\x2E\xA8\xA0\x26\xD1\x6B\x71\x82\x46\x0C\x52", + 40, + "\x41\xF5\x3F\xA5\xBF\xE7\x02\x6D\x91\xFA\xF9\xBE\x95\x91\x95\xA0" + "\x58\x70\x72\x73\xA9\x6A\x40\xF0\xA0\x19\x60\x62\x1A\xC6\x12\x74" + "\x8B\x9B\xBF\xBE\x7E\xB4\xCE\x3C", + 0, + "", + 0, + NULL + }, + { + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192, + 2, + 32, + "\x6D\x40\x4D\x37\xFA\xF7\x9F\x9D\xF0\xD3\x35\x68\xD3\x20\x66\x98" + "\x00\xEB\x48\x36\x47\x2E\xA8\xA0\x26\xD1\x6B\x71\x82\x46\x0C\x52", + 46, + "\x4E\xD7\xB3\x7C\x2B\xCA\xC8\xF7\x4F\x23\xC1\xCF\x07\xE6\x2B\xC7" + "\xB7\x5F\xB3\xF6\x37\xB9\xF5\x59\xC7\xF6\x64\xF6\x9E\xAB\x7B\x60" + "\x92\x23\x75\x26\xEA\x0D\x1F\x61\xCB\x20\xD6\x9D\x10\xF2", + 6, + "\x00\x01\x02\x03\x04\x05", + 0, + NULL + }, + { + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192, + 2, + 32, + "\x6D\x40\x4D\x37\xFA\xF7\x9F\x9D\xF0\xD3\x35\x68\xD3\x20\x66\x98" + "\x00\xEB\x48\x36\x47\x2E\xA8\xA0\x26\xD1\x6B\x71\x82\x46\x0C\x52", + 56, + "\xBC\x47\xFF\xEC\x79\x98\xEB\x91\xE8\x11\x5C\xF8\xD1\x9D\xAC\x4B" + "\xBB\xE2\xE1\x63\xE8\x7D\xD3\x7F\x49\xBE\xCA\x92\x02\x77\x64\xF6" + "\x8C\xF5\x1F\x14\xD7\x98\xC2\x27\x3F\x35\xDF\x57\x4D\x1F\x93\x2E" + "\x40\xC4\xFF\x25\x5B\x36\xA2\x66", + 16, + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F", + 0, + NULL + }, + { + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192, + 2, + 32, + "\x6D\x40\x4D\x37\xFA\xF7\x9F\x9D\xF0\xD3\x35\x68\xD3\x20\x66\x98" + "\x00\xEB\x48\x36\x47\x2E\xA8\xA0\x26\xD1\x6B\x71\x82\x46\x0C\x52", + 61, + "\x40\x01\x3E\x2D\xF5\x8E\x87\x51\x95\x7D\x28\x78\xBC\xD2\xD6\xFE" + "\x10\x1C\xCF\xD5\x56\xCB\x1E\xAE\x79\xDB\x3C\x3E\xE8\x64\x29\xF2" + "\xB2\xA6\x02\xAC\x86\xFE\xF6\xEC\xB6\x47\xD6\x29\x5F\xAE\x07\x7A" + "\x1F\xEB\x51\x75\x08\xD2\xC1\x6B\x41\x92\xE0\x1F\x62", + 21, + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" + "\x10\x11\x12\x13\x14", + 24, + "\x45\xEE\x79\x15\x67\xEE\xFC\xA3\x7F\x4A\xC1\xE0\x22\x2D\xE8\x0D" + "\x43\xC3\xBF\xA0\x66\x99\x67\x2A" } }; - static int krb_enc_test(krb5_context context) { @@ -621,10 +774,22 @@ krb_enc_test(krb5_context context) if (ret) errx(1, "krb_enc_iov2 failed with %d for test %d", ret, i); - ret = krb_checksum_iov(context, crypto, krbencs[i].usage, &plain); + ret = krb_checksum_iov(context, crypto, krbencs[i].usage, &plain, NULL); if (ret) errx(1, "krb_checksum_iov failed with %d for test %d", ret, i); + if (krbencs[i].cdata) { + krb5_data checksum; + + checksum.length = krbencs[i].clen; + checksum.data = krbencs[i].cdata; + + ret = krb_checksum_iov(context, crypto, krbencs[i].usage, + &plain, &checksum); + if (ret) + errx(1, "krb_checksum_iov(2) failed with %d for test %d", ret, i); + } + krb5_crypto_destroy(context, crypto); ret = krb_enc_mit(context, krbencs[i].enctype, &kb, @@ -637,9 +802,8 @@ krb_enc_test(krb5_context context) } static int -iov_test(krb5_context context) +iov_test(krb5_context context, krb5_enctype enctype) { - krb5_enctype enctype = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96; krb5_error_code ret; krb5_crypto crypto; krb5_keyblock key; @@ -867,7 +1031,9 @@ main(int argc, char **argv) val |= krb_enc_test(context); val |= random_to_key(context); - val |= iov_test(context); + val |= iov_test(context, KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96); + val |= iov_test(context, KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128); + val |= iov_test(context, KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192); if (verbose && val == 0) printf("all ok\n"); diff --git a/lib/krb5/context.c b/lib/krb5/context.c index 76c6f7c69..c5a9edc66 100644 --- a/lib/krb5/context.c +++ b/lib/krb5/context.c @@ -928,6 +928,8 @@ krb5_kerberos_enctypes(krb5_context context) static const krb5_enctype p[] = { ETYPE_AES256_CTS_HMAC_SHA1_96, ETYPE_AES128_CTS_HMAC_SHA1_96, + ETYPE_AES256_CTS_HMAC_SHA384_192, + ETYPE_AES128_CTS_HMAC_SHA256_128, ETYPE_DES3_CBC_SHA1, ETYPE_ARCFOUR_HMAC_MD5, ETYPE_NULL @@ -936,6 +938,8 @@ krb5_kerberos_enctypes(krb5_context context) static const krb5_enctype weak[] = { ETYPE_AES256_CTS_HMAC_SHA1_96, ETYPE_AES128_CTS_HMAC_SHA1_96, + ETYPE_AES256_CTS_HMAC_SHA384_192, + ETYPE_AES128_CTS_HMAC_SHA256_128, ETYPE_DES3_CBC_SHA1, ETYPE_DES3_CBC_MD5, ETYPE_ARCFOUR_HMAC_MD5, diff --git a/lib/krb5/crypto-aes.c b/lib/krb5/crypto-aes-sha1.c similarity index 90% rename from lib/krb5/crypto-aes.c rename to lib/krb5/crypto-aes-sha1.c index 6465e4255..30df0ee86 100644 --- a/lib/krb5/crypto-aes.c +++ b/lib/krb5/crypto-aes-sha1.c @@ -37,7 +37,7 @@ * AES */ -static struct _krb5_key_type keytype_aes128 = { +static struct _krb5_key_type keytype_aes128_sha1 = { KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96, "aes-128", 128, @@ -45,13 +45,13 @@ static struct _krb5_key_type keytype_aes128 = { sizeof(struct _krb5_evp_schedule), NULL, _krb5_evp_schedule, - _krb5_AES_salt, + _krb5_AES_SHA1_salt, NULL, _krb5_evp_cleanup, EVP_aes_128_cbc }; -static struct _krb5_key_type keytype_aes256 = { +static struct _krb5_key_type keytype_aes256_sha1 = { KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96, "aes-256", 256, @@ -59,7 +59,7 @@ static struct _krb5_key_type keytype_aes256 = { sizeof(struct _krb5_evp_schedule), NULL, _krb5_evp_schedule, - _krb5_AES_salt, + _krb5_AES_SHA1_salt, NULL, _krb5_evp_cleanup, EVP_aes_256_cbc @@ -86,10 +86,10 @@ struct _krb5_checksum_type _krb5_checksum_hmac_sha1_aes256 = { }; static krb5_error_code -AES_PRF(krb5_context context, - krb5_crypto crypto, - const krb5_data *in, - krb5_data *out) +AES_SHA1_PRF(krb5_context context, + krb5_crypto crypto, + const krb5_data *in, + krb5_data *out) { struct _krb5_checksum_type *ct = crypto->et->checksum; krb5_error_code ret; @@ -146,13 +146,13 @@ struct _krb5_encryption_type _krb5_enctype_aes128_cts_hmac_sha1 = { 16, 1, 16, - &keytype_aes128, + &keytype_aes128_sha1, &_krb5_checksum_sha1, &_krb5_checksum_hmac_sha1_aes128, - F_DERIVED, + F_DERIVED | F_RFC3961_ENC | F_RFC3961_KDF, _krb5_evp_encrypt_cts, 16, - AES_PRF + AES_SHA1_PRF }; struct _krb5_encryption_type _krb5_enctype_aes256_cts_hmac_sha1 = { @@ -162,11 +162,11 @@ struct _krb5_encryption_type _krb5_enctype_aes256_cts_hmac_sha1 = { 16, 1, 16, - &keytype_aes256, + &keytype_aes256_sha1, &_krb5_checksum_sha1, &_krb5_checksum_hmac_sha1_aes256, - F_DERIVED, + F_DERIVED | F_RFC3961_ENC | F_RFC3961_KDF, _krb5_evp_encrypt_cts, 16, - AES_PRF + AES_SHA1_PRF }; diff --git a/lib/krb5/crypto-aes-sha2.c b/lib/krb5/crypto-aes-sha2.c new file mode 100644 index 000000000..4630ce071 --- /dev/null +++ b/lib/krb5/crypto-aes-sha2.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +/* + * AES HMAC-SHA2 + */ + +krb5_error_code +_krb5_aes_sha2_md_for_enctype(krb5_context context, + krb5_enctype enctype, + const EVP_MD **md) +{ + switch (enctype) { + case ETYPE_AES128_CTS_HMAC_SHA256_128: + *md = EVP_sha256(); + break; + case ETYPE_AES256_CTS_HMAC_SHA384_192: + *md = EVP_sha384(); + break; + default: + return KRB5_PROG_ETYPE_NOSUPP; + break; + } + return 0; +} + +static krb5_error_code +SP_HMAC_SHA2_checksum(krb5_context context, + struct _krb5_key_data *key, + const void *data, + size_t len, + unsigned usage, + Checksum *result) +{ + krb5_error_code ret; + const EVP_MD *md; + unsigned char hmac[EVP_MAX_MD_SIZE]; + unsigned int hmaclen = sizeof(hmac); + + ret = _krb5_aes_sha2_md_for_enctype(context, key->key->keytype, &md); + if (ret) + return ret; + + HMAC(md, key->key->keyvalue.data, key->key->keyvalue.length, + data, len, hmac, &hmaclen); + + heim_assert(result->checksum.length <= hmaclen, "SHA2 internal error"); + + memcpy(result->checksum.data, hmac, result->checksum.length); + + return 0; +} + +static struct _krb5_key_type keytype_aes128_sha2 = { + KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128, + "aes-128-sha2", + 128, + 16, + sizeof(struct _krb5_evp_schedule), + NULL, + _krb5_evp_schedule, + _krb5_AES_SHA2_salt, + NULL, + _krb5_evp_cleanup, + EVP_aes_128_cbc +}; + +static struct _krb5_key_type keytype_aes256_sha2 = { + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192, + "aes-256-sha2", + 256, + 32, + sizeof(struct _krb5_evp_schedule), + NULL, + _krb5_evp_schedule, + _krb5_AES_SHA2_salt, + NULL, + _krb5_evp_cleanup, + EVP_aes_256_cbc +}; + +struct _krb5_checksum_type _krb5_checksum_hmac_sha256_128_aes128 = { + CKSUMTYPE_HMAC_SHA256_128_AES128, + "hmac-sha256-128-aes128", + 64, + 16, + F_KEYED | F_CPROOF | F_DERIVED, + SP_HMAC_SHA2_checksum, + NULL +}; + +struct _krb5_checksum_type _krb5_checksum_hmac_sha384_192_aes256 = { + CKSUMTYPE_HMAC_SHA384_192_AES256, + "hmac-sha384-192-aes256", + 128, + 24, + F_KEYED | F_CPROOF | F_DERIVED, + SP_HMAC_SHA2_checksum, + NULL +}; + +static krb5_error_code +AES_SHA2_PRF(krb5_context context, + krb5_crypto crypto, + const krb5_data *in, + krb5_data *out) +{ + krb5_error_code ret; + krb5_data label; + const EVP_MD *md = NULL; + + ret = _krb5_aes_sha2_md_for_enctype(context, crypto->et->type, &md); + if (ret) + return ret; + + label.data = "prf"; + label.length = 3; + + ret = krb5_data_alloc(out, EVP_MD_size(md)); + if (ret) + return ret; + + ret = _krb5_SP800_108_HMAC_KDF(context, &crypto->key.key->keyvalue, + &label, in, md, out); + + if (ret) + krb5_data_free(out); + + return ret; +} + +struct _krb5_encryption_type _krb5_enctype_aes128_cts_hmac_sha256_128 = { + ETYPE_AES128_CTS_HMAC_SHA256_128, + "aes128-cts-hmac-sha256-128", + "aes128-cts-sha256", + 16, + 1, + 16, + &keytype_aes128_sha2, + NULL, /* should never be called */ + &_krb5_checksum_hmac_sha256_128_aes128, + F_DERIVED | F_ENC_THEN_CKSUM | F_SP800_108_HMAC_KDF, + _krb5_evp_encrypt_cts, + 16, + AES_SHA2_PRF +}; + +struct _krb5_encryption_type _krb5_enctype_aes256_cts_hmac_sha384_192 = { + ETYPE_AES256_CTS_HMAC_SHA384_192, + "aes256-cts-hmac-sha384-192", + "aes256-cts-sha384", + 16, + 1, + 16, + &keytype_aes256_sha2, + NULL, /* should never be called */ + &_krb5_checksum_hmac_sha384_192_aes256, + F_DERIVED | F_ENC_THEN_CKSUM | F_SP800_108_HMAC_KDF, + _krb5_evp_encrypt_cts, + 16, + AES_SHA2_PRF +}; diff --git a/lib/krb5/crypto-algs.c b/lib/krb5/crypto-algs.c index ed31377bd..c0540257a 100644 --- a/lib/krb5/crypto-algs.c +++ b/lib/krb5/crypto-algs.c @@ -53,6 +53,8 @@ struct _krb5_checksum_type *_krb5_checksum_types[] = { &_krb5_checksum_hmac_sha1_des3, &_krb5_checksum_hmac_sha1_aes128, &_krb5_checksum_hmac_sha1_aes256, + &_krb5_checksum_hmac_sha256_128_aes128, + &_krb5_checksum_hmac_sha384_192_aes256, &_krb5_checksum_hmac_md5 }; @@ -64,6 +66,8 @@ int _krb5_num_checksums * (only relevant for !F_PSEUDO) */ struct _krb5_encryption_type *_krb5_etypes[] = { + &_krb5_enctype_aes256_cts_hmac_sha384_192, + &_krb5_enctype_aes128_cts_hmac_sha256_128, &_krb5_enctype_aes256_cts_hmac_sha1, &_krb5_enctype_aes128_cts_hmac_sha1, &_krb5_enctype_des3_cbc_sha1, diff --git a/lib/krb5/crypto-des3.c b/lib/krb5/crypto-des3.c index 566f31603..ed3e7c960 100644 --- a/lib/krb5/crypto-des3.c +++ b/lib/krb5/crypto-des3.c @@ -208,7 +208,7 @@ struct _krb5_encryption_type _krb5_enctype_des3_cbc_sha1 = { &keytype_des3_derived, &_krb5_checksum_sha1, &_krb5_checksum_hmac_sha1_des3, - F_DERIVED, + F_DERIVED | F_RFC3961_ENC | F_RFC3961_KDF, _krb5_evp_encrypt, 16, DES3_prf diff --git a/lib/krb5/crypto.c b/lib/krb5/crypto.c index b0c80dc8e..280b1908b 100644 --- a/lib/krb5/crypto.c +++ b/lib/krb5/crypto.c @@ -790,7 +790,6 @@ krb5_cksumtype_valid(krb5_context context, return 0; } - static krb5_boolean derived_crypto(krb5_context context, krb5_crypto crypto) @@ -798,13 +797,6 @@ derived_crypto(krb5_context context, return (crypto->et->flags & F_DERIVED) != 0; } -static krb5_boolean -special_crypto(krb5_context context, - krb5_crypto crypto) -{ - return (crypto->et->flags & F_SPECIAL) != 0; -} - #define CHECKSUMSIZE(C) ((C)->checksumsize) #define CHECKSUMTYPE(C) ((C)->type) @@ -872,6 +864,85 @@ encrypt_internal_derived(krb5_context context, return ret; } +static krb5_error_code +encrypt_internal_enc_then_cksum(krb5_context context, + krb5_crypto crypto, + unsigned usage, + const void *data, + size_t len, + krb5_data *result, + void *ivec) +{ + size_t sz, block_sz, checksum_sz, total_sz; + Checksum cksum; + unsigned char *p, *q, *ivc = NULL; + krb5_error_code ret; + struct _krb5_key_data *dkey; + const struct _krb5_encryption_type *et = crypto->et; + + checksum_sz = CHECKSUMSIZE(et->keyed_checksum); + + sz = et->confoundersize + len; + block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */ + total_sz = block_sz + checksum_sz; + p = calloc(1, total_sz); + if (p == NULL) + return krb5_enomem(context); + + q = p; + krb5_generate_random_block(q, et->confoundersize); /* XXX */ + q += et->confoundersize; + memcpy(q, data, len); + + ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); + if(ret) + goto fail; + ret = _key_schedule(context, dkey); + if(ret) + goto fail; + + /* XXX EVP style update API would avoid needing to allocate here */ + ivc = malloc(et->blocksize + block_sz); + if (ivc == NULL) { + ret = krb5_enomem(context); + goto fail; + } + if (ivec) + memcpy(ivc, ivec, et->blocksize); + else + memset(ivc, 0, et->blocksize); + + ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec); + if (ret) + goto fail; + memcpy(&ivc[et->blocksize], p, block_sz); + + ret = create_checksum(context, + et->keyed_checksum, + crypto, + INTEGRITY_USAGE(usage), + ivc, + et->blocksize + block_sz, + &cksum); + if(ret == 0 && cksum.checksum.length != checksum_sz) { + free_Checksum (&cksum); + krb5_clear_error_message (context); + ret = KRB5_CRYPTO_INTERNAL; + } + if(ret) + goto fail; + memcpy(p + block_sz, cksum.checksum.data, cksum.checksum.length); + free_Checksum (&cksum); + result->data = p; + result->length = total_sz; + free(ivc); + return 0; + fail: + memset_s(p, total_sz, 0, total_sz); + free(p); + free(ivc); + return ret; +} static krb5_error_code encrypt_internal(krb5_context context, @@ -1049,6 +1120,90 @@ decrypt_internal_derived(krb5_context context, return 0; } +static krb5_error_code +decrypt_internal_enc_then_cksum(krb5_context context, + krb5_crypto crypto, + unsigned usage, + void *data, + size_t len, + krb5_data *result, + void *ivec) +{ + size_t checksum_sz; + Checksum cksum; + unsigned char *p; + krb5_error_code ret; + struct _krb5_key_data *dkey; + struct _krb5_encryption_type *et = crypto->et; + unsigned long l; + + checksum_sz = CHECKSUMSIZE(et->keyed_checksum); + if (len < checksum_sz + et->confoundersize) { + krb5_set_error_message(context, KRB5_BAD_MSIZE, + N_("Encrypted data shorter then " + "checksum + confunder", "")); + return KRB5_BAD_MSIZE; + } + + if (((len - checksum_sz) % et->padsize) != 0) { + krb5_clear_error_message(context); + return KRB5_BAD_MSIZE; + } + + len -= checksum_sz; + + p = malloc(et->blocksize + len); + if (p == NULL) + return krb5_enomem(context); + + if (ivec) + memcpy(p, ivec, et->blocksize); + else + memset(p, 0, et->blocksize); + memcpy(&p[et->blocksize], data, len); + + cksum.checksum.data = (unsigned char *)data + len; + cksum.checksum.length = checksum_sz; + cksum.cksumtype = CHECKSUMTYPE(et->keyed_checksum); + + ret = verify_checksum(context, + crypto, + INTEGRITY_USAGE(usage), + p, + et->blocksize + len, + &cksum); + if(ret) { + free(p); + return ret; + } + + ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); + if(ret) { + free(p); + return ret; + } + ret = _key_schedule(context, dkey); + if(ret) { + free(p); + return ret; + } + ret = (*et->encrypt)(context, dkey, &p[et->blocksize], len, 0, usage, ivec); + if (ret) { + free(p); + return ret; + } + + l = len - et->confoundersize; + memmove(p, p + et->blocksize + et->confoundersize, l); + result->data = realloc(p, l); + if(result->data == NULL && l != 0) { + free(p); + return krb5_enomem(context); + } + result->length = l; + return 0; +} + static krb5_error_code decrypt_internal(krb5_context context, krb5_crypto crypto, @@ -1162,7 +1317,7 @@ decrypt_internal_special(krb5_context context, } static krb5_crypto_iov * -find_iv(krb5_crypto_iov *data, size_t num_data, unsigned type) +iov_find(krb5_crypto_iov *data, size_t num_data, unsigned type) { size_t i; for (i = 0; i < num_data; i++) @@ -1171,6 +1326,154 @@ find_iv(krb5_crypto_iov *data, size_t num_data, unsigned type) return NULL; } +static size_t +iov_enc_data_len(krb5_crypto_iov *data, int num_data) +{ + size_t i, len; + + for (len = 0, i = 0; i < num_data; i++) { + if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) + continue; + len += data[i].data.length; + } + + return len; +} + +static size_t +iov_sign_data_len(krb5_crypto_iov *data, int num_data) +{ + size_t i, len; + + for (len = 0, i = 0; i < num_data; i++) { + if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && + data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) + continue; + len += data[i].data.length; + } + + return len; +} + +static krb5_error_code +iov_coalesce(krb5_context context, + krb5_data *prefix, + krb5_crypto_iov *data, + int num_data, + krb5_boolean inc_sign_data, + krb5_data *out) +{ + unsigned char *p, *q; + krb5_crypto_iov *hiv, *piv; + size_t len; + unsigned int i; + + hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER); + + piv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_PADDING); + + len = 0; + if (prefix) + len += prefix->length; + len += hiv->data.length; + if (inc_sign_data) + len += iov_sign_data_len(data, num_data); + else + len += iov_enc_data_len(data, num_data); + if (piv) + len += piv->data.length; + + p = q = malloc(len); + if (p == NULL) + return krb5_enomem(context); + + if (prefix) { + memcpy(q, prefix->data, prefix->length); + q += prefix->length; + } + memcpy(q, hiv->data.data, hiv->data.length); + q += hiv->data.length; + for (i = 0; i < num_data; i++) { + if (data[i].flags == KRB5_CRYPTO_TYPE_DATA || + (inc_sign_data && data[i].flags == KRB5_CRYPTO_TYPE_SIGN_ONLY)) { + memcpy(q, data[i].data.data, data[i].data.length); + q += data[i].data.length; + } + } + if (piv) + memset(q, 0, piv->data.length); + + out->length = len; + out->data = p; + + return 0; +} + +static krb5_error_code +iov_uncoalesce(krb5_context context, + krb5_data *enc_data, + krb5_crypto_iov *data, + int num_data) +{ + unsigned char *q = enc_data->data; + krb5_crypto_iov *hiv, *piv; + unsigned int i; + + hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER); + + piv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_PADDING); + + memcpy(hiv->data.data, q, hiv->data.length); + q += hiv->data.length; + + for (i = 0; i < num_data; i++) { + if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) + continue; + memcpy(data[i].data.data, q, data[i].data.length); + q += data[i].data.length; + } + if (piv) + memcpy(piv->data.data, q, piv->data.length); + + return 0; +} + +static krb5_error_code +iov_pad_validate(const struct _krb5_encryption_type *et, + krb5_crypto_iov *data, + int num_data, + krb5_crypto_iov **ppiv) +{ + krb5_crypto_iov *piv; + size_t sz, headersz, block_sz, pad_sz, len; + + len = iov_enc_data_len(data, num_data); + + headersz = et->confoundersize; + + sz = headersz + len; + block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */ + + pad_sz = block_sz - sz; + + piv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_PADDING); + /* its ok to have no TYPE_PADDING if there is no padding */ + if (piv == NULL && pad_sz != 0) + return KRB5_BAD_MSIZE; + if (piv) { + if (piv->data.length < pad_sz) + return KRB5_BAD_MSIZE; + piv->data.length = pad_sz; + if (pad_sz) + memset(piv->data.data, pad_sz, pad_sz); + else + piv = NULL; + } + + *ppiv = piv; + return 0; +} + /** * Inline encrypt a kerberos message * @@ -1203,11 +1506,9 @@ krb5_encrypt_iov_ivec(krb5_context context, int num_data, void *ivec) { - size_t headersz, trailersz, len; - int i; - size_t sz, block_sz, pad_sz; + size_t headersz, trailersz; Checksum cksum; - unsigned char *p, *q; + krb5_data enc_data, sign_data; krb5_error_code ret; struct _krb5_key_data *dkey; const struct _krb5_encryption_type *et = crypto->et; @@ -1223,147 +1524,126 @@ krb5_encrypt_iov_ivec(krb5_context context, return KRB5_CRYPTO_INTERNAL; } + krb5_data_zero(&enc_data); + krb5_data_zero(&sign_data); + headersz = et->confoundersize; trailersz = CHECKSUMSIZE(et->keyed_checksum); - for (len = 0, i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) - continue; - len += data[i].data.length; - } - - sz = headersz + len; - block_sz = (sz + et->padsize - 1) &~ (et->padsize - 1); /* pad */ - - pad_sz = block_sz - sz; - /* header */ - - hiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_HEADER); + hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER); if (hiv == NULL || hiv->data.length != headersz) return KRB5_BAD_MSIZE; - krb5_generate_random_block(hiv->data.data, hiv->data.length); /* padding */ - piv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_PADDING); - /* its ok to have no TYPE_PADDING if there is no padding */ - if (piv == NULL && pad_sz != 0) - return KRB5_BAD_MSIZE; - if (piv) { - if (piv->data.length < pad_sz) - return KRB5_BAD_MSIZE; - piv->data.length = pad_sz; - if (pad_sz) - memset(piv->data.data, pad_sz, pad_sz); - else - piv = NULL; - } + ret = iov_pad_validate(et, data, num_data, &piv); + if(ret) + goto cleanup; /* trailer */ - tiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); - if (tiv == NULL || tiv->data.length != trailersz) - return KRB5_BAD_MSIZE; - - /* - * XXX replace with EVP_Sign? at least make create_checksum an iov - * function. - * XXX CTS EVP is broken, can't handle multi buffers :( - */ - - len = block_sz; - for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) - continue; - len += data[i].data.length; + tiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); + if (tiv == NULL || tiv->data.length != trailersz) { + ret = KRB5_BAD_MSIZE; + goto cleanup; } - p = q = malloc(len); + if (et->flags & F_ENC_THEN_CKSUM) { + unsigned char old_ivec[EVP_MAX_IV_LENGTH]; + krb5_data ivec_data; - memcpy(q, hiv->data.data, hiv->data.length); - q += hiv->data.length; - for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && - data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) - continue; - memcpy(q, data[i].data.data, data[i].data.length); - q += data[i].data.length; + ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data); + if(ret) + goto cleanup; + + ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); + if(ret) + goto cleanup; + + ret = _key_schedule(context, dkey); + if(ret) + goto cleanup; + + heim_assert(et->blocksize <= sizeof(old_ivec), + "blocksize too big for ivec buffer"); + + if (ivec) + memcpy(old_ivec, ivec, et->blocksize); + else + memset(old_ivec, 0, et->blocksize); + + ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length, + 1, usage, ivec); + if(ret) + goto cleanup; + + ret = iov_uncoalesce(context, &enc_data, data, num_data); + if(ret) + goto cleanup; + + ivec_data.length = et->blocksize; + ivec_data.data = old_ivec; + + ret = iov_coalesce(context, &ivec_data, data, num_data, TRUE, &sign_data); + if(ret) + goto cleanup; + } else { + ret = iov_coalesce(context, NULL, data, num_data, TRUE, &sign_data); + if(ret) + goto cleanup; } - if (piv) - memset(q, 0, piv->data.length); ret = create_checksum(context, et->keyed_checksum, crypto, INTEGRITY_USAGE(usage), - p, - len, + sign_data.data, + sign_data.length, &cksum); - free(p); if(ret == 0 && cksum.checksum.length != trailersz) { free_Checksum (&cksum); krb5_clear_error_message (context); ret = KRB5_CRYPTO_INTERNAL; } if(ret) - return ret; + goto cleanup; /* save cksum at end */ memcpy(tiv->data.data, cksum.checksum.data, cksum.checksum.length); free_Checksum (&cksum); - /* XXX replace with EVP_Cipher */ - p = q = malloc(block_sz); - if(p == NULL) - return ENOMEM; + if (!(et->flags & F_ENC_THEN_CKSUM)) { + ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data); + if(ret) + goto cleanup; - memcpy(q, hiv->data.data, hiv->data.length); - q += hiv->data.length; + ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); + if(ret) + goto cleanup; - for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) - continue; - memcpy(q, data[i].data.data, data[i].data.length); - q += data[i].data.length; - } - if (piv) - memset(q, 0, piv->data.length); + ret = _key_schedule(context, dkey); + if(ret) + goto cleanup; + ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length, + 1, usage, ivec); + if(ret) + goto cleanup; - ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); - if(ret) { - free(p); - return ret; - } - ret = _key_schedule(context, dkey); - if(ret) { - free(p); - return ret; + ret = iov_uncoalesce(context, &enc_data, data, num_data); + if(ret) + goto cleanup; } - ret = (*et->encrypt)(context, dkey, p, block_sz, 1, usage, ivec); - if (ret) { - free(p); - return ret; +cleanup: + if (enc_data.data) { + memset_s(enc_data.data, enc_data.length, 0, enc_data.length); + krb5_data_free(&enc_data); } - - /* now copy data back to buffers */ - q = p; - - memcpy(hiv->data.data, q, hiv->data.length); - q += hiv->data.length; - - for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) - continue; - memcpy(data[i].data.data, q, data[i].data.length); - q += data[i].data.length; + if (sign_data.data) { + memset_s(sign_data.data, sign_data.length, 0, sign_data.length); + krb5_data_free(&sign_data); } - if (piv) - memcpy(piv->data.data, q, pad_sz); - - free(p); - return ret; } @@ -1396,10 +1676,8 @@ krb5_decrypt_iov_ivec(krb5_context context, unsigned int num_data, void *ivec) { - unsigned int i; - size_t headersz, trailersz, len; Checksum cksum; - unsigned char *p, *q; + krb5_data enc_data, sign_data; krb5_error_code ret; struct _krb5_key_data *dkey; struct _krb5_encryption_type *et = crypto->et; @@ -1410,97 +1688,63 @@ krb5_decrypt_iov_ivec(krb5_context context, return KRB5_CRYPTO_INTERNAL; } - headersz = et->confoundersize; - - hiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_HEADER); - if (hiv == NULL || hiv->data.length != headersz) + /* header */ + hiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_HEADER); + if (hiv == NULL || hiv->data.length != et->confoundersize) return KRB5_BAD_MSIZE; /* trailer */ - trailersz = CHECKSUMSIZE(et->keyed_checksum); - - tiv = find_iv(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); - if (tiv->data.length != trailersz) + tiv = iov_find(data, num_data, KRB5_CRYPTO_TYPE_TRAILER); + if (tiv->data.length != CHECKSUMSIZE(et->keyed_checksum)) return KRB5_BAD_MSIZE; - /* Find length of data we will decrypt */ - - len = headersz; - for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) - continue; - len += data[i].data.length; - } - - if ((len % et->padsize) != 0) { + /* padding */ + if ((iov_enc_data_len(data, num_data) % et->padsize) != 0) { krb5_clear_error_message(context); return KRB5_BAD_MSIZE; } - /* XXX replace with EVP_Cipher */ + krb5_data_zero(&enc_data); + krb5_data_zero(&sign_data); - p = q = malloc(len); - if (p == NULL) - return ENOMEM; + if (!(et->flags & F_ENC_THEN_CKSUM)) { + ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data); + if(ret) + goto cleanup; - memcpy(q, hiv->data.data, hiv->data.length); - q += hiv->data.length; + ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); + if(ret) + goto cleanup; - for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) - continue; - memcpy(q, data[i].data.data, data[i].data.length); - q += data[i].data.length; - } + ret = _key_schedule(context, dkey); + if(ret) + goto cleanup; - ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); - if(ret) { - free(p); - return ret; - } - ret = _key_schedule(context, dkey); - if(ret) { - free(p); - return ret; - } + ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length, + 0, usage, ivec); + if(ret) + goto cleanup; - ret = (*et->encrypt)(context, dkey, p, len, 0, usage, ivec); - if (ret) { - free(p); - return ret; - } + ret = iov_uncoalesce(context, &enc_data, data, num_data); + if(ret) + goto cleanup; - /* copy data back to buffers */ - memcpy(hiv->data.data, p, hiv->data.length); - q = p + hiv->data.length; - for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_DATA) - continue; - memcpy(data[i].data.data, q, data[i].data.length); - q += data[i].data.length; - } + ret = iov_coalesce(context, NULL, data, num_data, TRUE, &sign_data); + if(ret) + goto cleanup; + } else { + krb5_data ivec_data; + static unsigned char zero_ivec[EVP_MAX_IV_LENGTH]; - free(p); + heim_assert(et->blocksize <= sizeof(zero_ivec), + "blocksize too big for ivec buffer"); - /* check signature */ - for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) - continue; - len += data[i].data.length; - } + ivec_data.length = et->blocksize; + ivec_data.data = ivec ? ivec : zero_ivec; - p = q = malloc(len); - if (p == NULL) - return ENOMEM; - - memcpy(q, hiv->data.data, hiv->data.length); - q += hiv->data.length; - for (i = 0; i < num_data; i++) { - if (data[i].flags != KRB5_CRYPTO_TYPE_DATA && - data[i].flags != KRB5_CRYPTO_TYPE_SIGN_ONLY) - continue; - memcpy(q, data[i].data.data, data[i].data.length); - q += data[i].data.length; + ret = iov_coalesce(context, &ivec_data, data, num_data, TRUE, &sign_data); + if(ret) + goto cleanup; } cksum.checksum.data = tiv->data.data; @@ -1510,10 +1754,44 @@ krb5_decrypt_iov_ivec(krb5_context context, ret = verify_checksum(context, crypto, INTEGRITY_USAGE(usage), - p, - len, + sign_data.data, + sign_data.length, &cksum); - free(p); + if(ret) + goto cleanup; + + if (et->flags & F_ENC_THEN_CKSUM) { + ret = iov_coalesce(context, NULL, data, num_data, FALSE, &enc_data); + if(ret) + goto cleanup; + + ret = _get_derived_key(context, crypto, ENCRYPTION_USAGE(usage), &dkey); + if(ret) + goto cleanup; + + ret = _key_schedule(context, dkey); + if(ret) + goto cleanup; + + ret = (*et->encrypt)(context, dkey, enc_data.data, enc_data.length, + 0, usage, ivec); + if(ret) + goto cleanup; + + ret = iov_uncoalesce(context, &enc_data, data, num_data); + if(ret) + goto cleanup; + } + +cleanup: + if (enc_data.data) { + memset_s(enc_data.data, enc_data.length, 0, enc_data.length); + krb5_data_free(&enc_data); + } + if (sign_data.data) { + memset_s(sign_data.data, sign_data.length, 0, sign_data.length); + krb5_data_free(&sign_data); + } return ret; } @@ -1551,7 +1829,7 @@ krb5_create_checksum_iov(krb5_context context, return KRB5_CRYPTO_INTERNAL; } - civ = find_iv(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM); + civ = iov_find(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM); if (civ == NULL) return KRB5_BAD_MSIZE; @@ -1630,7 +1908,7 @@ krb5_verify_checksum_iov(krb5_context context, return KRB5_CRYPTO_INTERNAL; } - civ = find_iv(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM); + civ = iov_find(data, num_data, KRB5_CRYPTO_TYPE_CHECKSUM); if (civ == NULL) return KRB5_BAD_MSIZE; @@ -1739,14 +2017,27 @@ krb5_encrypt_ivec(krb5_context context, krb5_data *result, void *ivec) { - if(derived_crypto(context, crypto)) - return encrypt_internal_derived(context, crypto, usage, + krb5_error_code ret; + + switch (crypto->et->flags & F_CRYPTO_MASK) { + case F_RFC3961_ENC: + ret = encrypt_internal_derived(context, crypto, usage, + data, len, result, ivec); + break; + case F_SPECIAL: + ret = encrypt_internal_special (context, crypto, usage, data, len, result, ivec); - else if (special_crypto(context, crypto)) - return encrypt_internal_special (context, crypto, usage, - data, len, result, ivec); - else - return encrypt_internal(context, crypto, data, len, result, ivec); + break; + case F_ENC_THEN_CKSUM: + ret = encrypt_internal_enc_then_cksum(context, crypto, usage, + data, len, result, ivec); + break; + default: + ret = encrypt_internal(context, crypto, data, len, result, ivec); + break; + } + + return ret; } KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL @@ -1787,14 +2078,27 @@ krb5_decrypt_ivec(krb5_context context, krb5_data *result, void *ivec) { - if(derived_crypto(context, crypto)) - return decrypt_internal_derived(context, crypto, usage, - data, len, result, ivec); - else if (special_crypto (context, crypto)) - return decrypt_internal_special(context, crypto, usage, - data, len, result, ivec); - else - return decrypt_internal(context, crypto, data, len, result, ivec); + krb5_error_code ret; + + switch (crypto->et->flags & F_CRYPTO_MASK) { + case F_RFC3961_ENC: + ret = decrypt_internal_derived(context, crypto, usage, + data, len, result, ivec); + break; + case F_SPECIAL: + ret = decrypt_internal_special(context, crypto, usage, + data, len, result, ivec); + break; + case F_ENC_THEN_CKSUM: + ret = decrypt_internal_enc_then_cksum(context, crypto, usage, + data, len, result, ivec); + break; + default: + ret = decrypt_internal(context, crypto, data, len, result, ivec); + break; + } + + return ret; } KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL @@ -1824,21 +2128,19 @@ krb5_decrypt_EncryptedData(krb5_context context, * * ************************************************************/ -KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL -_krb5_derive_key(krb5_context context, - struct _krb5_encryption_type *et, - struct _krb5_key_data *key, - const void *constant, - size_t len) +static krb5_error_code +derive_key_rfc3961(krb5_context context, + struct _krb5_encryption_type *et, + struct _krb5_key_data *key, + const void *constant, + size_t len) { + unsigned char *k = NULL; unsigned int nblocks = 0, i; krb5_error_code ret = 0; struct _krb5_key_type *kt = et->keytype; - ret = _key_schedule(context, key); - if(ret) - return ret; if(et->blocksize * 8 < kt->bits || len != et->blocksize) { nblocks = (kt->bits + et->blocksize * 8 - 1) / (et->blocksize * 8); k = malloc(nblocks * et->blocksize); @@ -1885,32 +2187,102 @@ _krb5_derive_key(krb5_context context, } } - /* XXX keytype dependent post-processing */ - switch(kt->type) { - case KRB5_ENCTYPE_OLD_DES3_CBC_SHA1: + if (kt->type == KRB5_ENCTYPE_OLD_DES3_CBC_SHA1) _krb5_DES3_random_to_key(context, key->key, k, nblocks * et->blocksize); - break; - case ETYPE_DES3_CBC_SHA1: - case KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96: - case KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96: + else memcpy(key->key->keyvalue.data, k, key->key->keyvalue.length); + + out: + if (k) { + memset_s(k, nblocks * et->blocksize, 0, nblocks * et->blocksize); + free(k); + } + return ret; +} + +static krb5_error_code +derive_key_sp800_hmac(krb5_context context, + struct _krb5_encryption_type *et, + struct _krb5_key_data *key, + const void *constant, + size_t len) +{ + krb5_error_code ret; + struct _krb5_key_type *kt = et->keytype; + krb5_data label; + const EVP_MD *md = NULL; + const unsigned char *c = constant; + size_t key_len; + krb5_data K1; + + ret = _krb5_aes_sha2_md_for_enctype(context, kt->type, &md); + if (ret) + return ret; + + /* + * PRF usage: not handled here (output cannot be longer) + * Integrity usage: truncated hash (half length) + * Encryption usage: base key length + */ + if (len == 5 && (c[4] == 0x99 || c[4] == 0x55)) + key_len = EVP_MD_size(md) / 2; + else + key_len = kt->size; + + ret = krb5_data_alloc(&K1, key_len); + if (ret) + return ret; + + label.data = (void *)constant; + label.length = len; + + ret = _krb5_SP800_108_HMAC_KDF(context, &key->key->keyvalue, + &label, NULL, md, &K1); + if (ret == 0) { + if (key->key->keyvalue.length > key_len) + key->key->keyvalue.length = key_len; + memcpy(key->key->keyvalue.data, K1.data, key_len); + } + + memset_s(K1.data, K1.length, 0, K1.length); + krb5_data_free(&K1); + + return ret; +} + +KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL +_krb5_derive_key(krb5_context context, + struct _krb5_encryption_type *et, + struct _krb5_key_data *key, + const void *constant, + size_t len) +{ + krb5_error_code ret; + + ret = _key_schedule(context, key); + if(ret) + return ret; + + switch (et->flags & F_KDF_MASK) { + case F_RFC3961_KDF: + ret = derive_key_rfc3961(context, et, key, constant, len); + break; + case F_SP800_108_HMAC_KDF: + ret = derive_key_sp800_hmac(context, et, key, constant, len); break; default: ret = KRB5_CRYPTO_INTERNAL; krb5_set_error_message(context, ret, N_("derive_key() called with unknown keytype (%u)", ""), - kt->type); + et->keytype->type); break; } - out: + if (key->schedule) { free_key_schedule(context, key, et); key->schedule = NULL; } - if (k) { - memset(k, 0, nblocks * et->blocksize); - free(k); - } + return ret; } @@ -2279,6 +2651,27 @@ krb5_is_enctype_weak(krb5_context context, krb5_enctype enctype) return FALSE; } +/** + * Returns whether the encryption type should use randomly generated salts + * + * @param context Kerberos 5 context + * @param enctype encryption type to probe + * + * @return Returns true if generated salts should have random component + * + * @ingroup krb5_crypto + */ +KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL +_krb5_enctype_requires_random_salt(krb5_context context, + krb5_enctype enctype) +{ + struct _krb5_encryption_type *et; + + et = _krb5_find_enctype (enctype); + + return et && (et->flags & F_SP800_108_HMAC_KDF); +} + static size_t wrapped_length (krb5_context context, krb5_crypto crypto, diff --git a/lib/krb5/crypto.h b/lib/krb5/crypto.h index 368d4f5db..6b0fe8d85 100644 --- a/lib/krb5/crypto.h +++ b/lib/krb5/crypto.h @@ -52,14 +52,22 @@ struct krb5_crypto_data { #define CRYPTO_ETYPE(C) ((C)->et->type) /* bits for `flags' below */ -#define F_KEYED 1 /* checksum is keyed */ -#define F_CPROOF 2 /* checksum is collision proof */ -#define F_DERIVED 4 /* uses derived keys */ -#define F_VARIANT 8 /* uses `variant' keys (6.4.3) */ -#define F_PSEUDO 16 /* not a real protocol type */ -#define F_SPECIAL 32 /* backwards */ -#define F_DISABLED 64 /* enctype/checksum disabled */ -#define F_WEAK 128 /* enctype is considered weak */ +#define F_KEYED 0x0001 /* checksum is keyed */ +#define F_CPROOF 0x0002 /* checksum is collision proof */ +#define F_DERIVED 0x0004 /* uses derived keys */ +#define F_VARIANT 0x0008 /* uses `variant' keys (6.4.3) */ +#define F_PSEUDO 0x0010 /* not a real protocol type */ +#define F_DISABLED 0x0020 /* enctype/checksum disabled */ +#define F_WEAK 0x0040 /* enctype is considered weak */ + +#define F_RFC3961_ENC 0x0100 /* RFC3961 simplified profile */ +#define F_SPECIAL 0x0200 /* backwards */ +#define F_ENC_THEN_CKSUM 0x0400 /* checksum is over encrypted data */ +#define F_CRYPTO_MASK 0x0F00 + +#define F_RFC3961_KDF 0x1000 /* RFC3961 KDF */ +#define F_SP800_108_HMAC_KDF 0x2000 /* SP800-108 HMAC KDF */ +#define F_KDF_MASK 0xF000 struct salt_type { krb5_salttype type; @@ -138,15 +146,19 @@ extern struct _krb5_checksum_type _krb5_checksum_rsa_md5; extern struct _krb5_checksum_type _krb5_checksum_hmac_sha1_des3; extern struct _krb5_checksum_type _krb5_checksum_hmac_sha1_aes128; extern struct _krb5_checksum_type _krb5_checksum_hmac_sha1_aes256; +extern struct _krb5_checksum_type _krb5_checksum_hmac_sha256_128_aes128; +extern struct _krb5_checksum_type _krb5_checksum_hmac_sha384_192_aes256; extern struct _krb5_checksum_type _krb5_checksum_hmac_md5; extern struct _krb5_checksum_type _krb5_checksum_sha1; +extern struct _krb5_checksum_type _krb5_checksum_sha2; extern struct _krb5_checksum_type *_krb5_checksum_types[]; extern int _krb5_num_checksums; /* Salts */ -extern struct salt_type _krb5_AES_salt[]; +extern struct salt_type _krb5_AES_SHA1_salt[]; +extern struct salt_type _krb5_AES_SHA2_salt[]; extern struct salt_type _krb5_arcfour_salt[]; extern struct salt_type _krb5_des_salt[]; extern struct salt_type _krb5_des3_salt[]; @@ -156,6 +168,8 @@ extern struct salt_type _krb5_des3_salt_derived[]; extern struct _krb5_encryption_type _krb5_enctype_aes256_cts_hmac_sha1; extern struct _krb5_encryption_type _krb5_enctype_aes128_cts_hmac_sha1; +extern struct _krb5_encryption_type _krb5_enctype_aes128_cts_hmac_sha256_128; +extern struct _krb5_encryption_type _krb5_enctype_aes256_cts_hmac_sha384_192; extern struct _krb5_encryption_type _krb5_enctype_des3_cbc_sha1; extern struct _krb5_encryption_type _krb5_enctype_des3_cbc_md5; extern struct _krb5_encryption_type _krb5_enctype_des3_cbc_none; diff --git a/lib/krb5/derived-key-test.c b/lib/krb5/derived-key-test.c index ba58c8bce..0e927643f 100644 --- a/lib/krb5/derived-key-test.c +++ b/lib/krb5/derived-key-test.c @@ -33,7 +33,7 @@ #include "krb5_locl.h" #include -enum { MAXSIZE = 24 }; +enum { MAXSIZE = 32 }; static struct testcase { krb5_enctype enctype; @@ -72,6 +72,30 @@ static struct testcase { {ETYPE_DES3_CBC_SHA1, {0x00, 0x00, 0x00, 0x01, 0xaa}, 5, {0x26, 0xdc, 0xe3, 0x34, 0xb5, 0x45, 0x29, 0x2f, 0x2f, 0xea, 0xb9, 0xa8, 0x70, 0x1a, 0x89, 0xa4, 0xb9, 0x9e, 0xb9, 0x94, 0x2c, 0xec, 0xd0, 0x16}, {0xf4, 0x8f, 0xfd, 0x6e, 0x83, 0xf8, 0x3e, 0x73, 0x54, 0xe6, 0x94, 0xfd, 0x25, 0x2c, 0xf8, 0x3b, 0xfe, 0x58, 0xf7, 0xd5, 0xba, 0x37, 0xec, 0x5d}}, + {ETYPE_AES128_CTS_HMAC_SHA256_128, {0x00, 0x00, 0x00, 0x02, 0x99}, 5, + {0x37, 0x05, 0xD9, 0x60, 0x80, 0xC1, 0x77, 0x28, 0xA0, 0xE8, 0x00, 0xEA, 0xB6, 0xE0, 0xD2, 0x3C}, + {0xB3, 0x1A, 0x01, 0x8A, 0x48, 0xF5, 0x47, 0x76, 0xF4, 0x03, 0xE9, 0xA3, 0x96, 0x32, 0x5D, 0xC3}}, + {ETYPE_AES128_CTS_HMAC_SHA256_128, {0x00, 0x00, 0x00, 0x02, 0xAA}, 5, + {0x37, 0x05, 0xD9, 0x60, 0x80, 0xC1, 0x77, 0x28, 0xA0, 0xE8, 0x00, 0xEA, 0xB6, 0xE0, 0xD2, 0x3C}, + {0x9B, 0x19, 0x7D, 0xD1, 0xE8, 0xC5, 0x60, 0x9D, 0x6E, 0x67, 0xC3, 0xE3, 0x7C, 0x62, 0xC7, 0x2E}}, + {ETYPE_AES128_CTS_HMAC_SHA256_128, {0x00, 0x00, 0x00, 0x02, 0x55}, 5, + {0x37, 0x05, 0xD9, 0x60, 0x80, 0xC1, 0x77, 0x28, 0xA0, 0xE8, 0x00, 0xEA, 0xB6, 0xE0, 0xD2, 0x3C}, + {0x9F, 0xDA, 0x0E, 0x56, 0xAB, 0x2D, 0x85, 0xE1, 0x56, 0x9A, 0x68, 0x86, 0x96, 0xC2, 0x6A, 0x6C}}, + {ETYPE_AES256_CTS_HMAC_SHA384_192, {0x00, 0x00, 0x00, 0x02, 0x99}, 5, + {0x6D, 0x40, 0x4D, 0x37, 0xFA, 0xF7, 0x9F, 0x9D, 0xF0, 0xD3, 0x35, 0x68, 0xD3, 0x20, 0x66, 0x98, + 0x00, 0xEB, 0x48, 0x36, 0x47, 0x2E, 0xA8, 0xA0, 0x26, 0xD1, 0x6B, 0x71, 0x82, 0x46, 0x0C, 0x52}, + {0xEF, 0x57, 0x18, 0xBE, 0x86, 0xCC, 0x84, 0x96, 0x3D, 0x8B, 0xBB, 0x50, 0x31, 0xE9, 0xF5, 0xC4, + 0xBA, 0x41, 0xF2, 0x8F, 0xAF, 0x69, 0xE7, 0x3D }}, + {ETYPE_AES256_CTS_HMAC_SHA384_192, {0x00, 0x00, 0x00, 0x02, 0xAA}, 5, + {0x6D, 0x40, 0x4D, 0x37, 0xFA, 0xF7, 0x9F, 0x9D, 0xF0, 0xD3, 0x35, 0x68, 0xD3, 0x20, 0x66, 0x98, + 0x00, 0xEB, 0x48, 0x36, 0x47, 0x2E, 0xA8, 0xA0, 0x26, 0xD1, 0x6B, 0x71, 0x82, 0x46, 0x0C, 0x52}, + {0x56, 0xAB, 0x22, 0xBE, 0xE6, 0x3D, 0x82, 0xD7, 0xBC, 0x52, 0x27, 0xF6, 0x77, 0x3F, 0x8E, 0xA7, + 0xA5, 0xEB, 0x1C, 0x82, 0x51, 0x60, 0xC3, 0x83, 0x12, 0x98, 0x0C, 0x44, 0x2E, 0x5C, 0x7E, 0x49}}, + {ETYPE_AES256_CTS_HMAC_SHA384_192, {0x00, 0x00, 0x00, 0x02, 0x55}, 5, + {0x6D, 0x40, 0x4D, 0x37, 0xFA, 0xF7, 0x9F, 0x9D, 0xF0, 0xD3, 0x35, 0x68, 0xD3, 0x20, 0x66, 0x98, + 0x00, 0xEB, 0x48, 0x36, 0x47, 0x2E, 0xA8, 0xA0, 0x26, 0xD1, 0x6B, 0x71, 0x82, 0x46, 0x0C, 0x52}, + {0x69, 0xB1, 0x65, 0x14, 0xE3, 0xCD, 0x8E, 0x56, 0xB8, 0x20, 0x10, 0xD5, 0xC7, 0x30, 0x12, 0xB6, + 0x22, 0xC4, 0xD0, 0x0F, 0xFC, 0x23, 0xED, 0x1F}}, {0, {0}, 0, {0}, {0}} }; @@ -91,8 +115,8 @@ main(int argc, char **argv) krb5_keyblock key; krb5_keyblock *dkey; - key.keytype = KEYTYPE_DES3; - key.keyvalue.length = MAXSIZE; + key.keytype = t->enctype; + krb5_enctype_keysize(context, t->enctype, &key.keyvalue.length); key.keyvalue.data = t->key; ret = krb5_derive_key(context, &key, t->enctype, t->constant, @@ -103,7 +127,7 @@ main(int argc, char **argv) const unsigned char *p = dkey->keyvalue.data; int i; - printf ("derive_key failed\n"); + printf ("derive_key failed (enctype %d)\n", t->enctype); printf ("should be: "); for (i = 0; i < dkey->keyvalue.length; ++i) printf ("%02x", t->res[i]); diff --git a/lib/krb5/krb5.h b/lib/krb5/krb5.h index 199eed983..572db7ed7 100644 --- a/lib/krb5/krb5.h +++ b/lib/krb5/krb5.h @@ -150,6 +150,8 @@ enum { ETYPE_DES3_CBC_SHA1 = KRB5_ENCTYPE_DES3_CBC_SHA1, ETYPE_AES128_CTS_HMAC_SHA1_96 = KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96, ETYPE_AES256_CTS_HMAC_SHA1_96 = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96, + ETYPE_AES128_CTS_HMAC_SHA256_128 = KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128, + ETYPE_AES256_CTS_HMAC_SHA384_192 = KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192, ETYPE_ARCFOUR_HMAC_MD5 = KRB5_ENCTYPE_ARCFOUR_HMAC_MD5, ETYPE_ARCFOUR_HMAC_MD5_56 = KRB5_ENCTYPE_ARCFOUR_HMAC_MD5_56, ETYPE_ENCTYPE_PK_CROSS = KRB5_ENCTYPE_ENCTYPE_PK_CROSS, diff --git a/lib/krb5/libkrb5-exports.def.in b/lib/krb5/libkrb5-exports.def.in index ede4db555..4236e1e73 100644 --- a/lib/krb5/libkrb5-exports.def.in +++ b/lib/krb5/libkrb5-exports.def.in @@ -747,7 +747,8 @@ EXPORTS _krb5_build_authenticator ; Shared with libkdc - _krb5_AES_string_to_default_iterator + _krb5_AES_SHA1_string_to_default_iterator + _krb5_AES_SHA2_string_to_default_iterator _krb5_dh_group_ok _krb5_get_host_realm_int _krb5_get_int @@ -759,6 +760,7 @@ EXPORTS _krb5_pk_mk_ContentInfo _krb5_pk_octetstring2key _krb5_plugin_run_f + _krb5_enctype_requires_random_salt _krb5_principal2principalname _krb5_principalname2krb5_principal _krb5_put_int diff --git a/lib/krb5/pseudo-random-test.c b/lib/krb5/pseudo-random-test.c new file mode 100644 index 000000000..4acf8082f --- /dev/null +++ b/lib/krb5/pseudo-random-test.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of KTH nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + +#include "krb5_locl.h" +#include + +enum { MAXSIZE = 48 }; + +static struct testcase { + krb5_enctype enctype; + unsigned char constant[MAXSIZE]; + size_t constant_len; + unsigned char key[MAXSIZE]; + unsigned char res[MAXSIZE]; +} tests[] = { + {ETYPE_AES128_CTS_HMAC_SHA256_128, "test", 4, + {0x37, 0x05, 0xD9, 0x60, 0x80, 0xC1, 0x77, 0x28, 0xA0, 0xE8, 0x00, 0xEA, 0xB6, 0xE0, 0xD2, 0x3C}, + {0x9D, 0x18, 0x86, 0x16, 0xF6, 0x38, 0x52, 0xFE, 0x86, 0x91, 0x5B, 0xB8, 0x40, 0xB4, 0xA8, 0x86, + 0xFF, 0x3E, 0x6B, 0xB0, 0xF8, 0x19, 0xB4, 0x9B, 0x89, 0x33, 0x93, 0xD3, 0x93, 0x85, 0x42, 0x95}}, + {ETYPE_AES256_CTS_HMAC_SHA384_192, "test", 4, + {0x6D, 0x40, 0x4D, 0x37, 0xFA, 0xF7, 0x9F, 0x9D, 0xF0, 0xD3, 0x35, 0x68, 0xD3, 0x20, 0x66, 0x98, + 0x00, 0xEB, 0x48, 0x36, 0x47, 0x2E, 0xA8, 0xA0, 0x26, 0xD1, 0x6B, 0x71, 0x82, 0x46, 0x0C, 0x52}, + {0x98, 0x01, 0xF6, 0x9A, 0x36, 0x8C, 0x2B, 0xF6, 0x75, 0xE5, 0x95, 0x21, 0xE1, 0x77, 0xD9, 0xA0, + 0x7F, 0x67, 0xEF, 0xE1, 0xCF, 0xDE, 0x8D, 0x3C, 0x8D, 0x6F, 0x6A, 0x02, 0x56, 0xE3, 0xB1, 0x7D, + 0xB3, 0xC1, 0xB6, 0x2A, 0xD1, 0xB8, 0x55, 0x33, 0x60, 0xD1, 0x73, 0x67, 0xEB, 0x15, 0x14, 0xD2}}, + {0, {0}, 0, {0}, {0}} +}; + +int +main(int argc, char **argv) +{ + struct testcase *t; + krb5_context context; + krb5_error_code ret; + int val = 0; + + ret = krb5_init_context (&context); + if (ret) + errx (1, "krb5_init_context failed: %d", ret); + + for (t = tests; t->enctype != 0; ++t) { + krb5_keyblock key; + krb5_crypto crypto; + krb5_data constant, prf; + + krb5_data_zero(&prf); + + key.keytype = t->enctype; + krb5_enctype_keysize(context, t->enctype, &key.keyvalue.length); + key.keyvalue.data = t->key; + + ret = krb5_crypto_init(context, &key, 0, &crypto); + if (ret) + krb5_err (context, 1, ret, "krb5_crypto_init"); + + constant.data = t->constant; + constant.length = t->constant_len; + + ret = krb5_crypto_prf(context, crypto, &constant, &prf); + if (ret) + krb5_err (context, 1, ret, "krb5_crypto_prf"); + + if (memcmp(prf.data, t->res, prf.length) != 0) { + const unsigned char *p = prf.data; + int i; + + printf ("PRF failed (enctype %d)\n", t->enctype); + printf ("should be: "); + for (i = 0; i < prf.length; ++i) + printf ("%02x", t->res[i]); + printf ("\nresult was: "); + for (i = 0; i < prf.length; ++i) + printf ("%02x", p[i]); + printf ("\n"); + val = 1; + } + krb5_data_free(&prf); + krb5_crypto_destroy(context, crypto); + } + krb5_free_context(context); + + return val; +} diff --git a/lib/krb5/salt-aes.c b/lib/krb5/salt-aes-sha1.c similarity index 83% rename from lib/krb5/salt-aes.c rename to lib/krb5/salt-aes-sha1.c index 2444d19b8..edd066df4 100644 --- a/lib/krb5/salt-aes.c +++ b/lib/krb5/salt-aes-sha1.c @@ -33,15 +33,15 @@ #include "krb5_locl.h" -int _krb5_AES_string_to_default_iterator = 4096; +int _krb5_AES_SHA1_string_to_default_iterator = 4096; static krb5_error_code -AES_string_to_key(krb5_context context, - krb5_enctype enctype, - krb5_data password, - krb5_salt salt, - krb5_data opaque, - krb5_keyblock *key) +AES_SHA1_string_to_key(krb5_context context, + krb5_enctype enctype, + krb5_data password, + krb5_salt salt, + krb5_data opaque, + krb5_keyblock *key) { krb5_error_code ret; uint32_t iter; @@ -49,7 +49,7 @@ AES_string_to_key(krb5_context context, struct _krb5_key_data kd; if (opaque.length == 0) - iter = _krb5_AES_string_to_default_iterator; + iter = _krb5_AES_SHA1_string_to_default_iterator; else if (opaque.length == 4) { unsigned long v; _krb5_get_int(opaque.data, &v, 4); @@ -72,10 +72,11 @@ AES_string_to_key(krb5_context context, return ret; } - ret = PKCS5_PBKDF2_HMAC_SHA1(password.data, password.length, - salt.saltvalue.data, salt.saltvalue.length, - iter, - et->keytype->size, kd.key->keyvalue.data); + ret = PKCS5_PBKDF2_HMAC(password.data, password.length, + salt.saltvalue.data, salt.saltvalue.length, + iter, + EVP_sha1(), + et->keytype->size, kd.key->keyvalue.data); if (ret != 1) { _krb5_free_key_data(context, &kd, et); krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP, @@ -91,11 +92,11 @@ AES_string_to_key(krb5_context context, return ret; } -struct salt_type _krb5_AES_salt[] = { +struct salt_type _krb5_AES_SHA1_salt[] = { { KRB5_PW_SALT, "pw-salt", - AES_string_to_key + AES_SHA1_string_to_key }, { 0, NULL, NULL } }; diff --git a/lib/krb5/salt-aes-sha2.c b/lib/krb5/salt-aes-sha2.c new file mode 100644 index 000000000..bfd726c34 --- /dev/null +++ b/lib/krb5/salt-aes-sha2.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "krb5_locl.h" + +int _krb5_AES_SHA2_string_to_default_iterator = 32768; + +static krb5_error_code +AES_SHA2_string_to_key(krb5_context context, + krb5_enctype enctype, + krb5_data password, + krb5_salt salt, + krb5_data opaque, + krb5_keyblock *key) +{ + krb5_error_code ret; + uint32_t iter; + struct _krb5_encryption_type *et = NULL; + struct _krb5_key_data kd; + krb5_data saltp; + size_t enctypesz; + const EVP_MD *md = NULL; + + krb5_data_zero(&saltp); + kd.key = NULL; + kd.schedule = NULL; + + if (opaque.length == 0) { + iter = _krb5_AES_SHA2_string_to_default_iterator; + } else if (opaque.length == 4) { + unsigned long v; + _krb5_get_int(opaque.data, &v, 4); + iter = ((uint32_t)v); + } else { + ret = KRB5_PROG_KEYTYPE_NOSUPP; /* XXX */ + goto cleanup; + } + + et = _krb5_find_enctype(enctype); + if (et == NULL) { + ret = KRB5_PROG_KEYTYPE_NOSUPP; + goto cleanup; + } + + kd.schedule = NULL; + ALLOC(kd.key, 1); + if (kd.key == NULL) { + ret = krb5_enomem(context); + goto cleanup; + } + kd.key->keytype = enctype; + ret = krb5_data_alloc(&kd.key->keyvalue, et->keytype->size); + if (ret) { + ret = krb5_enomem(context); + goto cleanup; + } + + enctypesz = strlen(et->name) + 1; + ret = krb5_data_alloc(&saltp, enctypesz + salt.saltvalue.length); + if (ret) { + ret = krb5_enomem(context); + goto cleanup; + } + memcpy(saltp.data, et->name, enctypesz); + memcpy((unsigned char *)saltp.data + enctypesz, + salt.saltvalue.data, salt.saltvalue.length); + + ret = _krb5_aes_sha2_md_for_enctype(context, enctype, &md); + if (ret) + goto cleanup; + + ret = PKCS5_PBKDF2_HMAC(password.data, password.length, + saltp.data, saltp.length, + iter, md, + et->keytype->size, kd.key->keyvalue.data); + if (ret != 1) { + krb5_set_error_message(context, KRB5_PROG_KEYTYPE_NOSUPP, + "Error calculating s2k"); + ret = KRB5_PROG_KEYTYPE_NOSUPP; + goto cleanup; + } + + ret = _krb5_derive_key(context, et, &kd, "kerberos", strlen("kerberos")); + if (ret) + goto cleanup; + + ret = krb5_copy_keyblock_contents(context, kd.key, key); + if (ret) + goto cleanup; + +cleanup: + krb5_data_free(&saltp); + _krb5_free_key_data(context, &kd, et); + + return ret; +} + +struct salt_type _krb5_AES_SHA2_salt[] = { + { + KRB5_PW_SALT, + "pw-salt", + AES_SHA2_string_to_key + }, + { 0, NULL, NULL } +}; diff --git a/lib/krb5/sp800-108-kdf.c b/lib/krb5/sp800-108-kdf.c new file mode 100755 index 000000000..fea49700e --- /dev/null +++ b/lib/krb5/sp800-108-kdf.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2015, Secure Endpoints Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "krb5_locl.h" + +/* + * SP800-108 KDF + */ + +/** + * As described in SP800-108 5.1 (for HMAC) + * + * @param context Kerberos 5 context + * @param kdc_K1 Base key material. + * @param kdf_label A string that identifies the purpose for the derived key. + * @param kdf_context A binary string containing parties, nonce, etc. + * @param md Message digest function to use for PRF. + * @param kdf_K0 Derived key data. + * + * @return Return an error code for an failure or 0 on success. + * @ingroup krb5_crypto + */ +krb5_error_code +_krb5_SP800_108_HMAC_KDF(krb5_context context, + const krb5_data *kdf_K1, + const krb5_data *kdf_label, + const krb5_data *kdf_context, + const EVP_MD *md, + krb5_data *kdf_K0) +{ + HMAC_CTX c; + unsigned char *p = kdf_K0->data; + size_t i, n, left = kdf_K0->length; + unsigned char hmac[EVP_MAX_MD_SIZE]; + unsigned int h = EVP_MD_size(md); + const size_t L = kdf_K0->length; + + heim_assert(md != NULL, "SP800-108 KDF internal error"); + + HMAC_CTX_init(&c); + + n = L / h; + + for (i = 0; i <= n; i++) { + unsigned char tmp[4]; + size_t len; + + HMAC_Init_ex(&c, kdf_K1->data, kdf_K1->length, md, NULL); + + _krb5_put_int(tmp, i + 1, 4); + HMAC_Update(&c, tmp, 4); + HMAC_Update(&c, kdf_label->data, kdf_label->length); + HMAC_Update(&c, (unsigned char *)"", 1); + if (kdf_context) + HMAC_Update(&c, kdf_context->data, kdf_context->length); + _krb5_put_int(tmp, L * 8, 4); + HMAC_Update(&c, tmp, 4); + + HMAC_Final(&c, hmac, &h); + len = h > left ? left : h; + memcpy(p, hmac, len); + p += len; + left -= len; + } + + HMAC_CTX_cleanup(&c); + + return 0; +} diff --git a/lib/krb5/test_crypto.c b/lib/krb5/test_crypto.c index f62f75987..34a709ada 100644 --- a/lib/krb5/test_crypto.c +++ b/lib/krb5/test_crypto.c @@ -164,7 +164,9 @@ main(int argc, char **argv) ETYPE_ARCFOUR_HMAC_MD5, #endif ETYPE_AES128_CTS_HMAC_SHA1_96, - ETYPE_AES256_CTS_HMAC_SHA1_96 + ETYPE_AES256_CTS_HMAC_SHA1_96, + ETYPE_AES128_CTS_HMAC_SHA256_128, + ETYPE_AES256_CTS_HMAC_SHA384_192 }; setprogname(argv[0]); diff --git a/lib/krb5/test_crypto_wrapping.c b/lib/krb5/test_crypto_wrapping.c index 81905a8ea..aff4e8d50 100644 --- a/lib/krb5/test_crypto_wrapping.c +++ b/lib/krb5/test_crypto_wrapping.c @@ -131,7 +131,9 @@ main(int argc, char **argv) ETYPE_DES3_CBC_SHA1, ETYPE_ARCFOUR_HMAC_MD5, ETYPE_AES128_CTS_HMAC_SHA1_96, - ETYPE_AES256_CTS_HMAC_SHA1_96 + ETYPE_AES256_CTS_HMAC_SHA1_96, + KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128, + KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192 }; setprogname(argv[0]); diff --git a/lib/krb5/test_rfc3961.c b/lib/krb5/test_rfc3961.c index 972af0c5f..f86b8bb3a 100644 --- a/lib/krb5/test_rfc3961.c +++ b/lib/krb5/test_rfc3961.c @@ -162,7 +162,9 @@ main(int argc, char **argv) ETYPE_DES3_CBC_SHA1, ETYPE_ARCFOUR_HMAC_MD5, ETYPE_AES128_CTS_HMAC_SHA1_96, - ETYPE_AES256_CTS_HMAC_SHA1_96 + ETYPE_AES256_CTS_HMAC_SHA1_96, + ETYPE_AES128_CTS_HMAC_SHA256_128, + ETYPE_AES256_CTS_HMAC_SHA384_192 }; setprogname(argv[0]); diff --git a/lib/krb5/version-script.map b/lib/krb5/version-script.map index e2ae54581..997103b2f 100644 --- a/lib/krb5/version-script.map +++ b/lib/krb5/version-script.map @@ -732,6 +732,7 @@ HEIMDAL_KRB5_2.0 { # shared with HDB _krb5_plugin_run_f; + _krb5_enctype_requires_random_salt; # Shared with GSSAPI krb5 _krb5_crc_init_table; @@ -740,7 +741,8 @@ HEIMDAL_KRB5_2.0 { _krb5_build_authenticator; # Shared with libkdc - _krb5_AES_string_to_default_iterator; + _krb5_AES_SHA1_string_to_default_iterator; + _krb5_AES_SHA2_string_to_default_iterator; _krb5_dh_group_ok; _krb5_get_host_realm_int; _krb5_get_int;