tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

pk11hpke.c (42401B)


      1 /*
      2 * draft-irtf-cfrg-hpke-07
      3 *
      4 * This Source Code Form is subject to the terms of the Mozilla Public
      5 * License, v. 2.0. If a copy of the MPL was not distributed with this
      6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
      7 */
      8 
      9 #include "keyhi.h"
     10 #include "pkcs11t.h"
     11 #include "pk11func.h"
     12 #include "pk11hpke.h"
     13 #include "pk11pqg.h"
     14 #include "secerr.h"
     15 #include "secitem.h"
     16 #include "secmod.h"
     17 #include "secmodi.h"
     18 #include "secmodti.h"
     19 #include "secutil.h"
     20 
     21 #define SERIALIZATION_VERSION 2
     22 
     23 static const char *V1_LABEL = "HPKE-v1";
     24 static const char *EXP_LABEL = "exp";
     25 static const char *HPKE_LABEL = "HPKE";
     26 static const char *INFO_LABEL = "info_hash";
     27 static const char *KEM_LABEL = "KEM";
     28 static const char *KEY_LABEL = "key";
     29 static const char *NONCE_LABEL = "base_nonce";
     30 static const char *PSK_ID_LABEL = "psk_id_hash";
     31 static const char *SECRET_LABEL = "secret";
     32 static const char *SEC_LABEL = "sec";
     33 static const char *EAE_PRK_LABEL = "eae_prk";
     34 static const char *SH_SEC_LABEL = "shared_secret";
     35 
     36 struct HpkeContextStr {
     37    const hpkeKemParams *kemParams;
     38    const hpkeKdfParams *kdfParams;
     39    const hpkeAeadParams *aeadParams;
     40    PRUint8 mode;               /* Base and PSK modes supported. */
     41    SECItem *encapPubKey;       /* Marshalled public key, sent to receiver. */
     42    SECItem *baseNonce;         /* Deterministic nonce for AEAD. */
     43    SECItem *pskId;             /* PSK identifier (non-secret). */
     44    PK11Context *aeadContext;   /* AEAD context used by Seal/Open. */
     45    PRUint64 sequenceNumber;    /* seqNo for decrypt IV construction. */
     46    PK11SymKey *sharedSecret;   /* ExtractAndExpand output key. */
     47    PK11SymKey *key;            /* Key used with the AEAD. */
     48    PK11SymKey *exporterSecret; /* Derivation key for ExportSecret. */
     49    PK11SymKey *psk;            /* PSK imported by the application. */
     50 };
     51 
     52 static const hpkeKemParams kemParams[] = {
     53    /* KEM, Nsk, Nsecret, Npk, oidTag, Hash mechanism  */
     54    { HpkeDhKemX25519Sha256, 32, 32, 32, SEC_OID_CURVE25519, CKM_SHA256 },
     55 };
     56 
     57 #define MAX_WRAPPED_EXP_LEN 72 // Largest kdfParams->Nh + 8
     58 static const hpkeKdfParams kdfParams[] = {
     59    /* KDF, Nh, mechanism  */
     60    { HpkeKdfHkdfSha256, SHA256_LENGTH, CKM_SHA256 },
     61    { HpkeKdfHkdfSha384, SHA384_LENGTH, CKM_SHA384 },
     62    { HpkeKdfHkdfSha512, SHA512_LENGTH, CKM_SHA512 },
     63 };
     64 #define MAX_WRAPPED_KEY_LEN 40 // Largest aeadParams->Nk + 8
     65 static const hpkeAeadParams aeadParams[] = {
     66    /* AEAD, Nk, Nn, tagLen, mechanism  */
     67    { HpkeAeadAes128Gcm, 16, 12, 16, CKM_AES_GCM },
     68    { HpkeAeadAes256Gcm, 32, 12, 16, CKM_AES_GCM },
     69    { HpkeAeadChaCha20Poly1305, 32, 12, 16, CKM_CHACHA20_POLY1305 },
     70 };
     71 
     72 static inline const hpkeKemParams *
     73 kemId2Params(HpkeKemId kemId)
     74 {
     75    switch (kemId) {
     76        case HpkeDhKemX25519Sha256:
     77            return &kemParams[0];
     78        default:
     79            return NULL;
     80    }
     81 }
     82 
     83 static inline const hpkeKdfParams *
     84 kdfId2Params(HpkeKdfId kdfId)
     85 {
     86    switch (kdfId) {
     87        case HpkeKdfHkdfSha256:
     88            return &kdfParams[0];
     89        case HpkeKdfHkdfSha384:
     90            return &kdfParams[1];
     91        case HpkeKdfHkdfSha512:
     92            return &kdfParams[2];
     93        default:
     94            return NULL;
     95    }
     96 }
     97 
     98 static const inline hpkeAeadParams *
     99 aeadId2Params(HpkeAeadId aeadId)
    100 {
    101    switch (aeadId) {
    102        case HpkeAeadAes128Gcm:
    103            return &aeadParams[0];
    104        case HpkeAeadAes256Gcm:
    105            return &aeadParams[1];
    106        case HpkeAeadChaCha20Poly1305:
    107            return &aeadParams[2];
    108        default:
    109            return NULL;
    110    }
    111 }
    112 
    113 static PRUint8 *
    114 encodeNumber(PRUint64 value, PRUint8 *b, size_t count)
    115 {
    116    PRUint64 encoded;
    117    PORT_Assert(b && count > 0 && count <= sizeof(encoded));
    118 
    119    encoded = PR_htonll(value);
    120    PORT_Memcpy(b, ((unsigned char *)(&encoded)) + (sizeof(encoded) - count),
    121                count);
    122    return b + count;
    123 }
    124 
    125 static PRUint8 *
    126 decodeNumber(PRUint64 *value, PRUint8 *b, size_t count)
    127 {
    128    unsigned int i;
    129    PRUint64 number = 0;
    130    PORT_Assert(b && value && count <= sizeof(*value));
    131 
    132    for (i = 0; i < count; i++) {
    133        number = (number << 8) + b[i];
    134    }
    135    *value = number;
    136    return b + count;
    137 }
    138 
    139 SECStatus
    140 PK11_HPKE_ValidateParameters(HpkeKemId kemId, HpkeKdfId kdfId, HpkeAeadId aeadId)
    141 {
    142    /* If more variants are added, ensure the combination is also
    143     * legal. For now it is, since only the AEAD may vary. */
    144    const hpkeKemParams *kem = kemId2Params(kemId);
    145    const hpkeKdfParams *kdf = kdfId2Params(kdfId);
    146    const hpkeAeadParams *aead = aeadId2Params(aeadId);
    147    if (!kem || !kdf || !aead) {
    148        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    149        return SECFailure;
    150    }
    151    return SECSuccess;
    152 }
    153 
    154 HpkeContext *
    155 PK11_HPKE_NewContext(HpkeKemId kemId, HpkeKdfId kdfId, HpkeAeadId aeadId,
    156                     PK11SymKey *psk, const SECItem *pskId)
    157 {
    158    SECStatus rv = SECSuccess;
    159    PK11SlotInfo *slot = NULL;
    160    HpkeContext *cx = NULL;
    161    /* Both the PSK and the PSK ID default to empty. */
    162    SECItem emptyItem = { siBuffer, NULL, 0 };
    163 
    164    cx = PORT_ZNew(HpkeContext);
    165    if (!cx) {
    166        return NULL;
    167    }
    168    cx->mode = psk ? HpkeModePsk : HpkeModeBase;
    169    cx->kemParams = kemId2Params(kemId);
    170    cx->kdfParams = kdfId2Params(kdfId);
    171    cx->aeadParams = aeadId2Params(aeadId);
    172    CHECK_FAIL_ERR((!!psk != !!pskId), SEC_ERROR_INVALID_ARGS);
    173    CHECK_FAIL_ERR(!cx->kemParams || !cx->kdfParams || !cx->aeadParams,
    174                   SEC_ERROR_INVALID_ARGS);
    175 
    176    /* Import the provided PSK or the default. */
    177    slot = PK11_GetBestSlot(CKM_EC_KEY_PAIR_GEN, NULL);
    178    CHECK_FAIL(!slot);
    179    if (psk) {
    180        cx->psk = PK11_ReferenceSymKey(psk);
    181        cx->pskId = SECITEM_DupItem(pskId);
    182    } else {
    183        cx->psk = PK11_ImportDataKey(slot, CKM_HKDF_DATA, PK11_OriginUnwrap,
    184                                     CKA_DERIVE, &emptyItem, NULL);
    185        cx->pskId = SECITEM_DupItem(&emptyItem);
    186    }
    187    CHECK_FAIL(!cx->psk);
    188    CHECK_FAIL(!cx->pskId);
    189 
    190 CLEANUP:
    191    if (rv != SECSuccess) {
    192        PK11_FreeSymKey(cx->psk);
    193        SECITEM_FreeItem(cx->pskId, PR_TRUE);
    194        cx->pskId = NULL;
    195        cx->psk = NULL;
    196        PORT_Free(cx);
    197        cx = NULL;
    198    }
    199    if (slot) {
    200        PK11_FreeSlot(slot);
    201    }
    202    return cx;
    203 }
    204 
    205 void
    206 PK11_HPKE_DestroyContext(HpkeContext *cx, PRBool freeit)
    207 {
    208    if (!cx) {
    209        return;
    210    }
    211 
    212    if (cx->aeadContext) {
    213        PK11_DestroyContext((PK11Context *)cx->aeadContext, PR_TRUE);
    214        cx->aeadContext = NULL;
    215    }
    216    PK11_FreeSymKey(cx->exporterSecret);
    217    PK11_FreeSymKey(cx->sharedSecret);
    218    PK11_FreeSymKey(cx->key);
    219    PK11_FreeSymKey(cx->psk);
    220    SECITEM_FreeItem(cx->pskId, PR_TRUE);
    221    SECITEM_FreeItem(cx->baseNonce, PR_TRUE);
    222    SECITEM_FreeItem(cx->encapPubKey, PR_TRUE);
    223    cx->exporterSecret = NULL;
    224    cx->sharedSecret = NULL;
    225    cx->key = NULL;
    226    cx->psk = NULL;
    227    cx->pskId = NULL;
    228    cx->baseNonce = NULL;
    229    cx->encapPubKey = NULL;
    230    if (freeit) {
    231        PORT_ZFree(cx, sizeof(HpkeContext));
    232    }
    233 }
    234 
    235 /* Export Format:
    236    struct {
    237        uint8 serilizationVersion;
    238        uint16 kemId;
    239        uint16 kdfId;
    240        uint16 aeadId;
    241        uint16 modeId;
    242        uint64 sequenceNumber;
    243        opaque senderPubKey<1..2^16-1>;
    244        opaque baseNonce<1..2^16-1>;
    245        opaque key<1..2^16-1>;
    246        opaque exporterSecret<1..2^16-1>;
    247    } HpkeSerializedContext
    248 */
    249 #define EXPORTED_CTX_BASE_LEN 25 /* Fixed size plus 2B for each variable. */
    250 #define REMAINING_BYTES(walker, buf) \
    251    buf->len - (walker - buf->data)
    252 SECStatus
    253 PK11_HPKE_ExportContext(const HpkeContext *cx, PK11SymKey *wrapKey, SECItem **serialized)
    254 {
    255    SECStatus rv;
    256    size_t allocLen;
    257    PRUint8 *walker;
    258    SECItem *keyBytes = NULL;      // Maybe wrapped
    259    SECItem *exporterBytes = NULL; // Maybe wrapped
    260    SECItem *serializedCx = NULL;
    261    PRUint8 wrappedKeyBytes[MAX_WRAPPED_KEY_LEN] = { 0 };
    262    PRUint8 wrappedExpBytes[MAX_WRAPPED_EXP_LEN] = { 0 };
    263    SECItem wrappedKey = { siBuffer, wrappedKeyBytes, sizeof(wrappedKeyBytes) };
    264    SECItem wrappedExp = { siBuffer, wrappedExpBytes, sizeof(wrappedExpBytes) };
    265 
    266    CHECK_FAIL_ERR((!cx || !cx->aeadContext || !serialized), SEC_ERROR_INVALID_ARGS);
    267    CHECK_FAIL_ERR((cx->aeadContext->operation != (CKA_NSS_MESSAGE | CKA_DECRYPT)),
    268                   SEC_ERROR_NOT_A_RECIPIENT);
    269 
    270    /* If a wrapping key was provided, do the wrap first
    271     * so that we know what size to allocate. */
    272    if (wrapKey) {
    273        rv = PK11_WrapSymKey(CKM_AES_KEY_WRAP_KWP, NULL, wrapKey,
    274                             cx->key, &wrappedKey);
    275        CHECK_RV(rv);
    276        rv = PK11_WrapSymKey(CKM_AES_KEY_WRAP_KWP, NULL, wrapKey,
    277                             cx->exporterSecret, &wrappedExp);
    278        CHECK_RV(rv);
    279 
    280        keyBytes = &wrappedKey;
    281        exporterBytes = &wrappedExp;
    282    } else {
    283        rv = PK11_ExtractKeyValue(cx->key);
    284        CHECK_RV(rv);
    285        keyBytes = PK11_GetKeyData(cx->key);
    286        CHECK_FAIL(!keyBytes);
    287        PORT_Assert(keyBytes->len == cx->aeadParams->Nk);
    288 
    289        rv = PK11_ExtractKeyValue(cx->exporterSecret);
    290        CHECK_RV(rv);
    291        exporterBytes = PK11_GetKeyData(cx->exporterSecret);
    292        CHECK_FAIL(!exporterBytes);
    293        PORT_Assert(exporterBytes->len == cx->kdfParams->Nh);
    294    }
    295 
    296    allocLen = EXPORTED_CTX_BASE_LEN + cx->baseNonce->len + cx->encapPubKey->len;
    297    allocLen += wrapKey ? wrappedKey.len : cx->aeadParams->Nk;
    298    allocLen += wrapKey ? wrappedExp.len : cx->kdfParams->Nh;
    299 
    300    serializedCx = SECITEM_AllocItem(NULL, NULL, allocLen);
    301    CHECK_FAIL(!serializedCx);
    302 
    303    walker = &serializedCx->data[0];
    304    *(walker)++ = (PRUint8)SERIALIZATION_VERSION;
    305 
    306    walker = encodeNumber(cx->kemParams->id, walker, 2);
    307    walker = encodeNumber(cx->kdfParams->id, walker, 2);
    308    walker = encodeNumber(cx->aeadParams->id, walker, 2);
    309    walker = encodeNumber(cx->mode, walker, 2);
    310    walker = encodeNumber(cx->sequenceNumber, walker, 8);
    311 
    312    /* sender public key, serialized. */
    313    walker = encodeNumber(cx->encapPubKey->len, walker, 2);
    314    PORT_Memcpy(walker, cx->encapPubKey->data, cx->encapPubKey->len);
    315    walker += cx->encapPubKey->len;
    316 
    317    /* base nonce */
    318    walker = encodeNumber(cx->baseNonce->len, walker, 2);
    319    PORT_Memcpy(walker, cx->baseNonce->data, cx->baseNonce->len);
    320    walker += cx->baseNonce->len;
    321 
    322    /* key. */
    323    walker = encodeNumber(keyBytes->len, walker, 2);
    324    PORT_Memcpy(walker, keyBytes->data, keyBytes->len);
    325    walker += keyBytes->len;
    326 
    327    /* exporter_secret. */
    328    walker = encodeNumber(exporterBytes->len, walker, 2);
    329    PORT_Memcpy(walker, exporterBytes->data, exporterBytes->len);
    330    walker += exporterBytes->len;
    331 
    332    CHECK_FAIL_ERR(REMAINING_BYTES(walker, serializedCx) != 0,
    333                   SEC_ERROR_LIBRARY_FAILURE);
    334    *serialized = serializedCx;
    335 
    336 CLEANUP:
    337    if (rv != SECSuccess) {
    338        SECITEM_ZfreeItem(serializedCx, PR_TRUE);
    339    }
    340    return rv;
    341 }
    342 
    343 HpkeContext *
    344 PK11_HPKE_ImportContext(const SECItem *serialized, PK11SymKey *wrapKey)
    345 {
    346    SECStatus rv = SECSuccess;
    347    HpkeContext *cx = NULL;
    348    PRUint8 *walker;
    349    PRUint64 tmpn;
    350    PRUint8 tmp8;
    351    HpkeKemId kem;
    352    HpkeKdfId kdf;
    353    HpkeAeadId aead;
    354    PK11SlotInfo *slot = NULL;
    355    PK11SymKey *tmpKey = NULL;
    356    SECItem tmpItem = { siBuffer, NULL, 0 };
    357    SECItem emptyItem = { siBuffer, NULL, 0 };
    358 
    359    CHECK_FAIL_ERR((!serialized || !serialized->data || serialized->len == 0),
    360                   SEC_ERROR_INVALID_ARGS);
    361    CHECK_FAIL_ERR((serialized->len < EXPORTED_CTX_BASE_LEN), SEC_ERROR_BAD_DATA);
    362 
    363    walker = serialized->data;
    364 
    365    tmp8 = *(walker++);
    366    CHECK_FAIL_ERR((tmp8 != SERIALIZATION_VERSION), SEC_ERROR_BAD_DATA);
    367 
    368    walker = decodeNumber(&tmpn, walker, 2);
    369    kem = (HpkeKemId)tmpn;
    370 
    371    walker = decodeNumber(&tmpn, walker, 2);
    372    kdf = (HpkeKdfId)tmpn;
    373 
    374    walker = decodeNumber(&tmpn, walker, 2);
    375    aead = (HpkeAeadId)tmpn;
    376 
    377    /* Create context. We'll manually set the mode, though we
    378     * no longer have the PSK and have no need for it. */
    379    cx = PK11_HPKE_NewContext(kem, kdf, aead, NULL, NULL);
    380    CHECK_FAIL(!cx);
    381 
    382    walker = decodeNumber(&tmpn, walker, 2);
    383    CHECK_FAIL_ERR((tmpn != HpkeModeBase && tmpn != HpkeModePsk),
    384                   SEC_ERROR_BAD_DATA);
    385    cx->mode = (HpkeModeId)tmpn;
    386 
    387    walker = decodeNumber(&cx->sequenceNumber, walker, 8);
    388    slot = PK11_GetBestSlot(CKM_HKDF_DERIVE, NULL);
    389    CHECK_FAIL(!slot);
    390 
    391    /* Import sender public key (serialized). */
    392    walker = decodeNumber(&tmpn, walker, 2);
    393    CHECK_FAIL_ERR(tmpn >= REMAINING_BYTES(walker, serialized),
    394                   SEC_ERROR_BAD_DATA);
    395    tmpItem.data = walker;
    396    tmpItem.len = tmpn;
    397    cx->encapPubKey = SECITEM_DupItem(&tmpItem);
    398    CHECK_FAIL(!cx->encapPubKey);
    399    walker += tmpItem.len;
    400 
    401    /* Import base_nonce. */
    402    walker = decodeNumber(&tmpn, walker, 2);
    403    CHECK_FAIL_ERR(tmpn != cx->aeadParams->Nn, SEC_ERROR_BAD_DATA);
    404    CHECK_FAIL_ERR(tmpn >= REMAINING_BYTES(walker, serialized),
    405                   SEC_ERROR_BAD_DATA);
    406    tmpItem.data = walker;
    407    tmpItem.len = tmpn;
    408    cx->baseNonce = SECITEM_DupItem(&tmpItem);
    409    CHECK_FAIL(!cx->baseNonce);
    410    walker += tmpItem.len;
    411 
    412    /* Import key */
    413    walker = decodeNumber(&tmpn, walker, 2);
    414    CHECK_FAIL_ERR(tmpn >= REMAINING_BYTES(walker, serialized),
    415                   SEC_ERROR_BAD_DATA);
    416    tmpItem.data = walker;
    417    tmpItem.len = tmpn;
    418    walker += tmpItem.len;
    419    if (wrapKey) {
    420        cx->key = PK11_UnwrapSymKey(wrapKey, CKM_AES_KEY_WRAP_KWP,
    421                                    NULL, &tmpItem, cx->aeadParams->mech,
    422                                    CKA_NSS_MESSAGE | CKA_DECRYPT, 0);
    423        CHECK_FAIL(!cx->key);
    424    } else {
    425        CHECK_FAIL_ERR(tmpn != cx->aeadParams->Nk, SEC_ERROR_BAD_DATA);
    426        tmpKey = PK11_ImportSymKey(slot, cx->aeadParams->mech,
    427                                   PK11_OriginUnwrap, CKA_NSS_MESSAGE | CKA_DECRYPT,
    428                                   &tmpItem, NULL);
    429        CHECK_FAIL(!tmpKey);
    430        cx->key = tmpKey;
    431    }
    432 
    433    /* Import exporter_secret. */
    434    walker = decodeNumber(&tmpn, walker, 2);
    435    CHECK_FAIL_ERR(tmpn != REMAINING_BYTES(walker, serialized),
    436                   SEC_ERROR_BAD_DATA);
    437    tmpItem.data = walker;
    438    tmpItem.len = tmpn;
    439    walker += tmpItem.len;
    440 
    441    if (wrapKey) {
    442        cx->exporterSecret = PK11_UnwrapSymKey(wrapKey, CKM_AES_KEY_WRAP_KWP,
    443                                               NULL, &tmpItem, cx->kdfParams->mech,
    444                                               CKM_HKDF_DERIVE, 0);
    445        CHECK_FAIL(!cx->exporterSecret);
    446    } else {
    447        CHECK_FAIL_ERR(tmpn != cx->kdfParams->Nh, SEC_ERROR_BAD_DATA);
    448        tmpKey = PK11_ImportSymKey(slot, CKM_HKDF_DERIVE, PK11_OriginUnwrap,
    449                                   CKA_DERIVE, &tmpItem, NULL);
    450        CHECK_FAIL(!tmpKey);
    451        cx->exporterSecret = tmpKey;
    452    }
    453 
    454    cx->aeadContext = PK11_CreateContextBySymKey(cx->aeadParams->mech,
    455                                                 CKA_NSS_MESSAGE | CKA_DECRYPT,
    456                                                 cx->key, &emptyItem);
    457 
    458 CLEANUP:
    459    if (rv != SECSuccess) {
    460        PK11_FreeSymKey(tmpKey);
    461        PK11_HPKE_DestroyContext(cx, PR_TRUE);
    462        cx = NULL;
    463    }
    464    if (slot) {
    465        PK11_FreeSlot(slot);
    466    }
    467 
    468    return cx;
    469 }
    470 
    471 SECStatus
    472 PK11_HPKE_Serialize(const SECKEYPublicKey *pk, PRUint8 *buf, unsigned int *len, unsigned int maxLen)
    473 {
    474    if (!pk || !len || pk->keyType != ecKey) {
    475        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    476        return SECFailure;
    477    }
    478 
    479    /* If no buffer provided, return the length required for
    480     * the serialized public key. */
    481    if (!buf) {
    482        *len = pk->u.ec.publicValue.len;
    483        return SECSuccess;
    484    }
    485 
    486    if (maxLen < pk->u.ec.publicValue.len) {
    487        PORT_SetError(SEC_ERROR_INPUT_LEN);
    488        return SECFailure;
    489    }
    490 
    491    PORT_Memcpy(buf, pk->u.ec.publicValue.data, pk->u.ec.publicValue.len);
    492    *len = pk->u.ec.publicValue.len;
    493    return SECSuccess;
    494 };
    495 
    496 SECStatus
    497 PK11_HPKE_Deserialize(const HpkeContext *cx, const PRUint8 *enc,
    498                      unsigned int encLen, SECKEYPublicKey **outPubKey)
    499 {
    500    SECStatus rv;
    501    SECKEYPublicKey *pubKey = NULL;
    502    SECOidData *oidData = NULL;
    503    PLArenaPool *arena;
    504 
    505    if (!cx || !enc || encLen == 0 || !outPubKey) {
    506        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    507        return SECFailure;
    508    }
    509 
    510    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    511    CHECK_FAIL(!arena);
    512    pubKey = PORT_ArenaZNew(arena, SECKEYPublicKey);
    513    CHECK_FAIL(!pubKey);
    514 
    515    pubKey->arena = arena;
    516    pubKey->keyType = ecKey;
    517    pubKey->pkcs11Slot = NULL;
    518    pubKey->pkcs11ID = CK_INVALID_HANDLE;
    519 
    520    rv = SECITEM_MakeItem(pubKey->arena, &pubKey->u.ec.publicValue,
    521                          enc, encLen);
    522    CHECK_RV(rv);
    523    pubKey->u.ec.encoding = ECPoint_Undefined;
    524    pubKey->u.ec.size = 0;
    525 
    526    oidData = SECOID_FindOIDByTag(cx->kemParams->oidTag);
    527    CHECK_FAIL_ERR(!oidData, SEC_ERROR_INVALID_ALGORITHM);
    528 
    529    // Create parameters.
    530    CHECK_FAIL(!SECITEM_AllocItem(pubKey->arena, &pubKey->u.ec.DEREncodedParams,
    531                                  2 + oidData->oid.len));
    532 
    533    // Set parameters.
    534    pubKey->u.ec.DEREncodedParams.data[0] = SEC_ASN1_OBJECT_ID;
    535    pubKey->u.ec.DEREncodedParams.data[1] = oidData->oid.len;
    536    PORT_Memcpy(pubKey->u.ec.DEREncodedParams.data + 2, oidData->oid.data, oidData->oid.len);
    537    *outPubKey = pubKey;
    538 
    539 CLEANUP:
    540    if (rv != SECSuccess) {
    541        SECKEY_DestroyPublicKey(pubKey);
    542    }
    543    return rv;
    544 };
    545 
    546 static SECStatus
    547 pk11_hpke_CheckKeys(const HpkeContext *cx, const SECKEYPublicKey *pk,
    548                    const SECKEYPrivateKey *sk)
    549 {
    550    SECOidTag pkTag;
    551    unsigned int i;
    552    if (pk->keyType != ecKey || (sk && sk->keyType != ecKey)) {
    553        PORT_SetError(SEC_ERROR_BAD_KEY);
    554        return SECFailure;
    555    }
    556    pkTag = SECKEY_GetECCOid(&pk->u.ec.DEREncodedParams);
    557    if (pkTag != cx->kemParams->oidTag) {
    558        PORT_SetError(SEC_ERROR_BAD_KEY);
    559        return SECFailure;
    560    }
    561    for (i = 0; i < PR_ARRAY_SIZE(kemParams); i++) {
    562        if (cx->kemParams->oidTag == kemParams[i].oidTag) {
    563            return SECSuccess;
    564        }
    565    }
    566 
    567    return SECFailure;
    568 }
    569 
    570 static SECStatus
    571 pk11_hpke_GenerateKeyPair(const HpkeContext *cx, SECKEYPublicKey **pkE,
    572                          SECKEYPrivateKey **skE)
    573 {
    574    SECStatus rv = SECSuccess;
    575    SECKEYPrivateKey *privKey = NULL;
    576    SECKEYPublicKey *pubKey = NULL;
    577    SECOidData *oidData = NULL;
    578    SECKEYECParams ecp;
    579    PK11SlotInfo *slot = NULL;
    580    ecp.data = NULL;
    581    PORT_Assert(cx && skE && pkE);
    582 
    583    oidData = SECOID_FindOIDByTag(cx->kemParams->oidTag);
    584    CHECK_FAIL_ERR(!oidData, SEC_ERROR_INVALID_ALGORITHM);
    585    ecp.data = PORT_Alloc(2 + oidData->oid.len);
    586    CHECK_FAIL(!ecp.data);
    587 
    588    ecp.len = 2 + oidData->oid.len;
    589    ecp.type = siDEROID;
    590    ecp.data[0] = SEC_ASN1_OBJECT_ID;
    591    ecp.data[1] = oidData->oid.len;
    592    PORT_Memcpy(&ecp.data[2], oidData->oid.data, oidData->oid.len);
    593 
    594    slot = PK11_GetBestSlot(CKM_EC_KEY_PAIR_GEN, NULL);
    595    CHECK_FAIL(!slot);
    596 
    597    privKey = PK11_GenerateKeyPair(slot, CKM_EC_KEY_PAIR_GEN, &ecp, &pubKey,
    598                                   PR_FALSE, PR_TRUE, NULL);
    599    CHECK_FAIL_ERR((!privKey || !pubKey), SEC_ERROR_KEYGEN_FAIL);
    600    PORT_Assert(rv == SECSuccess);
    601    *skE = privKey;
    602    *pkE = pubKey;
    603 
    604 CLEANUP:
    605    if (rv != SECSuccess) {
    606        SECKEY_DestroyPrivateKey(privKey);
    607        SECKEY_DestroyPublicKey(pubKey);
    608    }
    609    if (slot) {
    610        PK11_FreeSlot(slot);
    611    }
    612    PORT_Free(ecp.data);
    613    return rv;
    614 }
    615 
    616 static inline SECItem *
    617 pk11_hpke_MakeExtractLabel(const char *prefix, unsigned int prefixLen,
    618                           const char *label, unsigned int labelLen,
    619                           const SECItem *suiteId, const SECItem *ikm)
    620 {
    621    SECItem *out = NULL;
    622    PRUint8 *walker;
    623    out = SECITEM_AllocItem(NULL, NULL, prefixLen + labelLen + suiteId->len + (ikm ? ikm->len : 0));
    624    if (!out) {
    625        return NULL;
    626    }
    627 
    628    walker = out->data;
    629    PORT_Memcpy(walker, prefix, prefixLen);
    630    walker += prefixLen;
    631    PORT_Memcpy(walker, suiteId->data, suiteId->len);
    632    walker += suiteId->len;
    633    PORT_Memcpy(walker, label, labelLen);
    634    walker += labelLen;
    635    if (ikm && ikm->data) {
    636        PORT_Memcpy(walker, ikm->data, ikm->len);
    637    }
    638 
    639    return out;
    640 }
    641 
    642 static SECStatus
    643 pk11_hpke_LabeledExtractData(const HpkeContext *cx, SECItem *salt,
    644                             const SECItem *suiteId, const char *label,
    645                             unsigned int labelLen, const SECItem *ikm, SECItem **out)
    646 {
    647    SECStatus rv;
    648    CK_HKDF_PARAMS params = { 0 };
    649    PK11SymKey *importedIkm = NULL;
    650    PK11SymKey *prk = NULL;
    651    PK11SlotInfo *slot = NULL;
    652    SECItem *borrowed;
    653    SECItem *outDerived = NULL;
    654    SECItem *labeledIkm;
    655    SECItem paramsItem = { siBuffer, (unsigned char *)&params,
    656                           sizeof(params) };
    657    PORT_Assert(cx && ikm && label && labelLen && out && suiteId);
    658 
    659    labeledIkm = pk11_hpke_MakeExtractLabel(V1_LABEL, strlen(V1_LABEL), label, labelLen, suiteId, ikm);
    660    CHECK_FAIL(!labeledIkm);
    661    params.bExtract = CK_TRUE;
    662    params.bExpand = CK_FALSE;
    663    params.prfHashMechanism = cx->kdfParams->mech;
    664    params.ulSaltType = salt ? CKF_HKDF_SALT_DATA : CKF_HKDF_SALT_NULL;
    665    params.pSalt = salt ? (CK_BYTE_PTR)salt->data : NULL;
    666    params.ulSaltLen = salt ? salt->len : 0;
    667    params.pInfo = labeledIkm->data;
    668    params.ulInfoLen = labeledIkm->len;
    669 
    670    slot = PK11_GetBestSlot(CKM_EC_KEY_PAIR_GEN, NULL);
    671    CHECK_FAIL(!slot);
    672 
    673    importedIkm = PK11_ImportDataKey(slot, CKM_HKDF_DATA, PK11_OriginUnwrap,
    674                                     CKA_DERIVE, labeledIkm, NULL);
    675    CHECK_FAIL(!importedIkm);
    676    prk = PK11_Derive(importedIkm, CKM_HKDF_DATA, &paramsItem,
    677                      CKM_HKDF_DERIVE, CKA_DERIVE, 0);
    678    CHECK_FAIL(!prk);
    679    rv = PK11_ExtractKeyValue(prk);
    680    CHECK_RV(rv);
    681    borrowed = PK11_GetKeyData(prk);
    682    CHECK_FAIL(!borrowed);
    683    outDerived = SECITEM_DupItem(borrowed);
    684    CHECK_FAIL(!outDerived);
    685 
    686    *out = outDerived;
    687 
    688 CLEANUP:
    689    PK11_FreeSymKey(importedIkm);
    690    PK11_FreeSymKey(prk);
    691    SECITEM_FreeItem(labeledIkm, PR_TRUE);
    692    if (slot) {
    693        PK11_FreeSlot(slot);
    694    }
    695    return rv;
    696 }
    697 
    698 static SECStatus
    699 pk11_hpke_LabeledExtract(const HpkeContext *cx, PK11SymKey *salt,
    700                         const SECItem *suiteId, const char *label, CK_MECHANISM_TYPE hashMech,
    701                         unsigned int labelLen, PK11SymKey *ikm, PK11SymKey **out)
    702 {
    703    SECStatus rv = SECSuccess;
    704    SECItem *innerLabel = NULL;
    705    PK11SymKey *labeledIkm = NULL;
    706    PK11SymKey *prk = NULL;
    707    CK_HKDF_PARAMS params = { 0 };
    708    CK_KEY_DERIVATION_STRING_DATA labelData;
    709    SECItem labelDataItem = { siBuffer, NULL, 0 };
    710    SECItem paramsItem = { siBuffer, (unsigned char *)&params,
    711                           sizeof(params) };
    712    PORT_Assert(cx && ikm && label && labelLen && out && suiteId);
    713 
    714    innerLabel = pk11_hpke_MakeExtractLabel(V1_LABEL, strlen(V1_LABEL), label, labelLen, suiteId, NULL);
    715    CHECK_FAIL(!innerLabel);
    716    labelData.pData = innerLabel->data;
    717    labelData.ulLen = innerLabel->len;
    718    labelDataItem.data = (PRUint8 *)&labelData;
    719    labelDataItem.len = sizeof(labelData);
    720    labeledIkm = PK11_Derive(ikm, CKM_CONCATENATE_DATA_AND_BASE,
    721                             &labelDataItem, CKM_GENERIC_SECRET_KEY_GEN, CKA_DERIVE, 0);
    722    CHECK_FAIL(!labeledIkm);
    723 
    724    params.bExtract = CK_TRUE;
    725    params.bExpand = CK_FALSE;
    726    params.prfHashMechanism = hashMech;
    727    params.ulSaltType = salt ? CKF_HKDF_SALT_KEY : CKF_HKDF_SALT_NULL;
    728    params.hSaltKey = salt ? PK11_GetSymKeyHandle(salt) : CK_INVALID_HANDLE;
    729 
    730    prk = PK11_Derive(labeledIkm, CKM_HKDF_DERIVE, &paramsItem,
    731                      CKM_HKDF_DERIVE, CKA_DERIVE, 0);
    732    CHECK_FAIL(!prk);
    733    *out = prk;
    734 
    735 CLEANUP:
    736    PK11_FreeSymKey(labeledIkm);
    737    SECITEM_ZfreeItem(innerLabel, PR_TRUE);
    738    return rv;
    739 }
    740 
    741 static SECStatus
    742 pk11_hpke_LabeledExpand(const HpkeContext *cx, PK11SymKey *prk, const SECItem *suiteId,
    743                        const char *label, unsigned int labelLen, const SECItem *info,
    744                        unsigned int L, CK_MECHANISM_TYPE hashMech, PK11SymKey **outKey,
    745                        SECItem **outItem)
    746 {
    747    SECStatus rv = SECSuccess;
    748    CK_MECHANISM_TYPE keyMech;
    749    CK_MECHANISM_TYPE deriveMech;
    750    CK_HKDF_PARAMS params = { 0 };
    751    PK11SymKey *derivedKey = NULL;
    752    SECItem *labeledInfoItem = NULL;
    753    SECItem paramsItem = { siBuffer, (unsigned char *)&params,
    754                           sizeof(params) };
    755    SECItem *derivedKeyData;
    756    PRUint8 encodedL[2];
    757    PRUint8 *walker = encodedL;
    758    size_t len;
    759    PORT_Assert(cx && prk && label && (!!outKey != !!outItem));
    760 
    761    walker = encodeNumber(L, walker, 2);
    762    len = info ? info->len : 0;
    763    len += sizeof(encodedL) + strlen(V1_LABEL) + suiteId->len + labelLen;
    764    labeledInfoItem = SECITEM_AllocItem(NULL, NULL, len);
    765    CHECK_FAIL(!labeledInfoItem);
    766 
    767    walker = labeledInfoItem->data;
    768    PORT_Memcpy(walker, encodedL, sizeof(encodedL));
    769    walker += sizeof(encodedL);
    770    PORT_Memcpy(walker, V1_LABEL, strlen(V1_LABEL));
    771    walker += strlen(V1_LABEL);
    772    PORT_Memcpy(walker, suiteId->data, suiteId->len);
    773    walker += suiteId->len;
    774    PORT_Memcpy(walker, label, labelLen);
    775    walker += labelLen;
    776    if (info) {
    777        PORT_Memcpy(walker, info->data, info->len);
    778    }
    779 
    780    params.bExtract = CK_FALSE;
    781    params.bExpand = CK_TRUE;
    782    params.prfHashMechanism = hashMech;
    783    params.ulSaltType = CKF_HKDF_SALT_NULL;
    784    params.pInfo = labeledInfoItem->data;
    785    params.ulInfoLen = labeledInfoItem->len;
    786    deriveMech = outItem ? CKM_HKDF_DATA : CKM_HKDF_DERIVE;
    787    /* If we're expanding to the encryption key use the appropriate mechanism. */
    788    keyMech = (label && !strcmp(KEY_LABEL, label)) ? cx->aeadParams->mech : CKM_HKDF_DERIVE;
    789 
    790    derivedKey = PK11_Derive(prk, deriveMech, &paramsItem, keyMech, CKA_DERIVE, L);
    791    CHECK_FAIL(!derivedKey);
    792 
    793    if (outItem) {
    794        /* Don't allow export of real keys. */
    795        CHECK_FAIL_ERR(deriveMech != CKM_HKDF_DATA, SEC_ERROR_LIBRARY_FAILURE);
    796        rv = PK11_ExtractKeyValue(derivedKey);
    797        CHECK_RV(rv);
    798        derivedKeyData = PK11_GetKeyData(derivedKey);
    799        CHECK_FAIL_ERR((!derivedKeyData), SEC_ERROR_NO_KEY);
    800        *outItem = SECITEM_DupItem(derivedKeyData);
    801        CHECK_FAIL(!*outItem);
    802        PK11_FreeSymKey(derivedKey);
    803    } else {
    804        *outKey = derivedKey;
    805    }
    806 
    807 CLEANUP:
    808    if (rv != SECSuccess) {
    809        PK11_FreeSymKey(derivedKey);
    810    }
    811    SECITEM_ZfreeItem(labeledInfoItem, PR_TRUE);
    812    return rv;
    813 }
    814 
    815 static SECStatus
    816 pk11_hpke_ExtractAndExpand(const HpkeContext *cx, PK11SymKey *ikm,
    817                           const SECItem *kemContext, PK11SymKey **out)
    818 {
    819    SECStatus rv;
    820    PK11SymKey *eaePrk = NULL;
    821    PK11SymKey *sharedSecret = NULL;
    822    PRUint8 suiteIdBuf[5];
    823    PRUint8 *walker;
    824    PORT_Memcpy(suiteIdBuf, KEM_LABEL, strlen(KEM_LABEL));
    825    SECItem suiteIdItem = { siBuffer, suiteIdBuf, sizeof(suiteIdBuf) };
    826    PORT_Assert(cx && ikm && kemContext && out);
    827 
    828    walker = &suiteIdBuf[3];
    829    walker = encodeNumber(cx->kemParams->id, walker, 2);
    830 
    831    rv = pk11_hpke_LabeledExtract(cx, NULL, &suiteIdItem, EAE_PRK_LABEL,
    832                                  cx->kemParams->hashMech, strlen(EAE_PRK_LABEL),
    833                                  ikm, &eaePrk);
    834    CHECK_RV(rv);
    835 
    836    rv = pk11_hpke_LabeledExpand(cx, eaePrk, &suiteIdItem, SH_SEC_LABEL, strlen(SH_SEC_LABEL),
    837                                 kemContext, cx->kemParams->Nsecret, cx->kemParams->hashMech,
    838                                 &sharedSecret, NULL);
    839    CHECK_RV(rv);
    840    *out = sharedSecret;
    841 
    842 CLEANUP:
    843    if (rv != SECSuccess) {
    844        PK11_FreeSymKey(sharedSecret);
    845    }
    846    PK11_FreeSymKey(eaePrk);
    847    return rv;
    848 }
    849 
    850 static SECStatus
    851 pk11_hpke_Encap(HpkeContext *cx, const SECKEYPublicKey *pkE, SECKEYPrivateKey *skE,
    852                SECKEYPublicKey *pkR)
    853 {
    854    SECStatus rv;
    855    PK11SymKey *dh = NULL;
    856    SECItem *kemContext = NULL;
    857    SECItem *encPkR = NULL;
    858    unsigned int tmpLen;
    859 
    860    PORT_Assert(cx && skE && pkE && pkR);
    861 
    862    rv = pk11_hpke_CheckKeys(cx, pkE, skE);
    863    CHECK_RV(rv);
    864    rv = pk11_hpke_CheckKeys(cx, pkR, NULL);
    865    CHECK_RV(rv);
    866 
    867    dh = PK11_PubDeriveWithKDF(skE, pkR, PR_FALSE, NULL, NULL, CKM_ECDH1_DERIVE,
    868                               CKM_SHA512_HMAC /* unused */, CKA_DERIVE, 0,
    869                               CKD_NULL, NULL, NULL);
    870    CHECK_FAIL(!dh);
    871 
    872    /* Encapsulate our sender public key. Many use cases
    873     * (including ECH) require that the application fetch
    874     * this value, so do it once and store into the cx. */
    875    rv = PK11_HPKE_Serialize(pkE, NULL, &tmpLen, 0);
    876    CHECK_RV(rv);
    877    cx->encapPubKey = SECITEM_AllocItem(NULL, NULL, tmpLen);
    878    CHECK_FAIL(!cx->encapPubKey);
    879    rv = PK11_HPKE_Serialize(pkE, cx->encapPubKey->data,
    880                             &cx->encapPubKey->len, cx->encapPubKey->len);
    881    CHECK_RV(rv);
    882 
    883    rv = PK11_HPKE_Serialize(pkR, NULL, &tmpLen, 0);
    884    CHECK_RV(rv);
    885 
    886    kemContext = SECITEM_AllocItem(NULL, NULL, cx->encapPubKey->len + tmpLen);
    887    CHECK_FAIL(!kemContext);
    888 
    889    PORT_Memcpy(kemContext->data, cx->encapPubKey->data, cx->encapPubKey->len);
    890    rv = PK11_HPKE_Serialize(pkR, &kemContext->data[cx->encapPubKey->len], &tmpLen, tmpLen);
    891    CHECK_RV(rv);
    892 
    893    rv = pk11_hpke_ExtractAndExpand(cx, dh, kemContext, &cx->sharedSecret);
    894    CHECK_RV(rv);
    895 
    896 CLEANUP:
    897    if (rv != SECSuccess) {
    898        PK11_FreeSymKey(cx->sharedSecret);
    899        cx->sharedSecret = NULL;
    900    }
    901    SECITEM_FreeItem(encPkR, PR_TRUE);
    902    SECITEM_FreeItem(kemContext, PR_TRUE);
    903    PK11_FreeSymKey(dh);
    904    return rv;
    905 }
    906 
    907 SECStatus
    908 PK11_HPKE_ExportSecret(const HpkeContext *cx, const SECItem *info, unsigned int L,
    909                       PK11SymKey **out)
    910 {
    911    SECStatus rv;
    912    PK11SymKey *exported;
    913    PRUint8 suiteIdBuf[10];
    914    PRUint8 *walker;
    915    PORT_Memcpy(suiteIdBuf, HPKE_LABEL, strlen(HPKE_LABEL));
    916    SECItem suiteIdItem = { siBuffer, suiteIdBuf, sizeof(suiteIdBuf) };
    917 
    918    /* Arbitrary info length limit well under the specified max. */
    919    if (!cx || !info || (!info->data && info->len) || info->len > 0xFFFF ||
    920        !L || (L > 255 * cx->kdfParams->Nh)) {
    921        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    922        return SECFailure;
    923    }
    924 
    925    walker = &suiteIdBuf[4];
    926    walker = encodeNumber(cx->kemParams->id, walker, 2);
    927    walker = encodeNumber(cx->kdfParams->id, walker, 2);
    928    walker = encodeNumber(cx->aeadParams->id, walker, 2);
    929 
    930    rv = pk11_hpke_LabeledExpand(cx, cx->exporterSecret, &suiteIdItem, SEC_LABEL,
    931                                 strlen(SEC_LABEL), info, L, cx->kdfParams->mech,
    932                                 &exported, NULL);
    933    CHECK_RV(rv);
    934    *out = exported;
    935 
    936 CLEANUP:
    937    return rv;
    938 }
    939 
    940 PK11SymKey *
    941 PK11_HPKE_GetSharedSecret(const HpkeContext *cx)
    942 {
    943    return cx->sharedSecret;
    944 }
    945 
    946 static SECStatus
    947 pk11_hpke_Decap(HpkeContext *cx, const SECKEYPublicKey *pkR, SECKEYPrivateKey *skR,
    948                const SECItem *encS)
    949 {
    950    SECStatus rv;
    951    PK11SymKey *dh = NULL;
    952    SECItem *encR = NULL;
    953    SECItem *kemContext = NULL;
    954    SECKEYPublicKey *pkS = NULL;
    955    unsigned int tmpLen;
    956 
    957    if (!cx || !skR || !pkR || !encS || !encS->data || !encS->len) {
    958        PORT_SetError(SEC_ERROR_INVALID_ARGS);
    959        return SECFailure;
    960    }
    961 
    962    rv = PK11_HPKE_Deserialize(cx, encS->data, encS->len, &pkS);
    963    CHECK_RV(rv);
    964 
    965    rv = pk11_hpke_CheckKeys(cx, pkR, skR);
    966    CHECK_RV(rv);
    967    rv = pk11_hpke_CheckKeys(cx, pkS, NULL);
    968    CHECK_RV(rv);
    969 
    970    dh = PK11_PubDeriveWithKDF(skR, pkS, PR_FALSE, NULL, NULL, CKM_ECDH1_DERIVE,
    971                               CKM_SHA512_HMAC /* unused */, CKA_DERIVE, 0,
    972                               CKD_NULL, NULL, NULL);
    973    CHECK_FAIL(!dh);
    974 
    975    /* kem_context = concat(enc, pkRm) */
    976    rv = PK11_HPKE_Serialize(pkR, NULL, &tmpLen, 0);
    977    CHECK_RV(rv);
    978 
    979    kemContext = SECITEM_AllocItem(NULL, NULL, encS->len + tmpLen);
    980    CHECK_FAIL(!kemContext);
    981 
    982    PORT_Memcpy(kemContext->data, encS->data, encS->len);
    983    rv = PK11_HPKE_Serialize(pkR, &kemContext->data[encS->len], &tmpLen,
    984                             kemContext->len - encS->len);
    985    CHECK_RV(rv);
    986    rv = pk11_hpke_ExtractAndExpand(cx, dh, kemContext, &cx->sharedSecret);
    987    CHECK_RV(rv);
    988 
    989    /* Store the sender serialized public key, which
    990     * may be required by application use cases. */
    991    cx->encapPubKey = SECITEM_DupItem(encS);
    992    CHECK_FAIL(!cx->encapPubKey);
    993 
    994 CLEANUP:
    995    if (rv != SECSuccess) {
    996        PK11_FreeSymKey(cx->sharedSecret);
    997        cx->sharedSecret = NULL;
    998    }
    999    PK11_FreeSymKey(dh);
   1000    SECKEY_DestroyPublicKey(pkS);
   1001    SECITEM_FreeItem(encR, PR_TRUE);
   1002    SECITEM_ZfreeItem(kemContext, PR_TRUE);
   1003    return rv;
   1004 }
   1005 
   1006 const SECItem *
   1007 PK11_HPKE_GetEncapPubKey(const HpkeContext *cx)
   1008 {
   1009    if (!cx) {
   1010        return NULL;
   1011    }
   1012    return cx->encapPubKey;
   1013 }
   1014 
   1015 static SECStatus
   1016 pk11_hpke_KeySchedule(HpkeContext *cx, const SECItem *info)
   1017 {
   1018    SECStatus rv;
   1019    SECItem contextItem = { siBuffer, NULL, 0 };
   1020    unsigned int len;
   1021    unsigned int off;
   1022    PK11SymKey *secret = NULL;
   1023    SECItem *pskIdHash = NULL;
   1024    SECItem *infoHash = NULL;
   1025    PRUint8 suiteIdBuf[10];
   1026    PRUint8 *walker;
   1027    PORT_Memcpy(suiteIdBuf, HPKE_LABEL, strlen(HPKE_LABEL));
   1028    SECItem suiteIdItem = { siBuffer, suiteIdBuf, sizeof(suiteIdBuf) };
   1029    PORT_Assert(cx && info && cx->psk && cx->pskId);
   1030 
   1031    walker = &suiteIdBuf[4];
   1032    walker = encodeNumber(cx->kemParams->id, walker, 2);
   1033    walker = encodeNumber(cx->kdfParams->id, walker, 2);
   1034    walker = encodeNumber(cx->aeadParams->id, walker, 2);
   1035 
   1036    rv = pk11_hpke_LabeledExtractData(cx, NULL, &suiteIdItem, PSK_ID_LABEL,
   1037                                      strlen(PSK_ID_LABEL), cx->pskId, &pskIdHash);
   1038    CHECK_RV(rv);
   1039    rv = pk11_hpke_LabeledExtractData(cx, NULL, &suiteIdItem, INFO_LABEL,
   1040                                      strlen(INFO_LABEL), info, &infoHash);
   1041    CHECK_RV(rv);
   1042 
   1043    // Make the context string
   1044    len = sizeof(cx->mode) + pskIdHash->len + infoHash->len;
   1045    CHECK_FAIL(!SECITEM_AllocItem(NULL, &contextItem, len));
   1046    off = 0;
   1047    PORT_Memcpy(&contextItem.data[off], &cx->mode, sizeof(cx->mode));
   1048    off += sizeof(cx->mode);
   1049    PORT_Memcpy(&contextItem.data[off], pskIdHash->data, pskIdHash->len);
   1050    off += pskIdHash->len;
   1051    PORT_Memcpy(&contextItem.data[off], infoHash->data, infoHash->len);
   1052    off += infoHash->len;
   1053 
   1054    // Compute the keys
   1055    rv = pk11_hpke_LabeledExtract(cx, cx->sharedSecret, &suiteIdItem, SECRET_LABEL,
   1056                                  cx->kdfParams->mech, strlen(SECRET_LABEL),
   1057                                  cx->psk, &secret);
   1058    CHECK_RV(rv);
   1059    rv = pk11_hpke_LabeledExpand(cx, secret, &suiteIdItem, KEY_LABEL, strlen(KEY_LABEL),
   1060                                 &contextItem, cx->aeadParams->Nk, cx->kdfParams->mech,
   1061                                 &cx->key, NULL);
   1062    CHECK_RV(rv);
   1063    rv = pk11_hpke_LabeledExpand(cx, secret, &suiteIdItem, NONCE_LABEL, strlen(NONCE_LABEL),
   1064                                 &contextItem, cx->aeadParams->Nn, cx->kdfParams->mech,
   1065                                 NULL, &cx->baseNonce);
   1066    CHECK_RV(rv);
   1067    rv = pk11_hpke_LabeledExpand(cx, secret, &suiteIdItem, EXP_LABEL, strlen(EXP_LABEL),
   1068                                 &contextItem, cx->kdfParams->Nh, cx->kdfParams->mech,
   1069                                 &cx->exporterSecret, NULL);
   1070    CHECK_RV(rv);
   1071 
   1072 CLEANUP:
   1073    /* If !SECSuccess, callers will tear down the context. */
   1074    PK11_FreeSymKey(secret);
   1075    SECITEM_FreeItem(&contextItem, PR_FALSE);
   1076    SECITEM_FreeItem(infoHash, PR_TRUE);
   1077    SECITEM_FreeItem(pskIdHash, PR_TRUE);
   1078    return rv;
   1079 }
   1080 
   1081 SECStatus
   1082 PK11_HPKE_SetupR(HpkeContext *cx, const SECKEYPublicKey *pkR, SECKEYPrivateKey *skR,
   1083                 const SECItem *enc, const SECItem *info)
   1084 {
   1085    SECStatus rv;
   1086    SECItem empty = { siBuffer, NULL, 0 };
   1087 
   1088    CHECK_FAIL_ERR((!cx || !skR || !info || !enc || !enc->data || !enc->len),
   1089                   SEC_ERROR_INVALID_ARGS);
   1090    /* Already setup */
   1091    CHECK_FAIL_ERR((cx->aeadContext), SEC_ERROR_INVALID_STATE);
   1092 
   1093    rv = pk11_hpke_Decap(cx, pkR, skR, enc);
   1094    CHECK_RV(rv);
   1095    rv = pk11_hpke_KeySchedule(cx, info);
   1096    CHECK_RV(rv);
   1097 
   1098    /* Store the key context for subsequent calls to Open().
   1099     * PK11_CreateContextBySymKey refs the key internally. */
   1100    PORT_Assert(cx->key);
   1101    cx->aeadContext = PK11_CreateContextBySymKey(cx->aeadParams->mech,
   1102                                                 CKA_NSS_MESSAGE | CKA_DECRYPT,
   1103                                                 cx->key, &empty);
   1104    CHECK_FAIL_ERR((!cx->aeadContext), SEC_ERROR_LIBRARY_FAILURE);
   1105 
   1106 CLEANUP:
   1107    if (rv != SECSuccess) {
   1108        /* Clear everything past NewContext. */
   1109        PK11_HPKE_DestroyContext(cx, PR_FALSE);
   1110    }
   1111    return rv;
   1112 }
   1113 
   1114 SECStatus
   1115 PK11_HPKE_SetupS(HpkeContext *cx, const SECKEYPublicKey *pkE, SECKEYPrivateKey *skE,
   1116                 SECKEYPublicKey *pkR, const SECItem *info)
   1117 {
   1118    SECStatus rv;
   1119    SECItem empty = { siBuffer, NULL, 0 };
   1120    SECKEYPublicKey *tmpPkE = NULL;
   1121    SECKEYPrivateKey *tmpSkE = NULL;
   1122    CHECK_FAIL_ERR((!cx || !pkR || !info || (!!skE != !!pkE)), SEC_ERROR_INVALID_ARGS);
   1123    /* Already setup */
   1124    CHECK_FAIL_ERR((cx->aeadContext), SEC_ERROR_INVALID_STATE);
   1125 
   1126    /* If NULL was passed for the local keypair, generate one. */
   1127    if (skE == NULL) {
   1128        rv = pk11_hpke_GenerateKeyPair(cx, &tmpPkE, &tmpSkE);
   1129        if (rv != SECSuccess) {
   1130            /* Code set */
   1131            return SECFailure;
   1132        }
   1133        rv = pk11_hpke_Encap(cx, tmpPkE, tmpSkE, pkR);
   1134    } else {
   1135        rv = pk11_hpke_Encap(cx, pkE, skE, pkR);
   1136    }
   1137    CHECK_RV(rv);
   1138 
   1139    SECItem defaultInfo = { siBuffer, NULL, 0 };
   1140    if (!info || !info->data) {
   1141        info = &defaultInfo;
   1142    }
   1143    rv = pk11_hpke_KeySchedule(cx, info);
   1144    CHECK_RV(rv);
   1145 
   1146    PORT_Assert(cx->key);
   1147    cx->aeadContext = PK11_CreateContextBySymKey(cx->aeadParams->mech,
   1148                                                 CKA_NSS_MESSAGE | CKA_ENCRYPT,
   1149                                                 cx->key, &empty);
   1150    CHECK_FAIL_ERR((!cx->aeadContext), SEC_ERROR_LIBRARY_FAILURE);
   1151 
   1152 CLEANUP:
   1153    if (rv != SECSuccess) {
   1154        /* Clear everything past NewContext. */
   1155        PK11_HPKE_DestroyContext(cx, PR_FALSE);
   1156    }
   1157    SECKEY_DestroyPrivateKey(tmpSkE);
   1158    SECKEY_DestroyPublicKey(tmpPkE);
   1159    return rv;
   1160 }
   1161 
   1162 SECStatus
   1163 PK11_HPKE_Seal(HpkeContext *cx, const SECItem *aad, const SECItem *pt,
   1164               SECItem **out)
   1165 {
   1166    SECStatus rv;
   1167    PRUint8 ivOut[12] = { 0 };
   1168    SECItem *ct = NULL;
   1169    size_t maxOut;
   1170    unsigned char tagBuf[HASH_LENGTH_MAX];
   1171    size_t tagLen;
   1172    unsigned int fixedBits;
   1173 
   1174    /* aad may be NULL, PT may be zero-length but not NULL. */
   1175    if (!cx || !cx->aeadContext ||
   1176        (aad && aad->len && !aad->data) ||
   1177        !pt || (pt->len && !pt->data) ||
   1178        !out) {
   1179        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1180        return SECFailure;
   1181    }
   1182 
   1183    PORT_Assert(cx->baseNonce->len == sizeof(ivOut));
   1184    PORT_Memcpy(ivOut, cx->baseNonce->data, cx->baseNonce->len);
   1185 
   1186    tagLen = cx->aeadParams->tagLen;
   1187    maxOut = pt->len + tagLen;
   1188    fixedBits = (cx->baseNonce->len - 8) * 8;
   1189    ct = SECITEM_AllocItem(NULL, NULL, maxOut);
   1190    CHECK_FAIL(!ct);
   1191 
   1192    rv = PK11_AEADOp(cx->aeadContext,
   1193                     CKG_GENERATE_COUNTER_XOR, fixedBits,
   1194                     ivOut, sizeof(ivOut),
   1195                     aad ? aad->data : NULL,
   1196                     aad ? aad->len : 0,
   1197                     ct->data, (int *)&ct->len, maxOut,
   1198                     tagBuf, tagLen,
   1199                     pt->data, pt->len);
   1200    CHECK_RV(rv);
   1201    CHECK_FAIL_ERR((ct->len > maxOut - tagLen), SEC_ERROR_LIBRARY_FAILURE);
   1202 
   1203    /* Append the tag to the ciphertext. */
   1204    PORT_Memcpy(&ct->data[ct->len], tagBuf, tagLen);
   1205    ct->len += tagLen;
   1206    *out = ct;
   1207 
   1208 CLEANUP:
   1209    if (rv != SECSuccess) {
   1210        SECITEM_ZfreeItem(ct, PR_TRUE);
   1211    }
   1212    return rv;
   1213 }
   1214 
   1215 /* PKCS #11 defines the IV generator function to be ignored on
   1216 * decrypt (i.e. it uses the nonce input, as provided, as the IV).
   1217 * The sequence number is kept independently on each endpoint and
   1218 * the XORed IV is not transmitted, so we have to do our own IV
   1219 * construction XOR outside of the token. */
   1220 static SECStatus
   1221 pk11_hpke_makeIv(HpkeContext *cx, PRUint8 *iv, size_t ivLen)
   1222 {
   1223    unsigned int counterLen = sizeof(cx->sequenceNumber);
   1224    PORT_Assert(cx->baseNonce->len == ivLen);
   1225    PORT_Assert(counterLen == 8);
   1226    if (cx->sequenceNumber == PR_UINT64(0xffffffffffffffff)) {
   1227        /* Overflow */
   1228        PORT_SetError(SEC_ERROR_INVALID_KEY);
   1229        return SECFailure;
   1230    }
   1231 
   1232    PORT_Memcpy(iv, cx->baseNonce->data, cx->baseNonce->len);
   1233    for (size_t i = 0; i < counterLen; i++) {
   1234        iv[cx->baseNonce->len - 1 - i] ^=
   1235            PORT_GET_BYTE_BE(cx->sequenceNumber,
   1236                             counterLen - 1 - i, counterLen);
   1237    }
   1238    return SECSuccess;
   1239 }
   1240 
   1241 SECStatus
   1242 PK11_HPKE_Open(HpkeContext *cx, const SECItem *aad,
   1243               const SECItem *ct, SECItem **out)
   1244 {
   1245    SECStatus rv;
   1246    PRUint8 constructedNonce[12] = { 0 };
   1247    unsigned int tagLen;
   1248    SECItem *pt = NULL;
   1249 
   1250    /* aad may be NULL, CT may be zero-length but not NULL. */
   1251    if ((!cx || !cx->aeadContext || !ct || !out) ||
   1252        (aad && aad->len && !aad->data) ||
   1253        (!ct->data || (ct->data && !ct->len))) {
   1254        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1255        return SECFailure;
   1256    }
   1257    tagLen = cx->aeadParams->tagLen;
   1258    CHECK_FAIL_ERR((ct->len < tagLen), SEC_ERROR_INVALID_ARGS);
   1259 
   1260    pt = SECITEM_AllocItem(NULL, NULL, ct->len);
   1261    CHECK_FAIL(!pt);
   1262 
   1263    rv = pk11_hpke_makeIv(cx, constructedNonce, sizeof(constructedNonce));
   1264    CHECK_RV(rv);
   1265 
   1266    rv = PK11_AEADOp(cx->aeadContext, CKG_NO_GENERATE, 0,
   1267                     constructedNonce, sizeof(constructedNonce),
   1268                     aad ? aad->data : NULL,
   1269                     aad ? aad->len : 0,
   1270                     pt->data, (int *)&pt->len, pt->len,
   1271                     &ct->data[ct->len - tagLen], tagLen,
   1272                     ct->data, ct->len - tagLen);
   1273    CHECK_RV(rv);
   1274    cx->sequenceNumber++;
   1275    *out = pt;
   1276 
   1277 CLEANUP:
   1278    if (rv != SECSuccess) {
   1279        SECITEM_ZfreeItem(pt, PR_TRUE);
   1280    }
   1281    return rv;
   1282 }