From a98a875f0d8f1479b44d198166c9f27d5601e891 Mon Sep 17 00:00:00 2001 From: Ken Raeburn Date: Fri, 22 Sep 2006 20:29:24 +0000 Subject: [PATCH] New patch from Savitha, for new principal key storage format in LDAP git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@18606 dc483132-0cff-0310-8789-dd5450dbe970 --- src/plugins/kdb/ldap/libkdb_ldap/Makefile.in | 20 +- .../kdb/ldap/libkdb_ldap/ldap_principal2.c | 349 ++++----------- .../libkdb_ldap/princ_key_encode_decode.c | 396 ++++++++++++++++++ .../libkdb_ldap/princ_key_encode_decode.h | 9 + 4 files changed, 494 insertions(+), 280 deletions(-) create mode 100644 src/plugins/kdb/ldap/libkdb_ldap/princ_key_encode_decode.c create mode 100644 src/plugins/kdb/ldap/libkdb_ldap/princ_key_encode_decode.h diff --git a/src/plugins/kdb/ldap/libkdb_ldap/Makefile.in b/src/plugins/kdb/ldap/libkdb_ldap/Makefile.in index bbfcda054..b7d0175a5 100644 --- a/src/plugins/kdb/ldap/libkdb_ldap/Makefile.in +++ b/src/plugins/kdb/ldap/libkdb_ldap/Makefile.in @@ -18,7 +18,7 @@ DEFINES = \ -Dkrb5_dbe_update_tl_data=kdb_ldap_dbe_update_tl_data DEFS= -LOCALINCLUDES = -I$(SRCTOP)/lib/kdb +LOCALINCLUDES = -I$(SRCTOP)/lib/kdb -I$(SRCTOP)/lib/krb5/asn.1 LIBBASE=kdb_ldap LIBMAJOR=1 @@ -51,7 +51,8 @@ SRCS= $(srcdir)/kdb_ldap.c \ $(srcdir)/ldap_fetch_mkey.c \ $(srcdir)/ldap_service_stash.c \ $(srcdir)/kdb_xdr.c \ - $(srcdir)/ldap_err.c + $(srcdir)/ldap_err.c \ + $(srcdir)/princ_key_encode_decode.c STOBJLISTS=OBJS.ST STLIBOBJS= kdb_ldap.o \ @@ -70,7 +71,8 @@ STLIBOBJS= kdb_ldap.o \ ldap_fetch_mkey.o \ ldap_service_stash.o \ kdb_xdr.o \ - ldap_err.o + ldap_err.o \ + princ_key_encode_decode.o all-unix:: all-liblinks install-unix:: install-libs @@ -278,3 +280,15 @@ kdb_xdr.so kdb_xdr.po $(OUTPRE)kdb_xdr.$(OBJEXT): $(BUILDTOP)/include/autoconf.h ldap_err.so ldap_err.po $(OUTPRE)ldap_err.$(OBJEXT): \ $(BUILDTOP)/include/kdb5_err.h $(COM_ERR_DEPS) ldap_err.c \ ldap_err.h +princ_key_encode_decode.so princ_key_encode_decode.po $(OUTPRE)princ_key_encode_decode.$(OBJEXT): \ + $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \ + $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \ + $(COM_ERR_DEPS) $(SRCTOP)/include/k5-err.h $(SRCTOP)/include/k5-int.h \ + $(SRCTOP)/include/k5-platform.h $(SRCTOP)/include/k5-plugin.h \ + $(SRCTOP)/include/k5-thread.h $(SRCTOP)/include/kdb.h \ + $(SRCTOP)/include/krb5.h $(SRCTOP)/include/krb5/locate_plugin.h \ + $(SRCTOP)/include/port-sockets.h $(SRCTOP)/include/socket-utils.h \ + $(SRCTOP)/lib/krb5/asn.1/krbasn1.h $(SRCTOP)/lib/krb5/asn.1/asn1_encode.h \ + $(SRCTOP)/lib/krb5/asn.1/asn1_decode.h $(SRCTOP)/lib/krb5/asn.1/asn1_make.h \ + $(SRCTOP)/lib/krb5/asn.1/asn1_get.h \ + princ_key_encode_decode.c princ_key_encode_decode.h diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c index ff97b4095..4a85afd1e 100644 --- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c +++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c @@ -36,6 +36,7 @@ #include "ldap_tkt_policy.h" #include "ldap_pwd_policy.h" #include "ldap_err.h" +#include "princ_key_encode_decode.h" extern char* principal_attributes[]; extern char* max_pwd_life_attr[]; @@ -480,6 +481,46 @@ cleanup: return st; } +/* Decoding ASN.1 encoded key */ +static struct berval ** +krb5_encode_krbsecretkey(krb5_key_data *key_data, int n_key_data) { + struct berval **ret = NULL; + int currkvno; + int num_versions = 1; + int i, j, last; + + if (n_key_data <= 0) + return NULL; + + /* Find the number of key versions */ + for (i = 0; i < n_key_data - 1; i++) + if (key_data[i].key_data_kvno != key_data[i + 1].key_data_kvno) + num_versions++; + + ret = (struct berval **) malloc (num_versions * sizeof (struct berval *) + 1); + for (i = 0, last = 0, j = 0, currkvno = key_data[0].key_data_kvno; i < n_key_data; i++) { + krb5_data *code; + if (i == n_key_data - 1 || key_data[i + 1].key_data_kvno != currkvno) { + asn1_encode_sequence_of_keys ( + key_data+last, + (krb5_int16) i - last + 1, + 0, /* For now, mkvno == 0*/ + &code); + ret[j] = malloc (sizeof (struct berval)); + /*CHECK_NULL(ret[j]); */ + ret[j]->bv_len = code->length; + ret[j]->bv_val = code->data; + j++; + last = i + 1; + + currkvno = key_data[i].key_data_kvno; + } + } + ret[num_versions] = NULL; + + return ret; +} + krb5_error_code krb5_ldap_put_principal(context, entries, nentries, db_args) krb5_context context; @@ -498,7 +539,6 @@ krb5_ldap_put_principal(context, entries, nentries, db_args) krb5_boolean dnfound=TRUE, tktpolicy_set=FALSE; krb5_tl_data *tl_data=NULL; krb5_key_data **keys=NULL; - KEY *oldkeys=NULL; kdb5_dal_handle *dal_handle=NULL; krb5_ldap_context *ldap_context=NULL; krb5_ldap_server_handle *ldap_server_handle=NULL; @@ -532,8 +572,7 @@ krb5_ldap_put_principal(context, entries, nentries, db_args) } xargs.ptype = KDB_SERVICE_PRINCIPAL; if (((st=krb5_get_princ_type(context, entries, &(xargs.ptype))) != 0) || - ((st=krb5_get_userdn(context, entries, &(xargs.dn))) != 0) || - ((st=krb5_get_secretkeys(context, entries, &oldkeys)) != 0)) + ((st=krb5_get_userdn(context, entries, &(xargs.dn))) != 0)) goto cleanup; if ((st=process_db_args(context, db_args, &xargs)) != 0) @@ -771,140 +810,11 @@ krb5_ldap_put_principal(context, entries, nentries, db_args) int kcount=0, zero=0, salttype=0, totalkeys=0; char *currpos=NULL, *krbsecretkey=NULL; - /* delete the old keys */ - if (oldkeys) { - if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbsecretkey", LDAP_MOD_DELETE | LDAP_MOD_BVALUES, - oldkeys->keys)) != 0) - goto cleanup; - } - - bersecretkey = malloc (sizeof(struct berval *) * (entries->n_key_data + 1)); - CHECK_NULL(bersecretkey); - memset(bersecretkey, 0, sizeof(struct berval *) * (entries->n_key_data + 1)); - - keys = malloc (sizeof (krb5_key_data *) * entries->n_key_data + 1); - CHECK_NULL(keys); - memset(keys, 0, (sizeof (krb5_key_data *) * entries->n_key_data + 1)); - for (kcount=0; kcount < entries->n_key_data; ++kcount) - keys[kcount] = entries->key_data+kcount; - totalkeys = entries->n_key_data; - - kcount = 0; - while (totalkeys) { - int noofkeys=0, currkvno=0, currkvno_org=0, rlen=0; - krb5_timestamp last_pw_changed=0; - - krbsecretkey = malloc (MAX_KEY_LENGTH); - CHECK_NULL(krbsecretkey); - memset(krbsecretkey, 0, MAX_KEY_LENGTH); - currpos = krbsecretkey; - rlen = MAX_KEY_LENGTH; - - STORE16_INT(currpos, plen); /* principal len */ - currpos +=2; - rlen -=2; - - for (l=0; l < entries->n_key_data; ++l) - if (keys[l] != NULL) { - currkvno = keys[l]->key_data_kvno; - break; - } - - currkvno_org = currkvno; - STORE16_INT(currpos, currkvno); /* principal key version */ - currpos +=2; - rlen -=2; - - memset(currpos, 0, 2); /* master key version */ - currpos +=2; - rlen -=2; - - if ((st=krb5_dbe_lookup_last_pwd_change(context, entries, &last_pw_changed)) != 0) - goto cleanup; - STORE32_INT(currpos, last_pw_changed); /* last pwd change */ - currpos += 4; - rlen -=4; - - for (noofkeys=0; l < entries->n_key_data; ++l) - if (keys[l] && keys[l]->key_data_kvno == currkvno_org) - ++noofkeys; - - STORE16_INT(currpos, noofkeys); /* number of keys */ - currpos +=2; - rlen -=2; - - /* key type, key length, salt type and salt type */ - for (l=0; ln_key_data; ++l) { - if (keys[l] && keys[l]->key_data_kvno == currkvno_org) { - STORE16_INT(currpos, keys[l]->key_data_type[0]); - currpos +=2; - rlen -=2; - STORE16_INT(currpos, keys[l]->key_data_length[0]); - currpos +=2; - rlen -=2; - - STORE16_INT(currpos, keys[l]->key_data_type[1]); - currpos +=2; - rlen -=2; - salttype = keys[l]->key_data_type[1]; - if (salttype==KRB5_KDB_SALTTYPE_NOREALM || salttype==KRB5_KDB_SALTTYPE_ONLYREALM) { - STORE16_INT(currpos, zero); - } else { - STORE16_INT(currpos, keys[l]->key_data_length[1]); - } - currpos +=2; - rlen -=2; - } - } - if (plen > rlen) { - st = EINVAL; - snprintf(errbuf, sizeof(errbuf), "Insufficient buffer while storing the key of principal %s", user); - krb5_set_error_message(context, st, "%s", errbuf); - goto cleanup; - } - memcpy(currpos, user, (unsigned int)plen); /* principal name */ - currpos +=plen; - rlen -=plen; - - /* key value, salt value */ - for (l=0; ln_key_data; ++l) { - if (keys[l] && keys[l]->key_data_kvno == currkvno_org) { - if (keys[l]->key_data_length[0]) { - if (keys[l]->key_data_length[0] > rlen) { - st = EINVAL; - snprintf(errbuf, sizeof(errbuf), "Insufficient buffer while storing the key of principal %s", user); - krb5_set_error_message(context, st, "%s", errbuf); - goto cleanup; - } - memcpy(currpos, keys[l]->key_data_contents[0], keys[l]->key_data_length[0]); - currpos += keys[l]->key_data_length[0]; - rlen -= keys[l]->key_data_length[0]; - } + bersecretkey = krb5_encode_krbsecretkey (entries->key_data, + entries->n_key_data); - salttype = keys[l]->key_data_type[1]; - if (keys[l]->key_data_length[1] && (!(salttype==KRB5_KDB_SALTTYPE_NOREALM - || salttype==KRB5_KDB_SALTTYPE_ONLYREALM))) { - if (keys[l]->key_data_length[1] > rlen) { - st = EINVAL; - snprintf(errbuf, sizeof(errbuf), "Insufficient buffer while storing the key of principal %s", user); - krb5_set_error_message(context, st, "%s", errbuf); - goto cleanup; - } - memcpy(currpos, keys[l]->key_data_contents[1], keys[l]->key_data_length[1]); - currpos += keys[l]->key_data_length[1]; - rlen -= keys[l]->key_data_length[1]; - } - keys[l] = NULL; - } - } - bersecretkey[kcount] = malloc (sizeof (struct berval)); - CHECK_NULL(bersecretkey[kcount]); - bersecretkey[kcount]->bv_len = currpos - krbsecretkey; - bersecretkey[kcount++]->bv_val = krbsecretkey; - totalkeys = totalkeys - noofkeys; - } if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbsecretkey", - LDAP_MOD_ADD | LDAP_MOD_BVALUES, bersecretkey)) != 0) + LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, bersecretkey)) != 0) goto cleanup; if (!(entries->mask & KDB_PRINCIPAL)) { @@ -1032,15 +942,6 @@ cleanup: if (keys) free (keys); - if (oldkeys) { - for (l=0; l < oldkeys->nkey; ++l) { - if (oldkeys->keys[l]->bv_val) - free (oldkeys->keys[l]->bv_val); - free (oldkeys->keys[l]); - } - free (oldkeys->keys); - free (oldkeys); - } ldap_mods_free(mods, 1); krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); *nentries = i; @@ -1128,141 +1029,35 @@ krb5_decode_krbsecretkey(context, entries, bvalues, userinfo_tl_data) goto cleanup; for (i=0; bvalues[i] != NULL; ++i) { - - ptr = (char *) bvalues[i]->bv_val; - - /* check the consistency of the key */ - - if (bvalues[i]->bv_len < KEYHEADER) /* key smaller than the header size */ - continue; - - plen = PRINCIPALLEN(ptr); - if (NOOFKEYS(ptr) == 0) - continue; - - keylen = KEYHEADER + (8 * NOOFKEYS(ptr)); - if (bvalues[i]->bv_len < keylen) /* key or salt header info corrupted*/ - continue; - - keylen += plen; - if (bvalues[i]->bv_len < keylen) /* principal info corrupted */ - continue; - - for (k=0; kbv_len < keylen) /* key or salt values corrupted */ - continue; - - pname = PRINCIPALNAME(ptr); /* set pname to principalName field */ - - /* key doesn't belong to the principal */ - if (strncmp(user, pname, (unsigned) plen) != 0) - continue; - - /* Number of Principal Keys */ - noofkeys += NOOFKEYS(ptr); - - if ((st=store_tl_data(userinfo_tl_data, KDB_TL_KEYINFO, bvalues[i])) != 0) - goto cleanup; - - pkeyver = PKEYVER(ptr); /* Principal Key Version */ - mkeyver = MKEYVER(ptr); /* Master Key Version */ - - if (ist_pkeyver == 0 || pkeyver >= ist_pkeyver) { - ist_pkeyver = pkeyver; - /* last password changed */ - last_pw_changed = 0; - last_pw_changed += (ptr[6] & 0xFF) << 24; - last_pw_changed += (ptr[7] & 0xFF) << 16; - last_pw_changed += (ptr[8] & 0xFF) << 8; - last_pw_changed += (ptr[9] & 0xFF) << 0; - - if ((st=krb5_dbe_update_last_pwd_change(context, entries, - last_pw_changed)) != 0) - goto cleanup; - } - - reallocptr = key_data; - key_data = realloc(key_data, (sizeof(*key_data) * noofkeys)); - if (key_data == NULL) { - st = ENOMEM; - goto cleanup; - } - - currentkey = KEYBODY(ptr); - for (k=0; jprinc->realm.data; - key_data[j].key_data_length[1] = strlen (def_realm); - key_data[j].key_data_contents[1] = malloc (key_data[j].key_data_length[1]); - if (key_data[j].key_data_contents[1] == NULL) { - st = ENOMEM; - goto cleanup; - } - memcpy(key_data[j].key_data_contents[1], - def_realm, key_data[j].key_data_length[1]); - break; - - case KRB5_KDB_SALTTYPE_NOREALM: - memset(&norealmval, 0, sizeof(krb5_data)); - if ((st = krb5_principal2salt_norealm(context, entries->princ, - &norealmval)) != 0) { - goto cleanup; - } - - key_data[j].key_data_length[1] = norealmval.length; - key_data[j].key_data_contents[1] = (unsigned char *)norealmval.data; - break; - } - } else if (key_data[j].key_data_type[1] == KRB5_KDB_SALTTYPE_V4) { - key_data[j].key_data_contents[1] = NULL; - key_data[j].key_data_ver = 2; - } else { - key_data[j].key_data_contents[1] = NULL; - } - currentkey = currentsalt + key_data[j].key_data_length[1]; - } - entries->n_key_data = noofkeys; - entries->key_data = key_data; + int mkvno; /* Not used currently */ + krb5_int16 n_kd; + krb5_key_data *kd; + krb5_data in; + + if (bvalues[i]->bv_len == 0) + continue; + in.length = bvalues[i]->bv_len; + in.data = bvalues[i]->bv_val; + + st = asn1_decode_sequence_of_keys (&in, + &kd, + &n_kd, + &mkvno); + + if (st != 0) { + st = -1; /* Something more appropriate ? */ + goto cleanup; + } + noofkeys += n_kd; + key_data = realloc (key_data, noofkeys * sizeof (krb5_key_data)); + for (j = 0; j < n_kd; j++) + key_data[noofkeys - n_kd + j] = kd[j]; + free (kd); } + entries->n_key_data = noofkeys; + entries->key_data = key_data; + cleanup: ldap_value_free_len(bvalues); free (user); diff --git a/src/plugins/kdb/ldap/libkdb_ldap/princ_key_encode_decode.c b/src/plugins/kdb/ldap/libkdb_ldap/princ_key_encode_decode.c new file mode 100644 index 000000000..73ae1344f --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/princ_key_encode_decode.c @@ -0,0 +1,396 @@ +#include +#include + +krb5_error_code asn1_encode_sequence_of_keys (krb5_key_data *key_data, + krb5_int16 n_key_data, + krb5_int32 mkvno, /* Master key version number */ + krb5_data **code); + +krb5_error_code asn1_decode_sequence_of_keys ( krb5_data *in, + krb5_key_data **out, + krb5_int16 *n_key_data, + int *mkvno); + +#include "krbasn1.h" +#include "asn1_encode.h" +#include "asn1_decode.h" +#include "asn1_make.h" +#include "asn1_get.h" + +#define cleanup(err) \ + { \ + ret = err; \ + goto last; \ + } + +#define checkerr \ + if (ret != 0) \ + goto last + +/************************************************************************/ +/* Encode the Principal's keys */ +/************************************************************************/ + +static asn1_error_code asn1_encode_key(asn1buf *buf, + krb5_key_data key_data, + unsigned int *retlen) { + asn1_error_code ret = 0; + unsigned int length, sum = 0; + + // Encode the key type and value + { + unsigned int key_len = 0; + // key value + ret = asn1_encode_octetstring (buf, + key_data.key_data_length[0], + key_data.key_data_contents[0], + &length); checkerr; + key_len += length; + ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 1, length, &length); checkerr; + key_len += length; + // key type + ret = asn1_encode_integer (buf, key_data.key_data_type[0], &length); + checkerr; + key_len += length; + ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0, length, &length); checkerr; + key_len += length; + + ret = asn1_make_sequence(buf, key_len, &length); checkerr; + key_len += length; + ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 1, key_len, &length); checkerr; + key_len += length; + + sum += key_len; + } + // Encode the salt type and value (optional) + if (key_data.key_data_ver > 1) { + unsigned int salt_len = 0; + // salt value (optional) + if (key_data.key_data_length[1] > 0) { + ret = asn1_encode_octetstring (buf, + key_data.key_data_length[1], + key_data.key_data_contents[1], + &length); checkerr; + salt_len += length; + ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 1, length, &length); + checkerr; + salt_len += length; + } + // salt type + ret = asn1_encode_integer (buf, key_data.key_data_type[1], &length); + checkerr; + salt_len += length; + ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0, length, &length); checkerr; + salt_len += length; + + ret = asn1_make_sequence(buf, salt_len, &length); checkerr; + salt_len += length; + ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 1, salt_len, &length); checkerr; + salt_len += length; + + sum += salt_len; + } + + ret = asn1_make_sequence(buf, sum, &length); checkerr; + sum += length; + + *retlen = sum; + +last: + return ret; +} + +// Major version and minor version are both '1' - first version +//asn1_error_code asn1_encode_sequence_of_keys (krb5_key_data *key_data, +krb5_error_code asn1_encode_sequence_of_keys (krb5_key_data *key_data, + krb5_int16 n_key_data, + krb5_int32 mkvno, /* Master key version number */ + krb5_data **code) { + asn1_error_code ret = 0; + asn1buf *buf = NULL; + unsigned int length, sum = 0; + + *code = NULL; + + if(n_key_data == 0) cleanup (ASN1_MISSING_FIELD); + + // Allocate the buffer + asn1buf_create(&buf); + + // Sequence of keys + { + int i; + unsigned int seq_len = 0; + + for (i = n_key_data - 1; i >= 0; i--) { + ret = asn1_encode_key (buf, key_data[i], &length); checkerr; + seq_len += length; + } + ret = asn1_make_sequence(buf, seq_len, &length); checkerr; + seq_len += length; + ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 4, seq_len, &length); checkerr; + seq_len += length; + + sum += seq_len; + } + + // mkvno + if (mkvno < 0) + cleanup (ASN1_BAD_FORMAT); + ret = asn1_encode_unsigned_integer (buf, (unsigned int)mkvno, &length); checkerr; + sum += length; + ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 3, length, &length); checkerr; + sum += length; + + // kvno (assuming all keys in array have same version) + if (key_data[0].key_data_kvno < 0) + cleanup (ASN1_BAD_FORMAT); + ret = asn1_encode_unsigned_integer (buf, (unsigned int)key_data[0].key_data_kvno, &length); + checkerr; + sum += length; + ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 2, length, &length); checkerr; + sum += length; + + // attribute-minor-vno == 1 + ret = asn1_encode_unsigned_integer (buf, 1, &length); checkerr; + sum += length; + ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 1, length, &length); checkerr; + sum += length; + + // attribute-major-vno == 1 + ret = asn1_encode_unsigned_integer (buf, 1, &length); checkerr; + sum += length; + ret = asn1_make_etag(buf, CONTEXT_SPECIFIC, 0, length, &length); checkerr; + sum += length; + + ret = asn1_make_sequence(buf, sum, &length); checkerr; + sum += length; + + // The reverse encoding is straightened out here + ret = asn12krb5_buf (buf, code); checkerr; + +last: + asn1buf_destroy (&buf); + + if (ret != 0 && *code != NULL) + free (*code); + + return ret; +} + +/************************************************************************/ +/* Decode the Principal's keys */ +/************************************************************************/ + +#define safe_syncbuf(outer,inner) \ + if (! ((inner)->next == (inner)->bound + 1 && \ + (inner)->next == (outer)->next + buflen)) \ + cleanup (ASN1_BAD_LENGTH); \ + asn1buf_sync(outer, inner, 0, 0, 0, 0, 0); + +static asn1_error_code decode_tagged_integer (asn1buf *buf, + int expectedtag, + int *val) { + int buflen; + asn1_error_code ret = 0; + asn1buf tmp, subbuf; + taginfo t; + + // Work on a copy of 'buf' + ret = asn1buf_imbed(&tmp, buf, 0, 1); checkerr; + ret = asn1_get_tag_2(&tmp, &t); checkerr; + if (t.tagnum != expectedtag) + cleanup (ASN1_MISSING_FIELD); + + buflen = t.length; + ret = asn1buf_imbed(&subbuf, &tmp, t.length, 0); checkerr; + ret = asn1_decode_unsigned_integer(&subbuf, (long int *)val); checkerr; + + safe_syncbuf(&tmp, (&subbuf)); + *buf = tmp; + +last: + return ret; +} + +static asn1_error_code decode_tagged_octetstring (asn1buf *buf, + int expectedtag, + int *len, + asn1_octet **val) { + int buflen; + asn1_error_code ret = 0; + asn1buf tmp, subbuf; + taginfo t; + + *val = NULL; + + // Work on a copy of 'buf' + ret = asn1buf_imbed(&tmp, buf, 0, 1); checkerr; + ret = asn1_get_tag_2(&tmp, &t); checkerr; + if (t.tagnum != expectedtag) + cleanup (ASN1_MISSING_FIELD); + + buflen = t.length; + ret = asn1buf_imbed(&subbuf, &tmp, t.length, 0); checkerr; + ret = asn1_decode_octetstring (&subbuf, len, val); checkerr; + + safe_syncbuf(&tmp, (&subbuf)); + *buf = tmp; + +last: + if (ret != 0 && *val != NULL) + free (*val); + return ret; +} + +static asn1_error_code asn1_decode_key(asn1buf *buf, krb5_key_data *key) { + int buflen, seqindef; + unsigned int length; + asn1_error_code ret; + asn1buf subbuf; + taginfo t; + + key->key_data_contents[0] = NULL; + key->key_data_contents[1] = NULL; + + ret = asn1_get_sequence(buf, &length, &seqindef); checkerr; + buflen = length; + ret = asn1buf_imbed(&subbuf, buf, length, seqindef); checkerr; + + asn1_get_tag_2(&subbuf, &t); + // Salt + if (t.tagnum == 0) { + int buflen; + asn1buf slt; + + key->key_data_ver = 2; + asn1_get_sequence(&subbuf, &length, &seqindef); + buflen = length; + asn1buf_imbed(&slt, &subbuf, length, seqindef); + + ret = decode_tagged_integer (&slt, 0, (int *)&key->key_data_type[1]); + checkerr; + + ret = decode_tagged_octetstring (&slt, 1, + (int *)&key->key_data_length[1], + &key->key_data_contents[1]); checkerr; + + safe_syncbuf ((&subbuf), (&slt)); + + ret = asn1_get_tag_2(&subbuf, &t); checkerr; + } else + key->key_data_ver = 1; + + // Key + { + int buflen; + asn1buf kbuf; + if (t.tagnum != 1) + cleanup (ASN1_MISSING_FIELD); + + ret = asn1_get_sequence(&subbuf, &length, &seqindef); checkerr; + buflen = length; + ret = asn1buf_imbed(&kbuf, &subbuf, length, seqindef); checkerr; + + ret = decode_tagged_integer (&kbuf, 0, (int *)&key->key_data_type[0]); + checkerr; + + ret = decode_tagged_octetstring (&kbuf, 1, + (int *)&key->key_data_length[0], + &key->key_data_contents[0]); checkerr; + + safe_syncbuf (&subbuf, &kbuf); + } + + safe_syncbuf (buf, &subbuf); + +last: + if (ret != 0) { + if (key->key_data_contents[0] != NULL) { + free (key->key_data_contents[0]); + key->key_data_contents[0] = NULL; + } + if (key->key_data_contents[1] != NULL) { + free (key->key_data_contents[1]); + key->key_data_contents[1] = NULL; + } + } + return ret; +} + +//asn1_error_code asn1_decode_sequence_of_keys ( krb5_data *in, +krb5_error_code asn1_decode_sequence_of_keys ( krb5_data *in, + krb5_key_data **out, + krb5_int16 *n_key_data, + int *mkvno) { + asn1_error_code ret; + asn1buf buf, subbuf; \ + int seqindef; + unsigned int length; + taginfo t; + int kvno, maj, min; + + *n_key_data = 0; + *out = NULL; + + ret = asn1buf_wrap_data(&buf, in); checkerr; + + ret = asn1_get_sequence(&buf, &length, &seqindef); checkerr; + ret = asn1buf_imbed(&subbuf, &buf, length, seqindef); checkerr; + + // attribute-major-vno + ret = decode_tagged_integer (&subbuf, 0, &maj); checkerr; + + // attribute-minor-vno + ret = decode_tagged_integer (&subbuf, 1, &min); checkerr; + + if (maj != 1 || min != 1) + cleanup (ASN1_BAD_FORMAT); + + // kvno (assuming all keys in array have same version) + ret = decode_tagged_integer (&subbuf, 2, &kvno); checkerr; + + // mkvno (optional) + ret = decode_tagged_integer (&subbuf, 3, mkvno); checkerr; + + ret = asn1_get_tag_2(&subbuf, &t); checkerr; + + // Sequence of keys + { + int i, ret1, buflen; + asn1buf keyseq; + if (t.tagnum != 4) + cleanup (ASN1_MISSING_FIELD); + ret = asn1_get_sequence(&subbuf, &length, &seqindef); checkerr; + buflen = length; + ret = asn1buf_imbed(&keyseq, &subbuf, length, seqindef); checkerr; + for (i = 1, *out = NULL; ; i++) { + krb5_key_data *tmp; + tmp = (krb5_key_data *) realloc (*out, i * sizeof (krb5_key_data)); + if (tmp == NULL) + cleanup (ENOMEM); + *out = tmp; + (*out)[i - 1].key_data_kvno = kvno; + ret1 = asn1_decode_key(&keyseq, &(*out)[i - 1]); checkerr; + (*n_key_data)++; + if (asn1buf_remains(&keyseq, 0) == 0) + break; // Not freeing the last key structure + } + safe_syncbuf (&subbuf, &keyseq); + } + +last: + if (ret != 0) { + int i; + for (i = 0; i < *n_key_data; i++) { + if ((*out)[i].key_data_contents[0] != NULL) + free ((*out)[i].key_data_contents[0]); + if ((*out)[i].key_data_contents[1] != NULL) + free ((*out)[i].key_data_contents[1]); + } + free (*out); + *out = NULL; + } + + return ret; +} diff --git a/src/plugins/kdb/ldap/libkdb_ldap/princ_key_encode_decode.h b/src/plugins/kdb/ldap/libkdb_ldap/princ_key_encode_decode.h new file mode 100644 index 000000000..9851d002c --- /dev/null +++ b/src/plugins/kdb/ldap/libkdb_ldap/princ_key_encode_decode.h @@ -0,0 +1,9 @@ +krb5_error_code asn1_encode_sequence_of_keys (krb5_key_data *key_data, + krb5_int16 n_key_data, + krb5_int32 mkvno, + krb5_data **code); + +krb5_error_code asn1_decode_sequence_of_keys (krb5_data *in, + krb5_key_data **out, + krb5_int16 *n_key_data, + int *mkvno); -- 2.26.2