Add over_message issuance and redemption to Trust Tokens.
This adds function to allow for issuing and redeeming tokens derived
from a particular message rather than a completely random nonce.
Change-Id: Ia29ae06ca419405ffff79ab6defadbed4f184b29
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/55565
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: Steven Valdez <svaldez@google.com>
diff --git a/crypto/trust_token/internal.h b/crypto/trust_token/internal.h
index 31ecc49..093b4ac 100644
--- a/crypto/trust_token/internal.h
+++ b/crypto/trust_token/internal.h
@@ -71,6 +71,7 @@
// TRUST_TOKEN_PRETOKEN represents the intermediate state a client keeps during
// a Trust_Token issuance operation.
typedef struct pmb_pretoken_st {
+ uint8_t salt[TRUST_TOKEN_NONCE_SIZE];
uint8_t t[TRUST_TOKEN_NONCE_SIZE];
EC_SCALAR r;
EC_AFFINE Tp;
@@ -100,18 +101,22 @@
const uint8_t *in, size_t len);
int pmbtoken_exp1_issuer_key_from_bytes(TRUST_TOKEN_ISSUER_KEY *key,
const uint8_t *in, size_t len);
-STACK_OF(TRUST_TOKEN_PRETOKEN) * pmbtoken_exp1_blind(CBB *cbb, size_t count);
+STACK_OF(TRUST_TOKEN_PRETOKEN) *pmbtoken_exp1_blind(CBB *cbb, size_t count,
+ int include_message,
+ const uint8_t *msg,
+ size_t msg_len);
int pmbtoken_exp1_sign(const TRUST_TOKEN_ISSUER_KEY *key, CBB *cbb, CBS *cbs,
size_t num_requested, size_t num_to_issue,
uint8_t private_metadata);
-STACK_OF(TRUST_TOKEN) *
- pmbtoken_exp1_unblind(const TRUST_TOKEN_CLIENT_KEY *key,
- const STACK_OF(TRUST_TOKEN_PRETOKEN) * pretokens,
- CBS *cbs, size_t count, uint32_t key_id);
+STACK_OF(TRUST_TOKEN) *pmbtoken_exp1_unblind(
+ const TRUST_TOKEN_CLIENT_KEY *key,
+ const STACK_OF(TRUST_TOKEN_PRETOKEN) *pretokens, CBS *cbs, size_t count,
+ uint32_t key_id);
int pmbtoken_exp1_read(const TRUST_TOKEN_ISSUER_KEY *key,
uint8_t out_nonce[TRUST_TOKEN_NONCE_SIZE],
uint8_t *out_private_metadata, const uint8_t *token,
- size_t token_len);
+ size_t token_len, int include_message,
+ const uint8_t *msg, size_t msg_len);
// pmbtoken_exp1_get_h_for_testing returns H in uncompressed coordinates. This
// function is used to confirm H was computed as expected.
@@ -128,18 +133,22 @@
const uint8_t *in, size_t len);
int pmbtoken_exp2_issuer_key_from_bytes(TRUST_TOKEN_ISSUER_KEY *key,
const uint8_t *in, size_t len);
-STACK_OF(TRUST_TOKEN_PRETOKEN) * pmbtoken_exp2_blind(CBB *cbb, size_t count);
+STACK_OF(TRUST_TOKEN_PRETOKEN) *pmbtoken_exp2_blind(CBB *cbb, size_t count,
+ int include_message,
+ const uint8_t *msg,
+ size_t msg_len);
int pmbtoken_exp2_sign(const TRUST_TOKEN_ISSUER_KEY *key, CBB *cbb, CBS *cbs,
size_t num_requested, size_t num_to_issue,
uint8_t private_metadata);
-STACK_OF(TRUST_TOKEN) *
- pmbtoken_exp2_unblind(const TRUST_TOKEN_CLIENT_KEY *key,
- const STACK_OF(TRUST_TOKEN_PRETOKEN) * pretokens,
- CBS *cbs, size_t count, uint32_t key_id);
+STACK_OF(TRUST_TOKEN) *pmbtoken_exp2_unblind(
+ const TRUST_TOKEN_CLIENT_KEY *key,
+ const STACK_OF(TRUST_TOKEN_PRETOKEN) *pretokens, CBS *cbs, size_t count,
+ uint32_t key_id);
int pmbtoken_exp2_read(const TRUST_TOKEN_ISSUER_KEY *key,
uint8_t out_nonce[TRUST_TOKEN_NONCE_SIZE],
uint8_t *out_private_metadata, const uint8_t *token,
- size_t token_len);
+ size_t token_len, int include_message,
+ const uint8_t *msg, size_t msg_len);
// pmbtoken_exp2_get_h_for_testing returns H in uncompressed coordinates. This
// function is used to confirm H was computed as expected.
@@ -165,18 +174,22 @@
const uint8_t *in, size_t len);
int voprf_exp2_issuer_key_from_bytes(TRUST_TOKEN_ISSUER_KEY *key,
const uint8_t *in, size_t len);
-STACK_OF(TRUST_TOKEN_PRETOKEN) * voprf_exp2_blind(CBB *cbb, size_t count);
+STACK_OF(TRUST_TOKEN_PRETOKEN) *voprf_exp2_blind(CBB *cbb, size_t count,
+ int include_message,
+ const uint8_t *msg,
+ size_t msg_len);
int voprf_exp2_sign(const TRUST_TOKEN_ISSUER_KEY *key, CBB *cbb, CBS *cbs,
size_t num_requested, size_t num_to_issue,
uint8_t private_metadata);
-STACK_OF(TRUST_TOKEN) *
- voprf_exp2_unblind(const TRUST_TOKEN_CLIENT_KEY *key,
- const STACK_OF(TRUST_TOKEN_PRETOKEN) * pretokens,
- CBS *cbs, size_t count, uint32_t key_id);
+STACK_OF(TRUST_TOKEN) *voprf_exp2_unblind(
+ const TRUST_TOKEN_CLIENT_KEY *key,
+ const STACK_OF(TRUST_TOKEN_PRETOKEN) *pretokens, CBS *cbs, size_t count,
+ uint32_t key_id);
int voprf_exp2_read(const TRUST_TOKEN_ISSUER_KEY *key,
uint8_t out_nonce[TRUST_TOKEN_NONCE_SIZE],
uint8_t *out_private_metadata, const uint8_t *token,
- size_t token_len);
+ size_t token_len, int include_message, const uint8_t *msg,
+ size_t msg_len);
// Trust Tokens internals.
@@ -191,7 +204,7 @@
// |secret| and writes their serialized forms into |out_private| and
// |out_public|. It returns one on success and zero on failure.
int (*derive_key_from_secret)(CBB *out_private, CBB *out_public,
- const uint8_t *secret, size_t secret_len);
+ const uint8_t *secret, size_t secret_len);
// client_key_from_bytes decodes a client key from |in| and sets |key|
// to the resulting key. It returns one on success and zero
@@ -205,14 +218,17 @@
int (*issuer_key_from_bytes)(TRUST_TOKEN_ISSUER_KEY *key, const uint8_t *in,
size_t len);
- // blind generates a new issuance request for |count| tokens. On
+ // blind generates a new issuance request for |count| tokens. If
+ // |include_message| is set, then |msg| is used to derive the token nonces. On
// success, it returns a newly-allocated |STACK_OF(TRUST_TOKEN_PRETOKEN)| and
// writes a request to the issuer to |cbb|. On failure, it returns NULL. The
- // |STACK_OF(TRUST_TOKEN_PRETOKEN)|s should be passed to |pmbtoken_unblind| when
- // the server responds.
+ // |STACK_OF(TRUST_TOKEN_PRETOKEN)|s should be passed to |pmbtoken_unblind|
+ // when the server responds.
//
// This function implements the AT.Usr0 operation.
- STACK_OF(TRUST_TOKEN_PRETOKEN) * (*blind)(CBB *cbb, size_t count);
+ STACK_OF(TRUST_TOKEN_PRETOKEN) *(*blind)(CBB *cbb, size_t count,
+ int include_message,
+ const uint8_t *msg, size_t msg_len);
// sign parses a request for |num_requested| tokens from |cbs| and
// issues |num_to_issue| tokens with |key| and a private metadata value of
@@ -232,20 +248,22 @@
// returns NULL.
//
// This function implements the AT.Usr1 operation.
- STACK_OF(TRUST_TOKEN) *
- (*unblind)(const TRUST_TOKEN_CLIENT_KEY *key,
- const STACK_OF(TRUST_TOKEN_PRETOKEN) * pretokens, CBS *cbs,
- size_t count, uint32_t key_id);
+ STACK_OF(TRUST_TOKEN) *(*unblind)(
+ const TRUST_TOKEN_CLIENT_KEY *key,
+ const STACK_OF(TRUST_TOKEN_PRETOKEN) *pretokens, CBS *cbs, size_t count,
+ uint32_t key_id);
- // read parses a PMBToken from |token| and verifies it using |key|. On
- // success, it returns one and stores the nonce and private metadata bit in
- // |out_nonce| and |*out_private_metadata|. Otherwise, it returns zero. Note
- // that, unlike the output of |unblind|, |token| does not have a
- // four-byte key ID prepended.
+ // read parses a token from |token| and verifies it using |key|. If
+ // |include_message| is set, then the nonce is derived from |msg| and the salt
+ // in the token. On success, it returns one and stores the nonce and private
+ // metadata bit in |out_nonce| and |*out_private_metadata|. Otherwise, it
+ // returns zero. Note that, unlike the output of |unblind|, |token| does not
+ // have a four-byte key ID prepended.
int (*read)(const TRUST_TOKEN_ISSUER_KEY *key,
uint8_t out_nonce[TRUST_TOKEN_NONCE_SIZE],
uint8_t *out_private_metadata, const uint8_t *token,
- size_t token_len);
+ size_t token_len, int include_message, const uint8_t *msg,
+ size_t msg_len);
// whether the construction supports private metadata.
int has_private_metadata;
@@ -284,7 +302,7 @@
size_t num_keys;
// pretokens is the intermediate state during an active issuance.
- STACK_OF(TRUST_TOKEN_PRETOKEN)* pretokens;
+ STACK_OF(TRUST_TOKEN_PRETOKEN) *pretokens;
// srr_key is the public key used to verify the signature of the SRR.
EVP_PKEY *srr_key;
diff --git a/crypto/trust_token/pmbtoken.c b/crypto/trust_token/pmbtoken.c
index ab09f01..7a95a7d 100644
--- a/crypto/trust_token/pmbtoken.c
+++ b/crypto/trust_token/pmbtoken.c
@@ -324,8 +324,11 @@
return 1;
}
-static STACK_OF(TRUST_TOKEN_PRETOKEN) *
- pmbtoken_blind(const PMBTOKEN_METHOD *method, CBB *cbb, size_t count) {
+static STACK_OF(TRUST_TOKEN_PRETOKEN) *pmbtoken_blind(
+ const PMBTOKEN_METHOD *method, CBB *cbb, size_t count, int include_message,
+ const uint8_t *msg, size_t msg_len) {
+ SHA512_CTX hash_ctx;
+
const EC_GROUP *group = method->group;
STACK_OF(TRUST_TOKEN_PRETOKEN) *pretokens = sk_TRUST_TOKEN_PRETOKEN_new_null();
if (pretokens == NULL) {
@@ -343,7 +346,16 @@
goto err;
}
- RAND_bytes(pretoken->t, sizeof(pretoken->t));
+ RAND_bytes(pretoken->salt, sizeof(pretoken->salt));
+ if (include_message) {
+ assert(SHA512_DIGEST_LENGTH == TRUST_TOKEN_NONCE_SIZE);
+ SHA512_Init(&hash_ctx);
+ SHA512_Update(&hash_ctx, pretoken->salt, sizeof(pretoken->salt));
+ SHA512_Update(&hash_ctx, msg, msg_len);
+ SHA512_Final(pretoken->t, &hash_ctx);
+ } else {
+ OPENSSL_memcpy(pretoken->t, pretoken->salt, TRUST_TOKEN_NONCE_SIZE);
+ }
// We sample |pretoken->r| in Montgomery form to simplify inverting.
if (!ec_random_nonzero_scalar(group, &pretoken->r,
@@ -933,11 +945,10 @@
return ret;
}
-static STACK_OF(TRUST_TOKEN) *
- pmbtoken_unblind(const PMBTOKEN_METHOD *method,
- const TRUST_TOKEN_CLIENT_KEY *key,
- const STACK_OF(TRUST_TOKEN_PRETOKEN) * pretokens, CBS *cbs,
- size_t count, uint32_t key_id) {
+static STACK_OF(TRUST_TOKEN) *pmbtoken_unblind(
+ const PMBTOKEN_METHOD *method, const TRUST_TOKEN_CLIENT_KEY *key,
+ const STACK_OF(TRUST_TOKEN_PRETOKEN) *pretokens, CBS *cbs, size_t count,
+ uint32_t key_id) {
const EC_GROUP *group = method->group;
if (count > sk_TRUST_TOKEN_PRETOKEN_num(pretokens)) {
OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_DECODE_FAILURE);
@@ -1024,7 +1035,7 @@
if (!CBB_init(&token_cbb,
4 + TRUST_TOKEN_NONCE_SIZE + 3 * (2 + point_len)) ||
!CBB_add_u32(&token_cbb, key_id) ||
- !CBB_add_bytes(&token_cbb, pretoken->t, TRUST_TOKEN_NONCE_SIZE) ||
+ !CBB_add_bytes(&token_cbb, pretoken->salt, TRUST_TOKEN_NONCE_SIZE) ||
!cbb_add_prefixed_point(&token_cbb, group, &affines[0],
method->prefix_point) ||
!cbb_add_prefixed_point(&token_cbb, group, &affines[1],
@@ -1096,12 +1107,13 @@
const TRUST_TOKEN_ISSUER_KEY *key,
uint8_t out_nonce[TRUST_TOKEN_NONCE_SIZE],
uint8_t *out_private_metadata, const uint8_t *token,
- size_t token_len) {
+ size_t token_len, int include_message,
+ const uint8_t *msg, size_t msg_len) {
const EC_GROUP *group = method->group;
- CBS cbs;
+ CBS cbs, salt;
CBS_init(&cbs, token, token_len);
EC_AFFINE S, W, Ws;
- if (!CBS_copy_bytes(&cbs, out_nonce, TRUST_TOKEN_NONCE_SIZE) ||
+ if (!CBS_get_bytes(&cbs, &salt, TRUST_TOKEN_NONCE_SIZE) ||
!cbs_get_prefixed_point(&cbs, group, &S, method->prefix_point) ||
!cbs_get_prefixed_point(&cbs, group, &W, method->prefix_point) ||
!cbs_get_prefixed_point(&cbs, group, &Ws, method->prefix_point) ||
@@ -1110,6 +1122,16 @@
return 0;
}
+ if (include_message) {
+ SHA512_CTX hash_ctx;
+ assert(SHA512_DIGEST_LENGTH == TRUST_TOKEN_NONCE_SIZE);
+ SHA512_Init(&hash_ctx);
+ SHA512_Update(&hash_ctx, CBS_data(&salt), CBS_len(&salt));
+ SHA512_Update(&hash_ctx, msg, msg_len);
+ SHA512_Final(out_nonce, &hash_ctx);
+ } else {
+ OPENSSL_memcpy(out_nonce, CBS_data(&salt), CBS_len(&salt));
+ }
EC_RAW_POINT T;
if (!method->hash_t(group, &T, out_nonce)) {
@@ -1275,11 +1297,15 @@
return pmbtoken_issuer_key_from_bytes(&pmbtoken_exp1_method, key, in, len);
}
-STACK_OF(TRUST_TOKEN_PRETOKEN) * pmbtoken_exp1_blind(CBB *cbb, size_t count) {
+STACK_OF(TRUST_TOKEN_PRETOKEN) *pmbtoken_exp1_blind(CBB *cbb, size_t count,
+ int include_message,
+ const uint8_t *msg,
+ size_t msg_len) {
if (!pmbtoken_exp1_init_method()) {
return NULL;
}
- return pmbtoken_blind(&pmbtoken_exp1_method, cbb, count);
+ return pmbtoken_blind(&pmbtoken_exp1_method, cbb, count, include_message, msg,
+ msg_len);
}
int pmbtoken_exp1_sign(const TRUST_TOKEN_ISSUER_KEY *key, CBB *cbb, CBS *cbs,
@@ -1292,10 +1318,10 @@
num_to_issue, private_metadata);
}
-STACK_OF(TRUST_TOKEN) *
- pmbtoken_exp1_unblind(const TRUST_TOKEN_CLIENT_KEY *key,
- const STACK_OF(TRUST_TOKEN_PRETOKEN) * pretokens,
- CBS *cbs, size_t count, uint32_t key_id) {
+STACK_OF(TRUST_TOKEN) *pmbtoken_exp1_unblind(
+ const TRUST_TOKEN_CLIENT_KEY *key,
+ const STACK_OF(TRUST_TOKEN_PRETOKEN) *pretokens, CBS *cbs, size_t count,
+ uint32_t key_id) {
if (!pmbtoken_exp1_init_method()) {
return NULL;
}
@@ -1306,12 +1332,14 @@
int pmbtoken_exp1_read(const TRUST_TOKEN_ISSUER_KEY *key,
uint8_t out_nonce[TRUST_TOKEN_NONCE_SIZE],
uint8_t *out_private_metadata, const uint8_t *token,
- size_t token_len) {
+ size_t token_len, int include_message,
+ const uint8_t *msg, size_t msg_len) {
if (!pmbtoken_exp1_init_method()) {
return 0;
}
return pmbtoken_read(&pmbtoken_exp1_method, key, out_nonce,
- out_private_metadata, token, token_len);
+ out_private_metadata, token, token_len, include_message,
+ msg, msg_len);
}
int pmbtoken_exp1_get_h_for_testing(uint8_t out[97]) {
@@ -1444,11 +1472,15 @@
return pmbtoken_issuer_key_from_bytes(&pmbtoken_exp2_method, key, in, len);
}
-STACK_OF(TRUST_TOKEN_PRETOKEN) * pmbtoken_exp2_blind(CBB *cbb, size_t count) {
+STACK_OF(TRUST_TOKEN_PRETOKEN) *pmbtoken_exp2_blind(CBB *cbb, size_t count,
+ int include_message,
+ const uint8_t *msg,
+ size_t msg_len) {
if (!pmbtoken_exp2_init_method()) {
return NULL;
}
- return pmbtoken_blind(&pmbtoken_exp2_method, cbb, count);
+ return pmbtoken_blind(&pmbtoken_exp2_method, cbb, count, include_message, msg,
+ msg_len);
}
int pmbtoken_exp2_sign(const TRUST_TOKEN_ISSUER_KEY *key, CBB *cbb, CBS *cbs,
@@ -1461,10 +1493,10 @@
num_to_issue, private_metadata);
}
-STACK_OF(TRUST_TOKEN) *
- pmbtoken_exp2_unblind(const TRUST_TOKEN_CLIENT_KEY *key,
- const STACK_OF(TRUST_TOKEN_PRETOKEN) * pretokens,
- CBS *cbs, size_t count, uint32_t key_id) {
+STACK_OF(TRUST_TOKEN) *pmbtoken_exp2_unblind(
+ const TRUST_TOKEN_CLIENT_KEY *key,
+ const STACK_OF(TRUST_TOKEN_PRETOKEN) *pretokens, CBS *cbs, size_t count,
+ uint32_t key_id) {
if (!pmbtoken_exp2_init_method()) {
return NULL;
}
@@ -1475,12 +1507,14 @@
int pmbtoken_exp2_read(const TRUST_TOKEN_ISSUER_KEY *key,
uint8_t out_nonce[TRUST_TOKEN_NONCE_SIZE],
uint8_t *out_private_metadata, const uint8_t *token,
- size_t token_len) {
+ size_t token_len, int include_message,
+ const uint8_t *msg, size_t msg_len) {
if (!pmbtoken_exp2_init_method()) {
return 0;
}
return pmbtoken_read(&pmbtoken_exp2_method, key, out_nonce,
- out_private_metadata, token, token_len);
+ out_private_metadata, token, token_len, include_message,
+ msg, msg_len);
}
int pmbtoken_exp2_get_h_for_testing(uint8_t out[97]) {
diff --git a/crypto/trust_token/trust_token.c b/crypto/trust_token/trust_token.c
index 55785d5..2a0bacb 100644
--- a/crypto/trust_token/trust_token.c
+++ b/crypto/trust_token/trust_token.c
@@ -226,8 +226,9 @@
return 1;
}
-int TRUST_TOKEN_CLIENT_begin_issuance(TRUST_TOKEN_CLIENT *ctx, uint8_t **out,
- size_t *out_len, size_t count) {
+static int trust_token_client_begin_issuance_impl(
+ TRUST_TOKEN_CLIENT *ctx, uint8_t **out, size_t *out_len, size_t count,
+ int include_message, const uint8_t *msg, size_t msg_len) {
if (count > ctx->max_batchsize) {
count = ctx->max_batchsize;
}
@@ -241,7 +242,8 @@
goto err;
}
- pretokens = ctx->method->blind(&request, count);
+ pretokens =
+ ctx->method->blind(&request, count, include_message, msg, msg_len);
if (pretokens == NULL) {
goto err;
}
@@ -262,6 +264,20 @@
return ret;
}
+int TRUST_TOKEN_CLIENT_begin_issuance(TRUST_TOKEN_CLIENT *ctx, uint8_t **out,
+ size_t *out_len, size_t count) {
+ return trust_token_client_begin_issuance_impl(ctx, out, out_len, count,
+ /*include_message=*/0, NULL, 0);
+}
+
+int TRUST_TOKEN_CLIENT_begin_issuance_over_message(
+ TRUST_TOKEN_CLIENT *ctx, uint8_t **out, size_t *out_len, size_t count,
+ const uint8_t *msg, size_t msg_len) {
+ return trust_token_client_begin_issuance_impl(
+ ctx, out, out_len, count, /*include_message=*/1, msg, msg_len);
+}
+
+
STACK_OF(TRUST_TOKEN) *
TRUST_TOKEN_CLIENT_finish_issuance(TRUST_TOKEN_CLIENT *ctx,
size_t *out_key_index,
@@ -542,13 +558,11 @@
return ret;
}
-
-int TRUST_TOKEN_ISSUER_redeem_raw(const TRUST_TOKEN_ISSUER *ctx,
- uint32_t *out_public, uint8_t *out_private,
- TRUST_TOKEN **out_token,
- uint8_t **out_client_data,
- size_t *out_client_data_len,
- const uint8_t *request, size_t request_len) {
+static int trust_token_issuer_redeem_impl(
+ const TRUST_TOKEN_ISSUER *ctx, uint32_t *out_public, uint8_t *out_private,
+ TRUST_TOKEN **out_token, uint8_t **out_client_data,
+ size_t *out_client_data_len, const uint8_t *request, size_t request_len,
+ int include_message, const uint8_t *msg, size_t msg_len) {
CBS request_cbs, token_cbs;
CBS_init(&request_cbs, request, request_len);
if (!CBS_get_u16_length_prefixed(&request_cbs, &token_cbs)) {
@@ -570,7 +584,8 @@
uint8_t nonce[TRUST_TOKEN_NONCE_SIZE];
if (key == NULL ||
!ctx->method->read(&key->key, nonce, &private_metadata,
- CBS_data(&token_cbs), CBS_len(&token_cbs))) {
+ CBS_data(&token_cbs), CBS_len(&token_cbs),
+ include_message, msg, msg_len)) {
OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_INVALID_TOKEN);
return 0;
}
@@ -608,6 +623,28 @@
return 0;
}
+
+int TRUST_TOKEN_ISSUER_redeem_raw(const TRUST_TOKEN_ISSUER *ctx,
+ uint32_t *out_public, uint8_t *out_private,
+ TRUST_TOKEN **out_token,
+ uint8_t **out_client_data,
+ size_t *out_client_data_len,
+ const uint8_t *request, size_t request_len) {
+ return trust_token_issuer_redeem_impl(ctx, out_public, out_private, out_token,
+ out_client_data, out_client_data_len,
+ request, request_len, 0, NULL, 0);
+}
+
+int TRUST_TOKEN_ISSUER_redeem_over_message(
+ const TRUST_TOKEN_ISSUER *ctx, uint32_t *out_public, uint8_t *out_private,
+ TRUST_TOKEN **out_token, uint8_t **out_client_data,
+ size_t *out_client_data_len, const uint8_t *request, size_t request_len,
+ const uint8_t *msg, size_t msg_len) {
+ return trust_token_issuer_redeem_impl(ctx, out_public, out_private, out_token,
+ out_client_data, out_client_data_len,
+ request, request_len, 1, msg, msg_len);
+}
+
// https://tools.ietf.org/html/rfc7049#section-2.1
static int add_cbor_int_with_type(CBB *cbb, uint8_t major_type,
uint64_t value) {
@@ -691,9 +728,9 @@
const struct trust_token_issuer_key_st *key =
trust_token_issuer_get_key(ctx, public_metadata);
uint8_t nonce[TRUST_TOKEN_NONCE_SIZE];
- if (key == NULL ||
- !ctx->method->read(&key->key, nonce, &private_metadata,
- CBS_data(&token_cbs), CBS_len(&token_cbs))) {
+ if (key == NULL || !ctx->method->read(&key->key, nonce, &private_metadata,
+ CBS_data(&token_cbs),
+ CBS_len(&token_cbs), 0, NULL, 0)) {
OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_INVALID_TOKEN);
return 0;
}
diff --git a/crypto/trust_token/trust_token_test.cc b/crypto/trust_token/trust_token_test.cc
index f8a40d6..8c1e790 100644
--- a/crypto/trust_token/trust_token_test.cc
+++ b/crypto/trust_token/trust_token_test.cc
@@ -45,6 +45,8 @@
namespace {
+const uint8_t kMessage[] = "MSG";
+
TEST(TrustTokenTest, KeyGenExp1) {
uint8_t priv_key[TRUST_TOKEN_MAX_PRIVATE_KEY_SIZE];
uint8_t pub_key[TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE];
@@ -300,8 +302,9 @@
class TrustTokenProtocolTestBase : public ::testing::Test {
public:
- explicit TrustTokenProtocolTestBase(const TRUST_TOKEN_METHOD *method_arg)
- : method_(method_arg) {}
+ explicit TrustTokenProtocolTestBase(const TRUST_TOKEN_METHOD *method_arg,
+ bool use_msg)
+ : method_(method_arg), use_msg_(use_msg) {}
// KeyID returns the key ID associated with key index |i|.
static uint32_t KeyID(size_t i) {
@@ -312,6 +315,8 @@
const TRUST_TOKEN_METHOD *method() { return method_; }
+ const bool use_message() { return use_msg_; }
+
protected:
void SetupContexts() {
client.reset(TRUST_TOKEN_CLIENT_new(method(), client_max_batchsize));
@@ -350,6 +355,7 @@
}
const TRUST_TOKEN_METHOD *method_;
+ bool use_msg_;
uint16_t client_max_batchsize = 10;
uint16_t issuer_max_batchsize = 10;
bssl::UniquePtr<TRUST_TOKEN_CLIENT> client;
@@ -359,13 +365,17 @@
class TrustTokenProtocolTest
: public TrustTokenProtocolTestBase,
- public testing::WithParamInterface<const TRUST_TOKEN_METHOD *> {
+ public testing::WithParamInterface<
+ std::tuple<const TRUST_TOKEN_METHOD *, bool>> {
public:
- TrustTokenProtocolTest() : TrustTokenProtocolTestBase(GetParam()) {}
+ TrustTokenProtocolTest()
+ : TrustTokenProtocolTestBase(std::get<0>(GetParam()),
+ std::get<1>(GetParam())) {}
};
INSTANTIATE_TEST_SUITE_P(TrustTokenAllProtocolTest, TrustTokenProtocolTest,
- testing::ValuesIn(AllMethods()));
+ testing::Combine(testing::ValuesIn(AllMethods()),
+ testing::Bool()));
TEST_P(TrustTokenProtocolTest, InvalidToken) {
ASSERT_NO_FATAL_FAILURE(SetupContexts());
@@ -375,8 +385,13 @@
size_t key_index;
size_t tokens_issued;
- ASSERT_TRUE(
- TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg, &msg_len, 1));
+ if (use_message()) {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance_over_message(
+ client.get(), &issue_msg, &msg_len, 1, kMessage, sizeof(kMessage)));
+ } else {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
+ &msg_len, 1));
+ }
bssl::UniquePtr<uint8_t> free_issue_msg(issue_msg);
ASSERT_TRUE(TRUST_TOKEN_ISSUER_issue(
issuer.get(), &issue_resp, &resp_len, &tokens_issued, issue_msg, msg_len,
@@ -396,13 +411,20 @@
ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_redemption(
client.get(), &redeem_msg, &msg_len, token, NULL, 0, 0));
bssl::UniquePtr<uint8_t> free_redeem_msg(redeem_msg);
+ uint32_t public_value;
+ uint8_t private_value;
TRUST_TOKEN *rtoken;
uint8_t *client_data;
size_t client_data_len;
- uint64_t redemption_time;
- ASSERT_FALSE(TRUST_TOKEN_ISSUER_redeem(
- issuer.get(), &redeem_resp, &resp_len, &rtoken, &client_data,
- &client_data_len, &redemption_time, redeem_msg, msg_len, 600));
+ if (use_message()) {
+ ASSERT_FALSE(TRUST_TOKEN_ISSUER_redeem_over_message(
+ issuer.get(), &public_value, &private_value, &rtoken, &client_data,
+ &client_data_len, redeem_msg, msg_len, kMessage, sizeof(kMessage)));
+ } else {
+ ASSERT_FALSE(TRUST_TOKEN_ISSUER_redeem_raw(
+ issuer.get(), &public_value, &private_value, &rtoken,
+ &client_data, &client_data_len, redeem_msg, msg_len));
+ }
bssl::UniquePtr<uint8_t> free_redeem_resp(redeem_resp);
}
}
@@ -412,8 +434,13 @@
uint8_t *issue_msg = NULL, *issue_resp = NULL;
size_t msg_len, resp_len;
- ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
- &msg_len, 10));
+ if (use_message()) {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance_over_message(
+ client.get(), &issue_msg, &msg_len, 10, kMessage, sizeof(kMessage)));
+ } else {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
+ &msg_len, 10));
+ }
bssl::UniquePtr<uint8_t> free_issue_msg(issue_msg);
msg_len = 10;
size_t tokens_issued;
@@ -429,8 +456,13 @@
uint8_t *issue_msg = NULL, *issue_resp = NULL;
size_t msg_len, resp_len;
- ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
- &msg_len, 10));
+ if (use_message()) {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance_over_message(
+ client.get(), &issue_msg, &msg_len, 10, kMessage, sizeof(kMessage)));
+ } else {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
+ &msg_len, 10));
+ }
bssl::UniquePtr<uint8_t> free_issue_msg(issue_msg);
size_t tokens_issued;
ASSERT_TRUE(TRUST_TOKEN_ISSUER_issue(
@@ -451,8 +483,13 @@
uint8_t *request = NULL, *response = NULL;
size_t request_len, response_len;
- ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &request,
- &request_len, 10));
+ if (use_message()) {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance_over_message(
+ client.get(), &request, &request_len, 10, kMessage, sizeof(kMessage)));
+ } else {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &request,
+ &request_len, 10));
+ }
bssl::UniquePtr<uint8_t> free_request(request);
size_t tokens_issued;
ASSERT_TRUE(TRUST_TOKEN_ISSUER_issue(issuer.get(), &response, &response_len,
@@ -475,8 +512,13 @@
uint8_t *issue_msg = NULL, *issue_resp = NULL;
size_t msg_len, resp_len;
- ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
- &msg_len, 10));
+ if (use_message()) {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance_over_message(
+ client.get(), &issue_msg, &msg_len, 10, kMessage, sizeof(kMessage)));
+ } else {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
+ &msg_len, 10));
+ }
bssl::UniquePtr<uint8_t> free_issue_msg(issue_msg);
size_t tokens_issued;
ASSERT_TRUE(TRUST_TOKEN_ISSUER_issue(
@@ -494,30 +536,48 @@
const uint8_t kClientData[] = "\x70TEST CLIENT DATA";
uint64_t kRedemptionTime = (method()->has_srr ? 13374242 : 0);
- uint8_t *redeem_msg = NULL, *redeem_resp = NULL;
+ uint8_t *redeem_msg = NULL;
ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_redemption(
client.get(), &redeem_msg, &msg_len, token, kClientData,
sizeof(kClientData) - 1, kRedemptionTime));
bssl::UniquePtr<uint8_t> free_redeem_msg(redeem_msg);
msg_len = 10;
+ uint32_t public_value;
+ uint8_t private_value;
TRUST_TOKEN *rtoken;
uint8_t *client_data;
size_t client_data_len;
- uint64_t redemption_time;
- ASSERT_FALSE(TRUST_TOKEN_ISSUER_redeem(
- issuer.get(), &redeem_resp, &resp_len, &rtoken, &client_data,
- &client_data_len, &redemption_time, redeem_msg, msg_len, 600));
+ if (use_message()) {
+ ASSERT_FALSE(TRUST_TOKEN_ISSUER_redeem_over_message(
+ issuer.get(), &public_value, &private_value, &rtoken, &client_data,
+ &client_data_len, redeem_msg, msg_len, kMessage, sizeof(kMessage)));
+ } else {
+ ASSERT_FALSE(TRUST_TOKEN_ISSUER_redeem_raw(
+ issuer.get(), &public_value, &private_value, &rtoken,
+ &client_data, &client_data_len, redeem_msg, msg_len));
+ }
}
}
TEST_P(TrustTokenProtocolTest, TruncatedRedemptionResponse) {
ASSERT_NO_FATAL_FAILURE(SetupContexts());
+ // Token issuances derived from messages aren't supported by the old-style
+ // redemption record response.
+ if (use_message()) {
+ return;
+ }
+
uint8_t *issue_msg = NULL, *issue_resp = NULL;
size_t msg_len, resp_len;
- ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
- &msg_len, 10));
+ if (use_message()) {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance_over_message(
+ client.get(), &issue_msg, &msg_len, 10, kMessage, sizeof(kMessage)));
+ } else {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
+ &msg_len, 10));
+ }
bssl::UniquePtr<uint8_t> free_issue_msg(issue_msg);
size_t tokens_issued;
ASSERT_TRUE(TRUST_TOKEN_ISSUER_issue(
@@ -614,8 +674,13 @@
uint8_t *issue_msg = NULL, *issue_resp = NULL;
size_t msg_len, resp_len;
- ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
- &msg_len, 10));
+ if (use_message()) {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance_over_message(
+ client.get(), &issue_msg, &msg_len, 10, kMessage, sizeof(kMessage)));
+ } else {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
+ &msg_len, 10));
+ }
bssl::UniquePtr<uint8_t> free_issue_msg(issue_msg);
size_t tokens_issued;
ASSERT_TRUE(TRUST_TOKEN_ISSUER_issue(
@@ -631,22 +696,34 @@
class TrustTokenMetadataTest
: public TrustTokenProtocolTestBase,
public testing::WithParamInterface<
- std::tuple<const TRUST_TOKEN_METHOD *, int, bool>> {
+ std::tuple<const TRUST_TOKEN_METHOD *, bool, int, bool>> {
public:
TrustTokenMetadataTest()
- : TrustTokenProtocolTestBase(std::get<0>(GetParam())) {}
+ : TrustTokenProtocolTestBase(std::get<0>(GetParam()),
+ std::get<1>(GetParam())) {}
- int public_metadata() { return std::get<1>(GetParam()); }
- bool private_metadata() { return std::get<2>(GetParam()); }
+ int public_metadata() { return std::get<2>(GetParam()); }
+ bool private_metadata() { return std::get<3>(GetParam()); }
};
TEST_P(TrustTokenMetadataTest, SetAndGetMetadata) {
ASSERT_NO_FATAL_FAILURE(SetupContexts());
+ // Token issuances derived from messages aren't supported by the old-style
+ // redemption record response.
+ if (use_message()) {
+ return;
+ }
+
uint8_t *issue_msg = NULL, *issue_resp = NULL;
size_t msg_len, resp_len;
- ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
- &msg_len, 10));
+ if (use_message()) {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance_over_message(
+ client.get(), &issue_msg, &msg_len, 10, kMessage, sizeof(kMessage)));
+ } else {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
+ &msg_len, 10));
+ }
bssl::UniquePtr<uint8_t> free_issue_msg(issue_msg);
size_t tokens_issued;
bool result = TRUST_TOKEN_ISSUER_issue(
@@ -777,8 +854,13 @@
uint8_t *issue_msg = NULL, *issue_resp = NULL;
size_t msg_len, resp_len;
- ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
- &msg_len, 10));
+ if (use_message()) {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance_over_message(
+ client.get(), &issue_msg, &msg_len, 10, kMessage, sizeof(kMessage)));
+ } else {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
+ &msg_len, 10));
+ }
bssl::UniquePtr<uint8_t> free_issue_msg(issue_msg);
size_t tokens_issued;
bool result = TRUST_TOKEN_ISSUER_issue(
@@ -811,9 +893,15 @@
TRUST_TOKEN *rtoken;
uint8_t *client_data;
size_t client_data_len;
- ASSERT_TRUE(TRUST_TOKEN_ISSUER_redeem_raw(
- issuer.get(), &public_value, &private_value, &rtoken,
- &client_data, &client_data_len, redeem_msg, msg_len));
+ if (use_message()) {
+ ASSERT_TRUE(TRUST_TOKEN_ISSUER_redeem_over_message(
+ issuer.get(), &public_value, &private_value, &rtoken, &client_data,
+ &client_data_len, redeem_msg, msg_len, kMessage, sizeof(kMessage)));
+ } else {
+ ASSERT_TRUE(TRUST_TOKEN_ISSUER_redeem_raw(
+ issuer.get(), &public_value, &private_value, &rtoken,
+ &client_data, &client_data_len, redeem_msg, msg_len));
+ }
bssl::UniquePtr<uint8_t> free_client_data(client_data);
bssl::UniquePtr<TRUST_TOKEN> free_rtoken(rtoken);
@@ -834,8 +922,13 @@
uint8_t *issue_msg = NULL, *issue_resp = NULL;
size_t msg_len, resp_len;
- ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
- &msg_len, 10));
+ if (use_message()) {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance_over_message(
+ client.get(), &issue_msg, &msg_len, 10, kMessage, sizeof(kMessage)));
+ } else {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
+ &msg_len, 10));
+ }
bssl::UniquePtr<uint8_t> free_issue_msg(issue_msg);
size_t tokens_issued;
ASSERT_TRUE(TRUST_TOKEN_ISSUER_issue(
@@ -861,8 +954,13 @@
uint8_t *issue_msg = NULL, *issue_resp = NULL;
size_t msg_len, resp_len;
- ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
- &msg_len, 10));
+ if (use_message()) {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance_over_message(
+ client.get(), &issue_msg, &msg_len, 10, kMessage, sizeof(kMessage)));
+ } else {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
+ &msg_len, 10));
+ }
bssl::UniquePtr<uint8_t> free_issue_msg(issue_msg);
size_t tokens_issued;
ASSERT_TRUE(TRUST_TOKEN_ISSUER_issue(
@@ -924,8 +1022,13 @@
uint8_t *issue_msg = NULL, *issue_resp = NULL;
size_t msg_len, resp_len;
- ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
- &msg_len, 10));
+ if (use_message()) {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance_over_message(
+ client.get(), &issue_msg, &msg_len, 10, kMessage, sizeof(kMessage)));
+ } else {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
+ &msg_len, 10));
+ }
bssl::UniquePtr<uint8_t> free_issue_msg(issue_msg);
size_t tokens_issued;
ASSERT_TRUE(TRUST_TOKEN_ISSUER_issue(
@@ -982,6 +1085,7 @@
INSTANTIATE_TEST_SUITE_P(
TrustTokenAllMetadataTest, TrustTokenMetadataTest,
testing::Combine(testing::ValuesIn(AllMethods()),
+ testing::Bool(),
testing::Values(TrustTokenProtocolTest::KeyID(0),
TrustTokenProtocolTest::KeyID(1),
TrustTokenProtocolTest::KeyID(2)),
@@ -990,13 +1094,14 @@
class TrustTokenBadKeyTest
: public TrustTokenProtocolTestBase,
public testing::WithParamInterface<
- std::tuple<const TRUST_TOKEN_METHOD *, bool, int>> {
+ std::tuple<const TRUST_TOKEN_METHOD *, bool, bool, int>> {
public:
TrustTokenBadKeyTest()
- : TrustTokenProtocolTestBase(std::get<0>(GetParam())) {}
+ : TrustTokenProtocolTestBase(std::get<0>(GetParam()),
+ std::get<1>(GetParam())) {}
- bool private_metadata() { return std::get<1>(GetParam()); }
- int corrupted_key() { return std::get<2>(GetParam()); }
+ bool private_metadata() { return std::get<2>(GetParam()); }
+ int corrupted_key() { return std::get<3>(GetParam()); }
};
TEST_P(TrustTokenBadKeyTest, BadKey) {
@@ -1012,8 +1117,13 @@
uint8_t *issue_msg = NULL, *issue_resp = NULL;
size_t msg_len, resp_len;
- ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
- &msg_len, 10));
+ if (use_message()) {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance_over_message(
+ client.get(), &issue_msg, &msg_len, 10, kMessage, sizeof(kMessage)));
+ } else {
+ ASSERT_TRUE(TRUST_TOKEN_CLIENT_begin_issuance(client.get(), &issue_msg,
+ &msg_len, 10));
+ }
bssl::UniquePtr<uint8_t> free_issue_msg(issue_msg);
struct trust_token_issuer_key_st *key = &issuer->keys[0];
@@ -1045,6 +1155,7 @@
INSTANTIATE_TEST_SUITE_P(TrustTokenAllBadKeyTest, TrustTokenBadKeyTest,
testing::Combine(testing::ValuesIn(AllMethods()),
testing::Bool(),
+ testing::Bool(),
testing::Values(0, 1, 2, 3, 4, 5)));
} // namespace
diff --git a/crypto/trust_token/voprf.c b/crypto/trust_token/voprf.c
index f8e1c4c..da29c85 100644
--- a/crypto/trust_token/voprf.c
+++ b/crypto/trust_token/voprf.c
@@ -21,6 +21,7 @@
#include <openssl/mem.h>
#include <openssl/nid.h>
#include <openssl/rand.h>
+#include <openssl/sha.h>
#include "../ec_extra/internal.h"
#include "../fipsmodule/ec/internal.h"
@@ -200,8 +201,13 @@
return 1;
}
-static STACK_OF(TRUST_TOKEN_PRETOKEN) *
- voprf_blind(const VOPRF_METHOD *method, CBB *cbb, size_t count) {
+static STACK_OF(TRUST_TOKEN_PRETOKEN) *voprf_blind(const VOPRF_METHOD *method,
+ CBB *cbb, size_t count,
+ int include_message,
+ const uint8_t *msg,
+ size_t msg_len) {
+ SHA512_CTX hash_ctx;
+
const EC_GROUP *group = method->group;
STACK_OF(TRUST_TOKEN_PRETOKEN) *pretokens =
sk_TRUST_TOKEN_PRETOKEN_new_null();
@@ -221,7 +227,16 @@
goto err;
}
- RAND_bytes(pretoken->t, sizeof(pretoken->t));
+ RAND_bytes(pretoken->salt, sizeof(pretoken->salt));
+ if (include_message) {
+ assert(SHA512_DIGEST_LENGTH == TRUST_TOKEN_NONCE_SIZE);
+ SHA512_Init(&hash_ctx);
+ SHA512_Update(&hash_ctx, pretoken->salt, sizeof(pretoken->salt));
+ SHA512_Update(&hash_ctx, msg, msg_len);
+ SHA512_Final(pretoken->t, &hash_ctx);
+ } else {
+ OPENSSL_memcpy(pretoken->t, pretoken->salt, TRUST_TOKEN_NONCE_SIZE);
+ }
// We sample r in Montgomery form to simplify inverting.
EC_SCALAR r;
@@ -547,10 +562,10 @@
return ret;
}
-static STACK_OF(TRUST_TOKEN) *
- voprf_unblind(const VOPRF_METHOD *method, const TRUST_TOKEN_CLIENT_KEY *key,
- const STACK_OF(TRUST_TOKEN_PRETOKEN) * pretokens, CBS *cbs,
- size_t count, uint32_t key_id) {
+static STACK_OF(TRUST_TOKEN) *voprf_unblind(
+ const VOPRF_METHOD *method, const TRUST_TOKEN_CLIENT_KEY *key,
+ const STACK_OF(TRUST_TOKEN_PRETOKEN) *pretokens, CBS *cbs, size_t count,
+ uint32_t key_id) {
const EC_GROUP *group = method->group;
if (count > sk_TRUST_TOKEN_PRETOKEN_num(pretokens)) {
OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_DECODE_FAILURE);
@@ -617,7 +632,7 @@
size_t point_len = 1 + 2 * BN_num_bytes(&group->field);
if (!CBB_init(&token_cbb, 4 + TRUST_TOKEN_NONCE_SIZE + (2 + point_len)) ||
!CBB_add_u32(&token_cbb, key_id) ||
- !CBB_add_bytes(&token_cbb, pretoken->t, TRUST_TOKEN_NONCE_SIZE) ||
+ !CBB_add_bytes(&token_cbb, pretoken->salt, TRUST_TOKEN_NONCE_SIZE) ||
!cbb_add_point(&token_cbb, group, &N_affine) ||
!CBB_flush(&token_cbb)) {
CBB_cleanup(&token_cbb);
@@ -676,18 +691,30 @@
static int voprf_read(const VOPRF_METHOD *method,
const TRUST_TOKEN_ISSUER_KEY *key,
uint8_t out_nonce[TRUST_TOKEN_NONCE_SIZE],
- const uint8_t *token, size_t token_len) {
+ const uint8_t *token, size_t token_len,
+ int include_message, const uint8_t *msg, size_t msg_len) {
const EC_GROUP *group = method->group;
- CBS cbs;
+ CBS cbs, salt;
CBS_init(&cbs, token, token_len);
EC_AFFINE Ws;
- if (!CBS_copy_bytes(&cbs, out_nonce, TRUST_TOKEN_NONCE_SIZE) ||
+ if (!CBS_get_bytes(&cbs, &salt, TRUST_TOKEN_NONCE_SIZE) ||
!cbs_get_point(&cbs, group, &Ws) ||
CBS_len(&cbs) != 0) {
OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_INVALID_TOKEN);
return 0;
}
+ if (include_message) {
+ SHA512_CTX hash_ctx;
+ assert(SHA512_DIGEST_LENGTH == TRUST_TOKEN_NONCE_SIZE);
+ SHA512_Init(&hash_ctx);
+ SHA512_Update(&hash_ctx, CBS_data(&salt), CBS_len(&salt));
+ SHA512_Update(&hash_ctx, msg, msg_len);
+ SHA512_Final(out_nonce, &hash_ctx);
+ } else {
+ OPENSSL_memcpy(out_nonce, CBS_data(&salt), CBS_len(&salt));
+ }
+
EC_RAW_POINT T;
if (!method->hash_to_group(group, &T, out_nonce)) {
@@ -775,11 +802,15 @@
return voprf_issuer_key_from_bytes(&voprf_exp2_method, key, in, len);
}
-STACK_OF(TRUST_TOKEN_PRETOKEN) * voprf_exp2_blind(CBB *cbb, size_t count) {
+STACK_OF(TRUST_TOKEN_PRETOKEN) *voprf_exp2_blind(CBB *cbb, size_t count,
+ int include_message,
+ const uint8_t *msg,
+ size_t msg_len) {
if (!voprf_exp2_init_method()) {
return NULL;
}
- return voprf_blind(&voprf_exp2_method, cbb, count);
+ return voprf_blind(&voprf_exp2_method, cbb, count, include_message, msg,
+ msg_len);
}
int voprf_exp2_sign(const TRUST_TOKEN_ISSUER_KEY *key, CBB *cbb, CBS *cbs,
@@ -792,23 +823,24 @@
num_to_issue);
}
-STACK_OF(TRUST_TOKEN) *
- voprf_exp2_unblind(const TRUST_TOKEN_CLIENT_KEY *key,
- const STACK_OF(TRUST_TOKEN_PRETOKEN) * pretokens,
- CBS *cbs, size_t count, uint32_t key_id) {
+STACK_OF(TRUST_TOKEN) *voprf_exp2_unblind(
+ const TRUST_TOKEN_CLIENT_KEY *key,
+ const STACK_OF(TRUST_TOKEN_PRETOKEN) *pretokens, CBS *cbs, size_t count,
+ uint32_t key_id) {
if (!voprf_exp2_init_method()) {
return NULL;
}
- return voprf_unblind(&voprf_exp2_method, key, pretokens, cbs, count,
- key_id);
+ return voprf_unblind(&voprf_exp2_method, key, pretokens, cbs, count, key_id);
}
int voprf_exp2_read(const TRUST_TOKEN_ISSUER_KEY *key,
uint8_t out_nonce[TRUST_TOKEN_NONCE_SIZE],
uint8_t *out_private_metadata, const uint8_t *token,
- size_t token_len) {
+ size_t token_len, int include_message, const uint8_t *msg,
+ size_t msg_len) {
if (!voprf_exp2_init_method()) {
return 0;
}
- return voprf_read(&voprf_exp2_method, key, out_nonce, token, token_len);
+ return voprf_read(&voprf_exp2_method, key, out_nonce, token, token_len,
+ include_message, msg, msg_len);
}
diff --git a/include/openssl/trust_token.h b/include/openssl/trust_token.h
index 745a860..aef4e50 100644
--- a/include/openssl/trust_token.h
+++ b/include/openssl/trust_token.h
@@ -143,6 +143,15 @@
size_t *out_len,
size_t count);
+// TRUST_TOKEN_CLIENT_begin_issuance_over_message produces a request for a trust
+// token derived from |msg| and serializes the request into a newly-allocated
+// buffer, setting |*out| to that buffer and |*out_len| to its length. The
+// caller takes ownership of the buffer and must call |OPENSSL_free| when done.
+// It returns one on success and zero on error.
+OPENSSL_EXPORT int TRUST_TOKEN_CLIENT_begin_issuance_over_message(
+ TRUST_TOKEN_CLIENT *ctx, uint8_t **out, size_t *out_len, size_t count,
+ const uint8_t *msg, size_t msg_len);
+
// TRUST_TOKEN_CLIENT_finish_issuance consumes |response| from the issuer and
// extracts the tokens, returning a list of tokens and the index of the key used
// to sign the tokens in |*out_key_index|. The caller can use this to determine
@@ -278,6 +287,26 @@
TRUST_TOKEN **out_token, uint8_t **out_client_data,
size_t *out_client_data_len, const uint8_t *request, size_t request_len);
+// TRUST_TOKEN_ISSUER_redeem_over_message ingests a |request| for token
+// redemption and a message and verifies the token and that it is derived from
+// the provided |msg|. The public metadata is stored in
+// |*out_public|. The private metadata (if any) is stored in |*out_private|. The
+// extracted |TRUST_TOKEN| is stored into a newly-allocated buffer and stored in
+// |*out_token|. The extracted client data is stored into a newly-allocated
+// buffer and stored in |*out_client_data|. The caller takes ownership of each
+// output buffer and must call |OPENSSL_free| when done. It returns one on
+// success or zero on error.
+//
+// The caller must keep track of all values of |*out_token| seen globally before
+// returning a response to the client. If the value has been reused, the caller
+// must report an error to the client. Returning a response with replayed values
+// allows an attacker to double-spend tokens.
+OPENSSL_EXPORT int TRUST_TOKEN_ISSUER_redeem_over_message(
+ const TRUST_TOKEN_ISSUER *ctx, uint32_t *out_public, uint8_t *out_private,
+ TRUST_TOKEN **out_token, uint8_t **out_client_data,
+ size_t *out_client_data_len, const uint8_t *request, size_t request_len,
+ const uint8_t *msg, size_t msg_len);
+
// TRUST_TOKEN_decode_private_metadata decodes |encrypted_bit| using the
// private metadata key specified by a |key| buffer of length |key_len| and the
// nonce by a |nonce| buffer of length |nonce_len|. The nonce in