Skip to content

Commit

Permalink
Implement PSK variants of HPKE setup functions.
Browse files Browse the repository at this point in the history
Change-Id: Ic190ac1efbb079e42bb22b39083ccb96e0a61e57
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/42664
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
  • Loading branch information
dmcardle authored and CQ bot account: commit-bot@chromium.org committed Sep 2, 2020
1 parent bef6a2f commit bc24805
Show file tree
Hide file tree
Showing 8 changed files with 725 additions and 38 deletions.
1 change: 1 addition & 0 deletions crypto/err/evp.errordata
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ EVP,101,COMMAND_NOT_SUPPORTED
EVP,102,DECODE_ERROR
EVP,103,DIFFERENT_KEY_TYPES
EVP,104,DIFFERENT_PARAMETERS
EVP,136,EMPTY_PSK
EVP,105,ENCODE_ERROR
EVP,106,EXPECTING_AN_EC_KEY_KEY
EVP,107,EXPECTING_AN_RSA_KEY
Expand Down
4 changes: 4 additions & 0 deletions crypto/evp/evp.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@
// TODO(davidben): Fix Node to not touch the error queue itself and remove this.
OPENSSL_DECLARE_ERROR_REASON(EVP, NOT_XOF_OR_INVALID_LENGTH)

// The HPKE module uses the EVP error namespace, but it lives in another
// directory.
OPENSSL_DECLARE_ERROR_REASON(EVP, EMPTY_PSK)

EVP_PKEY *EVP_PKEY_new(void) {
EVP_PKEY *ret;

Expand Down
109 changes: 98 additions & 11 deletions crypto/hpke/hpke.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#define HPKE_SUITE_ID_LEN 10

#define HPKE_MODE_BASE 0
#define HPKE_MODE_PSK 1

static const char kHpkeRfcId[] = "HPKE-05 ";

Expand Down Expand Up @@ -115,7 +116,7 @@ static int hpke_extract_and_expand(const EVP_MD *hkdf_md, uint8_t *out_key,
X25519_PUBLIC_VALUE_LEN)) {
return 0;
}
const char kPRKExpandLabel[] = "shared_secret";
static const char kPRKExpandLabel[] = "shared_secret";
if (!hpke_labeled_expand(hkdf_md, out_key, out_len, prk, prk_len,
kX25519SuiteID, sizeof(kX25519SuiteID),
kPRKExpandLabel, kem_context, KEM_CONTEXT_LEN)) {
Expand Down Expand Up @@ -150,9 +151,28 @@ static const EVP_MD *hpke_get_kdf(uint16_t kdf_id) {
return NULL;
}

static int hpke_key_schedule(EVP_HPKE_CTX *hpke, const uint8_t *shared_secret,
static int hpke_key_schedule(EVP_HPKE_CTX *hpke, uint8_t mode,
const uint8_t *shared_secret,
size_t shared_secret_len, const uint8_t *info,
size_t info_len) {
size_t info_len, const uint8_t *psk,
size_t psk_len, const uint8_t *psk_id,
size_t psk_id_len) {
// Verify the PSK inputs.
switch (mode) {
case HPKE_MODE_BASE:
// This is an internal error, unreachable from the caller.
assert(psk_len == 0 && psk_id_len == 0);
break;
case HPKE_MODE_PSK:
if (psk_len == 0 || psk_id_len == 0) {
OPENSSL_PUT_ERROR(EVP, EVP_R_EMPTY_PSK);
return 0;
}
break;
default:
return 0;
}

// Attempt to get an EVP_AEAD*.
const EVP_AEAD *aead = hpke_get_aead(hpke->aead_id);
if (aead == NULL) {
Expand All @@ -170,7 +190,7 @@ static int hpke_key_schedule(EVP_HPKE_CTX *hpke, const uint8_t *shared_secret,
size_t psk_id_hash_len;
if (!hpke_labeled_extract(hpke->hkdf_md, psk_id_hash, &psk_id_hash_len, NULL,
0, suite_id, sizeof(suite_id), kPskIdHashLabel,
NULL, 0)) {
psk_id, psk_id_len)) {
return 0;
}

Expand All @@ -189,7 +209,7 @@ static int hpke_key_schedule(EVP_HPKE_CTX *hpke, const uint8_t *shared_secret,
size_t context_len;
CBB context_cbb;
if (!CBB_init_fixed(&context_cbb, context, sizeof(context)) ||
!CBB_add_u8(&context_cbb, HPKE_MODE_BASE) ||
!CBB_add_u8(&context_cbb, mode) ||
!CBB_add_bytes(&context_cbb, psk_id_hash, psk_id_hash_len) ||
!CBB_add_bytes(&context_cbb, info_hash, info_hash_len) ||
!CBB_finish(&context_cbb, NULL, &context_len)) {
Expand All @@ -201,8 +221,8 @@ static int hpke_key_schedule(EVP_HPKE_CTX *hpke, const uint8_t *shared_secret,
uint8_t psk_hash[EVP_MAX_MD_SIZE];
size_t psk_hash_len;
if (!hpke_labeled_extract(hpke->hkdf_md, psk_hash, &psk_hash_len, NULL, 0,
suite_id, sizeof(suite_id), kPskHashLabel, NULL,
0)) {
suite_id, sizeof(suite_id), kPskHashLabel, psk,
psk_len)) {
return 0;
}

Expand Down Expand Up @@ -338,8 +358,9 @@ int EVP_HPKE_CTX_setup_base_s_x25519_for_test(
uint8_t shared_secret[SHA256_DIGEST_LENGTH];
if (!hpke_encap(hpke, shared_secret, peer_public_value, ephemeral_private,
ephemeral_public) ||
!hpke_key_schedule(hpke, shared_secret, sizeof(shared_secret), info,
info_len)) {
!hpke_key_schedule(hpke, HPKE_MODE_BASE, shared_secret,
sizeof(shared_secret), info, info_len, NULL, 0, NULL,
0)) {
return 0;
}
return 1;
Expand All @@ -360,8 +381,74 @@ int EVP_HPKE_CTX_setup_base_r_x25519(
}
uint8_t shared_secret[SHA256_DIGEST_LENGTH];
if (!hpke_decap(hpke, shared_secret, enc, public_key, private_key) ||
!hpke_key_schedule(hpke, shared_secret, sizeof(shared_secret), info,
info_len)) {
!hpke_key_schedule(hpke, HPKE_MODE_BASE, shared_secret,
sizeof(shared_secret), info, info_len, NULL, 0, NULL,
0)) {
return 0;
}
return 1;
}

int EVP_HPKE_CTX_setup_psk_s_x25519(
EVP_HPKE_CTX *hpke, uint8_t out_enc[X25519_PUBLIC_VALUE_LEN],
uint16_t kdf_id, uint16_t aead_id,
const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
const uint8_t *info, size_t info_len, const uint8_t *psk, size_t psk_len,
const uint8_t *psk_id, size_t psk_id_len) {
// The GenerateKeyPair() step technically belongs in the KEM's Encap()
// function, but we've moved it up a layer to make it easier for tests to
// inject an ephemeral keypair.
uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN];
X25519_keypair(out_enc, ephemeral_private);
return EVP_HPKE_CTX_setup_psk_s_x25519_for_test(
hpke, kdf_id, aead_id, peer_public_value, info, info_len, psk, psk_len,
psk_id, psk_id_len, ephemeral_private, out_enc);
}

int EVP_HPKE_CTX_setup_psk_s_x25519_for_test(
EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
const uint8_t peer_public_value[X25519_PUBLIC_VALUE_LEN],
const uint8_t *info, size_t info_len, const uint8_t *psk, size_t psk_len,
const uint8_t *psk_id, size_t psk_id_len,
const uint8_t ephemeral_private[X25519_PRIVATE_KEY_LEN],
const uint8_t ephemeral_public[X25519_PUBLIC_VALUE_LEN]) {
hpke->is_sender = 1;
hpke->kdf_id = kdf_id;
hpke->aead_id = aead_id;
hpke->hkdf_md = hpke_get_kdf(kdf_id);
if (hpke->hkdf_md == NULL) {
return 0;
}
uint8_t shared_secret[SHA256_DIGEST_LENGTH];
if (!hpke_encap(hpke, shared_secret, peer_public_value, ephemeral_private,
ephemeral_public) ||
!hpke_key_schedule(hpke, HPKE_MODE_PSK, shared_secret,
sizeof(shared_secret), info, info_len, psk, psk_len,
psk_id, psk_id_len)) {
return 0;
}
return 1;
}

int EVP_HPKE_CTX_setup_psk_r_x25519(
EVP_HPKE_CTX *hpke, uint16_t kdf_id, uint16_t aead_id,
const uint8_t enc[X25519_PUBLIC_VALUE_LEN],
const uint8_t public_key[X25519_PUBLIC_VALUE_LEN],
const uint8_t private_key[X25519_PRIVATE_KEY_LEN], const uint8_t *info,
size_t info_len, const uint8_t *psk, size_t psk_len, const uint8_t *psk_id,
size_t psk_id_len) {
hpke->is_sender = 0;
hpke->kdf_id = kdf_id;
hpke->aead_id = aead_id;
hpke->hkdf_md = hpke_get_kdf(kdf_id);
if (hpke->hkdf_md == NULL) {
return 0;
}
uint8_t shared_secret[SHA256_DIGEST_LENGTH];
if (!hpke_decap(hpke, shared_secret, enc, public_key, private_key) ||
!hpke_key_schedule(hpke, HPKE_MODE_PSK, shared_secret,
sizeof(shared_secret), info, info_len, psk, psk_len,
psk_id, psk_id_len)) {
return 0;
}
return 1;
Expand Down
Loading

0 comments on commit bc24805

Please sign in to comment.