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 *)¶ms, | SECItem paramsItem = { siBuffer, (unsigned char *)¶ms, | |||
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 *)¶ms, | SECItem paramsItem = { siBuffer, (unsigned char *)¶ms, | |||
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, ¶msItem, | prk = PK11_Derive(labeledIkm, CKM_HKDF_DERIVE, ¶msItem, | |||
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 *)¶ms, | SECItem paramsItem = { siBuffer, (unsigned char *)¶ms, | |||
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, ¶msItem, keyMech, CKA_DERIVE, L); | derivedKey = PK11_Derive(prk, deriveMech, ¶msItem, 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 |