-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
$(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 \
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
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
#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[];
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;
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;
}
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)
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; l<entries->n_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; l<entries->n_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)) {
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;
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; k<NOOFKEYS(ptr); ++k)
- keylen += KEYLENGTH(ptr, k) + SALTLENGTH(ptr, k);
-
- if (bvalues[i]->bv_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; j<noofkeys; ++k, ++j) {
-
- key_data[j].key_data_ver = 1;
- key_data[j].key_data_kvno = pkeyver;
-
- key_data[j].key_data_type[0] = KEYTYPE(ptr,k); /* get key type */
- key_data[j].key_data_length[0] = KEYLENGTH(ptr,k); /* get key length */
- key_data[j].key_data_type[1] = SALTTYPE(ptr,k); /* get salt type */
- key_data[j].key_data_length[1] = SALTLENGTH(ptr,k); /* get salt length */
-
- key_data[j].key_data_contents[0] = malloc(key_data[j].key_data_length[0]);
- if (key_data[j].key_data_contents[0] == NULL) {
- st = ENOMEM;
- goto cleanup;
- }
- memcpy(key_data[j].key_data_contents[0], currentkey,
- key_data[j].key_data_length[0]);
-
- currentsalt = currentkey + key_data[j].key_data_length[0];
- if (key_data[j].key_data_length[1] != 0) {
-
- key_data[j].key_data_ver = 2;
- 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], currentsalt,
- key_data[j].key_data_length[1]);
-
- } else if (key_data[j].key_data_type[1] == KRB5_KDB_SALTTYPE_NOREALM ||
- key_data[j].key_data_type[1] == KRB5_KDB_SALTTYPE_ONLYREALM) {
- char *def_realm = NULL;
- krb5_data norealmval;
-
- key_data[j].key_data_ver = 2;
- switch (key_data[j].key_data_type[1]) {
- case KRB5_KDB_SALTTYPE_ONLYREALM:
- def_realm = entries->princ->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);
--- /dev/null
+#include <k5-int.h>
+#include <kdb.h>
+
+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;
+}
--- /dev/null
+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);