diff --git a/src/common/tortls.c b/src/common/tortls.c
index 23889be259..eaa5748f33 100644
--- a/src/common/tortls.c
+++ b/src/common/tortls.c
@@ -2448,6 +2448,28 @@ tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out))
return 0;
}
+/** Using the RFC5705 key material exporting construction, and the
+ * provided context (context_len bytes long) and
+ * label (a NUL-terminated string), compute a 32-byte secret in
+ * secrets_out that only the parties to this TLS session can
+ * compute. Return 0 on success and -1 on failure.
+ */
+MOCK_IMPL(int,
+tor_tls_export_key_material,(tor_tls_t *tls, uint8_t *secrets_out,
+ const uint8_t *context,
+ size_t context_len,
+ const char *label))
+{
+ tor_assert(tls);
+ tor_assert(tls->ssl);
+
+ int r = SSL_export_keying_material(tls->ssl,
+ secrets_out, DIGEST256_LEN,
+ label, strlen(label),
+ context, context_len, 1);
+ return (r == 1) ? 0 : -1;
+}
+
/** Examine the amount of memory used and available for buffers in tls.
* Set *rbuf_capacity to the amount of storage allocated for the read
* buffer and *rbuf_bytes to the amount actually used.
diff --git a/src/common/tortls.h b/src/common/tortls.h
index 7c035a2cd5..fe5898ef5c 100644
--- a/src/common/tortls.h
+++ b/src/common/tortls.h
@@ -226,6 +226,11 @@ int tor_tls_used_v1_handshake(tor_tls_t *tls);
int tor_tls_get_num_server_handshakes(tor_tls_t *tls);
int tor_tls_server_got_renegotiate(tor_tls_t *tls);
MOCK_DECL(int,tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out));
+MOCK_DECL(int,tor_tls_export_key_material,(
+ tor_tls_t *tls, uint8_t *secrets_out,
+ const uint8_t *context,
+ size_t context_len,
+ const char *label));
/* Log and abort if there are unhandled TLS errors in OpenSSL's error stack.
*/
diff --git a/src/or/connection_or.c b/src/or/connection_or.c
index 09579f80e1..d06a246ee2 100644
--- a/src/or/connection_or.c
+++ b/src/or/connection_or.c
@@ -2318,15 +2318,34 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
auth1_t *auth = NULL;
auth_ctx_t *ctx = auth_ctx_new();
int result;
+ int old_tlssecrets_algorithm = 0;
+ const char *authtype_str = NULL;
+
+ int is_ed = 0;
+ const int authtype = 1; /* XXXX this should be an argument. */
/* assert state is reasonable XXXX */
-
- ctx->is_ed = 0;
+ switch (authtype) {
+ case AUTHTYPE_RSA_SHA256_TLSSECRET:
+ authtype_str = "AUTH0001";
+ old_tlssecrets_algorithm = 1;
+ break;
+ case AUTHTYPE_RSA_SHA256_RFC5705:
+ authtype_str = "AUTH0002";
+ break;
+ case AUTHTYPE_ED25519_SHA256_RFC5705:
+ authtype_str = "AUTH0003";
+ is_ed = 1;
+ break;
+ default:
+ tor_assert(0);
+ break;
+ }
auth = auth1_new();
/* Type: 8 bytes. */
- memcpy(auth1_getarray_type(auth), "AUTH0001", 8);
+ memcpy(auth1_getarray_type(auth), authtype_str, 8);
{
const tor_x509_cert_t *id_cert=NULL, *link_cert=NULL;
@@ -2380,7 +2399,8 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
cert = freecert;
}
if (!cert) {
- log_warn(LD_OR, "Unable to find cert when making AUTH1 data.");
+ log_warn(LD_OR, "Unable to find cert when making %s data.",
+ authtype_str);
goto err;
}
@@ -2392,7 +2412,16 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
}
/* HMAC of clientrandom and serverrandom using master key : 32 octets */
- tor_tls_get_tlssecrets(conn->tls, auth->tlssecrets);
+ if (old_tlssecrets_algorithm) {
+ tor_tls_get_tlssecrets(conn->tls, auth->tlssecrets);
+ } else {
+ char label[128];
+ tor_snprintf(label, sizeof(label),
+ "EXPORTER FOR TOR TLS CLIENT BINDING %s", authtype_str);
+ tor_tls_export_key_material(conn->tls, auth->tlssecrets,
+ auth->cid, sizeof(auth->cid),
+ label);
+ }
/* 8 octets were reserved for the current time, but we're trying to get out
* of the habit of sending time around willynilly. Fortunately, nothing
diff --git a/src/or/or.h b/src/or/or.h
index 5b9b007ac1..402fbfde6b 100644
--- a/src/or/or.h
+++ b/src/or/or.h
@@ -1348,13 +1348,34 @@ typedef struct listener_connection_t {
#define OR_CERT_TYPE_RSA_ED_CROSSCERT 7
/**@}*/
-/** The one currently supported type of AUTHENTICATE cell. It contains
+/** The first supported type of AUTHENTICATE cell. It contains
* a bunch of structures signed with an RSA1024 key. The signed
* structures include a HMAC using negotiated TLS secrets, and a digest
* of all cells sent or received before the AUTHENTICATE cell (including
* the random server-generated AUTH_CHALLENGE cell).
*/
#define AUTHTYPE_RSA_SHA256_TLSSECRET 1
+/** As AUTHTYPE_RSA_SHA256_TLSSECRET, but instead of using the
+ * negotiated TLS secrets, uses exported keying material from the TLS
+ * session as described in RFC 5705.
+ *
+ * Not used by today's tors, since everything that supports this
+ * also supports ED25519_SHA3_5705, which is better.
+ **/
+#define AUTHTYPE_RSA_SHA256_RFC5705 2
+/** As AUTHTYPE_RSA_SHA256_RFC5705, but uses an Ed25519 identity key to
+ * authenticate. */
+#define AUTHTYPE_ED25519_SHA256_RFC5705 3
+/*
+ * NOTE: authchallenge_type_is_better() relies on these AUTHTYPE codes
+ * being sorted in order of preference. If we someday add one with
+ * a higher numerical value that we don't like as much, we should revise
+ * authchallenge_type_is_better().
+ */
+
+
+
+
/** The length of the part of the AUTHENTICATE cell body that the client and
* server can generate independently (when using RSA_SHA256_TLSSECRET). It