mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Move some krb5 keys related functions from ipa-client to util
This commit is contained in:
@@ -41,30 +41,6 @@
|
|||||||
#include "ipa_krb5.h"
|
#include "ipa_krb5.h"
|
||||||
#include "ipa-client-common.h"
|
#include "ipa-client-common.h"
|
||||||
|
|
||||||
/* Salt types */
|
|
||||||
#define NO_SALT -1
|
|
||||||
#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 KEYTAB_SET_OID "2.16.840.1.113730.3.8.10.1"
|
|
||||||
#define KEYTAB_RET_OID "2.16.840.1.113730.3.8.10.2"
|
|
||||||
|
|
||||||
struct krb_key_salt {
|
|
||||||
krb5_enctype enctype;
|
|
||||||
krb5_int32 salttype;
|
|
||||||
krb5_keyblock key;
|
|
||||||
krb5_data salt;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct keys_container {
|
|
||||||
krb5_int32 nkeys;
|
|
||||||
struct krb_key_salt *ksdata;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int ldap_sasl_interact(LDAP *ld, unsigned flags, void *priv_data, void *sit)
|
static int ldap_sasl_interact(LDAP *ld, unsigned flags, void *priv_data, void *sit)
|
||||||
{
|
{
|
||||||
sasl_interact_t *in = NULL;
|
sasl_interact_t *in = NULL;
|
||||||
@@ -122,357 +98,6 @@ static int ldap_sasl_interact(LDAP *ld, unsigned flags, void *priv_data, void *s
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_keys_contents(krb5_context krbctx, struct keys_container *keys)
|
|
||||||
{
|
|
||||||
struct krb_key_salt *ksdata;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
ksdata = keys->ksdata;
|
|
||||||
for (i = 0; i < keys->nkeys; i++) {
|
|
||||||
krb5_free_keyblock_contents(krbctx, &ksdata[i].key);
|
|
||||||
krb5_free_data_contents(krbctx, &ksdata[i].salt);
|
|
||||||
}
|
|
||||||
free(ksdata);
|
|
||||||
|
|
||||||
keys->ksdata = NULL;
|
|
||||||
keys->nkeys = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Determines Encryption and Salt types,
|
|
||||||
* allocates key_salt data storage,
|
|
||||||
* filters out equivalent encodings,
|
|
||||||
* returns 0 if no enctypes available, >0 if enctypes are available */
|
|
||||||
static int prep_ksdata(krb5_context krbctx, const char *str,
|
|
||||||
struct keys_container *keys)
|
|
||||||
{
|
|
||||||
struct krb_key_salt *ksdata;
|
|
||||||
krb5_error_code krberr;
|
|
||||||
int n, i, j, nkeys;
|
|
||||||
|
|
||||||
if (str == NULL) {
|
|
||||||
krb5_enctype *ktypes;
|
|
||||||
|
|
||||||
krberr = krb5_get_permitted_enctypes(krbctx, &ktypes);
|
|
||||||
if (krberr) {
|
|
||||||
fprintf(stderr, _("No system preferred enctypes ?!\n"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (n = 0; ktypes[n]; n++) /* count */ ;
|
|
||||||
|
|
||||||
ksdata = calloc(n + 1, sizeof(struct krb_key_salt));
|
|
||||||
if (NULL == ksdata) {
|
|
||||||
fprintf(stderr, _("Out of memory!?\n"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
ksdata[i].enctype = ktypes[i];
|
|
||||||
ksdata[i].salttype = KRB5_KDB_SALTTYPE_NORMAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ipa_krb5_free_ktypes(krbctx, ktypes);
|
|
||||||
|
|
||||||
nkeys = i;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
char *tmp, *t, *p, *q;
|
|
||||||
|
|
||||||
t = tmp = strdup(str);
|
|
||||||
if (!tmp) {
|
|
||||||
fprintf(stderr, _("Out of memory\n"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* count */
|
|
||||||
n = 0;
|
|
||||||
while ((p = strchr(t, ','))) {
|
|
||||||
t = p+1;
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
n++; /* count the last one that is 0 terminated instead */
|
|
||||||
|
|
||||||
/* at the end we will have at most n entries + 1 terminating */
|
|
||||||
ksdata = calloc(n + 1, sizeof(struct krb_key_salt));
|
|
||||||
if (!ksdata) {
|
|
||||||
fprintf(stderr, _("Out of memory\n"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0, j = 0, t = tmp; i < n; i++) {
|
|
||||||
|
|
||||||
p = strchr(t, ',');
|
|
||||||
if (p) *p = '\0';
|
|
||||||
|
|
||||||
q = strchr(t, ':');
|
|
||||||
if (q) *q++ = '\0';
|
|
||||||
|
|
||||||
krberr = krb5_string_to_enctype(t, &ksdata[j].enctype);
|
|
||||||
if (krberr != 0) {
|
|
||||||
fprintf(stderr,
|
|
||||||
_("Warning unrecognized encryption type: [%s]\n"), t);
|
|
||||||
if (p) t = p + 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (p) t = p + 1;
|
|
||||||
|
|
||||||
if (!q) {
|
|
||||||
ksdata[j].salttype = KRB5_KDB_SALTTYPE_NORMAL;
|
|
||||||
j++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
krberr = krb5_string_to_salttype(q, &ksdata[j].salttype);
|
|
||||||
if (krberr != 0) {
|
|
||||||
fprintf(stderr,
|
|
||||||
_("Warning unrecognized salt type: [%s]\n"), q);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
j++;
|
|
||||||
}
|
|
||||||
|
|
||||||
nkeys = j;
|
|
||||||
|
|
||||||
free(tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check we don't already have a key with a similar encoding,
|
|
||||||
* it would just produce redundant data and this is what the
|
|
||||||
* MIT code do anyway */
|
|
||||||
|
|
||||||
for (i = 0, n = 0; i < nkeys; i++ ) {
|
|
||||||
krb5_boolean similar = 0;
|
|
||||||
|
|
||||||
for (j = 0; j < i; j++) {
|
|
||||||
krberr = krb5_c_enctype_compare(krbctx,
|
|
||||||
ksdata[j].enctype,
|
|
||||||
ksdata[i].enctype,
|
|
||||||
&similar);
|
|
||||||
if (krberr) {
|
|
||||||
free_keys_contents(krbctx, keys);
|
|
||||||
free(ksdata);
|
|
||||||
fprintf(stderr, _("Enctype comparison failed!\n"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (similar &&
|
|
||||||
(ksdata[j].salttype == ksdata[i].salttype)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (j < i) {
|
|
||||||
/* redundant encoding, remove it, and shift others */
|
|
||||||
int x;
|
|
||||||
for (x = i; x < nkeys-1; x++) {
|
|
||||||
ksdata[x].enctype = ksdata[x+1].enctype;
|
|
||||||
ksdata[x].salttype = ksdata[x+1].salttype;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* count only confirmed enc/salt tuples */
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
|
|
||||||
keys->nkeys = n;
|
|
||||||
keys->ksdata = ksdata;
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int create_keys(krb5_context krbctx,
|
|
||||||
krb5_principal princ,
|
|
||||||
char *password,
|
|
||||||
const char *enctypes_string,
|
|
||||||
struct keys_container *keys)
|
|
||||||
{
|
|
||||||
struct krb_key_salt *ksdata;
|
|
||||||
krb5_error_code krberr;
|
|
||||||
krb5_data key_password;
|
|
||||||
krb5_data *realm = NULL;
|
|
||||||
int i, nkeys;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = prep_ksdata(krbctx, enctypes_string, keys);
|
|
||||||
if (ret == 0) return 0;
|
|
||||||
|
|
||||||
ksdata = keys->ksdata;
|
|
||||||
nkeys = keys->nkeys;
|
|
||||||
|
|
||||||
if (password) {
|
|
||||||
key_password.data = password;
|
|
||||||
key_password.length = strlen(password);
|
|
||||||
|
|
||||||
realm = krb5_princ_realm(krbctx, princ);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < nkeys; i++) {
|
|
||||||
krb5_data *salt;
|
|
||||||
|
|
||||||
if (!password) {
|
|
||||||
/* cool, random keys */
|
|
||||||
krberr = krb5_c_make_random_key(krbctx,
|
|
||||||
ksdata[i].enctype,
|
|
||||||
&ksdata[i].key);
|
|
||||||
if (krberr) {
|
|
||||||
fprintf(stderr, _("Failed to create random key!\n"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* set the salt to NO_SALT as the key was random */
|
|
||||||
ksdata[i].salttype = NO_SALT;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make keys using password and required salt */
|
|
||||||
switch (ksdata[i].salttype) {
|
|
||||||
case KRB5_KDB_SALTTYPE_ONLYREALM:
|
|
||||||
krberr = krb5_copy_data(krbctx, realm, &salt);
|
|
||||||
if (krberr) {
|
|
||||||
fprintf(stderr, _("Failed to create key!\n"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ksdata[i].salt.length = salt->length;
|
|
||||||
ksdata[i].salt.data = malloc(salt->length);
|
|
||||||
if (!ksdata[i].salt.data) {
|
|
||||||
fprintf(stderr, _("Out of memory!\n"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
memcpy(ksdata[i].salt.data, salt->data, salt->length);
|
|
||||||
krb5_free_data(krbctx, salt);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KRB5_KDB_SALTTYPE_NOREALM:
|
|
||||||
krberr = ipa_krb5_principal2salt_norealm(krbctx, princ, &ksdata[i].salt);
|
|
||||||
if (krberr) {
|
|
||||||
fprintf(stderr, _("Failed to create key!\n"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KRB5_KDB_SALTTYPE_NORMAL:
|
|
||||||
krberr = krb5_principal2salt(krbctx, princ, &ksdata[i].salt);
|
|
||||||
if (krberr) {
|
|
||||||
fprintf(stderr, _("Failed to create key!\n"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* no KRB5_KDB_SALTTYPE_V4, we do not support krb v4 */
|
|
||||||
|
|
||||||
case KRB5_KDB_SALTTYPE_AFS3:
|
|
||||||
/* Comment from MIT sources:
|
|
||||||
* * Why do we do this? Well, the afs_mit_string_to_key
|
|
||||||
* * needs to use strlen, and the realm is not NULL
|
|
||||||
* * terminated....
|
|
||||||
*/
|
|
||||||
ksdata[i].salt.data = (char *)malloc(realm->length + 1);
|
|
||||||
if (NULL == ksdata[i].salt.data) {
|
|
||||||
fprintf(stderr, _("Out of memory!\n"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
memcpy((char *)ksdata[i].salt.data,
|
|
||||||
(char *)realm->data, realm->length);
|
|
||||||
ksdata[i].salt.data[realm->length] = '\0';
|
|
||||||
/* AFS uses a special length (UGLY) */
|
|
||||||
ksdata[i].salt.length = SALT_TYPE_AFS_LENGTH;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
fprintf(stderr, _("Bad or unsupported salt type (%d)!\n"),
|
|
||||||
ksdata[i].salttype);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
krberr = krb5_c_string_to_key(krbctx,
|
|
||||||
ksdata[i].enctype,
|
|
||||||
&key_password,
|
|
||||||
&ksdata[i].salt,
|
|
||||||
&ksdata[i].key);
|
|
||||||
if (krberr) {
|
|
||||||
fprintf(stderr, _("Failed to create key!\n"));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set back salt length to real value if AFS3 */
|
|
||||||
if (ksdata[i].salttype == KRB5_KDB_SALTTYPE_AFS3) {
|
|
||||||
ksdata[i].salt.length = realm->length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nkeys;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct berval *create_key_control(struct keys_container *keys,
|
|
||||||
const char *principalName)
|
|
||||||
{
|
|
||||||
struct krb_key_salt *ksdata;
|
|
||||||
struct berval *bval;
|
|
||||||
BerElement *be;
|
|
||||||
int ret, i;
|
|
||||||
|
|
||||||
be = ber_alloc_t(LBER_USE_DER);
|
|
||||||
if (!be) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = ber_printf(be, "{s{", principalName);
|
|
||||||
if (ret == -1) {
|
|
||||||
ber_free(be, 1);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ksdata = keys->ksdata;
|
|
||||||
for (i = 0; i < keys->nkeys; i++) {
|
|
||||||
|
|
||||||
/* we set only the EncryptionKey and salt, no s2kparams */
|
|
||||||
|
|
||||||
ret = ber_printf(be, "{t[{t[i]t[o]}]",
|
|
||||||
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 0),
|
|
||||||
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 0),
|
|
||||||
(ber_int_t)ksdata[i].enctype,
|
|
||||||
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 1),
|
|
||||||
(char *)ksdata[i].key.contents, (ber_len_t)ksdata[i].key.length);
|
|
||||||
|
|
||||||
if (ret == -1) {
|
|
||||||
ber_free(be, 1);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ksdata[i].salttype == NO_SALT) {
|
|
||||||
ret = ber_printf(be, "}");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we have to pass a salt structure */
|
|
||||||
ret = ber_printf(be, "t[{t[i]t[o]}]}",
|
|
||||||
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 1),
|
|
||||||
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 0),
|
|
||||||
(ber_int_t)ksdata[i].salttype,
|
|
||||||
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 1),
|
|
||||||
(char *)ksdata[i].salt.data, (ber_len_t)ksdata[i].salt.length);
|
|
||||||
|
|
||||||
if (ret == -1) {
|
|
||||||
ber_free(be, 1);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = ber_printf(be, "}}");
|
|
||||||
if (ret == -1) {
|
|
||||||
ber_free(be, 1);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = ber_flatten(be, &bval);
|
|
||||||
if (ret == -1) {
|
|
||||||
ber_free(be, 1);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ber_free(be, 1);
|
|
||||||
return bval;
|
|
||||||
}
|
|
||||||
|
|
||||||
int filter_keys(krb5_context krbctx, struct keys_container *keys,
|
int filter_keys(krb5_context krbctx, struct keys_container *keys,
|
||||||
ber_int_t *enctypes)
|
ber_int_t *enctypes)
|
||||||
{
|
{
|
||||||
@@ -854,6 +479,7 @@ int main(int argc, const char *argv[])
|
|||||||
krb5_keytab kt;
|
krb5_keytab kt;
|
||||||
int kvno;
|
int kvno;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
char *err_msg;
|
||||||
|
|
||||||
ret = init_gettext();
|
ret = init_gettext();
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@@ -955,8 +581,11 @@ int main(int argc, const char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* create key material */
|
/* create key material */
|
||||||
ret = create_keys(krbctx, sprinc, password, enctypes_string, &keys);
|
ret = create_keys(krbctx, sprinc, password, enctypes_string, &keys, &err_msg);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
|
if (err_msg != NULL) {
|
||||||
|
fprintf(stderr, "%s", err_msg);
|
||||||
|
}
|
||||||
fprintf(stderr, _("Failed to create key material\n"));
|
fprintf(stderr, _("Failed to create key material\n"));
|
||||||
exit(8);
|
exit(8);
|
||||||
}
|
}
|
||||||
|
|||||||
362
util/ipa_krb5.c
362
util/ipa_krb5.c
@@ -26,6 +26,9 @@
|
|||||||
#include <lber.h>
|
#include <lber.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <libintl.h>
|
||||||
|
#define _(STRING) gettext(STRING)
|
||||||
|
|
||||||
#include "ipa_krb5.h"
|
#include "ipa_krb5.h"
|
||||||
|
|
||||||
/* Salt types */
|
/* Salt types */
|
||||||
@@ -530,3 +533,362 @@ krb5_error_code filter_key_salt_tuples(krb5_context context,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct berval *create_key_control(struct keys_container *keys,
|
||||||
|
const char *principalName)
|
||||||
|
{
|
||||||
|
struct krb_key_salt *ksdata;
|
||||||
|
struct berval *bval;
|
||||||
|
BerElement *be;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
be = ber_alloc_t(LBER_USE_DER);
|
||||||
|
if (!be) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ber_printf(be, "{s{", principalName);
|
||||||
|
if (ret == -1) {
|
||||||
|
ber_free(be, 1);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ksdata = keys->ksdata;
|
||||||
|
for (i = 0; i < keys->nkeys; i++) {
|
||||||
|
|
||||||
|
/* we set only the EncryptionKey and salt, no s2kparams */
|
||||||
|
|
||||||
|
ret = ber_printf(be, "{t[{t[i]t[o]}]",
|
||||||
|
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 0),
|
||||||
|
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 0),
|
||||||
|
(ber_int_t)ksdata[i].enctype,
|
||||||
|
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 1),
|
||||||
|
(char *)ksdata[i].key.contents, (ber_len_t)ksdata[i].key.length);
|
||||||
|
|
||||||
|
if (ret == -1) {
|
||||||
|
ber_free(be, 1);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ksdata[i].salttype == NO_SALT) {
|
||||||
|
ret = ber_printf(be, "}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we have to pass a salt structure */
|
||||||
|
ret = ber_printf(be, "t[{t[i]t[o]}]}",
|
||||||
|
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 1),
|
||||||
|
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 0),
|
||||||
|
(ber_int_t)ksdata[i].salttype,
|
||||||
|
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 1),
|
||||||
|
(char *)ksdata[i].salt.data, (ber_len_t)ksdata[i].salt.length);
|
||||||
|
|
||||||
|
if (ret == -1) {
|
||||||
|
ber_free(be, 1);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ber_printf(be, "}}");
|
||||||
|
if (ret == -1) {
|
||||||
|
ber_free(be, 1);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ber_flatten(be, &bval);
|
||||||
|
if (ret == -1) {
|
||||||
|
ber_free(be, 1);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ber_free(be, 1);
|
||||||
|
return bval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_keys_contents(krb5_context krbctx, struct keys_container *keys)
|
||||||
|
{
|
||||||
|
struct krb_key_salt *ksdata;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ksdata = keys->ksdata;
|
||||||
|
for (i = 0; i < keys->nkeys; i++) {
|
||||||
|
krb5_free_keyblock_contents(krbctx, &ksdata[i].key);
|
||||||
|
krb5_free_data_contents(krbctx, &ksdata[i].salt);
|
||||||
|
}
|
||||||
|
free(ksdata);
|
||||||
|
|
||||||
|
keys->ksdata = NULL;
|
||||||
|
keys->nkeys = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determines Encryption and Salt types,
|
||||||
|
* allocates key_salt data storage,
|
||||||
|
* filters out equivalent encodings,
|
||||||
|
* returns 0 if no enctypes available, >0 if enctypes are available */
|
||||||
|
static int prep_ksdata(krb5_context krbctx, const char *str,
|
||||||
|
struct keys_container *keys,
|
||||||
|
char **err_msg)
|
||||||
|
{
|
||||||
|
struct krb_key_salt *ksdata;
|
||||||
|
krb5_error_code krberr;
|
||||||
|
int n, i, j, nkeys;
|
||||||
|
|
||||||
|
*err_msg = NULL;
|
||||||
|
|
||||||
|
if (str == NULL) {
|
||||||
|
krb5_enctype *ktypes;
|
||||||
|
|
||||||
|
krberr = krb5_get_permitted_enctypes(krbctx, &ktypes);
|
||||||
|
if (krberr) {
|
||||||
|
*err_msg = _("No system preferred enctypes ?!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (n = 0; ktypes[n]; n++) /* count */ ;
|
||||||
|
|
||||||
|
ksdata = calloc(n + 1, sizeof(struct krb_key_salt));
|
||||||
|
if (NULL == ksdata) {
|
||||||
|
*err_msg = _("Out of memory!?\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
ksdata[i].enctype = ktypes[i];
|
||||||
|
ksdata[i].salttype = KRB5_KDB_SALTTYPE_NORMAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ipa_krb5_free_ktypes(krbctx, ktypes);
|
||||||
|
|
||||||
|
nkeys = i;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
char *tmp, *t, *p, *q;
|
||||||
|
|
||||||
|
t = tmp = strdup(str);
|
||||||
|
if (!tmp) {
|
||||||
|
*err_msg = _("Out of memory\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* count */
|
||||||
|
n = 0;
|
||||||
|
while ((p = strchr(t, ','))) {
|
||||||
|
t = p+1;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
n++; /* count the last one that is 0 terminated instead */
|
||||||
|
|
||||||
|
/* at the end we will have at most n entries + 1 terminating */
|
||||||
|
ksdata = calloc(n + 1, sizeof(struct krb_key_salt));
|
||||||
|
if (!ksdata) {
|
||||||
|
*err_msg = _("Out of memory\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0, j = 0, t = tmp; i < n; i++) {
|
||||||
|
|
||||||
|
p = strchr(t, ',');
|
||||||
|
if (p) *p = '\0';
|
||||||
|
|
||||||
|
q = strchr(t, ':');
|
||||||
|
if (q) *q++ = '\0';
|
||||||
|
|
||||||
|
krberr = krb5_string_to_enctype(t, &ksdata[j].enctype);
|
||||||
|
if (krberr != 0) {
|
||||||
|
*err_msg = _("Warning unrecognized encryption type.\n");
|
||||||
|
if (p) t = p + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (p) t = p + 1;
|
||||||
|
|
||||||
|
if (!q) {
|
||||||
|
ksdata[j].salttype = KRB5_KDB_SALTTYPE_NORMAL;
|
||||||
|
j++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
krberr = krb5_string_to_salttype(q, &ksdata[j].salttype);
|
||||||
|
if (krberr != 0) {
|
||||||
|
*err_msg = _("Warning unrecognized salt type.\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
nkeys = j;
|
||||||
|
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check we don't already have a key with a similar encoding,
|
||||||
|
* it would just produce redundant data and this is what the
|
||||||
|
* MIT code do anyway */
|
||||||
|
|
||||||
|
for (i = 0, n = 0; i < nkeys; i++ ) {
|
||||||
|
krb5_boolean similar = 0;
|
||||||
|
|
||||||
|
for (j = 0; j < i; j++) {
|
||||||
|
krberr = krb5_c_enctype_compare(krbctx,
|
||||||
|
ksdata[j].enctype,
|
||||||
|
ksdata[i].enctype,
|
||||||
|
&similar);
|
||||||
|
if (krberr) {
|
||||||
|
free_keys_contents(krbctx, keys);
|
||||||
|
free(ksdata);
|
||||||
|
*err_msg = _("Enctype comparison failed!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (similar &&
|
||||||
|
(ksdata[j].salttype == ksdata[i].salttype)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j < i) {
|
||||||
|
/* redundant encoding, remove it, and shift others */
|
||||||
|
int x;
|
||||||
|
for (x = i; x < nkeys-1; x++) {
|
||||||
|
ksdata[x].enctype = ksdata[x+1].enctype;
|
||||||
|
ksdata[x].salttype = ksdata[x+1].salttype;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* count only confirmed enc/salt tuples */
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
keys->nkeys = n;
|
||||||
|
keys->ksdata = ksdata;
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int create_keys(krb5_context krbctx,
|
||||||
|
krb5_principal princ,
|
||||||
|
char *password,
|
||||||
|
const char *enctypes_string,
|
||||||
|
struct keys_container *keys,
|
||||||
|
char **err_msg)
|
||||||
|
{
|
||||||
|
struct krb_key_salt *ksdata;
|
||||||
|
krb5_error_code krberr;
|
||||||
|
krb5_data key_password;
|
||||||
|
krb5_data *realm = NULL;
|
||||||
|
int i, nkeys;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
*err_msg = NULL;
|
||||||
|
|
||||||
|
ret = prep_ksdata(krbctx, enctypes_string, keys, err_msg);
|
||||||
|
if (ret == 0) return 0;
|
||||||
|
|
||||||
|
ksdata = keys->ksdata;
|
||||||
|
nkeys = keys->nkeys;
|
||||||
|
|
||||||
|
if (password) {
|
||||||
|
key_password.data = password;
|
||||||
|
key_password.length = strlen(password);
|
||||||
|
|
||||||
|
realm = krb5_princ_realm(krbctx, princ);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < nkeys; i++) {
|
||||||
|
krb5_data *salt;
|
||||||
|
|
||||||
|
if (!password) {
|
||||||
|
/* cool, random keys */
|
||||||
|
krberr = krb5_c_make_random_key(krbctx,
|
||||||
|
ksdata[i].enctype,
|
||||||
|
&ksdata[i].key);
|
||||||
|
if (krberr) {
|
||||||
|
*err_msg = _("Failed to create random key!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* set the salt to NO_SALT as the key was random */
|
||||||
|
ksdata[i].salttype = NO_SALT;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make keys using password and required salt */
|
||||||
|
switch (ksdata[i].salttype) {
|
||||||
|
case KRB5_KDB_SALTTYPE_ONLYREALM:
|
||||||
|
krberr = krb5_copy_data(krbctx, realm, &salt);
|
||||||
|
if (krberr) {
|
||||||
|
*err_msg = _("Failed to create key!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ksdata[i].salt.length = salt->length;
|
||||||
|
ksdata[i].salt.data = malloc(salt->length);
|
||||||
|
if (!ksdata[i].salt.data) {
|
||||||
|
*err_msg = _("Out of memory!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memcpy(ksdata[i].salt.data, salt->data, salt->length);
|
||||||
|
krb5_free_data(krbctx, salt);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KRB5_KDB_SALTTYPE_NOREALM:
|
||||||
|
krberr = ipa_krb5_principal2salt_norealm(krbctx, princ,
|
||||||
|
&ksdata[i].salt);
|
||||||
|
if (krberr) {
|
||||||
|
*err_msg = _("Failed to create key!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KRB5_KDB_SALTTYPE_NORMAL:
|
||||||
|
krberr = krb5_principal2salt(krbctx, princ, &ksdata[i].salt);
|
||||||
|
if (krberr) {
|
||||||
|
*err_msg = _("Failed to create key!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* no KRB5_KDB_SALTTYPE_V4, we do not support krb v4 */
|
||||||
|
|
||||||
|
case KRB5_KDB_SALTTYPE_AFS3:
|
||||||
|
/* Comment from MIT sources:
|
||||||
|
* * Why do we do this? Well, the afs_mit_string_to_key
|
||||||
|
* * needs to use strlen, and the realm is not NULL
|
||||||
|
* * terminated....
|
||||||
|
*/
|
||||||
|
ksdata[i].salt.data = (char *)malloc(realm->length + 1);
|
||||||
|
if (NULL == ksdata[i].salt.data) {
|
||||||
|
*err_msg = _("Out of memory!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memcpy((char *)ksdata[i].salt.data,
|
||||||
|
(char *)realm->data, realm->length);
|
||||||
|
ksdata[i].salt.data[realm->length] = '\0';
|
||||||
|
/* AFS uses a special length (UGLY) */
|
||||||
|
ksdata[i].salt.length = SALT_TYPE_AFS_LENGTH;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
*err_msg = _("Bad or unsupported salt type.\n");
|
||||||
|
/* FIXME:
|
||||||
|
fprintf(stderr, _("Bad or unsupported salt type (%d)!\n"),
|
||||||
|
ksdata[i].salttype);
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
krberr = krb5_c_string_to_key(krbctx,
|
||||||
|
ksdata[i].enctype,
|
||||||
|
&key_password,
|
||||||
|
&ksdata[i].salt,
|
||||||
|
&ksdata[i].key);
|
||||||
|
if (krberr) {
|
||||||
|
*err_msg = _("Failed to create key!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set back salt length to real value if AFS3 */
|
||||||
|
if (ksdata[i].salttype == KRB5_KDB_SALTTYPE_AFS3) {
|
||||||
|
ksdata[i].salt.length = realm->length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nkeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,30 @@
|
|||||||
#include <krb5/krb5.h>
|
#include <krb5/krb5.h>
|
||||||
#include <kdb.h>
|
#include <kdb.h>
|
||||||
|
|
||||||
|
struct krb_key_salt {
|
||||||
|
krb5_enctype enctype;
|
||||||
|
krb5_int32 salttype;
|
||||||
|
krb5_keyblock key;
|
||||||
|
krb5_data salt;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct keys_container {
|
||||||
|
krb5_int32 nkeys;
|
||||||
|
struct krb_key_salt *ksdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Salt types */
|
||||||
|
#define NO_SALT -1
|
||||||
|
#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 KEYTAB_SET_OID "2.16.840.1.113730.3.8.10.1"
|
||||||
|
#define KEYTAB_RET_OID "2.16.840.1.113730.3.8.10.2"
|
||||||
|
|
||||||
void
|
void
|
||||||
ipa_krb5_free_ktypes(krb5_context context, krb5_enctype *val);
|
ipa_krb5_free_ktypes(krb5_context context, krb5_enctype *val);
|
||||||
|
|
||||||
@@ -36,4 +60,16 @@ krb5_error_code filter_key_salt_tuples(krb5_context context,
|
|||||||
krb5_key_salt_tuple *req, int n_req,
|
krb5_key_salt_tuple *req, int n_req,
|
||||||
krb5_key_salt_tuple *supp, int n_supp,
|
krb5_key_salt_tuple *supp, int n_supp,
|
||||||
krb5_key_salt_tuple **res, int *n_res);
|
krb5_key_salt_tuple **res, int *n_res);
|
||||||
|
|
||||||
|
void free_keys_contents(krb5_context krbctx, struct keys_container *keys);
|
||||||
|
|
||||||
|
struct berval *create_key_control(struct keys_container *keys,
|
||||||
|
const char *principalName);
|
||||||
|
|
||||||
|
int create_keys(krb5_context krbctx,
|
||||||
|
krb5_principal princ,
|
||||||
|
char *password,
|
||||||
|
const char *enctypes_string,
|
||||||
|
struct keys_container *keys,
|
||||||
|
char **err_msg);
|
||||||
#endif /* __IPA_KRB5_H_ */
|
#endif /* __IPA_KRB5_H_ */
|
||||||
|
|||||||
Reference in New Issue
Block a user