New patch from Savitha, for new principal key storage format in LDAP
authorKen Raeburn <raeburn@mit.edu>
Fri, 22 Sep 2006 20:29:24 +0000 (20:29 +0000)
committerKen Raeburn <raeburn@mit.edu>
Fri, 22 Sep 2006 20:29:24 +0000 (20:29 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@18606 dc483132-0cff-0310-8789-dd5450dbe970

src/plugins/kdb/ldap/libkdb_ldap/Makefile.in
src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c
src/plugins/kdb/ldap/libkdb_ldap/princ_key_encode_decode.c [new file with mode: 0644]
src/plugins/kdb/ldap/libkdb_ldap/princ_key_encode_decode.h [new file with mode: 0644]

index bbfcda05425580747c9ccde57da749dd5f315004..b7d0175a5b1afa752151cd03c0127602b0c263f7 100644 (file)
@@ -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
index ff97b4095754952ed75e172f74d8733850a91092..4a85afd1e475ab97d7a47d96a120312eb481a6d0 100644 (file)
@@ -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; 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)) {
@@ -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; 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);
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 (file)
index 0000000..73ae134
--- /dev/null
@@ -0,0 +1,396 @@
+#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;
+}
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 (file)
index 0000000..9851d00
--- /dev/null
@@ -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);