Bug Summary

File:root/firefox-clang/security/nss/lib/pk11wrap/pk11hpke.c
Warning:line 1065, column 5
Value stored to 'off' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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