diff options
-rw-r--r-- | daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_encoding.c | 211 | ||||
-rw-r--r-- | util/ipa_krb5.c | 221 | ||||
-rw-r--r-- | util/ipa_krb5.h | 19 |
3 files changed, 244 insertions, 207 deletions
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_encoding.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_encoding.c index 3ce39609..a1b0e99f 100644 --- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_encoding.c +++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_encoding.c @@ -72,18 +72,6 @@ #define KTF_DISALLOW_SVR 0x00001000 #define KTF_PWCHANGE_SERVICE 0x00002000 -/* Salt types */ -#define KRB5_KDB_SALTTYPE_NORMAL 0 -#define KRB5_KDB_SALTTYPE_V4 1 -#define KRB5_KDB_SALTTYPE_NOREALM 2 -#define KRB5_KDB_SALTTYPE_ONLYREALM 3 -#define KRB5_KDB_SALTTYPE_SPECIAL 4 -#define KRB5_KDB_SALTTYPE_AFS3 5 -#define KRB5P_SALT_SIZE 16 - -void krb5int_c_free_keyblock_contents(krb5_context context, - register krb5_keyblock *key); - /* Novell key-format scheme: KrbKeySet ::= SEQUENCE { @@ -250,7 +238,7 @@ static Slapi_Value **encrypt_encode_key(struct ipapwd_krbcfg *krbcfg, { krb5_context krbctx; char *krbPrincipalName = NULL; - int kvno, i; + int kvno; struct berval *bval = NULL; Slapi_Value **svals = NULL; krb5_principal princ = NULL; @@ -300,198 +288,17 @@ static Slapi_Value **encrypt_encode_key(struct ipapwd_krbcfg *krbcfg, kset->kvno = kvno + 1; kset->mkvno = krbcfg->mkvno; - kset->num_keys = krbcfg->num_pref_encsalts; - kset->keys = calloc(kset->num_keys, sizeof(struct ipapwd_krbkey)); - if (!kset->keys) { - LOG_OOM(); + krberr = ipa_krb5_generate_key_data(krbctx, princ, + pwd, kvno, krbcfg->kmkey, + krbcfg->num_pref_encsalts, + krbcfg->pref_encsalts, + &kset->num_keys, &kset->keys); + if (krberr != 0) { + LOG_FATAL("generating kerberos keys failed [%s]\n", + krb5_get_error_message(krbctx, krberr)); goto enc_error; } - for (i = 0; i < kset->num_keys; i++) { - krb5_keyblock key; - krb5_data salt; - krb5_octet *ptr; - krb5_data plain; - krb5_enc_data cipher; - krb5_int16 t; - size_t len; - const char *p; - - salt.data = NULL; - - switch (krbcfg->pref_encsalts[i].ks_salttype) { - - case KRB5_KDB_SALTTYPE_ONLYREALM: - - p = strchr(krbPrincipalName, '@'); - if (!p) { - LOG_FATAL("Invalid principal name, no realm found!\n"); - goto enc_error; - } - p++; - salt.data = strdup(p); - if (!salt.data) { - LOG_OOM(); - goto enc_error; - } - salt.length = strlen(salt.data); /* final \0 omitted on purpose */ - break; - - case KRB5_KDB_SALTTYPE_NOREALM: - - krberr = ipa_krb5_principal2salt_norealm(krbctx, princ, &salt); - if (krberr) { - LOG_FATAL("krb5_principal2salt failed [%s]\n", - krb5_get_error_message(krbctx, krberr)); - goto enc_error; - } - break; - - case KRB5_KDB_SALTTYPE_NORMAL: - - krberr = krb5_principal2salt(krbctx, princ, &salt); - if (krberr) { - LOG_FATAL("krb5_principal2salt failed [%s]\n", - krb5_get_error_message(krbctx, krberr)); - goto enc_error; - } - break; - - case KRB5_KDB_SALTTYPE_SPECIAL: - - /* make random salt */ - salt.length = KRB5P_SALT_SIZE; - salt.data = malloc(KRB5P_SALT_SIZE); - if (!salt.data) { - LOG_OOM(); - goto enc_error; - } - krberr = krb5_c_random_make_octets(krbctx, &salt); - if (krberr) { - LOG_FATAL("krb5_c_random_make_octets failed [%s]\n", - krb5_get_error_message(krbctx, krberr)); - goto enc_error; - } - break; - - case KRB5_KDB_SALTTYPE_V4: - salt.length = 0; - break; - - case KRB5_KDB_SALTTYPE_AFS3: - - p = strchr(krbPrincipalName, '@'); - if (!p) { - LOG_FATAL("Invalid principal name, no realm found!\n"); - goto enc_error; - } - p++; - salt.data = strdup(p); - if (!salt.data) { - LOG_OOM(); - goto enc_error; - } - salt.length = SALT_TYPE_AFS_LENGTH; /* special value */ - break; - - default: - LOG_FATAL("Invalid salt type [%d]\n", - krbcfg->pref_encsalts[i].ks_salttype); - goto enc_error; - } - - /* need to build the key now to manage the AFS salt.length - * special case */ - krberr = krb5_c_string_to_key(krbctx, - krbcfg->pref_encsalts[i].ks_enctype, - &pwd, &salt, &key); - if (krberr) { - LOG_FATAL("krb5_c_string_to_key failed [%s]\n", - krb5_get_error_message(krbctx, krberr)); - krb5_free_data_contents(krbctx, &salt); - goto enc_error; - } - if (salt.length == SALT_TYPE_AFS_LENGTH) { - salt.length = strlen(salt.data); - } - - krberr = krb5_c_encrypt_length(krbctx, - krbcfg->kmkey->enctype, - key.length, &len); - if (krberr) { - LOG_FATAL("krb5_c_string_to_key failed [%s]\n", - krb5_get_error_message(krbctx, krberr)); - krb5int_c_free_keyblock_contents(krbctx, &key); - krb5_free_data_contents(krbctx, &salt); - goto enc_error; - } - - if ((ptr = (krb5_octet *) malloc(2 + len)) == NULL) { - LOG_OOM(); - krb5int_c_free_keyblock_contents(krbctx, &key); - krb5_free_data_contents(krbctx, &salt); - goto enc_error; - } - - t = htole16(key.length); - memcpy(ptr, &t, 2); - - plain.length = key.length; - plain.data = (char *)key.contents; - - cipher.ciphertext.length = len; - cipher.ciphertext.data = (char *)ptr+2; - - krberr = krb5_c_encrypt(krbctx, krbcfg->kmkey, 0, 0, &plain, &cipher); - if (krberr) { - LOG_FATAL("krb5_c_encrypt failed [%s]\n", - krb5_get_error_message(krbctx, krberr)); - krb5int_c_free_keyblock_contents(krbctx, &key); - krb5_free_data_contents(krbctx, &salt); - free(ptr); - goto enc_error; - } - - /* KrbSalt */ - kset->keys[i].salt = malloc(sizeof(struct ipapwd_krbkeydata)); - if (!kset->keys[i].salt) { - LOG_OOM(); - krb5int_c_free_keyblock_contents(krbctx, &key); - free(ptr); - goto enc_error; - } - - kset->keys[i].salt->type = krbcfg->pref_encsalts[i].ks_salttype; - - if (salt.length) { - kset->keys[i].salt->value.bv_len = salt.length; - kset->keys[i].salt->value.bv_val = salt.data; - } - - /* EncryptionKey */ - kset->keys[i].ekey = malloc(sizeof(struct ipapwd_krbkeydata)); - if (!kset->keys[i].ekey) { - LOG_OOM(); - krb5int_c_free_keyblock_contents(krbctx, &key); - free(ptr); - goto enc_error; - } - kset->keys[i].ekey->type = key.enctype; - kset->keys[i].ekey->value.bv_len = len+2; - kset->keys[i].ekey->value.bv_val = malloc(len+2); - if (!kset->keys[i].ekey->value.bv_val) { - LOG_OOM(); - krb5int_c_free_keyblock_contents(krbctx, &key); - free(ptr); - goto enc_error; - } - memcpy(kset->keys[i].ekey->value.bv_val, ptr, len+2); - - /* make sure we free the memory used now that we are done with it */ - krb5int_c_free_keyblock_contents(krbctx, &key); - free(ptr); - } - bval = encode_keys(kset); if (!bval) { LOG_FATAL("encoding asn1 KrbSalt failed\n"); diff --git a/util/ipa_krb5.c b/util/ipa_krb5.c index 5765087c..b75da1e2 100644 --- a/util/ipa_krb5.c +++ b/util/ipa_krb5.c @@ -4,6 +4,9 @@ #include "ipa_krb5.h" +/* Salt types */ +#define KRB5P_SALT_SIZE 16 + void ipa_krb5_free_ktypes(krb5_context context, krb5_enctype *val) { @@ -13,8 +16,9 @@ ipa_krb5_free_ktypes(krb5_context context, krb5_enctype *val) /* * Convert a krb5_principal into the default salt for that principal. */ -krb5_error_code -ipa_krb5_principal2salt_norealm(krb5_context context, krb5_const_principal pr, krb5_data *ret) +krb5_error_code ipa_krb5_principal2salt_norealm(krb5_context context, + krb5_const_principal pr, + krb5_data *ret) { unsigned int size = 0, offset=0; krb5_int32 nelem; @@ -42,3 +46,216 @@ ipa_krb5_principal2salt_norealm(krb5_context context, krb5_const_principal pr, k } return 0; } + +void krb5int_c_free_keyblock_contents(krb5_context context, + register krb5_keyblock *key); + +/* + * Generate a krb5_key_data set by encrypting keys according to + * enctype/salttype preferences + */ +krb5_error_code ipa_krb5_generate_key_data(krb5_context krbctx, + krb5_principal principal, + krb5_data pwd, int kvno, + krb5_keyblock *kmkey, + int num_encsalts, + krb5_key_salt_tuple *encsalts, + int *_num_keys, + krb5_key_data **_keys) +{ + krb5_error_code kerr; + krb5_key_data *keys; + int num_keys; + int i; + + num_keys = num_encsalts; + keys = calloc(num_keys, sizeof(krb5_key_data)); + if (!keys) { + return ENOMEM; + } + + for (i = 0; i < num_keys; i++) { + krb5_keyblock key; + krb5_data salt; + krb5_octet *ptr; + krb5_data plain; + krb5_enc_data cipher; + krb5_int16 t; + size_t len; + + salt.data = NULL; + + keys[i].key_data_ver = 2; /* we always have a salt */ + keys[i].key_data_kvno = kvno; + + switch (encsalts[i].ks_salttype) { + + case KRB5_KDB_SALTTYPE_ONLYREALM: + + if (!principal->realm.data) { + kerr = EINVAL; + goto done; + } + salt.length = principal->realm.length; + salt.data = malloc(salt.length); + if (!salt.data) { + kerr = ENOMEM; + goto done; + } + memcpy(salt.data, principal->realm.data, salt.length); + break; + + case KRB5_KDB_SALTTYPE_NOREALM: + + kerr = ipa_krb5_principal2salt_norealm(krbctx, principal, &salt); + if (kerr) { + goto done; + } + break; + + case KRB5_KDB_SALTTYPE_NORMAL: + + kerr = krb5_principal2salt(krbctx, principal, &salt); + if (kerr) { + goto done; + } + break; + + case KRB5_KDB_SALTTYPE_SPECIAL: + + /* make random salt */ + salt.length = KRB5P_SALT_SIZE; + salt.data = malloc(KRB5P_SALT_SIZE); + if (!salt.data) { + kerr = ENOMEM; + goto done; + } + kerr = krb5_c_random_make_octets(krbctx, &salt); + if (kerr) { + goto done; + } + break; + + case KRB5_KDB_SALTTYPE_V4: + salt.length = 0; + break; + + case KRB5_KDB_SALTTYPE_AFS3: + + if (!principal->realm.data) { + kerr = EINVAL; + goto done; + } + salt.data = strndup((char *)principal->realm.data, + principal->realm.length); + if (!salt.data) { + kerr = ENOMEM; + goto done; + } + salt.length = SALT_TYPE_AFS_LENGTH; /* special value */ + break; + + default: + kerr = EINVAL; + goto done; + } + + /* need to build the key now to manage the AFS salt.length + * special case */ + kerr = krb5_c_string_to_key(krbctx, + encsalts[i].ks_enctype, + &pwd, &salt, &key); + if (kerr) { + krb5_free_data_contents(krbctx, &salt); + goto done; + } + if (salt.length == SALT_TYPE_AFS_LENGTH) { + salt.length = strlen(salt.data); + } + + kerr = krb5_c_encrypt_length(krbctx, + kmkey->enctype, key.length, &len); + if (kerr) { + krb5int_c_free_keyblock_contents(krbctx, &key); + krb5_free_data_contents(krbctx, &salt); + goto done; + } + + if ((ptr = (krb5_octet *) malloc(2 + len)) == NULL) { + kerr = ENOMEM; + krb5int_c_free_keyblock_contents(krbctx, &key); + krb5_free_data_contents(krbctx, &salt); + goto done; + } + + t = htole16(key.length); + memcpy(ptr, &t, 2); + + plain.length = key.length; + plain.data = (char *)key.contents; + + cipher.ciphertext.length = len; + cipher.ciphertext.data = (char *)ptr+2; + + kerr = krb5_c_encrypt(krbctx, kmkey, 0, 0, &plain, &cipher); + if (kerr) { + krb5int_c_free_keyblock_contents(krbctx, &key); + krb5_free_data_contents(krbctx, &salt); + free(ptr); + goto done; + } + + /* KrbSalt */ + keys[i].key_data_type[1] = encsalts[i].ks_salttype; + + if (salt.length) { + keys[i].key_data_length[1] = salt.length; + keys[i].key_data_contents[1] = (krb5_octet *)salt.data; + } + + /* EncryptionKey */ + keys[i].key_data_type[0] = key.enctype; + keys[i].key_data_length[0] = len + 2; + keys[i].key_data_contents[0] = malloc(len + 2); + if (!keys[i].key_data_contents[0]) { + kerr = ENOMEM; + krb5int_c_free_keyblock_contents(krbctx, &key); + free(ptr); + goto done; + } + memcpy(keys[i].key_data_contents[0], ptr, len + 2); + + /* make sure we free the memory used now that we are done with it */ + krb5int_c_free_keyblock_contents(krbctx, &key); + free(ptr); + } + + *_num_keys = num_keys; + *_keys = keys; + kerr = 0; + +done: + if (kerr) { + ipa_krb5_free_key_data(keys, num_keys); + } + + return kerr; +} + +void ipa_krb5_free_key_data(krb5_key_data *keys, int num_keys) +{ + int i; + + for (i = 0; i < num_keys; i++) { + /* try to wipe key from memory, + * hopefully the compiler will not optimize it away */ + if (keys[i].key_data_length[0]) { + memset(keys[i].key_data_contents[0], + 0, keys[i].key_data_length[0]); + } + free(keys[i].key_data_contents[0]); + free(keys[i].key_data_contents[1]); + } + free(keys); +} + diff --git a/util/ipa_krb5.h b/util/ipa_krb5.h index 09f492ea..0bc667a9 100644 --- a/util/ipa_krb5.h +++ b/util/ipa_krb5.h @@ -1,12 +1,25 @@ #ifndef __IPA_KRB5_H_ #define __IPA_KRB5_H_ -#include <krb5.h> +#include <krb5/krb5.h> +#include <kdb.h> void ipa_krb5_free_ktypes(krb5_context context, krb5_enctype *val); -krb5_error_code -ipa_krb5_principal2salt_norealm(krb5_context context, krb5_const_principal pr, krb5_data *ret); +krb5_error_code ipa_krb5_principal2salt_norealm(krb5_context context, + krb5_const_principal pr, + krb5_data *ret); + +krb5_error_code ipa_krb5_generate_key_data(krb5_context krbctx, + krb5_principal principal, + krb5_data pwd, int kvno, + krb5_keyblock *kmkey, + int num_encsalts, + krb5_key_salt_tuple *encsalts, + int *_num_keys, + krb5_key_data **_keys); + +void ipa_krb5_free_key_data(krb5_key_data *keys, int num_keys); #endif /* __IPA_KRB5_H_ */ |