mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
ipa-pwd-extop: Move encryption of keys in common
This way we can reuse the same code from ipa-kdb later
This commit is contained in:
parent
b4aab3d98d
commit
4928229093
@ -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");
|
||||
|
221
util/ipa_krb5.c
221
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);
|
||||
}
|
||||
|
||||
|
@ -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_ */
|
||||
|
Loading…
Reference in New Issue
Block a user