"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "nss/lib/pk11wrap/pk11hpke.c" between
nss-3.61.tar.gz and nss-3.62.tar.gz

About: NSS is a set of libraries, APIs, utilities, and documentation designed to support cross-platform development of security-enabled client and server applications. It provides a complete implementation of the crypto libraries used by Mozilla and other companies.

pk11hpke.c  (nss-3.61):pk11hpke.c  (nss-3.62)
/* /*
* draft-irtf-cfrg-hpke-05 * draft-irtf-cfrg-hpke-07
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
#include "keyhi.h" #include "keyhi.h"
#include "pkcs11t.h" #include "pkcs11t.h"
#include "pk11func.h" #include "pk11func.h"
#include "pk11hpke.h" #include "pk11hpke.h"
skipping to change at line 56 skipping to change at line 56
{ {
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
} }
const SECItem * const SECItem *
PK11_HPKE_GetEncapPubKey(const HpkeContext *cx) PK11_HPKE_GetEncapPubKey(const HpkeContext *cx)
{ {
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return NULL; return NULL;
} }
SECStatus SECStatus
PK11_HPKE_ExportContext(const HpkeContext *cx, PK11SymKey *wrapKey, SECItem **se
rialized)
{
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return SECFailure;
}
SECStatus
PK11_HPKE_ExportSecret(const HpkeContext *cx, const SECItem *info, PK11_HPKE_ExportSecret(const HpkeContext *cx, const SECItem *info,
unsigned int L, PK11SymKey **outKey) unsigned int L, PK11SymKey **outKey)
{ {
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return SECFailure; return SECFailure;
} }
HpkeContext *
PK11_HPKE_ImportContext(const SECItem *serialized, PK11SymKey *wrapKey)
{
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return NULL;
}
SECStatus SECStatus
PK11_HPKE_Open(HpkeContext *cx, const SECItem *aad, const SECItem *ct, PK11_HPKE_Open(HpkeContext *cx, const SECItem *aad, const SECItem *ct,
SECItem **outPt) SECItem **outPt)
{ {
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return SECFailure; return SECFailure;
} }
SECStatus SECStatus
PK11_HPKE_Seal(HpkeContext *cx, const SECItem *aad, const SECItem *pt, SECItem * *outCt) PK11_HPKE_Seal(HpkeContext *cx, const SECItem *aad, const SECItem *pt, SECItem * *outCt)
{ {
skipping to change at line 97 skipping to change at line 109
} }
SECStatus SECStatus
PK11_HPKE_SetupR(HpkeContext *cx, const SECKEYPublicKey *pkR, SECKEYPrivateKey * skR, PK11_HPKE_SetupR(HpkeContext *cx, const SECKEYPublicKey *pkR, SECKEYPrivateKey * skR,
const SECItem *enc, const SECItem *info) const SECItem *enc, const SECItem *info)
{ {
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
return SECFailure; return SECFailure;
} }
#else #else
static const char *DRAFT_LABEL = "HPKE-05 "; #define SERIALIZATION_VERSION 1
static const char *DRAFT_LABEL = "HPKE-07";
static const char *EXP_LABEL = "exp"; static const char *EXP_LABEL = "exp";
static const char *HPKE_LABEL = "HPKE"; static const char *HPKE_LABEL = "HPKE";
static const char *INFO_LABEL = "info_hash"; static const char *INFO_LABEL = "info_hash";
static const char *KEM_LABEL = "KEM"; static const char *KEM_LABEL = "KEM";
static const char *KEY_LABEL = "key"; static const char *KEY_LABEL = "key";
static const char *NONCE_LABEL = "nonce"; static const char *NONCE_LABEL = "base_nonce";
static const char *PSK_ID_LABEL = "psk_id_hash"; static const char *PSK_ID_LABEL = "psk_id_hash";
static const char *PSK_LABEL = "psk_hash";
static const char *SECRET_LABEL = "secret"; static const char *SECRET_LABEL = "secret";
static const char *SEC_LABEL = "sec"; static const char *SEC_LABEL = "sec";
static const char *EAE_PRK_LABEL = "eae_prk"; static const char *EAE_PRK_LABEL = "eae_prk";
static const char *SH_SEC_LABEL = "shared_secret"; static const char *SH_SEC_LABEL = "shared_secret";
struct HpkeContextStr { struct HpkeContextStr {
const hpkeKemParams *kemParams; const hpkeKemParams *kemParams;
const hpkeKdfParams *kdfParams; const hpkeKdfParams *kdfParams;
const hpkeAeadParams *aeadParams; const hpkeAeadParams *aeadParams;
PRUint8 mode; /* Base and PSK modes supported. */ PRUint8 mode; /* Base and PSK modes supported. */
SECItem *encapPubKey; /* Marshalled public key, sent to receiver. */ SECItem *encapPubKey; /* Marshalled public key, sent to receiver. */
SECItem *nonce; /* Deterministic nonce for AEAD. */ SECItem *baseNonce; /* Deterministic nonce for AEAD. */
SECItem *pskId; /* PSK identifier (non-secret). */ SECItem *pskId; /* PSK identifier (non-secret). */
PK11Context *aeadContext; /* AEAD context used by Seal/Open. */ PK11Context *aeadContext; /* AEAD context used by Seal/Open. */
PRUint64 sequenceNumber; /* seqNo for decrypt IV construction. */ PRUint64 sequenceNumber; /* seqNo for decrypt IV construction. */
PK11SymKey *sharedSecret; /* ExtractAndExpand output key. */ PK11SymKey *sharedSecret; /* ExtractAndExpand output key. */
PK11SymKey *key; /* Key used with the AEAD. */ PK11SymKey *key; /* Key used with the AEAD. */
PK11SymKey *exporterSecret; /* Derivation key for ExportSecret. */ PK11SymKey *exporterSecret; /* Derivation key for ExportSecret. */
PK11SymKey *psk; /* PSK imported by the application. */ PK11SymKey *psk; /* PSK imported by the application. */
}; };
static const hpkeKemParams kemParams[] = { static const hpkeKemParams kemParams[] = {
/* KEM, Nsk, Nsecret, Npk, oidTag, Hash mechanism */ /* KEM, Nsk, Nsecret, Npk, oidTag, Hash mechanism */
{ HpkeDhKemX25519Sha256, 32, 32, 32, SEC_OID_CURVE25519, CKM_SHA256 }, { HpkeDhKemX25519Sha256, 32, 32, 32, SEC_OID_CURVE25519, CKM_SHA256 },
}; };
#define MAX_WRAPPED_EXP_LEN 72 // Largest kdfParams->Nh + 8
static const hpkeKdfParams kdfParams[] = { static const hpkeKdfParams kdfParams[] = {
/* KDF, Nh, mechanism */ /* KDF, Nh, mechanism */
{ HpkeKdfHkdfSha256, SHA256_LENGTH, CKM_SHA256 }, { HpkeKdfHkdfSha256, SHA256_LENGTH, CKM_SHA256 },
{ HpkeKdfHkdfSha384, SHA384_LENGTH, CKM_SHA384 },
{ HpkeKdfHkdfSha512, SHA512_LENGTH, CKM_SHA512 },
}; };
#define MAX_WRAPPED_KEY_LEN 40 // Largest aeadParams->Nk + 8
static const hpkeAeadParams aeadParams[] = { static const hpkeAeadParams aeadParams[] = {
/* AEAD, Nk, Nn, tagLen, mechanism */ /* AEAD, Nk, Nn, tagLen, mechanism */
{ HpkeAeadAes128Gcm, 16, 12, 16, CKM_AES_GCM }, { HpkeAeadAes128Gcm, 16, 12, 16, CKM_AES_GCM },
{ HpkeAeadChaCha20Poly1305, 32, 12, 16, CKM_CHACHA20_POLY1305 }, { HpkeAeadChaCha20Poly1305, 32, 12, 16, CKM_CHACHA20_POLY1305 },
}; };
static inline const hpkeKemParams * static inline const hpkeKemParams *
kemId2Params(HpkeKemId kemId) kemId2Params(HpkeKemId kemId)
{ {
switch (kemId) { switch (kemId) {
skipping to change at line 159 skipping to change at line 176
return NULL; return NULL;
} }
} }
static inline const hpkeKdfParams * static inline const hpkeKdfParams *
kdfId2Params(HpkeKdfId kdfId) kdfId2Params(HpkeKdfId kdfId)
{ {
switch (kdfId) { switch (kdfId) {
case HpkeKdfHkdfSha256: case HpkeKdfHkdfSha256:
return &kdfParams[0]; return &kdfParams[0];
case HpkeKdfHkdfSha384:
return &kdfParams[1];
case HpkeKdfHkdfSha512:
return &kdfParams[2];
default: default:
return NULL; return NULL;
} }
} }
static const inline hpkeAeadParams * static const inline hpkeAeadParams *
aeadId2Params(HpkeAeadId aeadId) aeadId2Params(HpkeAeadId aeadId)
{ {
switch (aeadId) { switch (aeadId) {
case HpkeAeadAes128Gcm: case HpkeAeadAes128Gcm:
return &aeadParams[0]; return &aeadParams[0];
case HpkeAeadChaCha20Poly1305: case HpkeAeadChaCha20Poly1305:
return &aeadParams[1]; return &aeadParams[1];
default: default:
return NULL; return NULL;
} }
} }
static SECStatus static PRUint8 *
encodeShort(PRUint32 val, PRUint8 *b) encodeNumber(PRUint64 value, PRUint8 *b, size_t count)
{ {
if (val > 0xFFFF || !b) { PRUint64 encoded;
PORT_SetError(SEC_ERROR_INVALID_ARGS); PORT_Assert(b && count > 0 && count <= sizeof(encoded));
return SECFailure;
encoded = PR_htonll(value);
PORT_Memcpy(b, ((unsigned char *)(&encoded)) + (sizeof(encoded) - count),
count);
return b + count;
}
static PRUint8 *
decodeNumber(PRUint64 *value, PRUint8 *b, size_t count)
{
unsigned int i;
PRUint64 number = 0;
PORT_Assert(b && value && count <= sizeof(*value));
for (i = 0; i < count; i++) {
number = (number << 8) + b[i];
} }
b[0] = (val >> 8) & 0xff; *value = number;
b[1] = val & 0xff; return b + count;
return SECSuccess;
} }
SECStatus SECStatus
PK11_HPKE_ValidateParameters(HpkeKemId kemId, HpkeKdfId kdfId, HpkeAeadId aeadId ) PK11_HPKE_ValidateParameters(HpkeKemId kemId, HpkeKdfId kdfId, HpkeAeadId aeadId )
{ {
/* If more variants are added, ensure the combination is also /* If more variants are added, ensure the combination is also
* legal. For now it is, since only the AEAD may vary. */ * legal. For now it is, since only the AEAD may vary. */
const hpkeKemParams *kem = kemId2Params(kemId); const hpkeKemParams *kem = kemId2Params(kemId);
const hpkeKdfParams *kdf = kdfId2Params(kdfId); const hpkeKdfParams *kdf = kdfId2Params(kdfId);
const hpkeAeadParams *aead = aeadId2Params(aeadId); const hpkeAeadParams *aead = aeadId2Params(aeadId);
skipping to change at line 271 skipping to change at line 306
if (cx->aeadContext) { if (cx->aeadContext) {
PK11_DestroyContext((PK11Context *)cx->aeadContext, PR_TRUE); PK11_DestroyContext((PK11Context *)cx->aeadContext, PR_TRUE);
cx->aeadContext = NULL; cx->aeadContext = NULL;
} }
PK11_FreeSymKey(cx->exporterSecret); PK11_FreeSymKey(cx->exporterSecret);
PK11_FreeSymKey(cx->sharedSecret); PK11_FreeSymKey(cx->sharedSecret);
PK11_FreeSymKey(cx->key); PK11_FreeSymKey(cx->key);
PK11_FreeSymKey(cx->psk); PK11_FreeSymKey(cx->psk);
SECITEM_FreeItem(cx->pskId, PR_TRUE); SECITEM_FreeItem(cx->pskId, PR_TRUE);
SECITEM_FreeItem(cx->nonce, PR_TRUE); SECITEM_FreeItem(cx->baseNonce, PR_TRUE);
SECITEM_FreeItem(cx->encapPubKey, PR_TRUE); SECITEM_FreeItem(cx->encapPubKey, PR_TRUE);
cx->exporterSecret = NULL; cx->exporterSecret = NULL;
cx->sharedSecret = NULL; cx->sharedSecret = NULL;
cx->key = NULL; cx->key = NULL;
cx->psk = NULL; cx->psk = NULL;
cx->pskId = NULL; cx->pskId = NULL;
cx->nonce = NULL; cx->baseNonce = NULL;
cx->encapPubKey = NULL; cx->encapPubKey = NULL;
if (freeit) { if (freeit) {
PORT_ZFree(cx, sizeof(HpkeContext)); PORT_ZFree(cx, sizeof(HpkeContext));
} }
} }
/* Export Format:
struct {
uint8 serilizationVersion;
uint8 hpkeVersion;
uint16 kemId;
uint16 kdfId;
uint16 aeadId;
uint16 modeId;
uint64 sequenceNumber;
opaque senderPubKey<1..2^16-1>;
opaque baseNonce<1..2^16-1>;
opaque key<1..2^16-1>;
opaque exporterSecret<1..2^16-1>;
} HpkeSerializedContext
*/
#define EXPORTED_CTX_BASE_LEN 26 /* Fixed size plus 2B for each variable. */
#define REMAINING_BYTES(walker, buf) \
buf->len - (walker - buf->data)
SECStatus
PK11_HPKE_ExportContext(const HpkeContext *cx, PK11SymKey *wrapKey, SECItem **se
rialized)
{
SECStatus rv;
size_t allocLen;
PRUint8 *walker;
SECItem *keyBytes = NULL; // Maybe wrapped
SECItem *exporterBytes = NULL; // Maybe wrapped
SECItem *serializedCx = NULL;
PRUint8 wrappedKeyBytes[MAX_WRAPPED_KEY_LEN] = { 0 };
PRUint8 wrappedExpBytes[MAX_WRAPPED_EXP_LEN] = { 0 };
SECItem wrappedKey = { siBuffer, wrappedKeyBytes, sizeof(wrappedKeyBytes) };
SECItem wrappedExp = { siBuffer, wrappedExpBytes, sizeof(wrappedExpBytes) };
CHECK_FAIL_ERR((!cx || !cx->aeadContext || !serialized), SEC_ERROR_INVALID_A
RGS);
CHECK_FAIL_ERR((cx->aeadContext->operation != (CKA_NSS_MESSAGE | CKA_DECRYPT
)),
SEC_ERROR_NOT_A_RECIPIENT);
/* If a wrapping key was provided, do the wrap first
* so that we know what size to allocate. */
if (wrapKey) {
rv = PK11_WrapSymKey(CKM_AES_KEY_WRAP_KWP, NULL, wrapKey,
cx->key, &wrappedKey);
CHECK_RV(rv);
rv = PK11_WrapSymKey(CKM_AES_KEY_WRAP_KWP, NULL, wrapKey,
cx->exporterSecret, &wrappedExp);
CHECK_RV(rv);
keyBytes = &wrappedKey;
exporterBytes = &wrappedExp;
} else {
rv = PK11_ExtractKeyValue(cx->key);
CHECK_RV(rv);
keyBytes = PK11_GetKeyData(cx->key);
CHECK_FAIL(!keyBytes);
PORT_Assert(keyBytes->len == cx->aeadParams->Nk);
rv = PK11_ExtractKeyValue(cx->exporterSecret);
CHECK_RV(rv);
exporterBytes = PK11_GetKeyData(cx->exporterSecret);
CHECK_FAIL(!exporterBytes);
PORT_Assert(exporterBytes->len == cx->kdfParams->Nh);
}
allocLen = EXPORTED_CTX_BASE_LEN + cx->baseNonce->len + cx->encapPubKey->len
;
allocLen += wrapKey ? wrappedKey.len : cx->aeadParams->Nk;
allocLen += wrapKey ? wrappedExp.len : cx->kdfParams->Nh;
serializedCx = SECITEM_AllocItem(NULL, NULL, allocLen);
CHECK_FAIL(!serializedCx);
walker = &serializedCx->data[0];
*(walker)++ = (PRUint8)SERIALIZATION_VERSION;
*(walker)++ = (PRUint8)HPKE_DRAFT_VERSION;
walker = encodeNumber(cx->kemParams->id, walker, 2);
walker = encodeNumber(cx->kdfParams->id, walker, 2);
walker = encodeNumber(cx->aeadParams->id, walker, 2);
walker = encodeNumber(cx->mode, walker, 2);
walker = encodeNumber(cx->sequenceNumber, walker, 8);
/* sender public key, serialized. */
walker = encodeNumber(cx->encapPubKey->len, walker, 2);
PORT_Memcpy(walker, cx->encapPubKey->data, cx->encapPubKey->len);
walker += cx->encapPubKey->len;
/* base nonce */
walker = encodeNumber(cx->baseNonce->len, walker, 2);
PORT_Memcpy(walker, cx->baseNonce->data, cx->baseNonce->len);
walker += cx->baseNonce->len;
/* key. */
walker = encodeNumber(keyBytes->len, walker, 2);
PORT_Memcpy(walker, keyBytes->data, keyBytes->len);
walker += keyBytes->len;
/* exporter_secret. */
walker = encodeNumber(exporterBytes->len, walker, 2);
PORT_Memcpy(walker, exporterBytes->data, exporterBytes->len);
walker += exporterBytes->len;
CHECK_FAIL_ERR(REMAINING_BYTES(walker, serializedCx) != 0,
SEC_ERROR_LIBRARY_FAILURE);
*serialized = serializedCx;
CLEANUP:
if (rv != SECSuccess) {
SECITEM_ZfreeItem(serializedCx, PR_TRUE);
}
return rv;
}
HpkeContext *
PK11_HPKE_ImportContext(const SECItem *serialized, PK11SymKey *wrapKey)
{
SECStatus rv = SECSuccess;
HpkeContext *cx = NULL;
PRUint8 *walker;
PRUint64 tmpn;
PRUint8 tmp8;
HpkeKemId kem;
HpkeKdfId kdf;
HpkeAeadId aead;
PK11SlotInfo *slot = NULL;
PK11SymKey *tmpKey = NULL;
SECItem tmpItem = { siBuffer, NULL, 0 };
SECItem emptyItem = { siBuffer, NULL, 0 };
CHECK_FAIL_ERR((!serialized || !serialized->data || serialized->len == 0),
SEC_ERROR_INVALID_ARGS);
CHECK_FAIL_ERR((serialized->len < EXPORTED_CTX_BASE_LEN), SEC_ERROR_BAD_DATA
);
walker = serialized->data;
tmp8 = *(walker++);
CHECK_FAIL_ERR((tmp8 != SERIALIZATION_VERSION), SEC_ERROR_BAD_DATA);
tmp8 = *(walker++);
CHECK_FAIL_ERR((tmp8 != HPKE_DRAFT_VERSION), SEC_ERROR_INVALID_ALGORITHM);
walker = decodeNumber(&tmpn, walker, 2);
kem = (HpkeKemId)tmpn;
walker = decodeNumber(&tmpn, walker, 2);
kdf = (HpkeKdfId)tmpn;
walker = decodeNumber(&tmpn, walker, 2);
aead = (HpkeAeadId)tmpn;
/* Create context. We'll manually set the mode, though we
* no longer have the PSK and have no need for it. */
cx = PK11_HPKE_NewContext(kem, kdf, aead, NULL, NULL);
CHECK_FAIL(!cx);
walker = decodeNumber(&tmpn, walker, 2);
CHECK_FAIL_ERR((tmpn != HpkeModeBase && tmpn != HpkeModePsk),
SEC_ERROR_BAD_DATA);
cx->mode = (HpkeModeId)tmpn;
walker = decodeNumber(&cx->sequenceNumber, walker, 8);
slot = PK11_GetBestSlot(CKM_HKDF_DERIVE, NULL);
CHECK_FAIL(!slot);
/* Import sender public key (serialized). */
walker = decodeNumber(&tmpn, walker, 2);
CHECK_FAIL_ERR(tmpn >= REMAINING_BYTES(walker, serialized),
SEC_ERROR_BAD_DATA);
tmpItem.data = walker;
tmpItem.len = tmpn;
cx->encapPubKey = SECITEM_DupItem(&tmpItem);
CHECK_FAIL(!cx->encapPubKey);
walker += tmpItem.len;
/* Import base_nonce. */
walker = decodeNumber(&tmpn, walker, 2);
CHECK_FAIL_ERR(tmpn != cx->aeadParams->Nn, SEC_ERROR_BAD_DATA);
CHECK_FAIL_ERR(tmpn >= REMAINING_BYTES(walker, serialized),
SEC_ERROR_BAD_DATA);
tmpItem.data = walker;
tmpItem.len = tmpn;
cx->baseNonce = SECITEM_DupItem(&tmpItem);
CHECK_FAIL(!cx->baseNonce);
walker += tmpItem.len;
/* Import key */
walker = decodeNumber(&tmpn, walker, 2);
CHECK_FAIL_ERR(tmpn >= REMAINING_BYTES(walker, serialized),
SEC_ERROR_BAD_DATA);
tmpItem.data = walker;
tmpItem.len = tmpn;
walker += tmpItem.len;
if (wrapKey) {
cx->key = PK11_UnwrapSymKey(wrapKey, CKM_AES_KEY_WRAP_KWP,
NULL, &tmpItem, cx->aeadParams->mech,
CKA_NSS_MESSAGE | CKA_DECRYPT, 0);
CHECK_FAIL(!cx->key);
} else {
CHECK_FAIL_ERR(tmpn != cx->aeadParams->Nk, SEC_ERROR_BAD_DATA);
tmpKey = PK11_ImportSymKey(slot, cx->aeadParams->mech,
PK11_OriginUnwrap, CKA_NSS_MESSAGE | CKA_DECR
YPT,
&tmpItem, NULL);
CHECK_FAIL(!tmpKey);
cx->key = tmpKey;
}
/* Import exporter_secret. */
walker = decodeNumber(&tmpn, walker, 2);
CHECK_FAIL_ERR(tmpn != REMAINING_BYTES(walker, serialized),
SEC_ERROR_BAD_DATA);
tmpItem.data = walker;
tmpItem.len = tmpn;
walker += tmpItem.len;
if (wrapKey) {
cx->exporterSecret = PK11_UnwrapSymKey(wrapKey, CKM_AES_KEY_WRAP_KWP,
NULL, &tmpItem, cx->kdfParams->me
ch,
CKM_HKDF_DERIVE, 0);
CHECK_FAIL(!cx->exporterSecret);
} else {
CHECK_FAIL_ERR(tmpn != cx->kdfParams->Nh, SEC_ERROR_BAD_DATA);
tmpKey = PK11_ImportSymKey(slot, CKM_HKDF_DERIVE, PK11_OriginUnwrap,
CKA_DERIVE, &tmpItem, NULL);
CHECK_FAIL(!tmpKey);
cx->exporterSecret = tmpKey;
}
cx->aeadContext = PK11_CreateContextBySymKey(cx->aeadParams->mech,
CKA_NSS_MESSAGE | CKA_DECRYPT,
cx->key, &emptyItem);
CLEANUP:
if (rv != SECSuccess) {
PK11_FreeSymKey(tmpKey);
PK11_HPKE_DestroyContext(cx, PR_TRUE);
cx = NULL;
}
if (slot) {
PK11_FreeSlot(slot);
}
return cx;
}
SECStatus SECStatus
PK11_HPKE_Serialize(const SECKEYPublicKey *pk, PRUint8 *buf, unsigned int *len, unsigned int maxLen) PK11_HPKE_Serialize(const SECKEYPublicKey *pk, PRUint8 *buf, unsigned int *len, unsigned int maxLen)
{ {
if (!pk || !len || pk->keyType != ecKey) { if (!pk || !len || pk->keyType != ecKey) {
PORT_SetError(SEC_ERROR_INVALID_ARGS); PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure; return SECFailure;
} }
/* If no buffer provided, return the length required for /* If no buffer provided, return the length required for
* the serialized public key. */ * the serialized public key. */
skipping to change at line 350 skipping to change at line 625
oidData = SECOID_FindOIDByTag(cx->kemParams->oidTag); oidData = SECOID_FindOIDByTag(cx->kemParams->oidTag);
CHECK_FAIL_ERR(!oidData, SEC_ERROR_INVALID_ALGORITHM); CHECK_FAIL_ERR(!oidData, SEC_ERROR_INVALID_ALGORITHM);
// Create parameters. // Create parameters.
CHECK_FAIL(!SECITEM_AllocItem(pubKey->arena, &pubKey->u.ec.DEREncodedParams, CHECK_FAIL(!SECITEM_AllocItem(pubKey->arena, &pubKey->u.ec.DEREncodedParams,
2 + oidData->oid.len)); 2 + oidData->oid.len));
// Set parameters. // Set parameters.
pubKey->u.ec.DEREncodedParams.data[0] = SEC_ASN1_OBJECT_ID; pubKey->u.ec.DEREncodedParams.data[0] = SEC_ASN1_OBJECT_ID;
pubKey->u.ec.DEREncodedParams.data[1] = oidData->oid.len; pubKey->u.ec.DEREncodedParams.data[1] = oidData->oid.len;
memcpy(pubKey->u.ec.DEREncodedParams.data + 2, oidData->oid.data, oidData->o id.len); PORT_Memcpy(pubKey->u.ec.DEREncodedParams.data + 2, oidData->oid.data, oidDa ta->oid.len);
*outPubKey = pubKey; *outPubKey = pubKey;
CLEANUP: CLEANUP:
if (rv != SECSuccess) { if (rv != SECSuccess) {
SECKEY_DestroyPublicKey(pubKey); SECKEY_DestroyPublicKey(pubKey);
} }
return rv; return rv;
}; };
static SECStatus static SECStatus
skipping to change at line 406 skipping to change at line 681
oidData = SECOID_FindOIDByTag(cx->kemParams->oidTag); oidData = SECOID_FindOIDByTag(cx->kemParams->oidTag);
CHECK_FAIL_ERR(!oidData, SEC_ERROR_INVALID_ALGORITHM); CHECK_FAIL_ERR(!oidData, SEC_ERROR_INVALID_ALGORITHM);
ecp.data = PORT_Alloc(2 + oidData->oid.len); ecp.data = PORT_Alloc(2 + oidData->oid.len);
CHECK_FAIL(!ecp.data); CHECK_FAIL(!ecp.data);
ecp.len = 2 + oidData->oid.len; ecp.len = 2 + oidData->oid.len;
ecp.type = siDEROID; ecp.type = siDEROID;
ecp.data[0] = SEC_ASN1_OBJECT_ID; ecp.data[0] = SEC_ASN1_OBJECT_ID;
ecp.data[1] = oidData->oid.len; ecp.data[1] = oidData->oid.len;
memcpy(&ecp.data[2], oidData->oid.data, oidData->oid.len); PORT_Memcpy(&ecp.data[2], oidData->oid.data, oidData->oid.len);
slot = PK11_GetBestSlot(CKM_EC_KEY_PAIR_GEN, NULL); slot = PK11_GetBestSlot(CKM_EC_KEY_PAIR_GEN, NULL);
CHECK_FAIL(!slot); CHECK_FAIL(!slot);
privKey = PK11_GenerateKeyPair(slot, CKM_EC_KEY_PAIR_GEN, &ecp, &pubKey, privKey = PK11_GenerateKeyPair(slot, CKM_EC_KEY_PAIR_GEN, &ecp, &pubKey,
PR_FALSE, PR_TRUE, NULL); PR_FALSE, PR_TRUE, NULL);
CHECK_FAIL_ERR((!privKey || !pubKey), SEC_ERROR_KEYGEN_FAIL); CHECK_FAIL_ERR((!privKey || !pubKey), SEC_ERROR_KEYGEN_FAIL);
PORT_Assert(rv == SECSuccess); PORT_Assert(rv == SECSuccess);
*skE = privKey; *skE = privKey;
*pkE = pubKey; *pkE = pubKey;
skipping to change at line 436 skipping to change at line 711
PORT_Free(ecp.data); PORT_Free(ecp.data);
return rv; return rv;
} }
static inline SECItem * static inline SECItem *
pk11_hpke_MakeExtractLabel(const char *prefix, unsigned int prefixLen, pk11_hpke_MakeExtractLabel(const char *prefix, unsigned int prefixLen,
const char *label, unsigned int labelLen, const char *label, unsigned int labelLen,
const SECItem *suiteId, const SECItem *ikm) const SECItem *suiteId, const SECItem *ikm)
{ {
SECItem *out = NULL; SECItem *out = NULL;
size_t off = 0; PRUint8 *walker;
out = SECITEM_AllocItem(NULL, NULL, prefixLen + labelLen + suiteId->len + (i km ? ikm->len : 0)); out = SECITEM_AllocItem(NULL, NULL, prefixLen + labelLen + suiteId->len + (i km ? ikm->len : 0));
if (!out) { if (!out) {
return NULL; return NULL;
} }
memcpy(&out->data[off], prefix, prefixLen); walker = out->data;
off += prefixLen; PORT_Memcpy(walker, prefix, prefixLen);
memcpy(&out->data[off], suiteId->data, suiteId->len); walker += prefixLen;
off += suiteId->len; PORT_Memcpy(walker, suiteId->data, suiteId->len);
memcpy(&out->data[off], label, labelLen); walker += suiteId->len;
off += labelLen; PORT_Memcpy(walker, label, labelLen);
walker += labelLen;
if (ikm && ikm->data) { if (ikm && ikm->data) {
memcpy(&out->data[off], ikm->data, ikm->len); PORT_Memcpy(walker, ikm->data, ikm->len);
off += ikm->len;
} }
return out; return out;
} }
static SECStatus static SECStatus
pk11_hpke_LabeledExtractData(const HpkeContext *cx, SECItem *salt, pk11_hpke_LabeledExtractData(const HpkeContext *cx, SECItem *salt,
const SECItem *suiteId, const char *label, const SECItem *suiteId, const char *label,
unsigned int labelLen, const SECItem *ikm, SECItem **out) unsigned int labelLen, const SECItem *ikm, SECItem **out)
{ {
skipping to change at line 477 skipping to change at line 752
SECItem *outDerived = NULL; SECItem *outDerived = NULL;
SECItem *labeledIkm; SECItem *labeledIkm;
SECItem paramsItem = { siBuffer, (unsigned char *)&params, SECItem paramsItem = { siBuffer, (unsigned char *)&params,
sizeof(params) }; sizeof(params) };
PORT_Assert(cx && ikm && label && labelLen && out && suiteId); PORT_Assert(cx && ikm && label && labelLen && out && suiteId);
labeledIkm = pk11_hpke_MakeExtractLabel(DRAFT_LABEL, strlen(DRAFT_LABEL), la bel, labelLen, suiteId, ikm); labeledIkm = pk11_hpke_MakeExtractLabel(DRAFT_LABEL, strlen(DRAFT_LABEL), la bel, labelLen, suiteId, ikm);
CHECK_FAIL(!labeledIkm); CHECK_FAIL(!labeledIkm);
params.bExtract = CK_TRUE; params.bExtract = CK_TRUE;
params.bExpand = CK_FALSE; params.bExpand = CK_FALSE;
params.prfHashMechanism = cx->kemParams->hashMech; params.prfHashMechanism = cx->kdfParams->mech;
params.ulSaltType = salt ? CKF_HKDF_SALT_DATA : CKF_HKDF_SALT_NULL; params.ulSaltType = salt ? CKF_HKDF_SALT_DATA : CKF_HKDF_SALT_NULL;
params.pSalt = salt ? (CK_BYTE_PTR)salt->data : NULL; params.pSalt = salt ? (CK_BYTE_PTR)salt->data : NULL;
params.ulSaltLen = salt ? salt->len : 0; params.ulSaltLen = salt ? salt->len : 0;
params.pInfo = labeledIkm->data; params.pInfo = labeledIkm->data;
params.ulInfoLen = labeledIkm->len; params.ulInfoLen = labeledIkm->len;
slot = PK11_GetBestSlot(CKM_EC_KEY_PAIR_GEN, NULL); slot = PK11_GetBestSlot(CKM_EC_KEY_PAIR_GEN, NULL);
CHECK_FAIL(!slot); CHECK_FAIL(!slot);
importedIkm = PK11_ImportDataKey(slot, CKM_HKDF_DATA, PK11_OriginUnwrap, importedIkm = PK11_ImportDataKey(slot, CKM_HKDF_DATA, PK11_OriginUnwrap,
skipping to change at line 514 skipping to change at line 789
PK11_FreeSymKey(prk); PK11_FreeSymKey(prk);
SECITEM_FreeItem(labeledIkm, PR_TRUE); SECITEM_FreeItem(labeledIkm, PR_TRUE);
if (slot) { if (slot) {
PK11_FreeSlot(slot); PK11_FreeSlot(slot);
} }
return rv; return rv;
} }
static SECStatus static SECStatus
pk11_hpke_LabeledExtract(const HpkeContext *cx, PK11SymKey *salt, pk11_hpke_LabeledExtract(const HpkeContext *cx, PK11SymKey *salt,
const SECItem *suiteId, const char *label, const SECItem *suiteId, const char *label, CK_MECHANISM _TYPE hashMech,
unsigned int labelLen, PK11SymKey *ikm, PK11SymKey **ou t) unsigned int labelLen, PK11SymKey *ikm, PK11SymKey **ou t)
{ {
SECStatus rv = SECSuccess; SECStatus rv = SECSuccess;
SECItem *innerLabel = NULL; SECItem *innerLabel = NULL;
PK11SymKey *labeledIkm = NULL; PK11SymKey *labeledIkm = NULL;
PK11SymKey *prk = NULL; PK11SymKey *prk = NULL;
CK_HKDF_PARAMS params = { 0 }; CK_HKDF_PARAMS params = { 0 };
CK_KEY_DERIVATION_STRING_DATA labelData; CK_KEY_DERIVATION_STRING_DATA labelData;
SECItem labelDataItem = { siBuffer, NULL, 0 }; SECItem labelDataItem = { siBuffer, NULL, 0 };
SECItem paramsItem = { siBuffer, (unsigned char *)&params, SECItem paramsItem = { siBuffer, (unsigned char *)&params,
skipping to change at line 540 skipping to change at line 815
labelData.pData = innerLabel->data; labelData.pData = innerLabel->data;
labelData.ulLen = innerLabel->len; labelData.ulLen = innerLabel->len;
labelDataItem.data = (PRUint8 *)&labelData; labelDataItem.data = (PRUint8 *)&labelData;
labelDataItem.len = sizeof(labelData); labelDataItem.len = sizeof(labelData);
labeledIkm = PK11_Derive(ikm, CKM_CONCATENATE_DATA_AND_BASE, labeledIkm = PK11_Derive(ikm, CKM_CONCATENATE_DATA_AND_BASE,
&labelDataItem, CKM_GENERIC_SECRET_KEY_GEN, CKA_DER IVE, 0); &labelDataItem, CKM_GENERIC_SECRET_KEY_GEN, CKA_DER IVE, 0);
CHECK_FAIL(!labeledIkm); CHECK_FAIL(!labeledIkm);
params.bExtract = CK_TRUE; params.bExtract = CK_TRUE;
params.bExpand = CK_FALSE; params.bExpand = CK_FALSE;
params.prfHashMechanism = cx->kemParams->hashMech; params.prfHashMechanism = hashMech;
params.ulSaltType = salt ? CKF_HKDF_SALT_KEY : CKF_HKDF_SALT_NULL; params.ulSaltType = salt ? CKF_HKDF_SALT_KEY : CKF_HKDF_SALT_NULL;
params.hSaltKey = salt ? PK11_GetSymKeyHandle(salt) : CK_INVALID_HANDLE; params.hSaltKey = salt ? PK11_GetSymKeyHandle(salt) : CK_INVALID_HANDLE;
prk = PK11_Derive(labeledIkm, CKM_HKDF_DERIVE, &paramsItem, prk = PK11_Derive(labeledIkm, CKM_HKDF_DERIVE, &paramsItem,
CKM_HKDF_DERIVE, CKA_DERIVE, 0); CKM_HKDF_DERIVE, CKA_DERIVE, 0);
CHECK_FAIL(!prk); CHECK_FAIL(!prk);
*out = prk; *out = prk;
CLEANUP: CLEANUP:
PK11_FreeSymKey(labeledIkm); PK11_FreeSymKey(labeledIkm);
SECITEM_ZfreeItem(innerLabel, PR_TRUE); SECITEM_ZfreeItem(innerLabel, PR_TRUE);
return rv; return rv;
} }
static SECStatus static SECStatus
pk11_hpke_LabeledExpand(const HpkeContext *cx, PK11SymKey *prk, const SECItem *s uiteId, pk11_hpke_LabeledExpand(const HpkeContext *cx, PK11SymKey *prk, const SECItem *s uiteId,
const char *label, unsigned int labelLen, const SECItem *info, const char *label, unsigned int labelLen, const SECItem *info,
unsigned int L, PK11SymKey **outKey, SECItem **outItem) unsigned int L, CK_MECHANISM_TYPE hashMech, PK11SymKey *
*outKey,
SECItem **outItem)
{ {
SECStatus rv; SECStatus rv = SECSuccess;
CK_MECHANISM_TYPE keyMech; CK_MECHANISM_TYPE keyMech;
CK_MECHANISM_TYPE deriveMech; CK_MECHANISM_TYPE deriveMech;
CK_HKDF_PARAMS params = { 0 }; CK_HKDF_PARAMS params = { 0 };
PK11SymKey *derivedKey = NULL; PK11SymKey *derivedKey = NULL;
SECItem *labeledInfoItem = NULL; SECItem *labeledInfoItem = NULL;
SECItem paramsItem = { siBuffer, (unsigned char *)&params, SECItem paramsItem = { siBuffer, (unsigned char *)&params,
sizeof(params) }; sizeof(params) };
SECItem *derivedKeyData; SECItem *derivedKeyData;
PRUint8 encodedL[2]; PRUint8 encodedL[2];
size_t off = 0; PRUint8 *walker = encodedL;
size_t len; size_t len;
PORT_Assert(cx && prk && label && (!!outKey != !!outItem)); PORT_Assert(cx && prk && label && (!!outKey != !!outItem));
rv = encodeShort(L, encodedL); walker = encodeNumber(L, walker, 2);
CHECK_RV(rv);
len = info ? info->len : 0; len = info ? info->len : 0;
len += sizeof(encodedL) + strlen(DRAFT_LABEL) + suiteId->len + labelLen; len += sizeof(encodedL) + strlen(DRAFT_LABEL) + suiteId->len + labelLen;
labeledInfoItem = SECITEM_AllocItem(NULL, NULL, len); labeledInfoItem = SECITEM_AllocItem(NULL, NULL, len);
CHECK_FAIL(!labeledInfoItem); CHECK_FAIL(!labeledInfoItem);
memcpy(&labeledInfoItem->data[off], encodedL, sizeof(encodedL)); walker = labeledInfoItem->data;
off += sizeof(encodedL); PORT_Memcpy(walker, encodedL, sizeof(encodedL));
memcpy(&labeledInfoItem->data[off], DRAFT_LABEL, strlen(DRAFT_LABEL)); walker += sizeof(encodedL);
off += strlen(DRAFT_LABEL); PORT_Memcpy(walker, DRAFT_LABEL, strlen(DRAFT_LABEL));
memcpy(&labeledInfoItem->data[off], suiteId->data, suiteId->len); walker += strlen(DRAFT_LABEL);
off += suiteId->len; PORT_Memcpy(walker, suiteId->data, suiteId->len);
memcpy(&labeledInfoItem->data[off], label, labelLen); walker += suiteId->len;
off += labelLen; PORT_Memcpy(walker, label, labelLen);
walker += labelLen;
if (info) { if (info) {
memcpy(&labeledInfoItem->data[off], info->data, info->len); PORT_Memcpy(walker, info->data, info->len);
off += info->len;
} }
params.bExtract = CK_FALSE; params.bExtract = CK_FALSE;
params.bExpand = CK_TRUE; params.bExpand = CK_TRUE;
params.prfHashMechanism = cx->kemParams->hashMech; params.prfHashMechanism = hashMech;
params.ulSaltType = CKF_HKDF_SALT_NULL; params.ulSaltType = CKF_HKDF_SALT_NULL;
params.pInfo = labeledInfoItem->data; params.pInfo = labeledInfoItem->data;
params.ulInfoLen = labeledInfoItem->len; params.ulInfoLen = labeledInfoItem->len;
deriveMech = outItem ? CKM_HKDF_DATA : CKM_HKDF_DERIVE; deriveMech = outItem ? CKM_HKDF_DATA : CKM_HKDF_DERIVE;
/* If we're expanding to the encryption key use the appropriate mechanism. * / /* If we're expanding to the encryption key use the appropriate mechanism. * /
keyMech = (label && !strcmp(KEY_LABEL, label)) ? cx->aeadParams->mech : CKM_ HKDF_DERIVE; keyMech = (label && !strcmp(KEY_LABEL, label)) ? cx->aeadParams->mech : CKM_ HKDF_DERIVE;
derivedKey = PK11_Derive(prk, deriveMech, &paramsItem, keyMech, CKA_DERIVE, L); derivedKey = PK11_Derive(prk, deriveMech, &paramsItem, keyMech, CKA_DERIVE, L);
CHECK_FAIL(!derivedKey); CHECK_FAIL(!derivedKey);
skipping to change at line 638 skipping to change at line 912
} }
static SECStatus static SECStatus
pk11_hpke_ExtractAndExpand(const HpkeContext *cx, PK11SymKey *ikm, pk11_hpke_ExtractAndExpand(const HpkeContext *cx, PK11SymKey *ikm,
const SECItem *kemContext, PK11SymKey **out) const SECItem *kemContext, PK11SymKey **out)
{ {
SECStatus rv; SECStatus rv;
PK11SymKey *eaePrk = NULL; PK11SymKey *eaePrk = NULL;
PK11SymKey *sharedSecret = NULL; PK11SymKey *sharedSecret = NULL;
PRUint8 suiteIdBuf[5]; PRUint8 suiteIdBuf[5];
PRUint8 *walker;
PORT_Memcpy(suiteIdBuf, KEM_LABEL, strlen(KEM_LABEL)); PORT_Memcpy(suiteIdBuf, KEM_LABEL, strlen(KEM_LABEL));
SECItem suiteIdItem = { siBuffer, suiteIdBuf, sizeof(suiteIdBuf) }; SECItem suiteIdItem = { siBuffer, suiteIdBuf, sizeof(suiteIdBuf) };
PORT_Assert(cx && ikm && kemContext && out); PORT_Assert(cx && ikm && kemContext && out);
rv = encodeShort(cx->kemParams->id, &suiteIdBuf[3]); walker = &suiteIdBuf[3];
CHECK_RV(rv); walker = encodeNumber(cx->kemParams->id, walker, 2);
rv = pk11_hpke_LabeledExtract(cx, NULL, &suiteIdItem, EAE_PRK_LABEL, rv = pk11_hpke_LabeledExtract(cx, NULL, &suiteIdItem, EAE_PRK_LABEL,
strlen(EAE_PRK_LABEL), ikm, &eaePrk); cx->kemParams->hashMech, strlen(EAE_PRK_LABEL)
,
ikm, &eaePrk);
CHECK_RV(rv); CHECK_RV(rv);
rv = pk11_hpke_LabeledExpand(cx, eaePrk, &suiteIdItem, SH_SEC_LABEL, strlen( SH_SEC_LABEL), rv = pk11_hpke_LabeledExpand(cx, eaePrk, &suiteIdItem, SH_SEC_LABEL, strlen( SH_SEC_LABEL),
kemContext, cx->kemParams->Nsecret, &sharedSecr kemContext, cx->kemParams->Nsecret, cx->kemPara
et, NULL); ms->hashMech,
&sharedSecret, NULL);
CHECK_RV(rv); CHECK_RV(rv);
*out = sharedSecret; *out = sharedSecret;
CLEANUP: CLEANUP:
if (rv != SECSuccess) { if (rv != SECSuccess) {
PK11_FreeSymKey(sharedSecret); PK11_FreeSymKey(sharedSecret);
} }
PK11_FreeSymKey(eaePrk); PK11_FreeSymKey(eaePrk);
return rv; return rv;
} }
skipping to change at line 701 skipping to change at line 978
rv = PK11_HPKE_Serialize(pkE, cx->encapPubKey->data, rv = PK11_HPKE_Serialize(pkE, cx->encapPubKey->data,
&cx->encapPubKey->len, cx->encapPubKey->len); &cx->encapPubKey->len, cx->encapPubKey->len);
CHECK_RV(rv); CHECK_RV(rv);
rv = PK11_HPKE_Serialize(pkR, NULL, &tmpLen, 0); rv = PK11_HPKE_Serialize(pkR, NULL, &tmpLen, 0);
CHECK_RV(rv); CHECK_RV(rv);
kemContext = SECITEM_AllocItem(NULL, NULL, cx->encapPubKey->len + tmpLen); kemContext = SECITEM_AllocItem(NULL, NULL, cx->encapPubKey->len + tmpLen);
CHECK_FAIL(!kemContext); CHECK_FAIL(!kemContext);
memcpy(kemContext->data, cx->encapPubKey->data, cx->encapPubKey->len); PORT_Memcpy(kemContext->data, cx->encapPubKey->data, cx->encapPubKey->len);
rv = PK11_HPKE_Serialize(pkR, &kemContext->data[cx->encapPubKey->len], &tmpL en, tmpLen); rv = PK11_HPKE_Serialize(pkR, &kemContext->data[cx->encapPubKey->len], &tmpL en, tmpLen);
CHECK_RV(rv); CHECK_RV(rv);
rv = pk11_hpke_ExtractAndExpand(cx, dh, kemContext, &cx->sharedSecret); rv = pk11_hpke_ExtractAndExpand(cx, dh, kemContext, &cx->sharedSecret);
CHECK_RV(rv); CHECK_RV(rv);
CLEANUP: CLEANUP:
if (rv != SECSuccess) { if (rv != SECSuccess) {
PK11_FreeSymKey(cx->sharedSecret); PK11_FreeSymKey(cx->sharedSecret);
cx->sharedSecret = NULL; cx->sharedSecret = NULL;
skipping to change at line 726 skipping to change at line 1003
return rv; return rv;
} }
SECStatus SECStatus
PK11_HPKE_ExportSecret(const HpkeContext *cx, const SECItem *info, unsigned int L, PK11_HPKE_ExportSecret(const HpkeContext *cx, const SECItem *info, unsigned int L,
PK11SymKey **out) PK11SymKey **out)
{ {
SECStatus rv; SECStatus rv;
PK11SymKey *exported; PK11SymKey *exported;
PRUint8 suiteIdBuf[10]; PRUint8 suiteIdBuf[10];
PRUint8 *walker;
PORT_Memcpy(suiteIdBuf, HPKE_LABEL, strlen(HPKE_LABEL)); PORT_Memcpy(suiteIdBuf, HPKE_LABEL, strlen(HPKE_LABEL));
SECItem suiteIdItem = { siBuffer, suiteIdBuf, sizeof(suiteIdBuf) }; SECItem suiteIdItem = { siBuffer, suiteIdBuf, sizeof(suiteIdBuf) };
/* Arbitrary info length limit well under the specified max. */ /* Arbitrary info length limit well under the specified max. */
if (!cx || !info || (!info->data && info->len) || info->len > 0xFFFF || if (!cx || !info || (!info->data && info->len) || info->len > 0xFFFF ||
!L || (L > 255 * cx->kdfParams->Nh)) { !L || (L > 255 * cx->kdfParams->Nh)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS); PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure; return SECFailure;
} }
rv = encodeShort(cx->kemParams->id, &suiteIdBuf[4]); walker = &suiteIdBuf[4];
CHECK_RV(rv); walker = encodeNumber(cx->kemParams->id, walker, 2);
rv = encodeShort(cx->kdfParams->id, &suiteIdBuf[6]); walker = encodeNumber(cx->kdfParams->id, walker, 2);
CHECK_RV(rv); walker = encodeNumber(cx->aeadParams->id, walker, 2);
rv = encodeShort(cx->aeadParams->id, &suiteIdBuf[8]);
CHECK_RV(rv);
rv = pk11_hpke_LabeledExpand(cx, cx->exporterSecret, &suiteIdItem, SEC_LABEL , rv = pk11_hpke_LabeledExpand(cx, cx->exporterSecret, &suiteIdItem, SEC_LABEL ,
strlen(SEC_LABEL), info, L, &exported, NULL); strlen(SEC_LABEL), info, L, cx->kdfParams->mech
,
&exported, NULL);
CHECK_RV(rv); CHECK_RV(rv);
*out = exported; *out = exported;
CLEANUP: CLEANUP:
return rv; return rv;
} }
static SECStatus static SECStatus
pk11_hpke_Decap(HpkeContext *cx, const SECKEYPublicKey *pkR, SECKEYPrivateKey *s kR, pk11_hpke_Decap(HpkeContext *cx, const SECKEYPublicKey *pkR, SECKEYPrivateKey *s kR,
const SECItem *encS) const SECItem *encS)
skipping to change at line 788 skipping to change at line 1065
CKD_NULL, NULL, NULL); CKD_NULL, NULL, NULL);
CHECK_FAIL(!dh); CHECK_FAIL(!dh);
/* kem_context = concat(enc, pkRm) */ /* kem_context = concat(enc, pkRm) */
rv = PK11_HPKE_Serialize(pkR, NULL, &tmpLen, 0); rv = PK11_HPKE_Serialize(pkR, NULL, &tmpLen, 0);
CHECK_RV(rv); CHECK_RV(rv);
kemContext = SECITEM_AllocItem(NULL, NULL, encS->len + tmpLen); kemContext = SECITEM_AllocItem(NULL, NULL, encS->len + tmpLen);
CHECK_FAIL(!kemContext); CHECK_FAIL(!kemContext);
memcpy(kemContext->data, encS->data, encS->len); PORT_Memcpy(kemContext->data, encS->data, encS->len);
rv = PK11_HPKE_Serialize(pkR, &kemContext->data[encS->len], &tmpLen, rv = PK11_HPKE_Serialize(pkR, &kemContext->data[encS->len], &tmpLen,
kemContext->len - encS->len); kemContext->len - encS->len);
CHECK_RV(rv); CHECK_RV(rv);
rv = pk11_hpke_ExtractAndExpand(cx, dh, kemContext, &cx->sharedSecret); rv = pk11_hpke_ExtractAndExpand(cx, dh, kemContext, &cx->sharedSecret);
CHECK_RV(rv); CHECK_RV(rv);
/* Store the sender serialized public key, which
* may be required by application use cases. */
cx->encapPubKey = SECITEM_DupItem(encS);
CHECK_FAIL(!cx->encapPubKey);
CLEANUP: CLEANUP:
if (rv != SECSuccess) { if (rv != SECSuccess) {
PK11_FreeSymKey(cx->sharedSecret); PK11_FreeSymKey(cx->sharedSecret);
cx->sharedSecret = NULL; cx->sharedSecret = NULL;
} }
PK11_FreeSymKey(dh); PK11_FreeSymKey(dh);
SECKEY_DestroyPublicKey(pkS); SECKEY_DestroyPublicKey(pkS);
SECITEM_FreeItem(encR, PR_TRUE); SECITEM_FreeItem(encR, PR_TRUE);
SECITEM_ZfreeItem(kemContext, PR_TRUE); SECITEM_ZfreeItem(kemContext, PR_TRUE);
return rv; return rv;
} }
const SECItem * const SECItem *
PK11_HPKE_GetEncapPubKey(const HpkeContext *cx) PK11_HPKE_GetEncapPubKey(const HpkeContext *cx)
{ {
if (!cx) { if (!cx) {
return NULL; return NULL;
} }
/* Will be NULL on receiver. */
return cx->encapPubKey; return cx->encapPubKey;
} }
static SECStatus static SECStatus
pk11_hpke_KeySchedule(HpkeContext *cx, const SECItem *info) pk11_hpke_KeySchedule(HpkeContext *cx, const SECItem *info)
{ {
SECStatus rv; SECStatus rv;
SECItem contextItem = { siBuffer, NULL, 0 }; SECItem contextItem = { siBuffer, NULL, 0 };
unsigned int len; unsigned int len;
unsigned int off; unsigned int off;
PK11SymKey *pskHash = NULL;
PK11SymKey *secret = NULL; PK11SymKey *secret = NULL;
SECItem *pskIdHash = NULL; SECItem *pskIdHash = NULL;
SECItem *infoHash = NULL; SECItem *infoHash = NULL;
PRUint8 suiteIdBuf[10]; PRUint8 suiteIdBuf[10];
PRUint8 *walker;
PORT_Memcpy(suiteIdBuf, HPKE_LABEL, strlen(HPKE_LABEL)); PORT_Memcpy(suiteIdBuf, HPKE_LABEL, strlen(HPKE_LABEL));
SECItem suiteIdItem = { siBuffer, suiteIdBuf, sizeof(suiteIdBuf) }; SECItem suiteIdItem = { siBuffer, suiteIdBuf, sizeof(suiteIdBuf) };
PORT_Assert(cx && info && cx->psk && cx->pskId); PORT_Assert(cx && info && cx->psk && cx->pskId);
rv = encodeShort(cx->kemParams->id, &suiteIdBuf[4]); walker = &suiteIdBuf[4];
CHECK_RV(rv); walker = encodeNumber(cx->kemParams->id, walker, 2);
rv = encodeShort(cx->kdfParams->id, &suiteIdBuf[6]); walker = encodeNumber(cx->kdfParams->id, walker, 2);
CHECK_RV(rv); walker = encodeNumber(cx->aeadParams->id, walker, 2);
rv = encodeShort(cx->aeadParams->id, &suiteIdBuf[8]);
CHECK_RV(rv);
rv = pk11_hpke_LabeledExtractData(cx, NULL, &suiteIdItem, PSK_ID_LABEL, rv = pk11_hpke_LabeledExtractData(cx, NULL, &suiteIdItem, PSK_ID_LABEL,
strlen(PSK_ID_LABEL), cx->pskId, &pskIdHas h); strlen(PSK_ID_LABEL), cx->pskId, &pskIdHas h);
CHECK_RV(rv); CHECK_RV(rv);
rv = pk11_hpke_LabeledExtractData(cx, NULL, &suiteIdItem, INFO_LABEL, rv = pk11_hpke_LabeledExtractData(cx, NULL, &suiteIdItem, INFO_LABEL,
strlen(INFO_LABEL), info, &infoHash); strlen(INFO_LABEL), info, &infoHash);
CHECK_RV(rv); CHECK_RV(rv);
// Make the context string // Make the context string
len = sizeof(cx->mode) + pskIdHash->len + infoHash->len; len = sizeof(cx->mode) + pskIdHash->len + infoHash->len;
CHECK_FAIL(!SECITEM_AllocItem(NULL, &contextItem, len)); CHECK_FAIL(!SECITEM_AllocItem(NULL, &contextItem, len));
off = 0; off = 0;
memcpy(&contextItem.data[off], &cx->mode, sizeof(cx->mode)); PORT_Memcpy(&contextItem.data[off], &cx->mode, sizeof(cx->mode));
off += sizeof(cx->mode); off += sizeof(cx->mode);
memcpy(&contextItem.data[off], pskIdHash->data, pskIdHash->len); PORT_Memcpy(&contextItem.data[off], pskIdHash->data, pskIdHash->len);
off += pskIdHash->len; off += pskIdHash->len;
memcpy(&contextItem.data[off], infoHash->data, infoHash->len); PORT_Memcpy(&contextItem.data[off], infoHash->data, infoHash->len);
off += infoHash->len; off += infoHash->len;
// Compute the keys // Compute the keys
rv = pk11_hpke_LabeledExtract(cx, NULL, &suiteIdItem, PSK_LABEL, rv = pk11_hpke_LabeledExtract(cx, cx->sharedSecret, &suiteIdItem, SECRET_LAB
strlen(PSK_LABEL), cx->psk, &pskHash); EL,
CHECK_RV(rv); cx->kdfParams->mech, strlen(SECRET_LABEL),
rv = pk11_hpke_LabeledExtract(cx, pskHash, &suiteIdItem, SECRET_LABEL, cx->psk, &secret);
strlen(SECRET_LABEL), cx->sharedSecret, &secre
t);
CHECK_RV(rv); CHECK_RV(rv);
rv = pk11_hpke_LabeledExpand(cx, secret, &suiteIdItem, KEY_LABEL, strlen(KEY _LABEL), rv = pk11_hpke_LabeledExpand(cx, secret, &suiteIdItem, KEY_LABEL, strlen(KEY _LABEL),
&contextItem, cx->aeadParams->Nk, &cx->key, NUL &contextItem, cx->aeadParams->Nk, cx->kdfParams
L); ->mech,
&cx->key, NULL);
CHECK_RV(rv); CHECK_RV(rv);
rv = pk11_hpke_LabeledExpand(cx, secret, &suiteIdItem, NONCE_LABEL, strlen(N ONCE_LABEL), rv = pk11_hpke_LabeledExpand(cx, secret, &suiteIdItem, NONCE_LABEL, strlen(N ONCE_LABEL),
&contextItem, cx->aeadParams->Nn, NULL, &cx->no &contextItem, cx->aeadParams->Nn, cx->kdfParams
nce); ->mech,
NULL, &cx->baseNonce);
CHECK_RV(rv); CHECK_RV(rv);
rv = pk11_hpke_LabeledExpand(cx, secret, &suiteIdItem, EXP_LABEL, strlen(EXP _LABEL), rv = pk11_hpke_LabeledExpand(cx, secret, &suiteIdItem, EXP_LABEL, strlen(EXP _LABEL),
&contextItem, cx->kdfParams->Nh, &cx->exporterS &contextItem, cx->kdfParams->Nh, cx->kdfParams-
ecret, NULL); >mech,
&cx->exporterSecret, NULL);
CHECK_RV(rv); CHECK_RV(rv);
CLEANUP: CLEANUP:
/* If !SECSuccess, callers will tear down the context. */ /* If !SECSuccess, callers will tear down the context. */
PK11_FreeSymKey(pskHash);
PK11_FreeSymKey(secret); PK11_FreeSymKey(secret);
SECITEM_FreeItem(&contextItem, PR_FALSE); SECITEM_FreeItem(&contextItem, PR_FALSE);
SECITEM_FreeItem(infoHash, PR_TRUE); SECITEM_FreeItem(infoHash, PR_TRUE);
SECITEM_FreeItem(pskIdHash, PR_TRUE); SECITEM_FreeItem(pskIdHash, PR_TRUE);
return rv; return rv;
} }
SECStatus SECStatus
PK11_HPKE_SetupR(HpkeContext *cx, const SECKEYPublicKey *pkR, SECKEYPrivateKey * skR, PK11_HPKE_SetupR(HpkeContext *cx, const SECKEYPublicKey *pkR, SECKEYPrivateKey * skR,
const SECItem *enc, const SECItem *info) const SECItem *enc, const SECItem *info)
{ {
SECStatus rv; SECStatus rv;
SECItem nullParams = { siBuffer, NULL, 0 }; SECItem empty = { siBuffer, NULL, 0 };
CHECK_FAIL_ERR((!cx || !skR || !info || !enc || !enc->data || !enc->len), CHECK_FAIL_ERR((!cx || !skR || !info || !enc || !enc->data || !enc->len),
SEC_ERROR_INVALID_ARGS); SEC_ERROR_INVALID_ARGS);
/* Already setup */ /* Already setup */
CHECK_FAIL_ERR((cx->aeadContext), SEC_ERROR_INVALID_STATE); CHECK_FAIL_ERR((cx->aeadContext), SEC_ERROR_INVALID_STATE);
rv = pk11_hpke_Decap(cx, pkR, skR, enc); rv = pk11_hpke_Decap(cx, pkR, skR, enc);
CHECK_RV(rv); CHECK_RV(rv);
rv = pk11_hpke_KeySchedule(cx, info); rv = pk11_hpke_KeySchedule(cx, info);
CHECK_RV(rv); CHECK_RV(rv);
/* Store the key context for subsequent calls to Open(). /* Store the key context for subsequent calls to Open().
* PK11_CreateContextBySymKey refs the key internally. */ * PK11_CreateContextBySymKey refs the key internally. */
PORT_Assert(cx->key); PORT_Assert(cx->key);
cx->aeadContext = PK11_CreateContextBySymKey(cx->aeadParams->mech, cx->aeadContext = PK11_CreateContextBySymKey(cx->aeadParams->mech,
CKA_NSS_MESSAGE | CKA_DECRYPT, CKA_NSS_MESSAGE | CKA_DECRYPT,
cx->key, &nullParams); cx->key, &empty);
CHECK_FAIL_ERR((!cx->aeadContext), SEC_ERROR_LIBRARY_FAILURE); CHECK_FAIL_ERR((!cx->aeadContext), SEC_ERROR_LIBRARY_FAILURE);
CLEANUP: CLEANUP:
if (rv != SECSuccess) { if (rv != SECSuccess) {
/* Clear everything past NewContext. */ /* Clear everything past NewContext. */
PK11_HPKE_DestroyContext(cx, PR_FALSE); PK11_HPKE_DestroyContext(cx, PR_FALSE);
} }
return rv; return rv;
} }
skipping to change at line 976 skipping to change at line 1256
PK11_HPKE_Seal(HpkeContext *cx, const SECItem *aad, const SECItem *pt, PK11_HPKE_Seal(HpkeContext *cx, const SECItem *aad, const SECItem *pt,
SECItem **out) SECItem **out)
{ {
SECStatus rv; SECStatus rv;
PRUint8 ivOut[12] = { 0 }; PRUint8 ivOut[12] = { 0 };
SECItem *ct = NULL; SECItem *ct = NULL;
size_t maxOut; size_t maxOut;
unsigned char tagBuf[HASH_LENGTH_MAX]; unsigned char tagBuf[HASH_LENGTH_MAX];
size_t tagLen; size_t tagLen;
unsigned int fixedBits; unsigned int fixedBits;
PORT_Assert(cx->nonce->len == sizeof(ivOut)); PORT_Assert(cx->baseNonce->len == sizeof(ivOut));
memcpy(ivOut, cx->nonce->data, cx->nonce->len); PORT_Memcpy(ivOut, cx->baseNonce->data, cx->baseNonce->len);
/* aad may be NULL, PT may be zero-length but not NULL. */ /* aad may be NULL, PT may be zero-length but not NULL. */
if (!cx || !cx->aeadContext || if (!cx || !cx->aeadContext ||
(aad && aad->len && !aad->data) || (aad && aad->len && !aad->data) ||
!pt || (pt->len && !pt->data) || !pt || (pt->len && !pt->data) ||
!out) { !out) {
PORT_SetError(SEC_ERROR_INVALID_ARGS); PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure; return SECFailure;
} }
tagLen = cx->aeadParams->tagLen; tagLen = cx->aeadParams->tagLen;
maxOut = pt->len + tagLen; maxOut = pt->len + tagLen;
fixedBits = (cx->nonce->len - 8) * 8; fixedBits = (cx->baseNonce->len - 8) * 8;
ct = SECITEM_AllocItem(NULL, NULL, maxOut); ct = SECITEM_AllocItem(NULL, NULL, maxOut);
CHECK_FAIL(!ct); CHECK_FAIL(!ct);
rv = PK11_AEADOp(cx->aeadContext, rv = PK11_AEADOp(cx->aeadContext,
CKG_GENERATE_COUNTER_XOR, fixedBits, CKG_GENERATE_COUNTER_XOR, fixedBits,
ivOut, sizeof(ivOut), ivOut, sizeof(ivOut),
aad ? aad->data : NULL, aad ? aad->data : NULL,
aad ? aad->len : 0, aad ? aad->len : 0,
ct->data, (int *)&ct->len, maxOut, ct->data, (int *)&ct->len, maxOut,
tagBuf, tagLen, tagBuf, tagLen,
pt->data, pt->len); pt->data, pt->len);
CHECK_RV(rv); CHECK_RV(rv);
CHECK_FAIL_ERR((ct->len > maxOut - tagLen), SEC_ERROR_LIBRARY_FAILURE); CHECK_FAIL_ERR((ct->len > maxOut - tagLen), SEC_ERROR_LIBRARY_FAILURE);
/* Append the tag to the ciphertext. */ /* Append the tag to the ciphertext. */
memcpy(&ct->data[ct->len], tagBuf, tagLen); PORT_Memcpy(&ct->data[ct->len], tagBuf, tagLen);
ct->len += tagLen; ct->len += tagLen;
*out = ct; *out = ct;
CLEANUP: CLEANUP:
if (rv != SECSuccess) { if (rv != SECSuccess) {
SECITEM_ZfreeItem(ct, PR_TRUE); SECITEM_ZfreeItem(ct, PR_TRUE);
} }
return rv; return rv;
} }
/* PKCS #11 defines the IV generator function to be ignored on /* PKCS #11 defines the IV generator function to be ignored on
* decrypt (i.e. it uses the nonce input, as provided, as the IV). * decrypt (i.e. it uses the nonce input, as provided, as the IV).
* The sequence number is kept independently on each endpoint and * The sequence number is kept independently on each endpoint and
* the XORed IV is not transmitted, so we have to do our own IV * the XORed IV is not transmitted, so we have to do our own IV
* construction XOR outside of the token. */ * construction XOR outside of the token. */
static SECStatus static SECStatus
pk11_hpke_makeIv(HpkeContext *cx, PRUint8 *iv, size_t ivLen) pk11_hpke_makeIv(HpkeContext *cx, PRUint8 *iv, size_t ivLen)
{ {
unsigned int counterLen = sizeof(cx->sequenceNumber); unsigned int counterLen = sizeof(cx->sequenceNumber);
PORT_Assert(cx->nonce->len == ivLen); PORT_Assert(cx->baseNonce->len == ivLen);
PORT_Assert(counterLen == 8); PORT_Assert(counterLen == 8);
if (cx->sequenceNumber == PR_UINT64(0xffffffffffffffff)) { if (cx->sequenceNumber == PR_UINT64(0xffffffffffffffff)) {
/* Overflow */ /* Overflow */
PORT_SetError(SEC_ERROR_INVALID_KEY); PORT_SetError(SEC_ERROR_INVALID_KEY);
return SECFailure; return SECFailure;
} }
memcpy(iv, cx->nonce->data, cx->nonce->len); PORT_Memcpy(iv, cx->baseNonce->data, cx->baseNonce->len);
for (size_t i = 0; i < counterLen; i++) { for (size_t i = 0; i < counterLen; i++) {
iv[cx->nonce->len - 1 - i] ^= iv[cx->baseNonce->len - 1 - i] ^=
PORT_GET_BYTE_BE(cx->sequenceNumber, PORT_GET_BYTE_BE(cx->sequenceNumber,
counterLen - 1 - i, counterLen); counterLen - 1 - i, counterLen);
} }
return SECSuccess; return SECSuccess;
} }
SECStatus SECStatus
PK11_HPKE_Open(HpkeContext *cx, const SECItem *aad, PK11_HPKE_Open(HpkeContext *cx, const SECItem *aad,
const SECItem *ct, SECItem **out) const SECItem *ct, SECItem **out)
{ {
skipping to change at line 1085 skipping to change at line 1365
CHECK_RV(rv); CHECK_RV(rv);
cx->sequenceNumber++; cx->sequenceNumber++;
*out = pt; *out = pt;
CLEANUP: CLEANUP:
if (rv != SECSuccess) { if (rv != SECSuccess) {
SECITEM_ZfreeItem(pt, PR_TRUE); SECITEM_ZfreeItem(pt, PR_TRUE);
} }
return rv; return rv;
} }
#endif // NSS_ENABLE_DRAFT_HPKE #endif // NSS_ENABLE_DRAFT_HPKE
 End of changes. 63 change blocks. 
93 lines changed or deleted 385 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)