]> git.ipfire.org Git - thirdparty/tor.git/commitdiff
Add trunnel-generated items for link handshake code.
authorNick Mathewson <nickm@torproject.org>
Wed, 8 Oct 2014 18:43:33 +0000 (14:43 -0400)
committerNick Mathewson <nickm@torproject.org>
Thu, 28 May 2015 14:41:49 +0000 (10:41 -0400)
This includes the link handshake variations for proposal220.

We'll use this for testing first, and then use it to extend our
current code to support prop220.

scripts/codegen/run_trunnel.sh
src/trunnel/include.am
src/trunnel/link_handshake.c [new file with mode: 0644]
src/trunnel/link_handshake.h [new file with mode: 0644]
src/trunnel/link_handshake.trunnel [new file with mode: 0644]

index 5f694ce6c90867cb1bbc552dee96e8d7da4bd7a9..d2669931e9446b153350d4a8b6f89c41912b7058 100755 (executable)
@@ -5,7 +5,7 @@ if test "x$TRUNNEL_PATH" != "x"; then
   export PYTHONPATH
 fi
 
-python -m trunnel --require-version=1.2 ./src/trunnel/*.trunnel
+python -m trunnel --require-version=1.4 ./src/trunnel/*.trunnel
 
-python -m trunnel --require-version=1.2 --write-c-files --target-dir=./src/ext/trunnel/
+python -m trunnel --require-version=1.4 --write-c-files --target-dir=./src/ext/trunnel/
 
index 6e7851aafe84986b6ce155c1bcefb845a8e31554..2d8c051f19de5b8e4d29ba4154b06b1211ebacd1 100644 (file)
@@ -11,11 +11,13 @@ AM_CPPFLAGS += -I$(srcdir)/src/ext/trunnel -I$(srcdir)/src/trunnel
 
 TRUNNELINPUTS = \
        src/trunnel/ed25519_cert.trunnel \
+       src/trunnel/link_handshake.trunnel \
        src/trunnel/pwbox.trunnel
 
 TRUNNELSOURCES = \
        src/ext/trunnel/trunnel.c \
        src/trunnel/ed25519_cert.c \
+       src/trunnel/link_handshake.c \
        src/trunnel/pwbox.c
 
 TRUNNELHEADERS = \
@@ -23,6 +25,7 @@ TRUNNELHEADERS = \
        src/ext/trunnel/trunnel-impl.h          \
        src/trunnel/trunnel-local.h             \
        src/trunnel/ed25519_cert.h              \
+       src/trunnel/link_handshake.h            \
        src/trunnel/pwbox.h
 
 src_trunnel_libor_trunnel_a_SOURCES = $(TRUNNELSOURCES)
diff --git a/src/trunnel/link_handshake.c b/src/trunnel/link_handshake.c
new file mode 100644 (file)
index 0000000..9630d13
--- /dev/null
@@ -0,0 +1,1885 @@
+/* link_handshake.c -- generated by Trunnel v1.4-pre.
+ * https://gitweb.torproject.org/trunnel.git
+ * You probably shouldn't edit this file.
+ */
+#include <stdlib.h>
+#include "trunnel-impl.h"
+
+#include "link_handshake.h"
+
+#define TRUNNEL_SET_ERROR_CODE(obj) \
+  do {                              \
+    (obj)->trunnel_error_code_ = 1; \
+  } while (0)
+
+#if defined(__COVERITY__) || defined(__clang_analyzer__)
+/* If we're runnning a static analysis tool, we don't want it to complain
+ * that some of our remaining-bytes checks are dead-code. */
+int linkhandshake_deadcode_dummy__ = 0;
+#define OR_DEADCODE_DUMMY || linkhandshake_deadcode_dummy__
+#else
+#define OR_DEADCODE_DUMMY
+#endif
+
+#define CHECK_REMAINING(nbytes, label)                           \
+  do {                                                           \
+    if (remaining < (nbytes) OR_DEADCODE_DUMMY) {                \
+      goto label;                                                \
+    }                                                            \
+  } while (0)
+
+auth_challenge_cell_t *
+auth_challenge_cell_new(void)
+{
+  auth_challenge_cell_t *val = trunnel_calloc(1, sizeof(auth_challenge_cell_t));
+  if (NULL == val)
+    return NULL;
+  return val;
+}
+
+/** Release all storage held inside 'obj', but do not free 'obj'.
+ */
+static void
+auth_challenge_cell_clear(auth_challenge_cell_t *obj)
+{
+  (void) obj;
+  TRUNNEL_DYNARRAY_WIPE(&obj->methods);
+  TRUNNEL_DYNARRAY_CLEAR(&obj->methods);
+}
+
+void
+auth_challenge_cell_free(auth_challenge_cell_t *obj)
+{
+  if (obj == NULL)
+    return;
+  auth_challenge_cell_clear(obj);
+  trunnel_memwipe(obj, sizeof(auth_challenge_cell_t));
+  trunnel_free_(obj);
+}
+
+size_t
+auth_challenge_cell_getlen_challenge(const auth_challenge_cell_t *inp)
+{
+  (void)inp;  return 32;
+}
+
+uint8_t
+auth_challenge_cell_get_challenge(const auth_challenge_cell_t *inp, size_t idx)
+{
+  trunnel_assert(idx < 32);
+  return inp->challenge[idx];
+}
+
+int
+auth_challenge_cell_set_challenge(auth_challenge_cell_t *inp, size_t idx, uint8_t elt)
+{
+  trunnel_assert(idx < 32);
+  inp->challenge[idx] = elt;
+  return 0;
+}
+
+uint8_t *
+auth_challenge_cell_getarray_challenge(auth_challenge_cell_t *inp)
+{
+  return inp->challenge;
+}
+uint16_t
+auth_challenge_cell_get_n_methods(auth_challenge_cell_t *inp)
+{
+  return inp->n_methods;
+}
+int
+auth_challenge_cell_set_n_methods(auth_challenge_cell_t *inp, uint16_t val)
+{
+  inp->n_methods = val;
+  return 0;
+}
+size_t
+auth_challenge_cell_getlen_methods(const auth_challenge_cell_t *inp)
+{
+  return TRUNNEL_DYNARRAY_LEN(&inp->methods);
+}
+
+uint16_t
+auth_challenge_cell_get_methods(auth_challenge_cell_t *inp, size_t idx)
+{
+  return TRUNNEL_DYNARRAY_GET(&inp->methods, idx);
+}
+
+int
+auth_challenge_cell_set_methods(auth_challenge_cell_t *inp, size_t idx, uint16_t elt)
+{
+  TRUNNEL_DYNARRAY_SET(&inp->methods, idx, elt);
+  return 0;
+}
+int
+auth_challenge_cell_add_methods(auth_challenge_cell_t *inp, uint16_t elt)
+{
+#if SIZE_MAX >= UINT16_MAX
+  if (inp->methods.n_ == UINT16_MAX)
+    goto trunnel_alloc_failed;
+#endif
+  TRUNNEL_DYNARRAY_ADD(uint16_t, &inp->methods, elt, {});
+  return 0;
+ trunnel_alloc_failed:
+  TRUNNEL_SET_ERROR_CODE(inp);
+  return -1;
+}
+
+uint16_t *
+auth_challenge_cell_getarray_methods(auth_challenge_cell_t *inp)
+{
+  return inp->methods.elts_;
+}
+int
+auth_challenge_cell_setlen_methods(auth_challenge_cell_t *inp, size_t newlen)
+{
+  uint16_t *newptr;
+#if UINT16_MAX < SIZE_MAX
+  if (newlen > UINT16_MAX)
+    goto trunnel_alloc_failed;
+#endif
+  newptr = trunnel_dynarray_setlen(&inp->methods.allocated_,
+                 &inp->methods.n_, inp->methods.elts_, newlen,
+                 sizeof(inp->methods.elts_[0]), (trunnel_free_fn_t) NULL,
+                 &inp->trunnel_error_code_);
+  if (newptr == NULL)
+    goto trunnel_alloc_failed;
+  inp->methods.elts_ = newptr;
+  return 0;
+ trunnel_alloc_failed:
+  TRUNNEL_SET_ERROR_CODE(inp);
+  return -1;
+}
+const char *
+auth_challenge_cell_check(const auth_challenge_cell_t *obj)
+{
+  if (obj == NULL)
+    return "Object was NULL";
+  if (obj->trunnel_error_code_)
+    return "A set function failed on this object";
+  if (TRUNNEL_DYNARRAY_LEN(&obj->methods) != obj->n_methods)
+    return "Length mismatch for methods";
+  return NULL;
+}
+
+ssize_t
+auth_challenge_cell_encoded_len(const auth_challenge_cell_t *obj)
+{
+  ssize_t result = 0;
+
+  if (NULL != auth_challenge_cell_check(obj))
+     return -1;
+
+
+  /* Length of u8 challenge[32] */
+  result += 32;
+
+  /* Length of u16 n_methods */
+  result += 2;
+
+  /* Length of u16 methods[n_methods] */
+  result += 2 * TRUNNEL_DYNARRAY_LEN(&obj->methods);
+  return result;
+}
+int
+auth_challenge_cell_clear_errors(auth_challenge_cell_t *obj)
+{
+  int r = obj->trunnel_error_code_;
+  obj->trunnel_error_code_ = 0;
+  return r;
+}
+ssize_t
+auth_challenge_cell_encode(uint8_t *output, const size_t avail, const auth_challenge_cell_t *obj)
+{
+  ssize_t result = 0;
+  size_t written = 0;
+  uint8_t *ptr = output;
+  const char *msg;
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+  const ssize_t encoded_len = auth_challenge_cell_encoded_len(obj);
+#endif
+
+  if (NULL != (msg = auth_challenge_cell_check(obj)))
+    goto check_failed;
+
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+  trunnel_assert(encoded_len >= 0);
+#endif
+
+  /* Encode u8 challenge[32] */
+  trunnel_assert(written <= avail);
+  if (avail - written < 32)
+    goto truncated;
+  memcpy(ptr, obj->challenge, 32);
+  written += 32; ptr += 32;
+
+  /* Encode u16 n_methods */
+  trunnel_assert(written <= avail);
+  if (avail - written < 2)
+    goto truncated;
+  trunnel_set_uint16(ptr, trunnel_htons(obj->n_methods));
+  written += 2; ptr += 2;
+
+  /* Encode u16 methods[n_methods] */
+  {
+
+    unsigned idx;
+    for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->methods); ++idx) {
+      trunnel_assert(written <= avail);
+      if (avail - written < 2)
+        goto truncated;
+      trunnel_set_uint16(ptr, trunnel_htons(TRUNNEL_DYNARRAY_GET(&obj->methods, idx)));
+      written += 2; ptr += 2;
+    }
+  }
+
+
+  trunnel_assert(ptr == output + written);
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+  {
+    trunnel_assert(encoded_len >= 0);
+    trunnel_assert((size_t)encoded_len == written);
+  }
+
+#endif
+
+  return written;
+
+ truncated:
+  result = -2;
+  goto fail;
+ check_failed:
+  (void)msg;
+  result = -1;
+  goto fail;
+ fail:
+  trunnel_assert(result < 0);
+  return result;
+}
+
+/** As auth_challenge_cell_parse(), but do not allocate the output
+ * object.
+ */
+static ssize_t
+auth_challenge_cell_parse_into(auth_challenge_cell_t *obj, const uint8_t *input, const size_t len_in)
+{
+  const uint8_t *ptr = input;
+  size_t remaining = len_in;
+  ssize_t result = 0;
+  (void)result;
+
+  /* Parse u8 challenge[32] */
+  CHECK_REMAINING(32, truncated);
+  memcpy(obj->challenge, ptr, 32);
+  remaining -= 32; ptr += 32;
+
+  /* Parse u16 n_methods */
+  CHECK_REMAINING(2, truncated);
+  obj->n_methods = trunnel_ntohs(trunnel_get_uint16(ptr));
+  remaining -= 2; ptr += 2;
+
+  /* Parse u16 methods[n_methods] */
+  TRUNNEL_DYNARRAY_EXPAND(uint16_t, &obj->methods, obj->n_methods, {});
+  {
+    uint16_t elt;
+    unsigned idx;
+    for (idx = 0; idx < obj->n_methods; ++idx) {
+      CHECK_REMAINING(2, truncated);
+      elt = trunnel_ntohs(trunnel_get_uint16(ptr));
+      remaining -= 2; ptr += 2;
+      TRUNNEL_DYNARRAY_ADD(uint16_t, &obj->methods, elt, {});
+    }
+  }
+  trunnel_assert(ptr + remaining == input + len_in);
+  return len_in - remaining;
+
+ truncated:
+  return -2;
+ trunnel_alloc_failed:
+  return -1;
+}
+
+ssize_t
+auth_challenge_cell_parse(auth_challenge_cell_t **output, const uint8_t *input, const size_t len_in)
+{
+  ssize_t result;
+  *output = auth_challenge_cell_new();
+  if (NULL == *output)
+    return -1;
+  result = auth_challenge_cell_parse_into(*output, input, len_in);
+  if (result < 0) {
+    auth_challenge_cell_free(*output);
+    *output = NULL;
+  }
+  return result;
+}
+auth_ctx_t *
+auth_ctx_new(void)
+{
+  auth_ctx_t *val = trunnel_calloc(1, sizeof(auth_ctx_t));
+  if (NULL == val)
+    return NULL;
+  return val;
+}
+
+/** Release all storage held inside 'obj', but do not free 'obj'.
+ */
+static void
+auth_ctx_clear(auth_ctx_t *obj)
+{
+  (void) obj;
+}
+
+void
+auth_ctx_free(auth_ctx_t *obj)
+{
+  if (obj == NULL)
+    return;
+  auth_ctx_clear(obj);
+  trunnel_memwipe(obj, sizeof(auth_ctx_t));
+  trunnel_free_(obj);
+}
+
+uint8_t
+auth_ctx_get_is_ed(auth_ctx_t *inp)
+{
+  return inp->is_ed;
+}
+int
+auth_ctx_set_is_ed(auth_ctx_t *inp, uint8_t val)
+{
+  inp->is_ed = val;
+  return 0;
+}
+certs_cell_cert_t *
+certs_cell_cert_new(void)
+{
+  certs_cell_cert_t *val = trunnel_calloc(1, sizeof(certs_cell_cert_t));
+  if (NULL == val)
+    return NULL;
+  return val;
+}
+
+/** Release all storage held inside 'obj', but do not free 'obj'.
+ */
+static void
+certs_cell_cert_clear(certs_cell_cert_t *obj)
+{
+  (void) obj;
+  TRUNNEL_DYNARRAY_WIPE(&obj->body);
+  TRUNNEL_DYNARRAY_CLEAR(&obj->body);
+}
+
+void
+certs_cell_cert_free(certs_cell_cert_t *obj)
+{
+  if (obj == NULL)
+    return;
+  certs_cell_cert_clear(obj);
+  trunnel_memwipe(obj, sizeof(certs_cell_cert_t));
+  trunnel_free_(obj);
+}
+
+uint8_t
+certs_cell_cert_get_cert_type(certs_cell_cert_t *inp)
+{
+  return inp->cert_type;
+}
+int
+certs_cell_cert_set_cert_type(certs_cell_cert_t *inp, uint8_t val)
+{
+  inp->cert_type = val;
+  return 0;
+}
+uint16_t
+certs_cell_cert_get_cert_len(certs_cell_cert_t *inp)
+{
+  return inp->cert_len;
+}
+int
+certs_cell_cert_set_cert_len(certs_cell_cert_t *inp, uint16_t val)
+{
+  inp->cert_len = val;
+  return 0;
+}
+size_t
+certs_cell_cert_getlen_body(const certs_cell_cert_t *inp)
+{
+  return TRUNNEL_DYNARRAY_LEN(&inp->body);
+}
+
+uint8_t
+certs_cell_cert_get_body(certs_cell_cert_t *inp, size_t idx)
+{
+  return TRUNNEL_DYNARRAY_GET(&inp->body, idx);
+}
+
+int
+certs_cell_cert_set_body(certs_cell_cert_t *inp, size_t idx, uint8_t elt)
+{
+  TRUNNEL_DYNARRAY_SET(&inp->body, idx, elt);
+  return 0;
+}
+int
+certs_cell_cert_add_body(certs_cell_cert_t *inp, uint8_t elt)
+{
+#if SIZE_MAX >= UINT16_MAX
+  if (inp->body.n_ == UINT16_MAX)
+    goto trunnel_alloc_failed;
+#endif
+  TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->body, elt, {});
+  return 0;
+ trunnel_alloc_failed:
+  TRUNNEL_SET_ERROR_CODE(inp);
+  return -1;
+}
+
+uint8_t *
+certs_cell_cert_getarray_body(certs_cell_cert_t *inp)
+{
+  return inp->body.elts_;
+}
+int
+certs_cell_cert_setlen_body(certs_cell_cert_t *inp, size_t newlen)
+{
+  uint8_t *newptr;
+#if UINT16_MAX < SIZE_MAX
+  if (newlen > UINT16_MAX)
+    goto trunnel_alloc_failed;
+#endif
+  newptr = trunnel_dynarray_setlen(&inp->body.allocated_,
+                 &inp->body.n_, inp->body.elts_, newlen,
+                 sizeof(inp->body.elts_[0]), (trunnel_free_fn_t) NULL,
+                 &inp->trunnel_error_code_);
+  if (newptr == NULL)
+    goto trunnel_alloc_failed;
+  inp->body.elts_ = newptr;
+  return 0;
+ trunnel_alloc_failed:
+  TRUNNEL_SET_ERROR_CODE(inp);
+  return -1;
+}
+const char *
+certs_cell_cert_check(const certs_cell_cert_t *obj)
+{
+  if (obj == NULL)
+    return "Object was NULL";
+  if (obj->trunnel_error_code_)
+    return "A set function failed on this object";
+  if (TRUNNEL_DYNARRAY_LEN(&obj->body) != obj->cert_len)
+    return "Length mismatch for body";
+  return NULL;
+}
+
+ssize_t
+certs_cell_cert_encoded_len(const certs_cell_cert_t *obj)
+{
+  ssize_t result = 0;
+
+  if (NULL != certs_cell_cert_check(obj))
+     return -1;
+
+
+  /* Length of u8 cert_type */
+  result += 1;
+
+  /* Length of u16 cert_len */
+  result += 2;
+
+  /* Length of u8 body[cert_len] */
+  result += TRUNNEL_DYNARRAY_LEN(&obj->body);
+  return result;
+}
+int
+certs_cell_cert_clear_errors(certs_cell_cert_t *obj)
+{
+  int r = obj->trunnel_error_code_;
+  obj->trunnel_error_code_ = 0;
+  return r;
+}
+ssize_t
+certs_cell_cert_encode(uint8_t *output, const size_t avail, const certs_cell_cert_t *obj)
+{
+  ssize_t result = 0;
+  size_t written = 0;
+  uint8_t *ptr = output;
+  const char *msg;
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+  const ssize_t encoded_len = certs_cell_cert_encoded_len(obj);
+#endif
+
+  if (NULL != (msg = certs_cell_cert_check(obj)))
+    goto check_failed;
+
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+  trunnel_assert(encoded_len >= 0);
+#endif
+
+  /* Encode u8 cert_type */
+  trunnel_assert(written <= avail);
+  if (avail - written < 1)
+    goto truncated;
+  trunnel_set_uint8(ptr, (obj->cert_type));
+  written += 1; ptr += 1;
+
+  /* Encode u16 cert_len */
+  trunnel_assert(written <= avail);
+  if (avail - written < 2)
+    goto truncated;
+  trunnel_set_uint16(ptr, trunnel_htons(obj->cert_len));
+  written += 2; ptr += 2;
+
+  /* Encode u8 body[cert_len] */
+  {
+    size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->body);
+    trunnel_assert(obj->cert_len == elt_len);
+    trunnel_assert(written <= avail);
+    if (avail - written < elt_len)
+      goto truncated;
+    memcpy(ptr, obj->body.elts_, elt_len);
+    written += elt_len; ptr += elt_len;
+  }
+
+
+  trunnel_assert(ptr == output + written);
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+  {
+    trunnel_assert(encoded_len >= 0);
+    trunnel_assert((size_t)encoded_len == written);
+  }
+
+#endif
+
+  return written;
+
+ truncated:
+  result = -2;
+  goto fail;
+ check_failed:
+  (void)msg;
+  result = -1;
+  goto fail;
+ fail:
+  trunnel_assert(result < 0);
+  return result;
+}
+
+/** As certs_cell_cert_parse(), but do not allocate the output object.
+ */
+static ssize_t
+certs_cell_cert_parse_into(certs_cell_cert_t *obj, const uint8_t *input, const size_t len_in)
+{
+  const uint8_t *ptr = input;
+  size_t remaining = len_in;
+  ssize_t result = 0;
+  (void)result;
+
+  /* Parse u8 cert_type */
+  CHECK_REMAINING(1, truncated);
+  obj->cert_type = (trunnel_get_uint8(ptr));
+  remaining -= 1; ptr += 1;
+
+  /* Parse u16 cert_len */
+  CHECK_REMAINING(2, truncated);
+  obj->cert_len = trunnel_ntohs(trunnel_get_uint16(ptr));
+  remaining -= 2; ptr += 2;
+
+  /* Parse u8 body[cert_len] */
+  CHECK_REMAINING(obj->cert_len, truncated);
+  TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->body, obj->cert_len, {});
+  obj->body.n_ = obj->cert_len;
+  memcpy(obj->body.elts_, ptr, obj->cert_len);
+  ptr += obj->cert_len; remaining -= obj->cert_len;
+  trunnel_assert(ptr + remaining == input + len_in);
+  return len_in - remaining;
+
+ truncated:
+  return -2;
+ trunnel_alloc_failed:
+  return -1;
+}
+
+ssize_t
+certs_cell_cert_parse(certs_cell_cert_t **output, const uint8_t *input, const size_t len_in)
+{
+  ssize_t result;
+  *output = certs_cell_cert_new();
+  if (NULL == *output)
+    return -1;
+  result = certs_cell_cert_parse_into(*output, input, len_in);
+  if (result < 0) {
+    certs_cell_cert_free(*output);
+    *output = NULL;
+  }
+  return result;
+}
+rsa_ed_crosscert_t *
+rsa_ed_crosscert_new(void)
+{
+  rsa_ed_crosscert_t *val = trunnel_calloc(1, sizeof(rsa_ed_crosscert_t));
+  if (NULL == val)
+    return NULL;
+  return val;
+}
+
+/** Release all storage held inside 'obj', but do not free 'obj'.
+ */
+static void
+rsa_ed_crosscert_clear(rsa_ed_crosscert_t *obj)
+{
+  (void) obj;
+  TRUNNEL_DYNARRAY_WIPE(&obj->sig);
+  TRUNNEL_DYNARRAY_CLEAR(&obj->sig);
+}
+
+void
+rsa_ed_crosscert_free(rsa_ed_crosscert_t *obj)
+{
+  if (obj == NULL)
+    return;
+  rsa_ed_crosscert_clear(obj);
+  trunnel_memwipe(obj, sizeof(rsa_ed_crosscert_t));
+  trunnel_free_(obj);
+}
+
+size_t
+rsa_ed_crosscert_getlen_ed_key(const rsa_ed_crosscert_t *inp)
+{
+  (void)inp;  return 32;
+}
+
+uint8_t
+rsa_ed_crosscert_get_ed_key(const rsa_ed_crosscert_t *inp, size_t idx)
+{
+  trunnel_assert(idx < 32);
+  return inp->ed_key[idx];
+}
+
+int
+rsa_ed_crosscert_set_ed_key(rsa_ed_crosscert_t *inp, size_t idx, uint8_t elt)
+{
+  trunnel_assert(idx < 32);
+  inp->ed_key[idx] = elt;
+  return 0;
+}
+
+uint8_t *
+rsa_ed_crosscert_getarray_ed_key(rsa_ed_crosscert_t *inp)
+{
+  return inp->ed_key;
+}
+uint32_t
+rsa_ed_crosscert_get_expiration(rsa_ed_crosscert_t *inp)
+{
+  return inp->expiration;
+}
+int
+rsa_ed_crosscert_set_expiration(rsa_ed_crosscert_t *inp, uint32_t val)
+{
+  inp->expiration = val;
+  return 0;
+}
+const uint8_t *
+rsa_ed_crosscert_get_end_of_signed(const rsa_ed_crosscert_t *inp)
+{
+  return inp->end_of_signed;
+}
+uint8_t
+rsa_ed_crosscert_get_sig_len(rsa_ed_crosscert_t *inp)
+{
+  return inp->sig_len;
+}
+int
+rsa_ed_crosscert_set_sig_len(rsa_ed_crosscert_t *inp, uint8_t val)
+{
+  inp->sig_len = val;
+  return 0;
+}
+size_t
+rsa_ed_crosscert_getlen_sig(const rsa_ed_crosscert_t *inp)
+{
+  return TRUNNEL_DYNARRAY_LEN(&inp->sig);
+}
+
+uint8_t
+rsa_ed_crosscert_get_sig(rsa_ed_crosscert_t *inp, size_t idx)
+{
+  return TRUNNEL_DYNARRAY_GET(&inp->sig, idx);
+}
+
+int
+rsa_ed_crosscert_set_sig(rsa_ed_crosscert_t *inp, size_t idx, uint8_t elt)
+{
+  TRUNNEL_DYNARRAY_SET(&inp->sig, idx, elt);
+  return 0;
+}
+int
+rsa_ed_crosscert_add_sig(rsa_ed_crosscert_t *inp, uint8_t elt)
+{
+#if SIZE_MAX >= UINT8_MAX
+  if (inp->sig.n_ == UINT8_MAX)
+    goto trunnel_alloc_failed;
+#endif
+  TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->sig, elt, {});
+  return 0;
+ trunnel_alloc_failed:
+  TRUNNEL_SET_ERROR_CODE(inp);
+  return -1;
+}
+
+uint8_t *
+rsa_ed_crosscert_getarray_sig(rsa_ed_crosscert_t *inp)
+{
+  return inp->sig.elts_;
+}
+int
+rsa_ed_crosscert_setlen_sig(rsa_ed_crosscert_t *inp, size_t newlen)
+{
+  uint8_t *newptr;
+#if UINT8_MAX < SIZE_MAX
+  if (newlen > UINT8_MAX)
+    goto trunnel_alloc_failed;
+#endif
+  newptr = trunnel_dynarray_setlen(&inp->sig.allocated_,
+                 &inp->sig.n_, inp->sig.elts_, newlen,
+                 sizeof(inp->sig.elts_[0]), (trunnel_free_fn_t) NULL,
+                 &inp->trunnel_error_code_);
+  if (newptr == NULL)
+    goto trunnel_alloc_failed;
+  inp->sig.elts_ = newptr;
+  return 0;
+ trunnel_alloc_failed:
+  TRUNNEL_SET_ERROR_CODE(inp);
+  return -1;
+}
+const char *
+rsa_ed_crosscert_check(const rsa_ed_crosscert_t *obj)
+{
+  if (obj == NULL)
+    return "Object was NULL";
+  if (obj->trunnel_error_code_)
+    return "A set function failed on this object";
+  if (TRUNNEL_DYNARRAY_LEN(&obj->sig) != obj->sig_len)
+    return "Length mismatch for sig";
+  return NULL;
+}
+
+ssize_t
+rsa_ed_crosscert_encoded_len(const rsa_ed_crosscert_t *obj)
+{
+  ssize_t result = 0;
+
+  if (NULL != rsa_ed_crosscert_check(obj))
+     return -1;
+
+
+  /* Length of u8 ed_key[32] */
+  result += 32;
+
+  /* Length of u32 expiration */
+  result += 4;
+
+  /* Length of u8 sig_len */
+  result += 1;
+
+  /* Length of u8 sig[sig_len] */
+  result += TRUNNEL_DYNARRAY_LEN(&obj->sig);
+  return result;
+}
+int
+rsa_ed_crosscert_clear_errors(rsa_ed_crosscert_t *obj)
+{
+  int r = obj->trunnel_error_code_;
+  obj->trunnel_error_code_ = 0;
+  return r;
+}
+ssize_t
+rsa_ed_crosscert_encode(uint8_t *output, const size_t avail, const rsa_ed_crosscert_t *obj)
+{
+  ssize_t result = 0;
+  size_t written = 0;
+  uint8_t *ptr = output;
+  const char *msg;
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+  const ssize_t encoded_len = rsa_ed_crosscert_encoded_len(obj);
+#endif
+
+  if (NULL != (msg = rsa_ed_crosscert_check(obj)))
+    goto check_failed;
+
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+  trunnel_assert(encoded_len >= 0);
+#endif
+
+  /* Encode u8 ed_key[32] */
+  trunnel_assert(written <= avail);
+  if (avail - written < 32)
+    goto truncated;
+  memcpy(ptr, obj->ed_key, 32);
+  written += 32; ptr += 32;
+
+  /* Encode u32 expiration */
+  trunnel_assert(written <= avail);
+  if (avail - written < 4)
+    goto truncated;
+  trunnel_set_uint32(ptr, trunnel_htonl(obj->expiration));
+  written += 4; ptr += 4;
+
+  /* Encode u8 sig_len */
+  trunnel_assert(written <= avail);
+  if (avail - written < 1)
+    goto truncated;
+  trunnel_set_uint8(ptr, (obj->sig_len));
+  written += 1; ptr += 1;
+
+  /* Encode u8 sig[sig_len] */
+  {
+    size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->sig);
+    trunnel_assert(obj->sig_len == elt_len);
+    trunnel_assert(written <= avail);
+    if (avail - written < elt_len)
+      goto truncated;
+    memcpy(ptr, obj->sig.elts_, elt_len);
+    written += elt_len; ptr += elt_len;
+  }
+
+
+  trunnel_assert(ptr == output + written);
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+  {
+    trunnel_assert(encoded_len >= 0);
+    trunnel_assert((size_t)encoded_len == written);
+  }
+
+#endif
+
+  return written;
+
+ truncated:
+  result = -2;
+  goto fail;
+ check_failed:
+  (void)msg;
+  result = -1;
+  goto fail;
+ fail:
+  trunnel_assert(result < 0);
+  return result;
+}
+
+/** As rsa_ed_crosscert_parse(), but do not allocate the output
+ * object.
+ */
+static ssize_t
+rsa_ed_crosscert_parse_into(rsa_ed_crosscert_t *obj, const uint8_t *input, const size_t len_in)
+{
+  const uint8_t *ptr = input;
+  size_t remaining = len_in;
+  ssize_t result = 0;
+  (void)result;
+
+  /* Parse u8 ed_key[32] */
+  CHECK_REMAINING(32, truncated);
+  memcpy(obj->ed_key, ptr, 32);
+  remaining -= 32; ptr += 32;
+
+  /* Parse u32 expiration */
+  CHECK_REMAINING(4, truncated);
+  obj->expiration = trunnel_ntohl(trunnel_get_uint32(ptr));
+  remaining -= 4; ptr += 4;
+  obj->end_of_signed = ptr;
+
+  /* Parse u8 sig_len */
+  CHECK_REMAINING(1, truncated);
+  obj->sig_len = (trunnel_get_uint8(ptr));
+  remaining -= 1; ptr += 1;
+
+  /* Parse u8 sig[sig_len] */
+  CHECK_REMAINING(obj->sig_len, truncated);
+  TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->sig, obj->sig_len, {});
+  obj->sig.n_ = obj->sig_len;
+  memcpy(obj->sig.elts_, ptr, obj->sig_len);
+  ptr += obj->sig_len; remaining -= obj->sig_len;
+  trunnel_assert(ptr + remaining == input + len_in);
+  return len_in - remaining;
+
+ truncated:
+  return -2;
+ trunnel_alloc_failed:
+  return -1;
+}
+
+ssize_t
+rsa_ed_crosscert_parse(rsa_ed_crosscert_t **output, const uint8_t *input, const size_t len_in)
+{
+  ssize_t result;
+  *output = rsa_ed_crosscert_new();
+  if (NULL == *output)
+    return -1;
+  result = rsa_ed_crosscert_parse_into(*output, input, len_in);
+  if (result < 0) {
+    rsa_ed_crosscert_free(*output);
+    *output = NULL;
+  }
+  return result;
+}
+auth1_t *
+auth1_new(void)
+{
+  auth1_t *val = trunnel_calloc(1, sizeof(auth1_t));
+  if (NULL == val)
+    return NULL;
+  return val;
+}
+
+/** Release all storage held inside 'obj', but do not free 'obj'.
+ */
+static void
+auth1_clear(auth1_t *obj)
+{
+  (void) obj;
+  TRUNNEL_DYNARRAY_WIPE(&obj->sig);
+  TRUNNEL_DYNARRAY_CLEAR(&obj->sig);
+}
+
+void
+auth1_free(auth1_t *obj)
+{
+  if (obj == NULL)
+    return;
+  auth1_clear(obj);
+  trunnel_memwipe(obj, sizeof(auth1_t));
+  trunnel_free_(obj);
+}
+
+size_t
+auth1_getlen_type(const auth1_t *inp)
+{
+  (void)inp;  return 8;
+}
+
+uint8_t
+auth1_get_type(const auth1_t *inp, size_t idx)
+{
+  trunnel_assert(idx < 8);
+  return inp->type[idx];
+}
+
+int
+auth1_set_type(auth1_t *inp, size_t idx, uint8_t elt)
+{
+  trunnel_assert(idx < 8);
+  inp->type[idx] = elt;
+  return 0;
+}
+
+uint8_t *
+auth1_getarray_type(auth1_t *inp)
+{
+  return inp->type;
+}
+size_t
+auth1_getlen_cid(const auth1_t *inp)
+{
+  (void)inp;  return 32;
+}
+
+uint8_t
+auth1_get_cid(const auth1_t *inp, size_t idx)
+{
+  trunnel_assert(idx < 32);
+  return inp->cid[idx];
+}
+
+int
+auth1_set_cid(auth1_t *inp, size_t idx, uint8_t elt)
+{
+  trunnel_assert(idx < 32);
+  inp->cid[idx] = elt;
+  return 0;
+}
+
+uint8_t *
+auth1_getarray_cid(auth1_t *inp)
+{
+  return inp->cid;
+}
+size_t
+auth1_getlen_sid(const auth1_t *inp)
+{
+  (void)inp;  return 32;
+}
+
+uint8_t
+auth1_get_sid(const auth1_t *inp, size_t idx)
+{
+  trunnel_assert(idx < 32);
+  return inp->sid[idx];
+}
+
+int
+auth1_set_sid(auth1_t *inp, size_t idx, uint8_t elt)
+{
+  trunnel_assert(idx < 32);
+  inp->sid[idx] = elt;
+  return 0;
+}
+
+uint8_t *
+auth1_getarray_sid(auth1_t *inp)
+{
+  return inp->sid;
+}
+size_t
+auth1_getlen_u1_cid_ed(const auth1_t *inp)
+{
+  (void)inp;  return 32;
+}
+
+uint8_t
+auth1_get_u1_cid_ed(const auth1_t *inp, size_t idx)
+{
+  trunnel_assert(idx < 32);
+  return inp->u1_cid_ed[idx];
+}
+
+int
+auth1_set_u1_cid_ed(auth1_t *inp, size_t idx, uint8_t elt)
+{
+  trunnel_assert(idx < 32);
+  inp->u1_cid_ed[idx] = elt;
+  return 0;
+}
+
+uint8_t *
+auth1_getarray_u1_cid_ed(auth1_t *inp)
+{
+  return inp->u1_cid_ed;
+}
+size_t
+auth1_getlen_u1_sid_ed(const auth1_t *inp)
+{
+  (void)inp;  return 32;
+}
+
+uint8_t
+auth1_get_u1_sid_ed(const auth1_t *inp, size_t idx)
+{
+  trunnel_assert(idx < 32);
+  return inp->u1_sid_ed[idx];
+}
+
+int
+auth1_set_u1_sid_ed(auth1_t *inp, size_t idx, uint8_t elt)
+{
+  trunnel_assert(idx < 32);
+  inp->u1_sid_ed[idx] = elt;
+  return 0;
+}
+
+uint8_t *
+auth1_getarray_u1_sid_ed(auth1_t *inp)
+{
+  return inp->u1_sid_ed;
+}
+size_t
+auth1_getlen_slog(const auth1_t *inp)
+{
+  (void)inp;  return 32;
+}
+
+uint8_t
+auth1_get_slog(const auth1_t *inp, size_t idx)
+{
+  trunnel_assert(idx < 32);
+  return inp->slog[idx];
+}
+
+int
+auth1_set_slog(auth1_t *inp, size_t idx, uint8_t elt)
+{
+  trunnel_assert(idx < 32);
+  inp->slog[idx] = elt;
+  return 0;
+}
+
+uint8_t *
+auth1_getarray_slog(auth1_t *inp)
+{
+  return inp->slog;
+}
+size_t
+auth1_getlen_clog(const auth1_t *inp)
+{
+  (void)inp;  return 32;
+}
+
+uint8_t
+auth1_get_clog(const auth1_t *inp, size_t idx)
+{
+  trunnel_assert(idx < 32);
+  return inp->clog[idx];
+}
+
+int
+auth1_set_clog(auth1_t *inp, size_t idx, uint8_t elt)
+{
+  trunnel_assert(idx < 32);
+  inp->clog[idx] = elt;
+  return 0;
+}
+
+uint8_t *
+auth1_getarray_clog(auth1_t *inp)
+{
+  return inp->clog;
+}
+size_t
+auth1_getlen_scert(const auth1_t *inp)
+{
+  (void)inp;  return 32;
+}
+
+uint8_t
+auth1_get_scert(const auth1_t *inp, size_t idx)
+{
+  trunnel_assert(idx < 32);
+  return inp->scert[idx];
+}
+
+int
+auth1_set_scert(auth1_t *inp, size_t idx, uint8_t elt)
+{
+  trunnel_assert(idx < 32);
+  inp->scert[idx] = elt;
+  return 0;
+}
+
+uint8_t *
+auth1_getarray_scert(auth1_t *inp)
+{
+  return inp->scert;
+}
+size_t
+auth1_getlen_tlssecrets(const auth1_t *inp)
+{
+  (void)inp;  return 32;
+}
+
+uint8_t
+auth1_get_tlssecrets(const auth1_t *inp, size_t idx)
+{
+  trunnel_assert(idx < 32);
+  return inp->tlssecrets[idx];
+}
+
+int
+auth1_set_tlssecrets(auth1_t *inp, size_t idx, uint8_t elt)
+{
+  trunnel_assert(idx < 32);
+  inp->tlssecrets[idx] = elt;
+  return 0;
+}
+
+uint8_t *
+auth1_getarray_tlssecrets(auth1_t *inp)
+{
+  return inp->tlssecrets;
+}
+const uint8_t *
+auth1_get_end_of_fixed_part(const auth1_t *inp)
+{
+  return inp->end_of_fixed_part;
+}
+size_t
+auth1_getlen_rand(const auth1_t *inp)
+{
+  (void)inp;  return 24;
+}
+
+uint8_t
+auth1_get_rand(const auth1_t *inp, size_t idx)
+{
+  trunnel_assert(idx < 24);
+  return inp->rand[idx];
+}
+
+int
+auth1_set_rand(auth1_t *inp, size_t idx, uint8_t elt)
+{
+  trunnel_assert(idx < 24);
+  inp->rand[idx] = elt;
+  return 0;
+}
+
+uint8_t *
+auth1_getarray_rand(auth1_t *inp)
+{
+  return inp->rand;
+}
+const uint8_t *
+auth1_get_end_of_signed(const auth1_t *inp)
+{
+  return inp->end_of_signed;
+}
+size_t
+auth1_getlen_sig(const auth1_t *inp)
+{
+  return TRUNNEL_DYNARRAY_LEN(&inp->sig);
+}
+
+uint8_t
+auth1_get_sig(auth1_t *inp, size_t idx)
+{
+  return TRUNNEL_DYNARRAY_GET(&inp->sig, idx);
+}
+
+int
+auth1_set_sig(auth1_t *inp, size_t idx, uint8_t elt)
+{
+  TRUNNEL_DYNARRAY_SET(&inp->sig, idx, elt);
+  return 0;
+}
+int
+auth1_add_sig(auth1_t *inp, uint8_t elt)
+{
+  TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->sig, elt, {});
+  return 0;
+ trunnel_alloc_failed:
+  TRUNNEL_SET_ERROR_CODE(inp);
+  return -1;
+}
+
+uint8_t *
+auth1_getarray_sig(auth1_t *inp)
+{
+  return inp->sig.elts_;
+}
+int
+auth1_setlen_sig(auth1_t *inp, size_t newlen)
+{
+  uint8_t *newptr;
+  newptr = trunnel_dynarray_setlen(&inp->sig.allocated_,
+                 &inp->sig.n_, inp->sig.elts_, newlen,
+                 sizeof(inp->sig.elts_[0]), (trunnel_free_fn_t) NULL,
+                 &inp->trunnel_error_code_);
+  if (newptr == NULL)
+    goto trunnel_alloc_failed;
+  inp->sig.elts_ = newptr;
+  return 0;
+ trunnel_alloc_failed:
+  TRUNNEL_SET_ERROR_CODE(inp);
+  return -1;
+}
+const char *
+auth1_check(const auth1_t *obj, const auth_ctx_t *auth_ctx_ctx)
+{
+  if (obj == NULL)
+    return "Object was NULL";
+  if (obj->trunnel_error_code_)
+    return "A set function failed on this object";
+  if (auth_ctx_ctx == NULL)
+    return "Context was NULL";
+  switch (auth_ctx_ctx->is_ed) {
+
+    case 0:
+      break;
+
+    case 1:
+      break;
+
+    default:
+        return "Bad tag for union";
+      break;
+  }
+  return NULL;
+}
+
+ssize_t
+auth1_encoded_len(const auth1_t *obj, const auth_ctx_t *auth_ctx_ctx)
+{
+  ssize_t result = 0;
+
+  if (NULL != auth1_check(obj, auth_ctx_ctx))
+     return -1;
+
+
+  /* Length of u8 type[8] */
+  result += 8;
+
+  /* Length of u8 cid[32] */
+  result += 32;
+
+  /* Length of u8 sid[32] */
+  result += 32;
+  switch (auth_ctx_ctx->is_ed) {
+
+    case 0:
+      break;
+
+    case 1:
+
+      /* Length of u8 u1_cid_ed[32] */
+      result += 32;
+
+      /* Length of u8 u1_sid_ed[32] */
+      result += 32;
+      break;
+
+    default:
+      trunnel_assert(0);
+      break;
+  }
+
+  /* Length of u8 slog[32] */
+  result += 32;
+
+  /* Length of u8 clog[32] */
+  result += 32;
+
+  /* Length of u8 scert[32] */
+  result += 32;
+
+  /* Length of u8 tlssecrets[32] */
+  result += 32;
+
+  /* Length of u8 rand[24] */
+  result += 24;
+
+  /* Length of u8 sig[] */
+  result += TRUNNEL_DYNARRAY_LEN(&obj->sig);
+  return result;
+}
+int
+auth1_clear_errors(auth1_t *obj)
+{
+  int r = obj->trunnel_error_code_;
+  obj->trunnel_error_code_ = 0;
+  return r;
+}
+ssize_t
+auth1_encode(uint8_t *output, const size_t avail, const auth1_t *obj, const auth_ctx_t *auth_ctx_ctx)
+{
+  ssize_t result = 0;
+  size_t written = 0;
+  uint8_t *ptr = output;
+  const char *msg;
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+  const ssize_t encoded_len = auth1_encoded_len(obj, auth_ctx_ctx);
+#endif
+
+  if (NULL != (msg = auth1_check(obj, auth_ctx_ctx)))
+    goto check_failed;
+
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+  trunnel_assert(encoded_len >= 0);
+#endif
+
+  /* Encode u8 type[8] */
+  trunnel_assert(written <= avail);
+  if (avail - written < 8)
+    goto truncated;
+  memcpy(ptr, obj->type, 8);
+  written += 8; ptr += 8;
+
+  /* Encode u8 cid[32] */
+  trunnel_assert(written <= avail);
+  if (avail - written < 32)
+    goto truncated;
+  memcpy(ptr, obj->cid, 32);
+  written += 32; ptr += 32;
+
+  /* Encode u8 sid[32] */
+  trunnel_assert(written <= avail);
+  if (avail - written < 32)
+    goto truncated;
+  memcpy(ptr, obj->sid, 32);
+  written += 32; ptr += 32;
+
+  /* Encode union u1[auth_ctx.is_ed] */
+  trunnel_assert(written <= avail);
+  switch (auth_ctx_ctx->is_ed) {
+
+    case 0:
+      break;
+
+    case 1:
+
+      /* Encode u8 u1_cid_ed[32] */
+      trunnel_assert(written <= avail);
+      if (avail - written < 32)
+        goto truncated;
+      memcpy(ptr, obj->u1_cid_ed, 32);
+      written += 32; ptr += 32;
+
+      /* Encode u8 u1_sid_ed[32] */
+      trunnel_assert(written <= avail);
+      if (avail - written < 32)
+        goto truncated;
+      memcpy(ptr, obj->u1_sid_ed, 32);
+      written += 32; ptr += 32;
+      break;
+
+    default:
+      trunnel_assert(0);
+      break;
+  }
+
+  /* Encode u8 slog[32] */
+  trunnel_assert(written <= avail);
+  if (avail - written < 32)
+    goto truncated;
+  memcpy(ptr, obj->slog, 32);
+  written += 32; ptr += 32;
+
+  /* Encode u8 clog[32] */
+  trunnel_assert(written <= avail);
+  if (avail - written < 32)
+    goto truncated;
+  memcpy(ptr, obj->clog, 32);
+  written += 32; ptr += 32;
+
+  /* Encode u8 scert[32] */
+  trunnel_assert(written <= avail);
+  if (avail - written < 32)
+    goto truncated;
+  memcpy(ptr, obj->scert, 32);
+  written += 32; ptr += 32;
+
+  /* Encode u8 tlssecrets[32] */
+  trunnel_assert(written <= avail);
+  if (avail - written < 32)
+    goto truncated;
+  memcpy(ptr, obj->tlssecrets, 32);
+  written += 32; ptr += 32;
+
+  /* Encode u8 rand[24] */
+  trunnel_assert(written <= avail);
+  if (avail - written < 24)
+    goto truncated;
+  memcpy(ptr, obj->rand, 24);
+  written += 24; ptr += 24;
+
+  /* Encode u8 sig[] */
+  {
+    size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->sig);
+    trunnel_assert(written <= avail);
+    if (avail - written < elt_len)
+      goto truncated;
+    memcpy(ptr, obj->sig.elts_, elt_len);
+    written += elt_len; ptr += elt_len;
+  }
+
+
+  trunnel_assert(ptr == output + written);
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+  {
+    trunnel_assert(encoded_len >= 0);
+    trunnel_assert((size_t)encoded_len == written);
+  }
+
+#endif
+
+  return written;
+
+ truncated:
+  result = -2;
+  goto fail;
+ check_failed:
+  (void)msg;
+  result = -1;
+  goto fail;
+ fail:
+  trunnel_assert(result < 0);
+  return result;
+}
+
+/** As auth1_parse(), but do not allocate the output object.
+ */
+static ssize_t
+auth1_parse_into(auth1_t *obj, const uint8_t *input, const size_t len_in, const auth_ctx_t *auth_ctx_ctx)
+{
+  const uint8_t *ptr = input;
+  size_t remaining = len_in;
+  ssize_t result = 0;
+  (void)result;
+  if (auth_ctx_ctx == NULL)
+    return -1;
+
+  /* Parse u8 type[8] */
+  CHECK_REMAINING(8, truncated);
+  memcpy(obj->type, ptr, 8);
+  remaining -= 8; ptr += 8;
+
+  /* Parse u8 cid[32] */
+  CHECK_REMAINING(32, truncated);
+  memcpy(obj->cid, ptr, 32);
+  remaining -= 32; ptr += 32;
+
+  /* Parse u8 sid[32] */
+  CHECK_REMAINING(32, truncated);
+  memcpy(obj->sid, ptr, 32);
+  remaining -= 32; ptr += 32;
+
+  /* Parse union u1[auth_ctx.is_ed] */
+  switch (auth_ctx_ctx->is_ed) {
+
+    case 0:
+      break;
+
+    case 1:
+
+      /* Parse u8 u1_cid_ed[32] */
+      CHECK_REMAINING(32, truncated);
+      memcpy(obj->u1_cid_ed, ptr, 32);
+      remaining -= 32; ptr += 32;
+
+      /* Parse u8 u1_sid_ed[32] */
+      CHECK_REMAINING(32, truncated);
+      memcpy(obj->u1_sid_ed, ptr, 32);
+      remaining -= 32; ptr += 32;
+      break;
+
+    default:
+      goto fail;
+      break;
+  }
+
+  /* Parse u8 slog[32] */
+  CHECK_REMAINING(32, truncated);
+  memcpy(obj->slog, ptr, 32);
+  remaining -= 32; ptr += 32;
+
+  /* Parse u8 clog[32] */
+  CHECK_REMAINING(32, truncated);
+  memcpy(obj->clog, ptr, 32);
+  remaining -= 32; ptr += 32;
+
+  /* Parse u8 scert[32] */
+  CHECK_REMAINING(32, truncated);
+  memcpy(obj->scert, ptr, 32);
+  remaining -= 32; ptr += 32;
+
+  /* Parse u8 tlssecrets[32] */
+  CHECK_REMAINING(32, truncated);
+  memcpy(obj->tlssecrets, ptr, 32);
+  remaining -= 32; ptr += 32;
+  obj->end_of_fixed_part = ptr;
+
+  /* Parse u8 rand[24] */
+  CHECK_REMAINING(24, truncated);
+  memcpy(obj->rand, ptr, 24);
+  remaining -= 24; ptr += 24;
+  obj->end_of_signed = ptr;
+
+  /* Parse u8 sig[] */
+  TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->sig, remaining, {});
+  obj->sig.n_ = remaining;
+  memcpy(obj->sig.elts_, ptr, remaining);
+  ptr += remaining; remaining -= remaining;
+  trunnel_assert(ptr + remaining == input + len_in);
+  return len_in - remaining;
+
+ truncated:
+  return -2;
+ trunnel_alloc_failed:
+  return -1;
+ fail:
+  result = -1;
+  return result;
+}
+
+ssize_t
+auth1_parse(auth1_t **output, const uint8_t *input, const size_t len_in, const auth_ctx_t *auth_ctx_ctx)
+{
+  ssize_t result;
+  *output = auth1_new();
+  if (NULL == *output)
+    return -1;
+  result = auth1_parse_into(*output, input, len_in, auth_ctx_ctx);
+  if (result < 0) {
+    auth1_free(*output);
+    *output = NULL;
+  }
+  return result;
+}
+certs_cell_t *
+certs_cell_new(void)
+{
+  certs_cell_t *val = trunnel_calloc(1, sizeof(certs_cell_t));
+  if (NULL == val)
+    return NULL;
+  return val;
+}
+
+/** Release all storage held inside 'obj', but do not free 'obj'.
+ */
+static void
+certs_cell_clear(certs_cell_t *obj)
+{
+  (void) obj;
+  {
+
+    unsigned idx;
+    for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->certs); ++idx) {
+      certs_cell_cert_free(TRUNNEL_DYNARRAY_GET(&obj->certs, idx));
+    }
+  }
+  TRUNNEL_DYNARRAY_WIPE(&obj->certs);
+  TRUNNEL_DYNARRAY_CLEAR(&obj->certs);
+}
+
+void
+certs_cell_free(certs_cell_t *obj)
+{
+  if (obj == NULL)
+    return;
+  certs_cell_clear(obj);
+  trunnel_memwipe(obj, sizeof(certs_cell_t));
+  trunnel_free_(obj);
+}
+
+uint8_t
+certs_cell_get_n_certs(certs_cell_t *inp)
+{
+  return inp->n_certs;
+}
+int
+certs_cell_set_n_certs(certs_cell_t *inp, uint8_t val)
+{
+  inp->n_certs = val;
+  return 0;
+}
+size_t
+certs_cell_getlen_certs(const certs_cell_t *inp)
+{
+  return TRUNNEL_DYNARRAY_LEN(&inp->certs);
+}
+
+struct certs_cell_cert_st *
+certs_cell_get_certs(certs_cell_t *inp, size_t idx)
+{
+  return TRUNNEL_DYNARRAY_GET(&inp->certs, idx);
+}
+
+int
+certs_cell_set_certs(certs_cell_t *inp, size_t idx, struct certs_cell_cert_st * elt)
+{
+  certs_cell_cert_t *oldval = TRUNNEL_DYNARRAY_GET(&inp->certs, idx);
+  if (oldval && oldval != elt)
+    certs_cell_cert_free(oldval);
+  return certs_cell_set0_certs(inp, idx, elt);
+}
+int
+certs_cell_set0_certs(certs_cell_t *inp, size_t idx, struct certs_cell_cert_st * elt)
+{
+  TRUNNEL_DYNARRAY_SET(&inp->certs, idx, elt);
+  return 0;
+}
+int
+certs_cell_add_certs(certs_cell_t *inp, struct certs_cell_cert_st * elt)
+{
+#if SIZE_MAX >= UINT8_MAX
+  if (inp->certs.n_ == UINT8_MAX)
+    goto trunnel_alloc_failed;
+#endif
+  TRUNNEL_DYNARRAY_ADD(struct certs_cell_cert_st *, &inp->certs, elt, {});
+  return 0;
+ trunnel_alloc_failed:
+  TRUNNEL_SET_ERROR_CODE(inp);
+  return -1;
+}
+
+struct certs_cell_cert_st * *
+certs_cell_getarray_certs(certs_cell_t *inp)
+{
+  return inp->certs.elts_;
+}
+int
+certs_cell_setlen_certs(certs_cell_t *inp, size_t newlen)
+{
+  struct certs_cell_cert_st * *newptr;
+#if UINT8_MAX < SIZE_MAX
+  if (newlen > UINT8_MAX)
+    goto trunnel_alloc_failed;
+#endif
+  newptr = trunnel_dynarray_setlen(&inp->certs.allocated_,
+                 &inp->certs.n_, inp->certs.elts_, newlen,
+                 sizeof(inp->certs.elts_[0]), (trunnel_free_fn_t) certs_cell_cert_free,
+                 &inp->trunnel_error_code_);
+  if (newptr == NULL)
+    goto trunnel_alloc_failed;
+  inp->certs.elts_ = newptr;
+  return 0;
+ trunnel_alloc_failed:
+  TRUNNEL_SET_ERROR_CODE(inp);
+  return -1;
+}
+const char *
+certs_cell_check(const certs_cell_t *obj)
+{
+  if (obj == NULL)
+    return "Object was NULL";
+  if (obj->trunnel_error_code_)
+    return "A set function failed on this object";
+  {
+    const char *msg;
+
+    unsigned idx;
+    for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->certs); ++idx) {
+      if (NULL != (msg = certs_cell_cert_check(TRUNNEL_DYNARRAY_GET(&obj->certs, idx))))
+        return msg;
+    }
+  }
+  if (TRUNNEL_DYNARRAY_LEN(&obj->certs) != obj->n_certs)
+    return "Length mismatch for certs";
+  return NULL;
+}
+
+ssize_t
+certs_cell_encoded_len(const certs_cell_t *obj)
+{
+  ssize_t result = 0;
+
+  if (NULL != certs_cell_check(obj))
+     return -1;
+
+
+  /* Length of u8 n_certs */
+  result += 1;
+
+  /* Length of struct certs_cell_cert certs[n_certs] */
+  {
+
+    unsigned idx;
+    for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->certs); ++idx) {
+      result += certs_cell_cert_encoded_len(TRUNNEL_DYNARRAY_GET(&obj->certs, idx));
+    }
+  }
+  return result;
+}
+int
+certs_cell_clear_errors(certs_cell_t *obj)
+{
+  int r = obj->trunnel_error_code_;
+  obj->trunnel_error_code_ = 0;
+  return r;
+}
+ssize_t
+certs_cell_encode(uint8_t *output, const size_t avail, const certs_cell_t *obj)
+{
+  ssize_t result = 0;
+  size_t written = 0;
+  uint8_t *ptr = output;
+  const char *msg;
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+  const ssize_t encoded_len = certs_cell_encoded_len(obj);
+#endif
+
+  if (NULL != (msg = certs_cell_check(obj)))
+    goto check_failed;
+
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+  trunnel_assert(encoded_len >= 0);
+#endif
+
+  /* Encode u8 n_certs */
+  trunnel_assert(written <= avail);
+  if (avail - written < 1)
+    goto truncated;
+  trunnel_set_uint8(ptr, (obj->n_certs));
+  written += 1; ptr += 1;
+
+  /* Encode struct certs_cell_cert certs[n_certs] */
+  {
+
+    unsigned idx;
+    for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->certs); ++idx) {
+      trunnel_assert(written <= avail);
+      result = certs_cell_cert_encode(ptr, avail - written, TRUNNEL_DYNARRAY_GET(&obj->certs, idx));
+      if (result < 0)
+        goto fail; /* XXXXXXX !*/
+      written += result; ptr += result;
+    }
+  }
+
+
+  trunnel_assert(ptr == output + written);
+#ifdef TRUNNEL_CHECK_ENCODED_LEN
+  {
+    trunnel_assert(encoded_len >= 0);
+    trunnel_assert((size_t)encoded_len == written);
+  }
+
+#endif
+
+  return written;
+
+ truncated:
+  result = -2;
+  goto fail;
+ check_failed:
+  (void)msg;
+  result = -1;
+  goto fail;
+ fail:
+  trunnel_assert(result < 0);
+  return result;
+}
+
+/** As certs_cell_parse(), but do not allocate the output object.
+ */
+static ssize_t
+certs_cell_parse_into(certs_cell_t *obj, const uint8_t *input, const size_t len_in)
+{
+  const uint8_t *ptr = input;
+  size_t remaining = len_in;
+  ssize_t result = 0;
+  (void)result;
+
+  /* Parse u8 n_certs */
+  CHECK_REMAINING(1, truncated);
+  obj->n_certs = (trunnel_get_uint8(ptr));
+  remaining -= 1; ptr += 1;
+
+  /* Parse struct certs_cell_cert certs[n_certs] */
+  TRUNNEL_DYNARRAY_EXPAND(certs_cell_cert_t *, &obj->certs, obj->n_certs, {});
+  {
+    certs_cell_cert_t * elt;
+    unsigned idx;
+    for (idx = 0; idx < obj->n_certs; ++idx) {
+      result = certs_cell_cert_parse(&elt, ptr, remaining);
+      if (result < 0)
+        goto relay_fail;
+      trunnel_assert((size_t)result <= remaining);
+      remaining -= result; ptr += result;
+      TRUNNEL_DYNARRAY_ADD(certs_cell_cert_t *, &obj->certs, elt, {certs_cell_cert_free(elt);});
+    }
+  }
+  trunnel_assert(ptr + remaining == input + len_in);
+  return len_in - remaining;
+
+ truncated:
+  return -2;
+ relay_fail:
+  if (result >= 0) result = -1;
+  return result;
+ trunnel_alloc_failed:
+  return -1;
+}
+
+ssize_t
+certs_cell_parse(certs_cell_t **output, const uint8_t *input, const size_t len_in)
+{
+  ssize_t result;
+  *output = certs_cell_new();
+  if (NULL == *output)
+    return -1;
+  result = certs_cell_parse_into(*output, input, len_in);
+  if (result < 0) {
+    certs_cell_free(*output);
+    *output = NULL;
+  }
+  return result;
+}
diff --git a/src/trunnel/link_handshake.h b/src/trunnel/link_handshake.h
new file mode 100644 (file)
index 0000000..109fe8d
--- /dev/null
@@ -0,0 +1,654 @@
+/* link_handshake.h -- generated by by Trunnel v1.4-pre.
+ * https://gitweb.torproject.org/trunnel.git
+ * You probably shouldn't edit this file.
+ */
+#ifndef TRUNNEL_LINK_HANDSHAKE_H
+#define TRUNNEL_LINK_HANDSHAKE_H
+
+#include <stdint.h>
+#include "trunnel.h"
+
+#define CERTTYPE_RSA1024_ID_LINK 1
+#define CERTTYPE_RSA1024_ID_ID 2
+#define CERTTYPE_RSA1024_ID_AUTH 3
+#define CERTTYPE_ED_ID_SIGN 4
+#define CERTTYPE_ED_SIGN_LINK 5
+#define CERTTYPE_ED_SIGN_AUTH 6
+#define CERTTYPE_RSA1024_ID_EDID 7
+#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_AUTH_CHALLENGE_CELL)
+struct auth_challenge_cell_st {
+  uint8_t challenge[32];
+  uint16_t n_methods;
+  TRUNNEL_DYNARRAY_HEAD(, uint16_t) methods;
+  uint8_t trunnel_error_code_;
+};
+#endif
+typedef struct auth_challenge_cell_st auth_challenge_cell_t;
+#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_AUTH_CTX)
+struct auth_ctx_st {
+  uint8_t is_ed;
+  uint8_t trunnel_error_code_;
+};
+#endif
+typedef struct auth_ctx_st auth_ctx_t;
+#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_CERTS_CELL_CERT)
+struct certs_cell_cert_st {
+  uint8_t cert_type;
+  uint16_t cert_len;
+  TRUNNEL_DYNARRAY_HEAD(, uint8_t) body;
+  uint8_t trunnel_error_code_;
+};
+#endif
+typedef struct certs_cell_cert_st certs_cell_cert_t;
+#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_RSA_ED_CROSSCERT)
+struct rsa_ed_crosscert_st {
+  uint8_t ed_key[32];
+  uint32_t expiration;
+  const uint8_t *end_of_signed;
+  uint8_t sig_len;
+  TRUNNEL_DYNARRAY_HEAD(, uint8_t) sig;
+  uint8_t trunnel_error_code_;
+};
+#endif
+typedef struct rsa_ed_crosscert_st rsa_ed_crosscert_t;
+#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_AUTH1)
+struct auth1_st {
+  uint8_t type[8];
+  uint8_t cid[32];
+  uint8_t sid[32];
+  uint8_t u1_cid_ed[32];
+  uint8_t u1_sid_ed[32];
+  uint8_t slog[32];
+  uint8_t clog[32];
+  uint8_t scert[32];
+  uint8_t tlssecrets[32];
+  const uint8_t *end_of_fixed_part;
+  uint8_t rand[24];
+  const uint8_t *end_of_signed;
+  TRUNNEL_DYNARRAY_HEAD(, uint8_t) sig;
+  uint8_t trunnel_error_code_;
+};
+#endif
+typedef struct auth1_st auth1_t;
+#if !defined(TRUNNEL_OPAQUE) && !defined(TRUNNEL_OPAQUE_CERTS_CELL)
+struct certs_cell_st {
+  uint8_t n_certs;
+  TRUNNEL_DYNARRAY_HEAD(, struct certs_cell_cert_st *) certs;
+  uint8_t trunnel_error_code_;
+};
+#endif
+typedef struct certs_cell_st certs_cell_t;
+/** Return a newly allocated auth_challenge_cell with all elements set
+ * to zero.
+ */
+auth_challenge_cell_t *auth_challenge_cell_new(void);
+/** Release all storage held by the auth_challenge_cell in 'victim'.
+ * (Do nothing if 'victim' is NULL.)
+ */
+void auth_challenge_cell_free(auth_challenge_cell_t *victim);
+/** Try to parse a auth_challenge_cell from the buffer in 'input',
+ * using up to 'len_in' bytes from the input buffer. On success,
+ * return the number of bytes consumed and set *output to the newly
+ * allocated auth_challenge_cell_t. On failure, return -2 if the input
+ * appears truncated, and -1 if the input is otherwise invalid.
+ */
+ssize_t auth_challenge_cell_parse(auth_challenge_cell_t **output, const uint8_t *input, const size_t len_in);
+/** Return the number of bytes we expect to need to encode the
+ * auth_challenge_cell in 'obj'. On failure, return a negative value.
+ * Note that this value may be an overestimate, and can even be an
+ * underestimate for certain unencodeable objects.
+ */
+ssize_t auth_challenge_cell_encoded_len(const auth_challenge_cell_t *obj);
+/** Try to encode the auth_challenge_cell from 'input' into the buffer
+ * at 'output', using up to 'avail' bytes of the output buffer. On
+ * success, return the number of bytes used. On failure, return -2 if
+ * the buffer was not long enough, and -1 if the input was invalid.
+ */
+ssize_t auth_challenge_cell_encode(uint8_t *output, const size_t avail, const auth_challenge_cell_t *input);
+/** Check whether the internal state of the auth_challenge_cell in
+ * 'obj' is consistent. Return NULL if it is, and a short message if
+ * it is not.
+ */
+const char *auth_challenge_cell_check(const auth_challenge_cell_t *obj);
+/** Clear any errors that were set on the object 'obj' by its setter
+ * functions. Return true iff errors were cleared.
+ */
+int auth_challenge_cell_clear_errors(auth_challenge_cell_t *obj);
+/** Return the (constant) length of the array holding the challenge
+ * field of the auth_challenge_cell_t in 'inp'.
+ */
+size_t auth_challenge_cell_getlen_challenge(const auth_challenge_cell_t *inp);
+/** Return the element at position 'idx' of the fixed array field
+ * challenge of the auth_challenge_cell_t in 'inp'.
+ */
+uint8_t auth_challenge_cell_get_challenge(const auth_challenge_cell_t *inp, size_t idx);
+/** Change the element at position 'idx' of the fixed array field
+ * challenge of the auth_challenge_cell_t in 'inp', so that it will
+ * hold the value 'elt'.
+ */
+int auth_challenge_cell_set_challenge(auth_challenge_cell_t *inp, size_t idx, uint8_t elt);
+/** Return a pointer to the 32-element array field challenge of 'inp'.
+ */
+uint8_t * auth_challenge_cell_getarray_challenge(auth_challenge_cell_t *inp);
+/** Return the value of the n_methods field of the
+ * auth_challenge_cell_t in 'inp'
+ */
+uint16_t auth_challenge_cell_get_n_methods(auth_challenge_cell_t *inp);
+/** Set the value of the n_methods field of the auth_challenge_cell_t
+ * in 'inp' to 'val'. Return 0 on success; return -1 and set the error
+ * code on 'inp' on failure.
+ */
+int auth_challenge_cell_set_n_methods(auth_challenge_cell_t *inp, uint16_t val);
+/** Return the length of the dynamic array holding the methods field
+ * of the auth_challenge_cell_t in 'inp'.
+ */
+size_t auth_challenge_cell_getlen_methods(const auth_challenge_cell_t *inp);
+/** Return the element at position 'idx' of the dynamic array field
+ * methods of the auth_challenge_cell_t in 'inp'.
+ */
+uint16_t auth_challenge_cell_get_methods(auth_challenge_cell_t *inp, size_t idx);
+/** Change the element at position 'idx' of the dynamic array field
+ * methods of the auth_challenge_cell_t in 'inp', so that it will hold
+ * the value 'elt'.
+ */
+int auth_challenge_cell_set_methods(auth_challenge_cell_t *inp, size_t idx, uint16_t elt);
+/** Append a new element 'elt' to the dynamic array field methods of
+ * the auth_challenge_cell_t in 'inp'.
+ */
+int auth_challenge_cell_add_methods(auth_challenge_cell_t *inp, uint16_t elt);
+/** Return a pointer to the variable-length array field methods of
+ * 'inp'.
+ */
+uint16_t * auth_challenge_cell_getarray_methods(auth_challenge_cell_t *inp);
+/** Change the length of the variable-length array field methods of
+ * 'inp' to 'newlen'.Fill extra elements with 0. Return 0 on success;
+ * return -1 and set the error code on 'inp' on failure.
+ */
+int auth_challenge_cell_setlen_methods(auth_challenge_cell_t *inp, size_t newlen);
+/** Return a newly allocated auth_ctx with all elements set to zero.
+ */
+auth_ctx_t *auth_ctx_new(void);
+/** Release all storage held by the auth_ctx in 'victim'. (Do nothing
+ * if 'victim' is NULL.)
+ */
+void auth_ctx_free(auth_ctx_t *victim);
+/** Return the value of the is_ed field of the auth_ctx_t in 'inp'
+ */
+uint8_t auth_ctx_get_is_ed(auth_ctx_t *inp);
+/** Set the value of the is_ed field of the auth_ctx_t in 'inp' to
+ * 'val'. Return 0 on success; return -1 and set the error code on
+ * 'inp' on failure.
+ */
+int auth_ctx_set_is_ed(auth_ctx_t *inp, uint8_t val);
+/** Return a newly allocated certs_cell_cert with all elements set to
+ * zero.
+ */
+certs_cell_cert_t *certs_cell_cert_new(void);
+/** Release all storage held by the certs_cell_cert in 'victim'. (Do
+ * nothing if 'victim' is NULL.)
+ */
+void certs_cell_cert_free(certs_cell_cert_t *victim);
+/** Try to parse a certs_cell_cert from the buffer in 'input', using
+ * up to 'len_in' bytes from the input buffer. On success, return the
+ * number of bytes consumed and set *output to the newly allocated
+ * certs_cell_cert_t. On failure, return -2 if the input appears
+ * truncated, and -1 if the input is otherwise invalid.
+ */
+ssize_t certs_cell_cert_parse(certs_cell_cert_t **output, const uint8_t *input, const size_t len_in);
+/** Return the number of bytes we expect to need to encode the
+ * certs_cell_cert in 'obj'. On failure, return a negative value. Note
+ * that this value may be an overestimate, and can even be an
+ * underestimate for certain unencodeable objects.
+ */
+ssize_t certs_cell_cert_encoded_len(const certs_cell_cert_t *obj);
+/** Try to encode the certs_cell_cert from 'input' into the buffer at
+ * 'output', using up to 'avail' bytes of the output buffer. On
+ * success, return the number of bytes used. On failure, return -2 if
+ * the buffer was not long enough, and -1 if the input was invalid.
+ */
+ssize_t certs_cell_cert_encode(uint8_t *output, const size_t avail, const certs_cell_cert_t *input);
+/** Check whether the internal state of the certs_cell_cert in 'obj'
+ * is consistent. Return NULL if it is, and a short message if it is
+ * not.
+ */
+const char *certs_cell_cert_check(const certs_cell_cert_t *obj);
+/** Clear any errors that were set on the object 'obj' by its setter
+ * functions. Return true iff errors were cleared.
+ */
+int certs_cell_cert_clear_errors(certs_cell_cert_t *obj);
+/** Return the value of the cert_type field of the certs_cell_cert_t
+ * in 'inp'
+ */
+uint8_t certs_cell_cert_get_cert_type(certs_cell_cert_t *inp);
+/** Set the value of the cert_type field of the certs_cell_cert_t in
+ * 'inp' to 'val'. Return 0 on success; return -1 and set the error
+ * code on 'inp' on failure.
+ */
+int certs_cell_cert_set_cert_type(certs_cell_cert_t *inp, uint8_t val);
+/** Return the value of the cert_len field of the certs_cell_cert_t in
+ * 'inp'
+ */
+uint16_t certs_cell_cert_get_cert_len(certs_cell_cert_t *inp);
+/** Set the value of the cert_len field of the certs_cell_cert_t in
+ * 'inp' to 'val'. Return 0 on success; return -1 and set the error
+ * code on 'inp' on failure.
+ */
+int certs_cell_cert_set_cert_len(certs_cell_cert_t *inp, uint16_t val);
+/** Return the length of the dynamic array holding the body field of
+ * the certs_cell_cert_t in 'inp'.
+ */
+size_t certs_cell_cert_getlen_body(const certs_cell_cert_t *inp);
+/** Return the element at position 'idx' of the dynamic array field
+ * body of the certs_cell_cert_t in 'inp'.
+ */
+uint8_t certs_cell_cert_get_body(certs_cell_cert_t *inp, size_t idx);
+/** Change the element at position 'idx' of the dynamic array field
+ * body of the certs_cell_cert_t in 'inp', so that it will hold the
+ * value 'elt'.
+ */
+int certs_cell_cert_set_body(certs_cell_cert_t *inp, size_t idx, uint8_t elt);
+/** Append a new element 'elt' to the dynamic array field body of the
+ * certs_cell_cert_t in 'inp'.
+ */
+int certs_cell_cert_add_body(certs_cell_cert_t *inp, uint8_t elt);
+/** Return a pointer to the variable-length array field body of 'inp'.
+ */
+uint8_t * certs_cell_cert_getarray_body(certs_cell_cert_t *inp);
+/** Change the length of the variable-length array field body of 'inp'
+ * to 'newlen'.Fill extra elements with 0. Return 0 on success; return
+ * -1 and set the error code on 'inp' on failure.
+ */
+int certs_cell_cert_setlen_body(certs_cell_cert_t *inp, size_t newlen);
+/** Return a newly allocated rsa_ed_crosscert with all elements set to
+ * zero.
+ */
+rsa_ed_crosscert_t *rsa_ed_crosscert_new(void);
+/** Release all storage held by the rsa_ed_crosscert in 'victim'. (Do
+ * nothing if 'victim' is NULL.)
+ */
+void rsa_ed_crosscert_free(rsa_ed_crosscert_t *victim);
+/** Try to parse a rsa_ed_crosscert from the buffer in 'input', using
+ * up to 'len_in' bytes from the input buffer. On success, return the
+ * number of bytes consumed and set *output to the newly allocated
+ * rsa_ed_crosscert_t. On failure, return -2 if the input appears
+ * truncated, and -1 if the input is otherwise invalid.
+ */
+ssize_t rsa_ed_crosscert_parse(rsa_ed_crosscert_t **output, const uint8_t *input, const size_t len_in);
+/** Return the number of bytes we expect to need to encode the
+ * rsa_ed_crosscert in 'obj'. On failure, return a negative value.
+ * Note that this value may be an overestimate, and can even be an
+ * underestimate for certain unencodeable objects.
+ */
+ssize_t rsa_ed_crosscert_encoded_len(const rsa_ed_crosscert_t *obj);
+/** Try to encode the rsa_ed_crosscert from 'input' into the buffer at
+ * 'output', using up to 'avail' bytes of the output buffer. On
+ * success, return the number of bytes used. On failure, return -2 if
+ * the buffer was not long enough, and -1 if the input was invalid.
+ */
+ssize_t rsa_ed_crosscert_encode(uint8_t *output, const size_t avail, const rsa_ed_crosscert_t *input);
+/** Check whether the internal state of the rsa_ed_crosscert in 'obj'
+ * is consistent. Return NULL if it is, and a short message if it is
+ * not.
+ */
+const char *rsa_ed_crosscert_check(const rsa_ed_crosscert_t *obj);
+/** Clear any errors that were set on the object 'obj' by its setter
+ * functions. Return true iff errors were cleared.
+ */
+int rsa_ed_crosscert_clear_errors(rsa_ed_crosscert_t *obj);
+/** Return the (constant) length of the array holding the ed_key field
+ * of the rsa_ed_crosscert_t in 'inp'.
+ */
+size_t rsa_ed_crosscert_getlen_ed_key(const rsa_ed_crosscert_t *inp);
+/** Return the element at position 'idx' of the fixed array field
+ * ed_key of the rsa_ed_crosscert_t in 'inp'.
+ */
+uint8_t rsa_ed_crosscert_get_ed_key(const rsa_ed_crosscert_t *inp, size_t idx);
+/** Change the element at position 'idx' of the fixed array field
+ * ed_key of the rsa_ed_crosscert_t in 'inp', so that it will hold the
+ * value 'elt'.
+ */
+int rsa_ed_crosscert_set_ed_key(rsa_ed_crosscert_t *inp, size_t idx, uint8_t elt);
+/** Return a pointer to the 32-element array field ed_key of 'inp'.
+ */
+uint8_t * rsa_ed_crosscert_getarray_ed_key(rsa_ed_crosscert_t *inp);
+/** Return the value of the expiration field of the rsa_ed_crosscert_t
+ * in 'inp'
+ */
+uint32_t rsa_ed_crosscert_get_expiration(rsa_ed_crosscert_t *inp);
+/** Set the value of the expiration field of the rsa_ed_crosscert_t in
+ * 'inp' to 'val'. Return 0 on success; return -1 and set the error
+ * code on 'inp' on failure.
+ */
+int rsa_ed_crosscert_set_expiration(rsa_ed_crosscert_t *inp, uint32_t val);
+/** Return the position for end_of_signed when we parsed this object
+ */
+const uint8_t * rsa_ed_crosscert_get_end_of_signed(const rsa_ed_crosscert_t *inp);
+/** Return the value of the sig_len field of the rsa_ed_crosscert_t in
+ * 'inp'
+ */
+uint8_t rsa_ed_crosscert_get_sig_len(rsa_ed_crosscert_t *inp);
+/** Set the value of the sig_len field of the rsa_ed_crosscert_t in
+ * 'inp' to 'val'. Return 0 on success; return -1 and set the error
+ * code on 'inp' on failure.
+ */
+int rsa_ed_crosscert_set_sig_len(rsa_ed_crosscert_t *inp, uint8_t val);
+/** Return the length of the dynamic array holding the sig field of
+ * the rsa_ed_crosscert_t in 'inp'.
+ */
+size_t rsa_ed_crosscert_getlen_sig(const rsa_ed_crosscert_t *inp);
+/** Return the element at position 'idx' of the dynamic array field
+ * sig of the rsa_ed_crosscert_t in 'inp'.
+ */
+uint8_t rsa_ed_crosscert_get_sig(rsa_ed_crosscert_t *inp, size_t idx);
+/** Change the element at position 'idx' of the dynamic array field
+ * sig of the rsa_ed_crosscert_t in 'inp', so that it will hold the
+ * value 'elt'.
+ */
+int rsa_ed_crosscert_set_sig(rsa_ed_crosscert_t *inp, size_t idx, uint8_t elt);
+/** Append a new element 'elt' to the dynamic array field sig of the
+ * rsa_ed_crosscert_t in 'inp'.
+ */
+int rsa_ed_crosscert_add_sig(rsa_ed_crosscert_t *inp, uint8_t elt);
+/** Return a pointer to the variable-length array field sig of 'inp'.
+ */
+uint8_t * rsa_ed_crosscert_getarray_sig(rsa_ed_crosscert_t *inp);
+/** Change the length of the variable-length array field sig of 'inp'
+ * to 'newlen'.Fill extra elements with 0. Return 0 on success; return
+ * -1 and set the error code on 'inp' on failure.
+ */
+int rsa_ed_crosscert_setlen_sig(rsa_ed_crosscert_t *inp, size_t newlen);
+/** Return a newly allocated auth1 with all elements set to zero.
+ */
+auth1_t *auth1_new(void);
+/** Release all storage held by the auth1 in 'victim'. (Do nothing if
+ * 'victim' is NULL.)
+ */
+void auth1_free(auth1_t *victim);
+/** Try to parse a auth1 from the buffer in 'input', using up to
+ * 'len_in' bytes from the input buffer. On success, return the number
+ * of bytes consumed and set *output to the newly allocated auth1_t.
+ * On failure, return -2 if the input appears truncated, and -1 if the
+ * input is otherwise invalid.
+ */
+ssize_t auth1_parse(auth1_t **output, const uint8_t *input, const size_t len_in, const auth_ctx_t *auth_ctx_ctx);
+/** Return the number of bytes we expect to need to encode the auth1
+ * in 'obj'. On failure, return a negative value. Note that this value
+ * may be an overestimate, and can even be an underestimate for
+ * certain unencodeable objects.
+ */
+ssize_t auth1_encoded_len(const auth1_t *obj, const auth_ctx_t *auth_ctx_ctx);
+/** Try to encode the auth1 from 'input' into the buffer at 'output',
+ * using up to 'avail' bytes of the output buffer. On success, return
+ * the number of bytes used. On failure, return -2 if the buffer was
+ * not long enough, and -1 if the input was invalid.
+ */
+ssize_t auth1_encode(uint8_t *output, const size_t avail, const auth1_t *input, const auth_ctx_t *auth_ctx_ctx);
+/** Check whether the internal state of the auth1 in 'obj' is
+ * consistent. Return NULL if it is, and a short message if it is not.
+ */
+const char *auth1_check(const auth1_t *obj, const auth_ctx_t *auth_ctx_ctx);
+/** Clear any errors that were set on the object 'obj' by its setter
+ * functions. Return true iff errors were cleared.
+ */
+int auth1_clear_errors(auth1_t *obj);
+/** Return the (constant) length of the array holding the type field
+ * of the auth1_t in 'inp'.
+ */
+size_t auth1_getlen_type(const auth1_t *inp);
+/** Return the element at position 'idx' of the fixed array field type
+ * of the auth1_t in 'inp'.
+ */
+uint8_t auth1_get_type(const auth1_t *inp, size_t idx);
+/** Change the element at position 'idx' of the fixed array field type
+ * of the auth1_t in 'inp', so that it will hold the value 'elt'.
+ */
+int auth1_set_type(auth1_t *inp, size_t idx, uint8_t elt);
+/** Return a pointer to the 8-element array field type of 'inp'.
+ */
+uint8_t * auth1_getarray_type(auth1_t *inp);
+/** Return the (constant) length of the array holding the cid field of
+ * the auth1_t in 'inp'.
+ */
+size_t auth1_getlen_cid(const auth1_t *inp);
+/** Return the element at position 'idx' of the fixed array field cid
+ * of the auth1_t in 'inp'.
+ */
+uint8_t auth1_get_cid(const auth1_t *inp, size_t idx);
+/** Change the element at position 'idx' of the fixed array field cid
+ * of the auth1_t in 'inp', so that it will hold the value 'elt'.
+ */
+int auth1_set_cid(auth1_t *inp, size_t idx, uint8_t elt);
+/** Return a pointer to the 32-element array field cid of 'inp'.
+ */
+uint8_t * auth1_getarray_cid(auth1_t *inp);
+/** Return the (constant) length of the array holding the sid field of
+ * the auth1_t in 'inp'.
+ */
+size_t auth1_getlen_sid(const auth1_t *inp);
+/** Return the element at position 'idx' of the fixed array field sid
+ * of the auth1_t in 'inp'.
+ */
+uint8_t auth1_get_sid(const auth1_t *inp, size_t idx);
+/** Change the element at position 'idx' of the fixed array field sid
+ * of the auth1_t in 'inp', so that it will hold the value 'elt'.
+ */
+int auth1_set_sid(auth1_t *inp, size_t idx, uint8_t elt);
+/** Return a pointer to the 32-element array field sid of 'inp'.
+ */
+uint8_t * auth1_getarray_sid(auth1_t *inp);
+/** Return the (constant) length of the array holding the u1_cid_ed
+ * field of the auth1_t in 'inp'.
+ */
+size_t auth1_getlen_u1_cid_ed(const auth1_t *inp);
+/** Return the element at position 'idx' of the fixed array field
+ * u1_cid_ed of the auth1_t in 'inp'.
+ */
+uint8_t auth1_get_u1_cid_ed(const auth1_t *inp, size_t idx);
+/** Change the element at position 'idx' of the fixed array field
+ * u1_cid_ed of the auth1_t in 'inp', so that it will hold the value
+ * 'elt'.
+ */
+int auth1_set_u1_cid_ed(auth1_t *inp, size_t idx, uint8_t elt);
+/** Return a pointer to the 32-element array field u1_cid_ed of 'inp'.
+ */
+uint8_t * auth1_getarray_u1_cid_ed(auth1_t *inp);
+/** Return the (constant) length of the array holding the u1_sid_ed
+ * field of the auth1_t in 'inp'.
+ */
+size_t auth1_getlen_u1_sid_ed(const auth1_t *inp);
+/** Return the element at position 'idx' of the fixed array field
+ * u1_sid_ed of the auth1_t in 'inp'.
+ */
+uint8_t auth1_get_u1_sid_ed(const auth1_t *inp, size_t idx);
+/** Change the element at position 'idx' of the fixed array field
+ * u1_sid_ed of the auth1_t in 'inp', so that it will hold the value
+ * 'elt'.
+ */
+int auth1_set_u1_sid_ed(auth1_t *inp, size_t idx, uint8_t elt);
+/** Return a pointer to the 32-element array field u1_sid_ed of 'inp'.
+ */
+uint8_t * auth1_getarray_u1_sid_ed(auth1_t *inp);
+/** Return the (constant) length of the array holding the slog field
+ * of the auth1_t in 'inp'.
+ */
+size_t auth1_getlen_slog(const auth1_t *inp);
+/** Return the element at position 'idx' of the fixed array field slog
+ * of the auth1_t in 'inp'.
+ */
+uint8_t auth1_get_slog(const auth1_t *inp, size_t idx);
+/** Change the element at position 'idx' of the fixed array field slog
+ * of the auth1_t in 'inp', so that it will hold the value 'elt'.
+ */
+int auth1_set_slog(auth1_t *inp, size_t idx, uint8_t elt);
+/** Return a pointer to the 32-element array field slog of 'inp'.
+ */
+uint8_t * auth1_getarray_slog(auth1_t *inp);
+/** Return the (constant) length of the array holding the clog field
+ * of the auth1_t in 'inp'.
+ */
+size_t auth1_getlen_clog(const auth1_t *inp);
+/** Return the element at position 'idx' of the fixed array field clog
+ * of the auth1_t in 'inp'.
+ */
+uint8_t auth1_get_clog(const auth1_t *inp, size_t idx);
+/** Change the element at position 'idx' of the fixed array field clog
+ * of the auth1_t in 'inp', so that it will hold the value 'elt'.
+ */
+int auth1_set_clog(auth1_t *inp, size_t idx, uint8_t elt);
+/** Return a pointer to the 32-element array field clog of 'inp'.
+ */
+uint8_t * auth1_getarray_clog(auth1_t *inp);
+/** Return the (constant) length of the array holding the scert field
+ * of the auth1_t in 'inp'.
+ */
+size_t auth1_getlen_scert(const auth1_t *inp);
+/** Return the element at position 'idx' of the fixed array field
+ * scert of the auth1_t in 'inp'.
+ */
+uint8_t auth1_get_scert(const auth1_t *inp, size_t idx);
+/** Change the element at position 'idx' of the fixed array field
+ * scert of the auth1_t in 'inp', so that it will hold the value
+ * 'elt'.
+ */
+int auth1_set_scert(auth1_t *inp, size_t idx, uint8_t elt);
+/** Return a pointer to the 32-element array field scert of 'inp'.
+ */
+uint8_t * auth1_getarray_scert(auth1_t *inp);
+/** Return the (constant) length of the array holding the tlssecrets
+ * field of the auth1_t in 'inp'.
+ */
+size_t auth1_getlen_tlssecrets(const auth1_t *inp);
+/** Return the element at position 'idx' of the fixed array field
+ * tlssecrets of the auth1_t in 'inp'.
+ */
+uint8_t auth1_get_tlssecrets(const auth1_t *inp, size_t idx);
+/** Change the element at position 'idx' of the fixed array field
+ * tlssecrets of the auth1_t in 'inp', so that it will hold the value
+ * 'elt'.
+ */
+int auth1_set_tlssecrets(auth1_t *inp, size_t idx, uint8_t elt);
+/** Return a pointer to the 32-element array field tlssecrets of
+ * 'inp'.
+ */
+uint8_t * auth1_getarray_tlssecrets(auth1_t *inp);
+/** Return the position for end_of_fixed_part when we parsed this
+ * object
+ */
+const uint8_t * auth1_get_end_of_fixed_part(const auth1_t *inp);
+/** Return the (constant) length of the array holding the rand field
+ * of the auth1_t in 'inp'.
+ */
+size_t auth1_getlen_rand(const auth1_t *inp);
+/** Return the element at position 'idx' of the fixed array field rand
+ * of the auth1_t in 'inp'.
+ */
+uint8_t auth1_get_rand(const auth1_t *inp, size_t idx);
+/** Change the element at position 'idx' of the fixed array field rand
+ * of the auth1_t in 'inp', so that it will hold the value 'elt'.
+ */
+int auth1_set_rand(auth1_t *inp, size_t idx, uint8_t elt);
+/** Return a pointer to the 24-element array field rand of 'inp'.
+ */
+uint8_t * auth1_getarray_rand(auth1_t *inp);
+/** Return the position for end_of_signed when we parsed this object
+ */
+const uint8_t * auth1_get_end_of_signed(const auth1_t *inp);
+/** Return the length of the dynamic array holding the sig field of
+ * the auth1_t in 'inp'.
+ */
+size_t auth1_getlen_sig(const auth1_t *inp);
+/** Return the element at position 'idx' of the dynamic array field
+ * sig of the auth1_t in 'inp'.
+ */
+uint8_t auth1_get_sig(auth1_t *inp, size_t idx);
+/** Change the element at position 'idx' of the dynamic array field
+ * sig of the auth1_t in 'inp', so that it will hold the value 'elt'.
+ */
+int auth1_set_sig(auth1_t *inp, size_t idx, uint8_t elt);
+/** Append a new element 'elt' to the dynamic array field sig of the
+ * auth1_t in 'inp'.
+ */
+int auth1_add_sig(auth1_t *inp, uint8_t elt);
+/** Return a pointer to the variable-length array field sig of 'inp'.
+ */
+uint8_t * auth1_getarray_sig(auth1_t *inp);
+/** Change the length of the variable-length array field sig of 'inp'
+ * to 'newlen'.Fill extra elements with 0. Return 0 on success; return
+ * -1 and set the error code on 'inp' on failure.
+ */
+int auth1_setlen_sig(auth1_t *inp, size_t newlen);
+/** Return a newly allocated certs_cell with all elements set to zero.
+ */
+certs_cell_t *certs_cell_new(void);
+/** Release all storage held by the certs_cell in 'victim'. (Do
+ * nothing if 'victim' is NULL.)
+ */
+void certs_cell_free(certs_cell_t *victim);
+/** Try to parse a certs_cell from the buffer in 'input', using up to
+ * 'len_in' bytes from the input buffer. On success, return the number
+ * of bytes consumed and set *output to the newly allocated
+ * certs_cell_t. On failure, return -2 if the input appears truncated,
+ * and -1 if the input is otherwise invalid.
+ */
+ssize_t certs_cell_parse(certs_cell_t **output, const uint8_t *input, const size_t len_in);
+/** Return the number of bytes we expect to need to encode the
+ * certs_cell in 'obj'. On failure, return a negative value. Note that
+ * this value may be an overestimate, and can even be an underestimate
+ * for certain unencodeable objects.
+ */
+ssize_t certs_cell_encoded_len(const certs_cell_t *obj);
+/** Try to encode the certs_cell from 'input' into the buffer at
+ * 'output', using up to 'avail' bytes of the output buffer. On
+ * success, return the number of bytes used. On failure, return -2 if
+ * the buffer was not long enough, and -1 if the input was invalid.
+ */
+ssize_t certs_cell_encode(uint8_t *output, const size_t avail, const certs_cell_t *input);
+/** Check whether the internal state of the certs_cell in 'obj' is
+ * consistent. Return NULL if it is, and a short message if it is not.
+ */
+const char *certs_cell_check(const certs_cell_t *obj);
+/** Clear any errors that were set on the object 'obj' by its setter
+ * functions. Return true iff errors were cleared.
+ */
+int certs_cell_clear_errors(certs_cell_t *obj);
+/** Return the value of the n_certs field of the certs_cell_t in 'inp'
+ */
+uint8_t certs_cell_get_n_certs(certs_cell_t *inp);
+/** Set the value of the n_certs field of the certs_cell_t in 'inp' to
+ * 'val'. Return 0 on success; return -1 and set the error code on
+ * 'inp' on failure.
+ */
+int certs_cell_set_n_certs(certs_cell_t *inp, uint8_t val);
+/** Return the length of the dynamic array holding the certs field of
+ * the certs_cell_t in 'inp'.
+ */
+size_t certs_cell_getlen_certs(const certs_cell_t *inp);
+/** Return the element at position 'idx' of the dynamic array field
+ * certs of the certs_cell_t in 'inp'.
+ */
+struct certs_cell_cert_st * certs_cell_get_certs(certs_cell_t *inp, size_t idx);
+/** Change the element at position 'idx' of the dynamic array field
+ * certs of the certs_cell_t in 'inp', so that it will hold the value
+ * 'elt'. Free the previous value, if any.
+ */
+int certs_cell_set_certs(certs_cell_t *inp, size_t idx, struct certs_cell_cert_st * elt);
+/** As certs_cell_set_certs, but does not free the previous value.
+ */
+int certs_cell_set0_certs(certs_cell_t *inp, size_t idx, struct certs_cell_cert_st * elt);
+/** Append a new element 'elt' to the dynamic array field certs of the
+ * certs_cell_t in 'inp'.
+ */
+int certs_cell_add_certs(certs_cell_t *inp, struct certs_cell_cert_st * elt);
+/** Return a pointer to the variable-length array field certs of
+ * 'inp'.
+ */
+struct certs_cell_cert_st * * certs_cell_getarray_certs(certs_cell_t *inp);
+/** Change the length of the variable-length array field certs of
+ * 'inp' to 'newlen'.Fill extra elements with NULL; free removed
+ * elements. Return 0 on success; return -1 and set the error code on
+ * 'inp' on failure.
+ */
+int certs_cell_setlen_certs(certs_cell_t *inp, size_t newlen);
+
+
+#endif
diff --git a/src/trunnel/link_handshake.trunnel b/src/trunnel/link_handshake.trunnel
new file mode 100644 (file)
index 0000000..b858e17
--- /dev/null
@@ -0,0 +1,57 @@
+
+struct certs_cell {
+  u8 n_certs;
+  struct certs_cell_cert certs[n_certs];
+}
+
+const CERTTYPE_RSA1024_ID_LINK = 1;
+const CERTTYPE_RSA1024_ID_ID   = 2;
+const CERTTYPE_RSA1024_ID_AUTH = 3;
+const CERTTYPE_ED_ID_SIGN      = 4;
+const CERTTYPE_ED_SIGN_LINK    = 5;
+const CERTTYPE_ED_SIGN_AUTH    = 6;
+const CERTTYPE_RSA1024_ID_EDID = 7;
+
+struct certs_cell_cert {
+  u8 cert_type;
+  u16 cert_len;
+  u8 body[cert_len];
+}
+
+struct rsa_ed_crosscert {
+  u8 ed_key[32];
+  u32 expiration;
+  @ptr end_of_signed;
+  u8 sig_len;
+  u8 sig[sig_len]; // mismatches spec.
+}
+
+struct auth_challenge_cell {
+  u8 challenge[32];
+  u16 n_methods;
+  u16 methods[n_methods];
+}
+
+context auth_ctx {
+  u8 is_ed;
+}
+
+struct auth1 with context auth_ctx {
+  u8 type[8];
+  u8 cid[32];
+  u8 sid[32];
+  union u1[auth_ctx.is_ed] {
+    0 : ;
+    1 : u8 cid_ed[32];
+        u8 sid_ed[32];
+    default: fail;
+  };
+  u8 slog[32];
+  u8 clog[32];
+  u8 scert[32];
+  u8 tlssecrets[32];
+  @ptr end_of_fixed_part;
+  u8 rand[24];
+  @ptr end_of_signed;
+  u8 sig[];
+}