[tor-commits] [tor/master] Merge branch 'ticket17238_029_02-resquash'
nickm at torproject.org
nickm at torproject.org
Fri Nov 4 18:48:12 UTC 2016
commit c35c43d7d9df793c890deb14800e24327fbca452
Merge: bd6aa4f c189cb5
Author: Nick Mathewson <nickm at torproject.org>
Date: Fri Nov 4 13:26:37 2016 -0400
Merge branch 'ticket17238_029_02-resquash'
Conflicts:
src/or/rendclient.c
src/or/rendcommon.c
src/or/routerparse.c
src/test/test_dir.c
src/trunnel/ed25519_cert.h
src/or/circuitlist.c | 38 +-
src/or/circuitlist.h | 2 +-
src/or/circuituse.c | 9 +-
src/or/connection.c | 5 +-
src/or/connection_edge.c | 10 +-
src/or/control.c | 21 +-
src/or/directory.c | 179 +++-
src/or/directory.h | 15 +-
src/or/hs_cache.c | 384 ++++++++
src/or/hs_cache.h | 61 ++
src/or/hs_common.c | 280 ++++++
src/or/hs_common.h | 39 +
src/or/hs_descriptor.c | 1939 ++++++++++++++++++++++++++++++++++++++
src/or/hs_descriptor.h | 238 +++++
src/or/include.am | 8 +
src/or/main.c | 4 +-
src/or/or.h | 42 +-
src/or/parsecommon.c | 450 +++++++++
src/or/parsecommon.h | 314 ++++++
src/or/relay.c | 5 +-
src/or/rendcache.c | 79 +-
src/or/rendcache.h | 13 +-
src/or/rendclient.c | 148 +--
src/or/rendclient.h | 2 +-
src/or/rendcommon.c | 149 +--
src/or/rendcommon.h | 24 +-
src/or/rendservice.c | 87 +-
src/or/routerparse.c | 723 +-------------
src/or/torcert.h | 15 +-
src/test/include.am | 2 +
src/test/test.c | 2 +
src/test/test.h | 2 +
src/test/test_connection.c | 12 +-
src/test/test_dir.c | 62 ++
src/test/test_dir_handle_get.c | 13 -
src/test/test_helpers.c | 13 +
src/test/test_helpers.h | 4 +
src/test/test_hs.c | 103 +-
src/test/test_hs_cache.c | 479 ++++++++++
src/test/test_hs_descriptor.c | 1130 ++++++++++++++++++++++
src/test/test_rendcache.c | 57 +-
src/trunnel/ed25519_cert.c | 881 +++++++++++++++++
src/trunnel/ed25519_cert.h | 300 ++++++
src/trunnel/ed25519_cert.trunnel | 7 +-
44 files changed, 7168 insertions(+), 1182 deletions(-)
diff --cc src/or/connection_edge.c
index 0c18de0,2726349..875c911
--- a/src/or/connection_edge.c
+++ b/src/or/connection_edge.c
@@@ -72,9 -27,9 +72,10 @@@
#include "control.h"
#include "dns.h"
#include "dnsserv.h"
+#include "directory.h"
#include "dirserv.h"
#include "hibernate.h"
+ #include "hs_common.h"
#include "main.h"
#include "nodelist.h"
#include "policies.h"
@@@ -1861,11 -1708,12 +1862,12 @@@ connection_ap_handshake_rewrite_and_att
if (rend_data == NULL) {
return -1;
}
+ const char *onion_address = rend_data_get_address(rend_data);
log_info(LD_REND,"Got a hidden service request for ID '%s'",
- safe_str_client(rend_data->onion_address));
+ safe_str_client(onion_address));
- /* Lookup the given onion address. If invalid, stop right now else we
- * might have it in the cache or not, it will be tested later on. */
+ /* Lookup the given onion address. If invalid, stop right now.
+ * Otherwise, we might have it in the cache or not. */
unsigned int refetch_desc = 0;
rend_cache_entry_t *entry = NULL;
const int rend_cache_lookup_result =
diff --cc src/or/directory.h
index f1cdd9f,210d623..acb7394
--- a/src/or/directory.h
+++ b/src/or/directory.h
@@@ -132,11 -132,18 +132,19 @@@ int download_status_get_n_failures(cons
int download_status_get_n_attempts(const download_status_t *dls);
time_t download_status_get_next_attempt_at(const download_status_t *dls);
-int purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose);
+int purpose_needs_anonymity(uint8_t dir_purpose, uint8_t router_purpose,
+ const char *resource);
+ #ifdef DIRECTORY_PRIVATE
+
+ struct get_handler_args_t;
+ STATIC int handle_get_hs_descriptor_v3(dir_connection_t *conn,
+ const struct get_handler_args_t *args);
+
+ #endif
+
#ifdef TOR_UNIT_TESTS
- /* Used only by directory.c and test_dir.c */
+ /* Used only by test_dir.c */
STATIC int parse_http_url(const char *headers, char **url);
STATIC dirinfo_type_t dir_fetch_type(int dir_purpose, int router_purpose,
diff --cc src/or/include.am
index b4554aa,02d67fa..10f8b85
--- a/src/or/include.am
+++ b/src/or/include.am
@@@ -59,8 -62,8 +62,9 @@@ LIBTOR_A_SOURCES =
src/or/shared_random.c \
src/or/shared_random_state.c \
src/or/transports.c \
+ src/or/parsecommon.c \
src/or/periodic.c \
+ src/or/protover.c \
src/or/policies.c \
src/or/reasons.c \
src/or/relay.c \
@@@ -171,9 -177,9 +178,10 @@@ ORHEADERS =
src/or/shared_random.h \
src/or/shared_random_state.h \
src/or/transports.h \
+ src/or/parsecommon.h \
src/or/periodic.h \
src/or/policies.h \
+ src/or/protover.h \
src/or/reasons.h \
src/or/relay.h \
src/or/rendcache.h \
diff --cc src/or/parsecommon.h
index 0000000,be7cba4..3a86c52
mode 000000,100644..100644
--- a/src/or/parsecommon.h
+++ b/src/or/parsecommon.h
@@@ -1,0 -1,306 +1,314 @@@
+ /* Copyright (c) 2016, The Tor Project, Inc. */
+ /* See LICENSE for licensing information */
+
+ /**
+ * \file parsecommon.h
+ * \brief Header file for parsecommon.c
+ **/
+
+ #ifndef TOR_PARSECOMMON_H
+ #define TOR_PARSECOMMON_H
+
+ #include "container.h"
+ #include "crypto.h"
+ #include "memarea.h"
+
+ /** Enumeration of possible token types. The ones starting with K_ correspond
+ * to directory 'keywords'. A_ is for an annotation, R or C is related to
+ * hidden services, ERR_ is an error in the tokenizing process, EOF_ is an
+ * end-of-file marker, and NIL_ is used to encode not-a-token.
+ */
+ typedef enum {
+ K_ACCEPT = 0,
+ K_ACCEPT6,
+ K_DIRECTORY_SIGNATURE,
+ K_RECOMMENDED_SOFTWARE,
+ K_REJECT,
+ K_REJECT6,
+ K_ROUTER,
+ K_SIGNED_DIRECTORY,
+ K_SIGNING_KEY,
+ K_ONION_KEY,
+ K_ONION_KEY_NTOR,
+ K_ROUTER_SIGNATURE,
+ K_PUBLISHED,
+ K_RUNNING_ROUTERS,
+ K_ROUTER_STATUS,
+ K_PLATFORM,
++ K_PROTO,
+ K_OPT,
+ K_BANDWIDTH,
+ K_CONTACT,
+ K_NETWORK_STATUS,
+ K_UPTIME,
+ K_DIR_SIGNING_KEY,
+ K_FAMILY,
+ K_FINGERPRINT,
+ K_HIBERNATING,
+ K_READ_HISTORY,
+ K_WRITE_HISTORY,
+ K_NETWORK_STATUS_VERSION,
+ K_DIR_SOURCE,
+ K_DIR_OPTIONS,
+ K_CLIENT_VERSIONS,
+ K_SERVER_VERSIONS,
++ K_RECOMMENDED_CLIENT_PROTOCOLS,
++ K_RECOMMENDED_RELAY_PROTOCOLS,
++ K_REQUIRED_CLIENT_PROTOCOLS,
++ K_REQUIRED_RELAY_PROTOCOLS,
+ K_OR_ADDRESS,
+ K_ID,
+ K_P,
+ K_P6,
+ K_R,
+ K_A,
+ K_S,
+ K_V,
+ K_W,
+ K_M,
+ K_EXTRA_INFO,
+ K_EXTRA_INFO_DIGEST,
+ K_CACHES_EXTRA_INFO,
+ K_HIDDEN_SERVICE_DIR,
+ K_ALLOW_SINGLE_HOP_EXITS,
+ K_IPV6_POLICY,
+ K_ROUTER_SIG_ED25519,
+ K_IDENTITY_ED25519,
+ K_MASTER_KEY_ED25519,
+ K_ONION_KEY_CROSSCERT,
+ K_NTOR_ONION_KEY_CROSSCERT,
+
+ K_DIRREQ_END,
+ K_DIRREQ_V2_IPS,
+ K_DIRREQ_V3_IPS,
+ K_DIRREQ_V2_REQS,
+ K_DIRREQ_V3_REQS,
+ K_DIRREQ_V2_SHARE,
+ K_DIRREQ_V3_SHARE,
+ K_DIRREQ_V2_RESP,
+ K_DIRREQ_V3_RESP,
+ K_DIRREQ_V2_DIR,
+ K_DIRREQ_V3_DIR,
+ K_DIRREQ_V2_TUN,
+ K_DIRREQ_V3_TUN,
+ K_ENTRY_END,
+ K_ENTRY_IPS,
+ K_CELL_END,
+ K_CELL_PROCESSED,
+ K_CELL_QUEUED,
+ K_CELL_TIME,
+ K_CELL_CIRCS,
+ K_EXIT_END,
+ K_EXIT_WRITTEN,
+ K_EXIT_READ,
+ K_EXIT_OPENED,
+
+ K_DIR_KEY_CERTIFICATE_VERSION,
+ K_DIR_IDENTITY_KEY,
+ K_DIR_KEY_PUBLISHED,
+ K_DIR_KEY_EXPIRES,
+ K_DIR_KEY_CERTIFICATION,
+ K_DIR_KEY_CROSSCERT,
+ K_DIR_ADDRESS,
+ K_DIR_TUNNELLED,
+
+ K_VOTE_STATUS,
+ K_VALID_AFTER,
+ K_FRESH_UNTIL,
+ K_VALID_UNTIL,
+ K_VOTING_DELAY,
+
+ K_KNOWN_FLAGS,
+ K_PARAMS,
+ K_BW_WEIGHTS,
+ K_VOTE_DIGEST,
+ K_CONSENSUS_DIGEST,
+ K_ADDITIONAL_DIGEST,
+ K_ADDITIONAL_SIGNATURE,
+ K_CONSENSUS_METHODS,
+ K_CONSENSUS_METHOD,
+ K_LEGACY_DIR_KEY,
+ K_DIRECTORY_FOOTER,
+ K_SIGNING_CERT_ED,
+ K_SR_FLAG,
+ K_COMMIT,
+ K_PREVIOUS_SRV,
+ K_CURRENT_SRV,
+ K_PACKAGE,
+
+ A_PURPOSE,
+ A_LAST_LISTED,
+ A_UNKNOWN_,
+
+ R_RENDEZVOUS_SERVICE_DESCRIPTOR,
+ R_VERSION,
+ R_PERMANENT_KEY,
+ R_SECRET_ID_PART,
+ R_PUBLICATION_TIME,
+ R_PROTOCOL_VERSIONS,
+ R_INTRODUCTION_POINTS,
+ R_SIGNATURE,
+
+ R_HS_DESCRIPTOR, /* From version 3, this MUST be generic to all future
+ descriptor versions thus making it R_. */
+ R3_DESC_LIFETIME,
+ R3_DESC_SIGNING_CERT,
+ R3_REVISION_COUNTER,
+ R3_ENCRYPTED,
+ R3_SIGNATURE,
+ R3_CREATE2_FORMATS,
+ R3_AUTHENTICATION_REQUIRED,
+ R3_INTRODUCTION_POINT,
+ R3_INTRO_AUTH_KEY,
+ R3_INTRO_ENC_KEY,
+ R3_INTRO_ENC_KEY_CERTIFICATION,
+
+ R_IPO_IDENTIFIER,
+ R_IPO_IP_ADDRESS,
+ R_IPO_ONION_PORT,
+ R_IPO_ONION_KEY,
+ R_IPO_SERVICE_KEY,
+
+ C_CLIENT_NAME,
+ C_DESCRIPTOR_COOKIE,
+ C_CLIENT_KEY,
+
+ ERR_,
+ EOF_,
+ NIL_
+ } directory_keyword;
+
+ /** Structure to hold a single directory token.
+ *
+ * We parse a directory by breaking it into "tokens", each consisting
+ * of a keyword, a line full of arguments, and a binary object. The
+ * arguments and object are both optional, depending on the keyword
+ * type.
+ *
+ * This structure is only allocated in memareas; do not allocate it on
+ * the heap, or token_clear() won't work.
+ */
+ typedef struct directory_token_t {
+ directory_keyword tp; /**< Type of the token. */
+ int n_args:30; /**< Number of elements in args */
+ char **args; /**< Array of arguments from keyword line. */
+
+ char *object_type; /**< -----BEGIN [object_type]-----*/
+ size_t object_size; /**< Bytes in object_body */
+ char *object_body; /**< Contents of object, base64-decoded. */
+
+ crypto_pk_t *key; /**< For public keys only. Heap-allocated. */
+
+ char *error; /**< For ERR_ tokens only. */
+ } directory_token_t;
+
+ /** We use a table of rules to decide how to parse each token type. */
+
+ /** Rules for whether the keyword needs an object. */
+ typedef enum {
+ NO_OBJ, /**< No object, ever. */
+ NEED_OBJ, /**< Object is required. */
+ NEED_SKEY_1024,/**< Object is required, and must be a 1024 bit private key */
+ NEED_KEY_1024, /**< Object is required, and must be a 1024 bit public key */
+ NEED_KEY, /**< Object is required, and must be a public key. */
+ OBJ_OK, /**< Object is optional. */
+ } obj_syntax;
+
+ #define AT_START 1
+ #define AT_END 2
+
+ #define TS_ANNOTATIONS_OK 1
+ #define TS_NOCHECK 2
+ #define TS_NO_NEW_ANNOTATIONS 4
+
-/*
++/**
++ * @name macros for defining token rules
++ *
+ * Helper macros to define token tables. 's' is a string, 't' is a
+ * directory_keyword, 'a' is a trio of argument multiplicities, and 'o' is an
+ * object syntax.
- *
+ */
++/**@{*/
+
+ /** Appears to indicate the end of a table. */
+ #define END_OF_TABLE { NULL, NIL_, 0,0,0, NO_OBJ, 0, INT_MAX, 0, 0 }
+ /** An item with no restrictions: used for obsolete document types */
+ #define T(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0, 0 }
+ /** An item with no restrictions on multiplicity or location. */
+ #define T0N(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0, 0 }
+ /** An item that must appear exactly once */
+ #define T1(s,t,a,o) { s, t, a, o, 1, 1, 0, 0 }
+ /** An item that must appear exactly once, at the start of the document */
+ #define T1_START(s,t,a,o) { s, t, a, o, 1, 1, AT_START, 0 }
+ /** An item that must appear exactly once, at the end of the document */
+ #define T1_END(s,t,a,o) { s, t, a, o, 1, 1, AT_END, 0 }
+ /** An item that must appear one or more times */
+ #define T1N(s,t,a,o) { s, t, a, o, 1, INT_MAX, 0, 0 }
+ /** An item that must appear no more than once */
+ #define T01(s,t,a,o) { s, t, a, o, 0, 1, 0, 0 }
+ /** An annotation that must appear no more than once */
+ #define A01(s,t,a,o) { s, t, a, o, 0, 1, 0, 1 }
+
-/* Argument multiplicity: any number of arguments. */
++/** Argument multiplicity: any number of arguments. */
+ #define ARGS 0,INT_MAX,0
-/* Argument multiplicity: no arguments. */
++/** Argument multiplicity: no arguments. */
+ #define NO_ARGS 0,0,0
-/* Argument multiplicity: concatenate all arguments. */
++/** Argument multiplicity: concatenate all arguments. */
+ #define CONCAT_ARGS 1,1,1
-/* Argument multiplicity: at least <b>n</b> arguments. */
++/** Argument multiplicity: at least <b>n</b> arguments. */
+ #define GE(n) n,INT_MAX,0
-/* Argument multiplicity: exactly <b>n</b> arguments. */
++/** Argument multiplicity: exactly <b>n</b> arguments. */
+ #define EQ(n) n,n,0
++/**@}*/
+
+ /** Determines the parsing rules for a single token type. */
+ typedef struct token_rule_t {
+ /** The string value of the keyword identifying the type of item. */
+ const char *t;
+ /** The corresponding directory_keyword enum. */
+ directory_keyword v;
+ /** Minimum number of arguments for this item */
+ int min_args;
+ /** Maximum number of arguments for this item */
+ int max_args;
+ /** If true, we concatenate all arguments for this item into a single
+ * string. */
+ int concat_args;
+ /** Requirements on object syntax for this item. */
+ obj_syntax os;
+ /** Lowest number of times this item may appear in a document. */
+ int min_cnt;
+ /** Highest number of times this item may appear in a document. */
+ int max_cnt;
+ /** One or more of AT_START/AT_END to limit where the item may appear in a
+ * document. */
+ int pos;
+ /** True iff this token is an annotation. */
+ int is_annotation;
+ } token_rule_t;
+
+ void token_clear(directory_token_t *tok);
+
+ int tokenize_string(memarea_t *area,
+ const char *start, const char *end,
+ smartlist_t *out,
+ token_rule_t *table,
+ int flags);
+ directory_token_t *get_next_token(memarea_t *area,
+ const char **s,
+ const char *eos,
+ token_rule_t *table);
+
+ directory_token_t *find_by_keyword_(smartlist_t *s,
+ directory_keyword keyword,
+ const char *keyword_str);
+
+ #define find_by_keyword(s, keyword) \
+ find_by_keyword_((s), (keyword), #keyword)
+
+ directory_token_t *find_opt_by_keyword(smartlist_t *s,
+ directory_keyword keyword);
+ smartlist_t * find_all_by_keyword(smartlist_t *s, directory_keyword k);
+
+ #endif /* TOR_PARSECOMMON_H */
+
diff --cc src/or/rendclient.c
index a93bc94,0bfc1a1..b0dcf52
--- a/src/or/rendclient.c
+++ b/src/or/rendclient.c
@@@ -149,13 -150,15 +151,13 @@@ rend_client_send_introduction(origin_ci
tor_assert(rendcirc->base_.purpose == CIRCUIT_PURPOSE_C_REND_READY);
tor_assert(introcirc->rend_data);
tor_assert(rendcirc->rend_data);
- tor_assert(!rend_cmp_service_ids(introcirc->rend_data->onion_address,
- rendcirc->rend_data->onion_address));
+ tor_assert(!rend_cmp_service_ids(rend_data_get_address(introcirc->rend_data),
+ rend_data_get_address(rendcirc->rend_data)));
-#ifndef NON_ANONYMOUS_MODE_ENABLED
- tor_assert(!(introcirc->build_state->onehop_tunnel));
- tor_assert(!(rendcirc->build_state->onehop_tunnel));
-#endif
+ assert_circ_anonymity_ok(introcirc, options);
+ assert_circ_anonymity_ok(rendcirc, options);
+ onion_address = rend_data_get_address(introcirc->rend_data);
- r = rend_cache_lookup_entry(introcirc->rend_data->onion_address, -1,
- &entry);
+ r = rend_cache_lookup_entry(onion_address, -1, &entry);
/* An invalid onion address is not possible else we have a big issue. */
tor_assert(r != -EINVAL);
if (r < 0 || !rend_client_any_intro_points_usable(entry)) {
diff --cc src/or/rendcommon.c
index d9d39b1,125aa0f..1e5d1ab
--- a/src/or/rendcommon.c
+++ b/src/or/rendcommon.c
@@@ -1067,52 -950,32 +950,82 @@@ rend_auth_decode_cookie(const char *coo
return res;
}
+/* Is this a rend client or server that allows direct (non-anonymous)
+ * connections?
+ * Clients must be specifically compiled and configured in this mode.
+ * Onion services can be configured to start in this mode.
+ * Prefer rend_client_allow_non_anonymous_connection() or
+ * rend_service_allow_non_anonymous_connection() whenever possible, so that
+ * checks are specific to Single Onion Services or Tor2web. */
+int
+rend_allow_non_anonymous_connection(const or_options_t* options)
+{
+ return (rend_client_allow_non_anonymous_connection(options)
+ || rend_service_allow_non_anonymous_connection(options));
+}
+
+/* Is this a rend client or server in non-anonymous mode?
+ * Clients must be specifically compiled in this mode.
+ * Onion services can be configured to start in this mode.
+ * Prefer rend_client_non_anonymous_mode_enabled() or
+ * rend_service_non_anonymous_mode_enabled() whenever possible, so that checks
+ * are specific to Single Onion Services or Tor2web. */
+int
+rend_non_anonymous_mode_enabled(const or_options_t *options)
+{
+ return (rend_client_non_anonymous_mode_enabled(options)
+ || rend_service_non_anonymous_mode_enabled(options));
+}
+
+/* Make sure that tor only builds one-hop circuits when they would not
+ * compromise user anonymity.
+ *
+ * One-hop circuits are permitted in Tor2web or Single Onion modes.
+ *
+ * Tor2web or Single Onion modes are also allowed to make multi-hop circuits.
+ * For example, single onion HSDir circuits are 3-hop to prevent denial of
+ * service.
+ */
+void
+assert_circ_anonymity_ok(origin_circuit_t *circ,
+ const or_options_t *options)
+{
+ tor_assert(options);
+ tor_assert(circ);
+ tor_assert(circ->build_state);
+
+ if (circ->build_state->onehop_tunnel) {
+ tor_assert(rend_allow_non_anonymous_connection(options));
+ }
+}
+
+ /* Return 1 iff the given <b>digest</b> of a permenanent hidden service key is
+ * equal to the digest in the origin circuit <b>ocirc</b> of its rend data .
+ * If the rend data doesn't exist, 0 is returned. This function is agnostic to
+ * the rend data version. */
+ int
+ rend_circuit_pk_digest_eq(const origin_circuit_t *ocirc,
+ const uint8_t *digest)
+ {
+ size_t rend_pk_digest_len;
+ const uint8_t *rend_pk_digest;
+
+ tor_assert(ocirc);
+ tor_assert(digest);
+
+ if (ocirc->rend_data == NULL) {
+ goto no_match;
+ }
+
+ rend_pk_digest = rend_data_get_pk_digest(ocirc->rend_data,
+ &rend_pk_digest_len);
+ if (tor_memeq(rend_pk_digest, digest, rend_pk_digest_len)) {
+ goto match;
+ }
+ no_match:
+ return 0;
+ match:
+ return 1;
+ }
+
++
diff --cc src/or/rendservice.c
index 7083051,21e88eb..b6bf63d
--- a/src/or/rendservice.c
+++ b/src/or/rendservice.c
@@@ -1681,8 -1474,12 +1682,10 @@@ rend_service_receive_introduction(origi
goto err;
}
-#ifndef NON_ANONYMOUS_MODE_ENABLED
- tor_assert(!(circuit->build_state->onehop_tunnel));
-#endif
+ assert_circ_anonymity_ok(circuit, options);
tor_assert(circuit->rend_data);
+ /* XXX: This is version 2 specific (only one supported). */
+ rend_pk_digest = (char *) rend_data_get_pk_digest(circuit->rend_data, NULL);
/* We'll use this in a bazillion log messages */
base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
@@@ -2970,17 -2702,21 +2971,19 @@@ rend_service_intro_has_opened(origin_ci
char auth[DIGEST_LEN + 9];
char serviceid[REND_SERVICE_ID_LEN_BASE32+1];
int reason = END_CIRC_REASON_TORPROTOCOL;
+ const char *rend_pk_digest;
tor_assert(circuit->base_.purpose == CIRCUIT_PURPOSE_S_ESTABLISH_INTRO);
-#ifndef NON_ANONYMOUS_MODE_ENABLED
- tor_assert(!(circuit->build_state->onehop_tunnel));
-#endif
+ assert_circ_anonymity_ok(circuit, get_options());
tor_assert(circuit->cpath);
tor_assert(circuit->rend_data);
+ /* XXX: This is version 2 specific (only on supported). */
+ rend_pk_digest = (char *) rend_data_get_pk_digest(circuit->rend_data, NULL);
base32_encode(serviceid, REND_SERVICE_ID_LEN_BASE32+1,
- circuit->rend_data->rend_pk_digest, REND_SERVICE_ID_LEN);
+ rend_pk_digest, REND_SERVICE_ID_LEN);
- service = rend_service_get_by_pk_digest(
- circuit->rend_data->rend_pk_digest);
+ service = rend_service_get_by_pk_digest(rend_pk_digest);
if (!service) {
log_warn(LD_REND, "Unrecognized service ID %s on introduction circuit %u.",
safe_str_client(serviceid), (unsigned)circuit->base_.n_circ_id);
@@@ -3168,9 -2906,16 +3173,14 @@@ rend_service_rendezvous_has_opened(orig
tor_assert(circuit->base_.purpose == CIRCUIT_PURPOSE_S_CONNECT_REND);
tor_assert(circuit->cpath);
tor_assert(circuit->build_state);
-#ifndef NON_ANONYMOUS_MODE_ENABLED
- tor_assert(!(circuit->build_state->onehop_tunnel));
-#endif
+ assert_circ_anonymity_ok(circuit, get_options());
tor_assert(circuit->rend_data);
+ /* XXX: This is version 2 specific (only one supported). */
+ rend_pk_digest = (char *) rend_data_get_pk_digest(circuit->rend_data,
+ NULL);
+ rend_cookie = circuit->rend_data->rend_cookie;
+
/* Declare the circuit dirty to avoid reuse, and for path-bias */
if (!circuit->base_.timestamp_dirty)
circuit->base_.timestamp_dirty = time(NULL);
diff --cc src/or/routerparse.c
index cb2bc72,ef6273b..5bc2d39
--- a/src/or/routerparse.c
+++ b/src/or/routerparse.c
@@@ -60,8 -16,8 +60,9 @@@
#include "circuitstats.h"
#include "dirserv.h"
#include "dirvote.h"
+ #include "parsecommon.h"
#include "policies.h"
+#include "protover.h"
#include "rendcommon.h"
#include "router.h"
#include "routerlist.h"
diff --cc src/test/test_dir.c
index cf0b94c,4a2538b..c8daa18
--- a/src/test/test_dir.c
+++ b/src/test/test_dir.c
@@@ -5698,48 -5346,66 +5698,109 @@@ test_dir_find_dl_schedule(void* data
}
static void
+test_dir_assumed_flags(void *arg)
+{
+ (void)arg;
+ smartlist_t *tokens = smartlist_new();
+ memarea_t *area = memarea_new();
+ routerstatus_t *rs = NULL;
+
+ /* First, we should always assume that the Running flag is set, even
+ * when it isn't listed, since the consensus method is always
+ * higher than 4. */
+ const char *str1 =
+ "r example hereiswhereyouridentitygoes 2015-08-30 12:00:00 "
+ "192.168.0.1 9001 0\n"
+ "m thisoneislongerbecauseitisa256bitmddigest33\n"
+ "s Fast Guard Stable\n";
+
+ const char *cp = str1;
+ rs = routerstatus_parse_entry_from_string(area, &cp, tokens, NULL, NULL,
+ 23, FLAV_MICRODESC);
+ tt_assert(rs);
+ tt_assert(rs->is_flagged_running);
+ tt_assert(! rs->is_valid);
+ tt_assert(! rs->is_exit);
+ tt_assert(rs->is_fast);
+ routerstatus_free(rs);
+
+ /* With method 24 or later, we can assume "valid" is set. */
+ cp = str1;
+ rs = routerstatus_parse_entry_from_string(area, &cp, tokens, NULL, NULL,
+ 24, FLAV_MICRODESC);
+ tt_assert(rs);
+ tt_assert(rs->is_flagged_running);
+ tt_assert(rs->is_valid);
+ tt_assert(! rs->is_exit);
+ tt_assert(rs->is_fast);
+
+ done:
+ smartlist_free(tokens);
+ memarea_drop_all(area);
+ routerstatus_free(rs);
+}
+
++static void
+ test_dir_post_parsing(void *arg)
+ {
+ (void) arg;
+
+ /* Test the version parsing from an HS descriptor publish request. */
+ {
+ const char *end;
+ const char *prefix = "/tor/hs/";
+ int version = parse_hs_version_from_post("/tor/hs//publish", prefix, &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ version = parse_hs_version_from_post("/tor/hs/a/publish", prefix, &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ version = parse_hs_version_from_post("/tor/hs/3/publish", prefix, &end);
+ tt_int_op(version, OP_EQ, 3);
+ tt_str_op(end, OP_EQ, "/publish");
+ version = parse_hs_version_from_post("/tor/hs/42/publish", prefix, &end);
+ tt_int_op(version, OP_EQ, 42);
+ tt_str_op(end, OP_EQ, "/publish");
+ version = parse_hs_version_from_post("/tor/hs/18163/publish", prefix, &end);
+ tt_int_op(version, OP_EQ, 18163);
+ tt_str_op(end, OP_EQ, "/publish");
+ version = parse_hs_version_from_post("JUNKJUNKJUNK", prefix, &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ version = parse_hs_version_from_post("/tor/hs/3/publish", "blah", &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ /* Missing the '/' at the end of the prefix. */
+ version = parse_hs_version_from_post("/tor/hs/3/publish", "/tor/hs", &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ version = parse_hs_version_from_post("/random/blah/tor/hs/3/publish",
+ prefix, &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ version = parse_hs_version_from_post("/tor/hs/3/publish/random/junk",
+ prefix, &end);
+ tt_int_op(version, OP_EQ, 3);
+ tt_str_op(end, OP_EQ, "/publish/random/junk");
+ version = parse_hs_version_from_post("/tor/hs/-1/publish", prefix, &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ /* INT_MAX */
+ version = parse_hs_version_from_post("/tor/hs/2147483647/publish",
+ prefix, &end);
+ tt_int_op(version, OP_EQ, INT_MAX);
+ tt_str_op(end, OP_EQ, "/publish");
+ /* INT_MAX + 1*/
+ version = parse_hs_version_from_post("/tor/hs/2147483648/publish",
+ prefix, &end);
+ tt_int_op(version, OP_EQ, -1);
+ tt_ptr_op(end, OP_EQ, NULL);
+ }
+
+ done:
+ ;
+ }
+
#define DIR_LEGACY(name) \
{ #name, test_dir_ ## name , TT_FORK, NULL, NULL }
@@@ -5773,11 -5439,8 +5834,12 @@@ struct testcase_t dir_tests[] =
DIR(fmt_control_ns, 0),
DIR(dirserv_set_routerstatus_testing, 0),
DIR(http_handling, 0),
+ DIR(purpose_needs_anonymity_returns_true_for_bridges, 0),
+ DIR(purpose_needs_anonymity_returns_false_for_own_bridge_desc, 0),
+ DIR(purpose_needs_anonymity_returns_true_by_default, 0),
+ DIR(purpose_needs_anonymity_returns_true_for_sensitive_purpose, 0),
+ DIR(purpose_needs_anonymity_ret_false_for_non_sensitive_conn, 0),
+ DIR(post_parsing, 0),
- DIR(purpose_needs_anonymity, 0),
DIR(fetch_type, 0),
DIR(packages, 0),
DIR(download_status_schedule, 0),
diff --cc src/test/test_hs.c
index fd5ab15,3bf4e6d..67ce1cf
--- a/src/test/test_hs.c
+++ b/src/test/test_hs.c
@@@ -14,8 -13,8 +14,9 @@@
#include "test.h"
#include "control.h"
#include "config.h"
+ #include "hs_common.h"
#include "rendcommon.h"
+#include "rendservice.h"
#include "routerset.h"
#include "circuitbuild.h"
#include "test_helpers.h"
diff --cc src/test/test_rendcache.c
index a5d3f35,afcd117..7f72e44
--- a/src/test/test_rendcache.c
+++ b/src/test/test_rendcache.c
@@@ -10,9 -10,9 +10,10 @@@
#include "router.h"
#include "routerlist.h"
#include "config.h"
+ #include "hs_common.h"
#include <openssl/rsa.h>
#include "rend_test_helpers.h"
+#include "log_test_helpers.h"
#define NS_MODULE rend_cache
diff --cc src/trunnel/ed25519_cert.c
index a492ada,dc1485d..dd5088b
--- a/src/trunnel/ed25519_cert.c
+++ b/src/trunnel/ed25519_cert.c
@@@ -430,6 -410,557 +430,597 @@@ ed25519_cert_extension_parse(ed25519_ce
}
return result;
}
+ link_specifier_t *
+ link_specifier_new(void)
+ {
+ link_specifier_t *val = trunnel_calloc(1, sizeof(link_specifier_t));
+ if (NULL == val)
+ return NULL;
+ return val;
+ }
+
+ /** Release all storage held inside 'obj', but do not free 'obj'.
+ */
+ static void
+ link_specifier_clear(link_specifier_t *obj)
+ {
+ (void) obj;
+ TRUNNEL_DYNARRAY_WIPE(&obj->un_unrecognized);
+ TRUNNEL_DYNARRAY_CLEAR(&obj->un_unrecognized);
+ }
+
+ void
+ link_specifier_free(link_specifier_t *obj)
+ {
+ if (obj == NULL)
+ return;
+ link_specifier_clear(obj);
+ trunnel_memwipe(obj, sizeof(link_specifier_t));
+ trunnel_free_(obj);
+ }
+
+ uint8_t
+ link_specifier_get_ls_type(link_specifier_t *inp)
+ {
+ return inp->ls_type;
+ }
+ int
+ link_specifier_set_ls_type(link_specifier_t *inp, uint8_t val)
+ {
+ inp->ls_type = val;
+ return 0;
+ }
+ uint8_t
+ link_specifier_get_ls_len(link_specifier_t *inp)
+ {
+ return inp->ls_len;
+ }
+ int
+ link_specifier_set_ls_len(link_specifier_t *inp, uint8_t val)
+ {
+ inp->ls_len = val;
+ return 0;
+ }
+ uint32_t
+ link_specifier_get_un_ipv4_addr(link_specifier_t *inp)
+ {
+ return inp->un_ipv4_addr;
+ }
+ int
+ link_specifier_set_un_ipv4_addr(link_specifier_t *inp, uint32_t val)
+ {
+ inp->un_ipv4_addr = val;
+ return 0;
+ }
+ uint16_t
+ link_specifier_get_un_ipv4_port(link_specifier_t *inp)
+ {
+ return inp->un_ipv4_port;
+ }
+ int
+ link_specifier_set_un_ipv4_port(link_specifier_t *inp, uint16_t val)
+ {
+ inp->un_ipv4_port = val;
+ return 0;
+ }
+ size_t
+ link_specifier_getlen_un_ipv6_addr(const link_specifier_t *inp)
+ {
+ (void)inp; return 16;
+ }
+
+ uint8_t
-link_specifier_get_un_ipv6_addr(const link_specifier_t *inp, size_t idx)
++link_specifier_get_un_ipv6_addr(link_specifier_t *inp, size_t idx)
+ {
+ trunnel_assert(idx < 16);
+ return inp->un_ipv6_addr[idx];
+ }
+
++uint8_t
++link_specifier_getconst_un_ipv6_addr(const link_specifier_t *inp, size_t idx)
++{
++ return link_specifier_get_un_ipv6_addr((link_specifier_t*)inp, idx);
++}
+ int
+ link_specifier_set_un_ipv6_addr(link_specifier_t *inp, size_t idx, uint8_t elt)
+ {
+ trunnel_assert(idx < 16);
+ inp->un_ipv6_addr[idx] = elt;
+ return 0;
+ }
+
+ uint8_t *
+ link_specifier_getarray_un_ipv6_addr(link_specifier_t *inp)
+ {
+ return inp->un_ipv6_addr;
+ }
++const uint8_t *
++link_specifier_getconstarray_un_ipv6_addr(const link_specifier_t *inp)
++{
++ return (const uint8_t *)link_specifier_getarray_un_ipv6_addr((link_specifier_t*)inp);
++}
+ uint16_t
+ link_specifier_get_un_ipv6_port(link_specifier_t *inp)
+ {
+ return inp->un_ipv6_port;
+ }
+ int
+ link_specifier_set_un_ipv6_port(link_specifier_t *inp, uint16_t val)
+ {
+ inp->un_ipv6_port = val;
+ return 0;
+ }
+ size_t
+ link_specifier_getlen_un_legacy_id(const link_specifier_t *inp)
+ {
+ (void)inp; return 20;
+ }
+
+ uint8_t
-link_specifier_get_un_legacy_id(const link_specifier_t *inp, size_t idx)
++link_specifier_get_un_legacy_id(link_specifier_t *inp, size_t idx)
+ {
+ trunnel_assert(idx < 20);
+ return inp->un_legacy_id[idx];
+ }
+
++uint8_t
++link_specifier_getconst_un_legacy_id(const link_specifier_t *inp, size_t idx)
++{
++ return link_specifier_get_un_legacy_id((link_specifier_t*)inp, idx);
++}
+ int
+ link_specifier_set_un_legacy_id(link_specifier_t *inp, size_t idx, uint8_t elt)
+ {
+ trunnel_assert(idx < 20);
+ inp->un_legacy_id[idx] = elt;
+ return 0;
+ }
+
+ uint8_t *
+ link_specifier_getarray_un_legacy_id(link_specifier_t *inp)
+ {
+ return inp->un_legacy_id;
+ }
++const uint8_t *
++link_specifier_getconstarray_un_legacy_id(const link_specifier_t *inp)
++{
++ return (const uint8_t *)link_specifier_getarray_un_legacy_id((link_specifier_t*)inp);
++}
+ size_t
+ link_specifier_getlen_un_ed25519_id(const link_specifier_t *inp)
+ {
+ (void)inp; return 32;
+ }
+
+ uint8_t
-link_specifier_get_un_ed25519_id(const link_specifier_t *inp, size_t idx)
++link_specifier_get_un_ed25519_id(link_specifier_t *inp, size_t idx)
+ {
+ trunnel_assert(idx < 32);
+ return inp->un_ed25519_id[idx];
+ }
+
++uint8_t
++link_specifier_getconst_un_ed25519_id(const link_specifier_t *inp, size_t idx)
++{
++ return link_specifier_get_un_ed25519_id((link_specifier_t*)inp, idx);
++}
+ int
+ link_specifier_set_un_ed25519_id(link_specifier_t *inp, size_t idx, uint8_t elt)
+ {
+ trunnel_assert(idx < 32);
+ inp->un_ed25519_id[idx] = elt;
+ return 0;
+ }
+
+ uint8_t *
+ link_specifier_getarray_un_ed25519_id(link_specifier_t *inp)
+ {
+ return inp->un_ed25519_id;
+ }
++const uint8_t *
++link_specifier_getconstarray_un_ed25519_id(const link_specifier_t *inp)
++{
++ return (const uint8_t *)link_specifier_getarray_un_ed25519_id((link_specifier_t*)inp);
++}
+ size_t
+ link_specifier_getlen_un_unrecognized(const link_specifier_t *inp)
+ {
+ return TRUNNEL_DYNARRAY_LEN(&inp->un_unrecognized);
+ }
+
+ uint8_t
+ link_specifier_get_un_unrecognized(link_specifier_t *inp, size_t idx)
+ {
+ return TRUNNEL_DYNARRAY_GET(&inp->un_unrecognized, idx);
+ }
+
++uint8_t
++link_specifier_getconst_un_unrecognized(const link_specifier_t *inp, size_t idx)
++{
++ return link_specifier_get_un_unrecognized((link_specifier_t*)inp, idx);
++}
+ int
+ link_specifier_set_un_unrecognized(link_specifier_t *inp, size_t idx, uint8_t elt)
+ {
+ TRUNNEL_DYNARRAY_SET(&inp->un_unrecognized, idx, elt);
+ return 0;
+ }
+ int
+ link_specifier_add_un_unrecognized(link_specifier_t *inp, uint8_t elt)
+ {
+ TRUNNEL_DYNARRAY_ADD(uint8_t, &inp->un_unrecognized, elt, {});
+ return 0;
+ trunnel_alloc_failed:
+ TRUNNEL_SET_ERROR_CODE(inp);
+ return -1;
+ }
+
+ uint8_t *
+ link_specifier_getarray_un_unrecognized(link_specifier_t *inp)
+ {
+ return inp->un_unrecognized.elts_;
+ }
++const uint8_t *
++link_specifier_getconstarray_un_unrecognized(const link_specifier_t *inp)
++{
++ return (const uint8_t *)link_specifier_getarray_un_unrecognized((link_specifier_t*)inp);
++}
+ int
+ link_specifier_setlen_un_unrecognized(link_specifier_t *inp, size_t newlen)
+ {
+ uint8_t *newptr;
+ newptr = trunnel_dynarray_setlen(&inp->un_unrecognized.allocated_,
+ &inp->un_unrecognized.n_, inp->un_unrecognized.elts_, newlen,
+ sizeof(inp->un_unrecognized.elts_[0]), (trunnel_free_fn_t) NULL,
+ &inp->trunnel_error_code_);
- if (newptr == NULL)
++ if (newlen != 0 && newptr == NULL)
+ goto trunnel_alloc_failed;
+ inp->un_unrecognized.elts_ = newptr;
+ return 0;
+ trunnel_alloc_failed:
+ TRUNNEL_SET_ERROR_CODE(inp);
+ return -1;
+ }
+ const char *
+ link_specifier_check(const link_specifier_t *obj)
+ {
+ if (obj == NULL)
+ return "Object was NULL";
+ if (obj->trunnel_error_code_)
+ return "A set function failed on this object";
+ switch (obj->ls_type) {
+
+ case LS_IPV4:
+ break;
+
+ case LS_IPV6:
+ break;
+
+ case LS_LEGACY_ID:
+ break;
+
+ case LS_ED25519_ID:
+ break;
+
+ default:
+ break;
+ }
+ return NULL;
+ }
+
+ ssize_t
+ link_specifier_encoded_len(const link_specifier_t *obj)
+ {
+ ssize_t result = 0;
+
+ if (NULL != link_specifier_check(obj))
+ return -1;
+
+
+ /* Length of u8 ls_type */
+ result += 1;
+
+ /* Length of u8 ls_len */
+ result += 1;
+ switch (obj->ls_type) {
+
+ case LS_IPV4:
+
+ /* Length of u32 un_ipv4_addr */
+ result += 4;
+
+ /* Length of u16 un_ipv4_port */
+ result += 2;
+ break;
+
+ case LS_IPV6:
+
+ /* Length of u8 un_ipv6_addr[16] */
+ result += 16;
+
+ /* Length of u16 un_ipv6_port */
+ result += 2;
+ break;
+
+ case LS_LEGACY_ID:
+
+ /* Length of u8 un_legacy_id[20] */
+ result += 20;
+ break;
+
+ case LS_ED25519_ID:
+
+ /* Length of u8 un_ed25519_id[32] */
+ result += 32;
+ break;
+
+ default:
+
+ /* Length of u8 un_unrecognized[] */
+ result += TRUNNEL_DYNARRAY_LEN(&obj->un_unrecognized);
+ break;
+ }
+ return result;
+ }
+ int
+ link_specifier_clear_errors(link_specifier_t *obj)
+ {
+ int r = obj->trunnel_error_code_;
+ obj->trunnel_error_code_ = 0;
+ return r;
+ }
+ ssize_t
+ link_specifier_encode(uint8_t *output, const size_t avail, const link_specifier_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 = link_specifier_encoded_len(obj);
+ #endif
+
+ uint8_t *backptr_ls_len = NULL;
+
+ if (NULL != (msg = link_specifier_check(obj)))
+ goto check_failed;
+
+ #ifdef TRUNNEL_CHECK_ENCODED_LEN
+ trunnel_assert(encoded_len >= 0);
+ #endif
+
+ /* Encode u8 ls_type */
+ trunnel_assert(written <= avail);
+ if (avail - written < 1)
+ goto truncated;
+ trunnel_set_uint8(ptr, (obj->ls_type));
+ written += 1; ptr += 1;
+
+ /* Encode u8 ls_len */
+ backptr_ls_len = ptr;
+ trunnel_assert(written <= avail);
+ if (avail - written < 1)
+ goto truncated;
+ trunnel_set_uint8(ptr, (obj->ls_len));
+ written += 1; ptr += 1;
+ {
+ size_t written_before_union = written;
+
+ /* Encode union un[ls_type] */
+ trunnel_assert(written <= avail);
+ switch (obj->ls_type) {
+
+ case LS_IPV4:
+
+ /* Encode u32 un_ipv4_addr */
+ trunnel_assert(written <= avail);
+ if (avail - written < 4)
+ goto truncated;
+ trunnel_set_uint32(ptr, trunnel_htonl(obj->un_ipv4_addr));
+ written += 4; ptr += 4;
+
+ /* Encode u16 un_ipv4_port */
+ trunnel_assert(written <= avail);
+ if (avail - written < 2)
+ goto truncated;
+ trunnel_set_uint16(ptr, trunnel_htons(obj->un_ipv4_port));
+ written += 2; ptr += 2;
+ break;
+
+ case LS_IPV6:
+
+ /* Encode u8 un_ipv6_addr[16] */
+ trunnel_assert(written <= avail);
+ if (avail - written < 16)
+ goto truncated;
+ memcpy(ptr, obj->un_ipv6_addr, 16);
+ written += 16; ptr += 16;
+
+ /* Encode u16 un_ipv6_port */
+ trunnel_assert(written <= avail);
+ if (avail - written < 2)
+ goto truncated;
+ trunnel_set_uint16(ptr, trunnel_htons(obj->un_ipv6_port));
+ written += 2; ptr += 2;
+ break;
+
+ case LS_LEGACY_ID:
+
+ /* Encode u8 un_legacy_id[20] */
+ trunnel_assert(written <= avail);
+ if (avail - written < 20)
+ goto truncated;
+ memcpy(ptr, obj->un_legacy_id, 20);
+ written += 20; ptr += 20;
+ break;
+
+ case LS_ED25519_ID:
+
+ /* Encode u8 un_ed25519_id[32] */
+ trunnel_assert(written <= avail);
+ if (avail - written < 32)
+ goto truncated;
+ memcpy(ptr, obj->un_ed25519_id, 32);
+ written += 32; ptr += 32;
+ break;
+
+ default:
+
+ /* Encode u8 un_unrecognized[] */
+ {
+ size_t elt_len = TRUNNEL_DYNARRAY_LEN(&obj->un_unrecognized);
+ trunnel_assert(written <= avail);
+ if (avail - written < elt_len)
+ goto truncated;
+ if (elt_len)
+ memcpy(ptr, obj->un_unrecognized.elts_, elt_len);
+ written += elt_len; ptr += elt_len;
+ }
+ break;
+ }
+ /* Write the length field back to ls_len */
+ trunnel_assert(written >= written_before_union);
+ #if UINT8_MAX < SIZE_MAX
+ if (written - written_before_union > UINT8_MAX)
+ goto check_failed;
+ #endif
+ trunnel_set_uint8(backptr_ls_len, (written - written_before_union));
+ }
+
+
+ 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 link_specifier_parse(), but do not allocate the output object.
+ */
+ static ssize_t
+ link_specifier_parse_into(link_specifier_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 ls_type */
+ CHECK_REMAINING(1, truncated);
+ obj->ls_type = (trunnel_get_uint8(ptr));
+ remaining -= 1; ptr += 1;
+
+ /* Parse u8 ls_len */
+ CHECK_REMAINING(1, truncated);
+ obj->ls_len = (trunnel_get_uint8(ptr));
+ remaining -= 1; ptr += 1;
+ {
+ size_t remaining_after;
+ CHECK_REMAINING(obj->ls_len, truncated);
+ remaining_after = remaining - obj->ls_len;
+ remaining = obj->ls_len;
+
+ /* Parse union un[ls_type] */
+ switch (obj->ls_type) {
+
+ case LS_IPV4:
+
+ /* Parse u32 un_ipv4_addr */
+ CHECK_REMAINING(4, fail);
+ obj->un_ipv4_addr = trunnel_ntohl(trunnel_get_uint32(ptr));
+ remaining -= 4; ptr += 4;
+
+ /* Parse u16 un_ipv4_port */
+ CHECK_REMAINING(2, fail);
+ obj->un_ipv4_port = trunnel_ntohs(trunnel_get_uint16(ptr));
+ remaining -= 2; ptr += 2;
+ break;
+
+ case LS_IPV6:
+
+ /* Parse u8 un_ipv6_addr[16] */
+ CHECK_REMAINING(16, fail);
+ memcpy(obj->un_ipv6_addr, ptr, 16);
+ remaining -= 16; ptr += 16;
+
+ /* Parse u16 un_ipv6_port */
+ CHECK_REMAINING(2, fail);
+ obj->un_ipv6_port = trunnel_ntohs(trunnel_get_uint16(ptr));
+ remaining -= 2; ptr += 2;
+ break;
+
+ case LS_LEGACY_ID:
+
+ /* Parse u8 un_legacy_id[20] */
+ CHECK_REMAINING(20, fail);
+ memcpy(obj->un_legacy_id, ptr, 20);
+ remaining -= 20; ptr += 20;
+ break;
+
+ case LS_ED25519_ID:
+
+ /* Parse u8 un_ed25519_id[32] */
+ CHECK_REMAINING(32, fail);
+ memcpy(obj->un_ed25519_id, ptr, 32);
+ remaining -= 32; ptr += 32;
+ break;
+
+ default:
+
+ /* Parse u8 un_unrecognized[] */
+ TRUNNEL_DYNARRAY_EXPAND(uint8_t, &obj->un_unrecognized, remaining, {});
+ obj->un_unrecognized.n_ = remaining;
+ if (remaining)
+ memcpy(obj->un_unrecognized.elts_, ptr, remaining);
+ ptr += remaining; remaining -= remaining;
+ break;
+ }
+ if (remaining != 0)
+ goto fail;
+ remaining = remaining_after;
+ }
+ 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
+ link_specifier_parse(link_specifier_t **output, const uint8_t *input, const size_t len_in)
+ {
+ ssize_t result;
+ *output = link_specifier_new();
+ if (NULL == *output)
+ return -1;
+ result = link_specifier_parse_into(*output, input, len_in);
+ if (result < 0) {
+ link_specifier_free(*output);
+ *output = NULL;
+ }
+ return result;
+ }
ed25519_cert_t *
ed25519_cert_new(void)
{
@@@ -937,3 -1438,283 +1528,293 @@@ ed25519_cert_parse(ed25519_cert_t **out
}
return result;
}
+ link_specifier_list_t *
+ link_specifier_list_new(void)
+ {
+ link_specifier_list_t *val = trunnel_calloc(1, sizeof(link_specifier_list_t));
+ if (NULL == val)
+ return NULL;
+ return val;
+ }
+
+ /** Release all storage held inside 'obj', but do not free 'obj'.
+ */
+ static void
+ link_specifier_list_clear(link_specifier_list_t *obj)
+ {
+ (void) obj;
+ {
+
+ unsigned idx;
+ for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->spec); ++idx) {
+ link_specifier_free(TRUNNEL_DYNARRAY_GET(&obj->spec, idx));
+ }
+ }
+ TRUNNEL_DYNARRAY_WIPE(&obj->spec);
+ TRUNNEL_DYNARRAY_CLEAR(&obj->spec);
+ }
+
+ void
+ link_specifier_list_free(link_specifier_list_t *obj)
+ {
+ if (obj == NULL)
+ return;
+ link_specifier_list_clear(obj);
+ trunnel_memwipe(obj, sizeof(link_specifier_list_t));
+ trunnel_free_(obj);
+ }
+
+ uint8_t
+ link_specifier_list_get_n_spec(link_specifier_list_t *inp)
+ {
+ return inp->n_spec;
+ }
+ int
+ link_specifier_list_set_n_spec(link_specifier_list_t *inp, uint8_t val)
+ {
+ inp->n_spec = val;
+ return 0;
+ }
+ size_t
+ link_specifier_list_getlen_spec(const link_specifier_list_t *inp)
+ {
+ return TRUNNEL_DYNARRAY_LEN(&inp->spec);
+ }
+
+ struct link_specifier_st *
+ link_specifier_list_get_spec(link_specifier_list_t *inp, size_t idx)
+ {
+ return TRUNNEL_DYNARRAY_GET(&inp->spec, idx);
+ }
+
++ const struct link_specifier_st *
++link_specifier_list_getconst_spec(const link_specifier_list_t *inp, size_t idx)
++{
++ return link_specifier_list_get_spec((link_specifier_list_t*)inp, idx);
++}
+ int
+ link_specifier_list_set_spec(link_specifier_list_t *inp, size_t idx, struct link_specifier_st * elt)
+ {
+ link_specifier_t *oldval = TRUNNEL_DYNARRAY_GET(&inp->spec, idx);
+ if (oldval && oldval != elt)
+ link_specifier_free(oldval);
+ return link_specifier_list_set0_spec(inp, idx, elt);
+ }
+ int
+ link_specifier_list_set0_spec(link_specifier_list_t *inp, size_t idx, struct link_specifier_st * elt)
+ {
+ TRUNNEL_DYNARRAY_SET(&inp->spec, idx, elt);
+ return 0;
+ }
+ int
+ link_specifier_list_add_spec(link_specifier_list_t *inp, struct link_specifier_st * elt)
+ {
+ #if SIZE_MAX >= UINT8_MAX
+ if (inp->spec.n_ == UINT8_MAX)
+ goto trunnel_alloc_failed;
+ #endif
+ TRUNNEL_DYNARRAY_ADD(struct link_specifier_st *, &inp->spec, elt, {});
+ return 0;
+ trunnel_alloc_failed:
+ TRUNNEL_SET_ERROR_CODE(inp);
+ return -1;
+ }
+
+ struct link_specifier_st * *
+ link_specifier_list_getarray_spec(link_specifier_list_t *inp)
+ {
+ return inp->spec.elts_;
+ }
++const struct link_specifier_st * const *
++link_specifier_list_getconstarray_spec(const link_specifier_list_t *inp)
++{
++ return (const struct link_specifier_st * const *)link_specifier_list_getarray_spec((link_specifier_list_t*)inp);
++}
+ int
+ link_specifier_list_setlen_spec(link_specifier_list_t *inp, size_t newlen)
+ {
+ struct link_specifier_st * *newptr;
+ #if UINT8_MAX < SIZE_MAX
+ if (newlen > UINT8_MAX)
+ goto trunnel_alloc_failed;
+ #endif
+ newptr = trunnel_dynarray_setlen(&inp->spec.allocated_,
+ &inp->spec.n_, inp->spec.elts_, newlen,
+ sizeof(inp->spec.elts_[0]), (trunnel_free_fn_t) link_specifier_free,
+ &inp->trunnel_error_code_);
- if (newptr == NULL)
++ if (newlen != 0 && newptr == NULL)
+ goto trunnel_alloc_failed;
+ inp->spec.elts_ = newptr;
+ return 0;
+ trunnel_alloc_failed:
+ TRUNNEL_SET_ERROR_CODE(inp);
+ return -1;
+ }
+ const char *
+ link_specifier_list_check(const link_specifier_list_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->spec); ++idx) {
+ if (NULL != (msg = link_specifier_check(TRUNNEL_DYNARRAY_GET(&obj->spec, idx))))
+ return msg;
+ }
+ }
+ if (TRUNNEL_DYNARRAY_LEN(&obj->spec) != obj->n_spec)
+ return "Length mismatch for spec";
+ return NULL;
+ }
+
+ ssize_t
+ link_specifier_list_encoded_len(const link_specifier_list_t *obj)
+ {
+ ssize_t result = 0;
+
+ if (NULL != link_specifier_list_check(obj))
+ return -1;
+
+
+ /* Length of u8 n_spec */
+ result += 1;
+
+ /* Length of struct link_specifier spec[n_spec] */
+ {
+
+ unsigned idx;
+ for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->spec); ++idx) {
+ result += link_specifier_encoded_len(TRUNNEL_DYNARRAY_GET(&obj->spec, idx));
+ }
+ }
+ return result;
+ }
+ int
+ link_specifier_list_clear_errors(link_specifier_list_t *obj)
+ {
+ int r = obj->trunnel_error_code_;
+ obj->trunnel_error_code_ = 0;
+ return r;
+ }
+ ssize_t
+ link_specifier_list_encode(uint8_t *output, const size_t avail, const link_specifier_list_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 = link_specifier_list_encoded_len(obj);
+ #endif
+
+ if (NULL != (msg = link_specifier_list_check(obj)))
+ goto check_failed;
+
+ #ifdef TRUNNEL_CHECK_ENCODED_LEN
+ trunnel_assert(encoded_len >= 0);
+ #endif
+
+ /* Encode u8 n_spec */
+ trunnel_assert(written <= avail);
+ if (avail - written < 1)
+ goto truncated;
+ trunnel_set_uint8(ptr, (obj->n_spec));
+ written += 1; ptr += 1;
+
+ /* Encode struct link_specifier spec[n_spec] */
+ {
+
+ unsigned idx;
+ for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->spec); ++idx) {
+ trunnel_assert(written <= avail);
+ result = link_specifier_encode(ptr, avail - written, TRUNNEL_DYNARRAY_GET(&obj->spec, 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 link_specifier_list_parse(), but do not allocate the output
+ * object.
+ */
+ static ssize_t
+ link_specifier_list_parse_into(link_specifier_list_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_spec */
+ CHECK_REMAINING(1, truncated);
+ obj->n_spec = (trunnel_get_uint8(ptr));
+ remaining -= 1; ptr += 1;
+
+ /* Parse struct link_specifier spec[n_spec] */
+ TRUNNEL_DYNARRAY_EXPAND(link_specifier_t *, &obj->spec, obj->n_spec, {});
+ {
+ link_specifier_t * elt;
+ unsigned idx;
+ for (idx = 0; idx < obj->n_spec; ++idx) {
+ result = link_specifier_parse(&elt, ptr, remaining);
+ if (result < 0)
+ goto relay_fail;
+ trunnel_assert((size_t)result <= remaining);
+ remaining -= result; ptr += result;
+ TRUNNEL_DYNARRAY_ADD(link_specifier_t *, &obj->spec, elt, {link_specifier_free(elt);});
+ }
+ }
+ trunnel_assert(ptr + remaining == input + len_in);
+ return len_in - remaining;
+
+ truncated:
+ return -2;
+ relay_fail:
+ trunnel_assert(result < 0);
+ return result;
+ trunnel_alloc_failed:
+ return -1;
+ }
+
+ ssize_t
+ link_specifier_list_parse(link_specifier_list_t **output, const uint8_t *input, const size_t len_in)
+ {
+ ssize_t result;
+ *output = link_specifier_list_new();
+ if (NULL == *output)
+ return -1;
+ result = link_specifier_list_parse_into(*output, input, len_in);
+ if (result < 0) {
+ link_specifier_list_free(*output);
+ *output = NULL;
+ }
+ return result;
+ }
diff --cc src/trunnel/ed25519_cert.h
index 9804d84,1893957..571e6d1
--- a/src/trunnel/ed25519_cert.h
+++ b/src/trunnel/ed25519_cert.h
@@@ -157,6 -168,164 +184,196 @@@ const uint8_t * ed25519_cert_extension
* success; return -1 and set the error code on 'inp' on failure.
*/
int ed25519_cert_extension_setlen_un_unparsed(ed25519_cert_extension_t *inp, size_t newlen);
+ /** Return a newly allocated link_specifier with all elements set to
+ * zero.
+ */
+ link_specifier_t *link_specifier_new(void);
+ /** Release all storage held by the link_specifier in 'victim'. (Do
+ * nothing if 'victim' is NULL.)
+ */
+ void link_specifier_free(link_specifier_t *victim);
+ /** Try to parse a link_specifier 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
+ * link_specifier_t. On failure, return -2 if the input appears
+ * truncated, and -1 if the input is otherwise invalid.
+ */
+ ssize_t link_specifier_parse(link_specifier_t **output, const uint8_t *input, const size_t len_in);
+ /** Return the number of bytes we expect to need to encode the
+ * link_specifier 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 link_specifier_encoded_len(const link_specifier_t *obj);
+ /** Try to encode the link_specifier 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 link_specifier_encode(uint8_t *output, size_t avail, const link_specifier_t *input);
+ /** Check whether the internal state of the link_specifier in 'obj' is
+ * consistent. Return NULL if it is, and a short message if it is not.
+ */
+ const char *link_specifier_check(const link_specifier_t *obj);
+ /** Clear any errors that were set on the object 'obj' by its setter
+ * functions. Return true iff errors were cleared.
+ */
+ int link_specifier_clear_errors(link_specifier_t *obj);
+ /** Return the value of the ls_type field of the link_specifier_t in
+ * 'inp'
+ */
+ uint8_t link_specifier_get_ls_type(link_specifier_t *inp);
+ /** Set the value of the ls_type field of the link_specifier_t in
+ * 'inp' to 'val'. Return 0 on success; return -1 and set the error
+ * code on 'inp' on failure.
+ */
+ int link_specifier_set_ls_type(link_specifier_t *inp, uint8_t val);
+ /** Return the value of the ls_len field of the link_specifier_t in
+ * 'inp'
+ */
+ uint8_t link_specifier_get_ls_len(link_specifier_t *inp);
+ /** Set the value of the ls_len field of the link_specifier_t in 'inp'
+ * to 'val'. Return 0 on success; return -1 and set the error code on
+ * 'inp' on failure.
+ */
+ int link_specifier_set_ls_len(link_specifier_t *inp, uint8_t val);
+ /** Return the value of the un_ipv4_addr field of the link_specifier_t
+ * in 'inp'
+ */
+ uint32_t link_specifier_get_un_ipv4_addr(link_specifier_t *inp);
+ /** Set the value of the un_ipv4_addr field of the link_specifier_t in
+ * 'inp' to 'val'. Return 0 on success; return -1 and set the error
+ * code on 'inp' on failure.
+ */
+ int link_specifier_set_un_ipv4_addr(link_specifier_t *inp, uint32_t val);
+ /** Return the value of the un_ipv4_port field of the link_specifier_t
+ * in 'inp'
+ */
+ uint16_t link_specifier_get_un_ipv4_port(link_specifier_t *inp);
+ /** Set the value of the un_ipv4_port field of the link_specifier_t in
+ * 'inp' to 'val'. Return 0 on success; return -1 and set the error
+ * code on 'inp' on failure.
+ */
+ int link_specifier_set_un_ipv4_port(link_specifier_t *inp, uint16_t val);
+ /** Return the (constant) length of the array holding the un_ipv6_addr
+ * field of the link_specifier_t in 'inp'.
+ */
+ size_t link_specifier_getlen_un_ipv6_addr(const link_specifier_t *inp);
+ /** Return the element at position 'idx' of the fixed array field
+ * un_ipv6_addr of the link_specifier_t in 'inp'.
+ */
-uint8_t link_specifier_get_un_ipv6_addr(const link_specifier_t *inp, size_t idx);
++uint8_t link_specifier_get_un_ipv6_addr(link_specifier_t *inp, size_t idx);
++/** As link_specifier_get_un_ipv6_addr, but take and return a const
++ * pointer
++ */
++uint8_t link_specifier_getconst_un_ipv6_addr(const link_specifier_t *inp, size_t idx);
+ /** Change the element at position 'idx' of the fixed array field
+ * un_ipv6_addr of the link_specifier_t in 'inp', so that it will hold
+ * the value 'elt'.
+ */
+ int link_specifier_set_un_ipv6_addr(link_specifier_t *inp, size_t idx, uint8_t elt);
+ /** Return a pointer to the 16-element array field un_ipv6_addr of
+ * 'inp'.
+ */
+ uint8_t * link_specifier_getarray_un_ipv6_addr(link_specifier_t *inp);
++/** As link_specifier_get_un_ipv6_addr, but take and return a const
++ * pointer
++ */
++const uint8_t * link_specifier_getconstarray_un_ipv6_addr(const link_specifier_t *inp);
+ /** Return the value of the un_ipv6_port field of the link_specifier_t
+ * in 'inp'
+ */
+ uint16_t link_specifier_get_un_ipv6_port(link_specifier_t *inp);
+ /** Set the value of the un_ipv6_port field of the link_specifier_t in
+ * 'inp' to 'val'. Return 0 on success; return -1 and set the error
+ * code on 'inp' on failure.
+ */
+ int link_specifier_set_un_ipv6_port(link_specifier_t *inp, uint16_t val);
+ /** Return the (constant) length of the array holding the un_legacy_id
+ * field of the link_specifier_t in 'inp'.
+ */
+ size_t link_specifier_getlen_un_legacy_id(const link_specifier_t *inp);
+ /** Return the element at position 'idx' of the fixed array field
+ * un_legacy_id of the link_specifier_t in 'inp'.
+ */
-uint8_t link_specifier_get_un_legacy_id(const link_specifier_t *inp, size_t idx);
++uint8_t link_specifier_get_un_legacy_id(link_specifier_t *inp, size_t idx);
++/** As link_specifier_get_un_legacy_id, but take and return a const
++ * pointer
++ */
++uint8_t link_specifier_getconst_un_legacy_id(const link_specifier_t *inp, size_t idx);
+ /** Change the element at position 'idx' of the fixed array field
+ * un_legacy_id of the link_specifier_t in 'inp', so that it will hold
+ * the value 'elt'.
+ */
+ int link_specifier_set_un_legacy_id(link_specifier_t *inp, size_t idx, uint8_t elt);
+ /** Return a pointer to the 20-element array field un_legacy_id of
+ * 'inp'.
+ */
+ uint8_t * link_specifier_getarray_un_legacy_id(link_specifier_t *inp);
++/** As link_specifier_get_un_legacy_id, but take and return a const
++ * pointer
++ */
++const uint8_t * link_specifier_getconstarray_un_legacy_id(const link_specifier_t *inp);
+ /** Return the (constant) length of the array holding the
+ * un_ed25519_id field of the link_specifier_t in 'inp'.
+ */
+ size_t link_specifier_getlen_un_ed25519_id(const link_specifier_t *inp);
+ /** Return the element at position 'idx' of the fixed array field
+ * un_ed25519_id of the link_specifier_t in 'inp'.
+ */
-uint8_t link_specifier_get_un_ed25519_id(const link_specifier_t *inp, size_t idx);
++uint8_t link_specifier_get_un_ed25519_id(link_specifier_t *inp, size_t idx);
++/** As link_specifier_get_un_ed25519_id, but take and return a const
++ * pointer
++ */
++uint8_t link_specifier_getconst_un_ed25519_id(const link_specifier_t *inp, size_t idx);
+ /** Change the element at position 'idx' of the fixed array field
+ * un_ed25519_id of the link_specifier_t in 'inp', so that it will
+ * hold the value 'elt'.
+ */
+ int link_specifier_set_un_ed25519_id(link_specifier_t *inp, size_t idx, uint8_t elt);
+ /** Return a pointer to the 32-element array field un_ed25519_id of
+ * 'inp'.
+ */
+ uint8_t * link_specifier_getarray_un_ed25519_id(link_specifier_t *inp);
++/** As link_specifier_get_un_ed25519_id, but take and return a const
++ * pointer
++ */
++const uint8_t * link_specifier_getconstarray_un_ed25519_id(const link_specifier_t *inp);
+ /** Return the length of the dynamic array holding the un_unrecognized
+ * field of the link_specifier_t in 'inp'.
+ */
+ size_t link_specifier_getlen_un_unrecognized(const link_specifier_t *inp);
+ /** Return the element at position 'idx' of the dynamic array field
+ * un_unrecognized of the link_specifier_t in 'inp'.
+ */
+ uint8_t link_specifier_get_un_unrecognized(link_specifier_t *inp, size_t idx);
++/** As link_specifier_get_un_unrecognized, but take and return a const
++ * pointer
++ */
++uint8_t link_specifier_getconst_un_unrecognized(const link_specifier_t *inp, size_t idx);
+ /** Change the element at position 'idx' of the dynamic array field
+ * un_unrecognized of the link_specifier_t in 'inp', so that it will
+ * hold the value 'elt'.
+ */
+ int link_specifier_set_un_unrecognized(link_specifier_t *inp, size_t idx, uint8_t elt);
+ /** Append a new element 'elt' to the dynamic array field
+ * un_unrecognized of the link_specifier_t in 'inp'.
+ */
+ int link_specifier_add_un_unrecognized(link_specifier_t *inp, uint8_t elt);
+ /** Return a pointer to the variable-length array field
+ * un_unrecognized of 'inp'.
+ */
+ uint8_t * link_specifier_getarray_un_unrecognized(link_specifier_t *inp);
++/** As link_specifier_get_un_unrecognized, but take and return a const
++ * pointer
++ */
++const uint8_t * link_specifier_getconstarray_un_unrecognized(const link_specifier_t *inp);
+ /** Change the length of the variable-length array field
+ * un_unrecognized 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 link_specifier_setlen_un_unrecognized(link_specifier_t *inp, size_t newlen);
/** Return a newly allocated ed25519_cert with all elements set to
* zero.
*/
@@@ -316,9 -468,81 +533,92 @@@ int ed25519_cert_set_signature(ed25519_
/** Return a pointer to the 64-element array field signature of 'inp'.
*/
uint8_t * ed25519_cert_getarray_signature(ed25519_cert_t *inp);
+/** As ed25519_cert_get_signature, but take and return a const pointer
+ */
+const uint8_t * ed25519_cert_getconstarray_signature(const ed25519_cert_t *inp);
+ /** Return a newly allocated link_specifier_list with all elements set
+ * to zero.
+ */
+ link_specifier_list_t *link_specifier_list_new(void);
+ /** Release all storage held by the link_specifier_list in 'victim'.
+ * (Do nothing if 'victim' is NULL.)
+ */
+ void link_specifier_list_free(link_specifier_list_t *victim);
+ /** Try to parse a link_specifier_list 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 link_specifier_list_t. On failure, return -2 if the input
+ * appears truncated, and -1 if the input is otherwise invalid.
+ */
+ ssize_t link_specifier_list_parse(link_specifier_list_t **output, const uint8_t *input, const size_t len_in);
+ /** Return the number of bytes we expect to need to encode the
+ * link_specifier_list 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 link_specifier_list_encoded_len(const link_specifier_list_t *obj);
+ /** Try to encode the link_specifier_list 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 link_specifier_list_encode(uint8_t *output, size_t avail, const link_specifier_list_t *input);
+ /** Check whether the internal state of the link_specifier_list in
+ * 'obj' is consistent. Return NULL if it is, and a short message if
+ * it is not.
+ */
+ const char *link_specifier_list_check(const link_specifier_list_t *obj);
+ /** Clear any errors that were set on the object 'obj' by its setter
+ * functions. Return true iff errors were cleared.
+ */
+ int link_specifier_list_clear_errors(link_specifier_list_t *obj);
+ /** Return the value of the n_spec field of the link_specifier_list_t
+ * in 'inp'
+ */
+ uint8_t link_specifier_list_get_n_spec(link_specifier_list_t *inp);
+ /** Set the value of the n_spec field of the link_specifier_list_t in
+ * 'inp' to 'val'. Return 0 on success; return -1 and set the error
+ * code on 'inp' on failure.
+ */
+ int link_specifier_list_set_n_spec(link_specifier_list_t *inp, uint8_t val);
+ /** Return the length of the dynamic array holding the spec field of
+ * the link_specifier_list_t in 'inp'.
+ */
+ size_t link_specifier_list_getlen_spec(const link_specifier_list_t *inp);
+ /** Return the element at position 'idx' of the dynamic array field
+ * spec of the link_specifier_list_t in 'inp'.
+ */
+ struct link_specifier_st * link_specifier_list_get_spec(link_specifier_list_t *inp, size_t idx);
++/** As link_specifier_list_get_spec, but take and return a const
++ * pointer
++ */
++ const struct link_specifier_st * link_specifier_list_getconst_spec(const link_specifier_list_t *inp, size_t idx);
+ /** Change the element at position 'idx' of the dynamic array field
+ * spec of the link_specifier_list_t in 'inp', so that it will hold
+ * the value 'elt'. Free the previous value, if any.
+ */
+ int link_specifier_list_set_spec(link_specifier_list_t *inp, size_t idx, struct link_specifier_st * elt);
+ /** As link_specifier_list_set_spec, but does not free the previous
+ * value.
+ */
+ int link_specifier_list_set0_spec(link_specifier_list_t *inp, size_t idx, struct link_specifier_st * elt);
+ /** Append a new element 'elt' to the dynamic array field spec of the
+ * link_specifier_list_t in 'inp'.
+ */
+ int link_specifier_list_add_spec(link_specifier_list_t *inp, struct link_specifier_st * elt);
+ /** Return a pointer to the variable-length array field spec of 'inp'.
+ */
+ struct link_specifier_st * * link_specifier_list_getarray_spec(link_specifier_list_t *inp);
++/** As link_specifier_list_get_spec, but take and return a const
++ * pointer
++ */
++const struct link_specifier_st * const * link_specifier_list_getconstarray_spec(const link_specifier_list_t *inp);
+ /** Change the length of the variable-length array field spec 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 link_specifier_list_setlen_spec(link_specifier_list_t *inp, size_t newlen);
#endif
More information about the tor-commits
mailing list