summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--daemons/ipa-slapi-plugins/ipa-pwd-extop/ipapwd_encoding.c211
-rw-r--r--util/ipa_krb5.c221
-rw-r--r--util/ipa_krb5.h19
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 3ce396099..a1b0e99f5 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 5765087c9..b75da1e25 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 09f492ea1..0bc667a93 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_ */