Bug Summary

File:s/lib/pk11wrap/pk11hpke.c
Warning:line 829, column 5
Value stored to 'walker' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -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 -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/lib/pk11wrap -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/lib/pk11wrap -resource-dir /usr/lib/llvm-18/lib/clang/18 -D HAVE_STRERROR -D LINUX -D linux -D XP_UNIX -D XP_UNIX -D SHLIB_SUFFIX="so" -D SHLIB_PREFIX="lib" -D NSS_SHLIB_VERSION="3" -D SOFTOKEN_SHLIB_VERSION="3" -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D NSS_DISABLE_SSE3 -D NSS_NO_INIT_SUPPORT -D USE_UTIL_DIRECTLY -D NO_NSPR_10_SUPPORT -D SSL_DISABLE_DEPRECATED_CIPHER_SUITE_NAMES -I ../../../dist/Linux4.19_x86_64_gcc_glibc_PTH_64_DBG.OBJ/include -I ../../../dist/public/nss -I ../../../dist/private/nss -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=c99 -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-05-18-082241-28900-1 -x c 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 "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_VERSION2 2
22
23static const char *V1_LABEL = "HPKE-v1";
24static const char *EXP_LABEL = "exp";
25static const char *HPKE_LABEL = "HPKE";
26static const char *INFO_LABEL = "info_hash";
27static const char *KEM_LABEL = "KEM";
28static const char *KEY_LABEL = "key";
29static const char *NONCE_LABEL = "base_nonce";
30static const char *PSK_ID_LABEL = "psk_id_hash";
31static const char *SECRET_LABEL = "secret";
32static const char *SEC_LABEL = "sec";
33static const char *EAE_PRK_LABEL = "eae_prk";
34static const char *SH_SEC_LABEL = "shared_secret";
35
36struct 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
52static const hpkeKemParams kemParams[] = {
53 /* KEM, Nsk, Nsecret, Npk, oidTag, Hash mechanism */
54 { HpkeDhKemX25519Sha256, 32, 32, 32, SEC_OID_CURVE25519, CKM_SHA2560x00000250UL },
55};
56
57#define MAX_WRAPPED_EXP_LEN72 72 // Largest kdfParams->Nh + 8
58static const hpkeKdfParams kdfParams[] = {
59 /* KDF, Nh, mechanism */
60 { HpkeKdfHkdfSha256, SHA256_LENGTH32, CKM_SHA2560x00000250UL },
61 { HpkeKdfHkdfSha384, SHA384_LENGTH48, CKM_SHA3840x00000260UL },
62 { HpkeKdfHkdfSha512, SHA512_LENGTH64, CKM_SHA5120x00000270UL },
63};
64#define MAX_WRAPPED_KEY_LEN40 40 // Largest aeadParams->Nk + 8
65static const hpkeAeadParams aeadParams[] = {
66 /* AEAD, Nk, Nn, tagLen, mechanism */
67 { HpkeAeadAes128Gcm, 16, 12, 16, CKM_AES_GCM0x00001087UL },
68 { HpkeAeadAes256Gcm, 32, 12, 16, CKM_AES_GCM0x00001087UL },
69 { HpkeAeadChaCha20Poly1305, 32, 12, 16, CKM_CHACHA20_POLY13050x00004021UL },
70};
71
72static inline const hpkeKemParams *
73kemId2Params(HpkeKemId kemId)
74{
75 switch (kemId) {
76 case HpkeDhKemX25519Sha256:
77 return &kemParams[0];
78 default:
79 return NULL((void*)0);
80 }
81}
82
83static inline const hpkeKdfParams *
84kdfId2Params(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((void*)0);
95 }
96}
97
98static const inline hpkeAeadParams *
99aeadId2Params(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((void*)0);
110 }
111}
112
113static PRUint8 *
114encodeNumber(PRUint64 value, PRUint8 *b, size_t count)
115{
116 PRUint64 encoded;
117 PORT_Assert(b && count > 0 && count <= sizeof(encoded))((b && count > 0 && count <= sizeof(encoded
))?((void)0):PR_Assert("b && count > 0 && count <= sizeof(encoded)"
,"pk11hpke.c",117))
;
118
119 encoded = PR_htonll(value);
120 PORT_Memcpymemcpy(b, ((unsigned char *)(&encoded)) + (sizeof(encoded) - count),
121 count);
122 return b + count;
123}
124
125static PRUint8 *
126decodeNumber(PRUint64 *value, PRUint8 *b, size_t count)
127{
128 unsigned int i;
129 PRUint64 number = 0;
130 PORT_Assert(b && value && count <= sizeof(*value))((b && value && count <= sizeof(*value))?(
(void)0):PR_Assert("b && value && count <= sizeof(*value)"
,"pk11hpke.c",130))
;
131
132 for (i = 0; i < count; i++) {
133 number = (number << 8) + b[i];
134 }
135 *value = number;
136 return b + count;
137}
138
139SECStatus
140PK11_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_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
149 return SECFailure;
150 }
151 return SECSuccess;
152}
153
154HpkeContext *
155PK11_HPKE_NewContext(HpkeKemId kemId, HpkeKdfId kdfId, HpkeAeadId aeadId,
156 PK11SymKey *psk, const SECItem *pskId)
157{
158 SECStatus rv = SECSuccess;
159 PK11SlotInfo *slot = NULL((void*)0);
160 HpkeContext *cx = NULL((void*)0);
161 /* Both the PSK and the PSK ID default to empty. */
162 SECItem emptyItem = { siBuffer, NULL((void*)0), 0 };
163
164 cx = PORT_ZNew(HpkeContext)(HpkeContext *)PORT_ZAlloc_Util(sizeof(HpkeContext));
165 if (!cx) {
166 return NULL((void*)0);
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)if (((!!psk != !!pskId))) { PORT_SetError_Util((SEC_ERROR_INVALID_ARGS
)); rv = SECFailure; goto cleanup; }
;
173 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; }
174 SEC_ERROR_INVALID_ARGS)if ((!cx->kemParams || !cx->kdfParams || !cx->aeadParams
)) { PORT_SetError_Util((SEC_ERROR_INVALID_ARGS)); rv = SECFailure
; goto cleanup; }
;
175
176 /* Import the provided PSK or the default. */
177 slot = PK11_GetBestSlot(CKM_EC_KEY_PAIR_GEN0x00001040UL, NULL((void*)0));
178 CHECK_FAIL(!slot)if ((!slot)) { rv = SECFailure; goto cleanup; };
179 if (psk) {
180 cx->psk = PK11_ReferenceSymKey(psk);
181 cx->pskId = SECITEM_DupItemSECITEM_DupItem_Util(pskId);
182 } else {
183 cx->psk = PK11_ImportDataKey(slot, CKM_HKDF_DATA0x0000402bUL, PK11_OriginUnwrap,
184 CKA_DERIVE0x0000010CUL, &emptyItem, NULL((void*)0));
185 cx->pskId = SECITEM_DupItemSECITEM_DupItem_Util(&emptyItem);
186 }
187 CHECK_FAIL(!cx->psk)if ((!cx->psk)) { rv = SECFailure; goto cleanup; };
188 CHECK_FAIL(!cx->pskId)if ((!cx->pskId)) { rv = SECFailure; goto cleanup; };
189
190CLEANUP((rv == SECSuccess)?((void)0):PR_Assert("rv == SECSuccess","pk11hpke.c"
,190)); cleanup
:
191 if (rv != SECSuccess) {
192 PK11_FreeSymKey(cx->psk);
193 SECITEM_FreeItemSECITEM_FreeItem_Util(cx->pskId, PR_TRUE1);
194 cx->pskId = NULL((void*)0);
195 cx->psk = NULL((void*)0);
196 PORT_FreePORT_Free_Util(cx);
197 cx = NULL((void*)0);
198 }
199 if (slot) {
200 PK11_FreeSlot(slot);
201 }
202 return cx;
203}
204
205void
206PK11_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_TRUE1);
214 cx->aeadContext = NULL((void*)0);
215 }
216 PK11_FreeSymKey(cx->exporterSecret);
217 PK11_FreeSymKey(cx->sharedSecret);
218 PK11_FreeSymKey(cx->key);
219 PK11_FreeSymKey(cx->psk);
220 SECITEM_FreeItemSECITEM_FreeItem_Util(cx->pskId, PR_TRUE1);
221 SECITEM_FreeItemSECITEM_FreeItem_Util(cx->baseNonce, PR_TRUE1);
222 SECITEM_FreeItemSECITEM_FreeItem_Util(cx->encapPubKey, PR_TRUE1);
223 cx->exporterSecret = NULL((void*)0);
224 cx->sharedSecret = NULL((void*)0);
225 cx->key = NULL((void*)0);
226 cx->psk = NULL((void*)0);
227 cx->pskId = NULL((void*)0);
228 cx->baseNonce = NULL((void*)0);
229 cx->encapPubKey = NULL((void*)0);
230 if (freeit) {
231 PORT_ZFreePORT_ZFree_Util(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_LEN25 25 /* Fixed size plus 2B for each variable. */
250#define REMAINING_BYTES(walker, buf)buf->len - (walker - buf->data) \
251 buf->len - (walker - buf->data)
252SECStatus
253PK11_HPKE_ExportContext(const HpkeContext *cx, PK11SymKey *wrapKey, SECItem **serialized)
254{
255 SECStatus rv;
256 size_t allocLen;
257 PRUint8 *walker;
258 SECItem *keyBytes = NULL((void*)0); // Maybe wrapped
259 SECItem *exporterBytes = NULL((void*)0); // Maybe wrapped
260 SECItem *serializedCx = NULL((void*)0);
261 PRUint8 wrappedKeyBytes[MAX_WRAPPED_KEY_LEN40] = { 0 };
262 PRUint8 wrappedExpBytes[MAX_WRAPPED_EXP_LEN72] = { 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)if (((!cx || !cx->aeadContext || !serialized))) { PORT_SetError_Util
((SEC_ERROR_INVALID_ARGS)); rv = SECFailure; goto cleanup; }
;
267 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; }
268 SEC_ERROR_NOT_A_RECIPIENT)if (((cx->aeadContext->operation != (0x82000000L | 0x00000105UL
)))) { PORT_SetError_Util((SEC_ERROR_NOT_A_RECIPIENT)); rv = SECFailure
; goto cleanup; }
;
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_KWP0x0000210BUL, NULL((void*)0), wrapKey,
274 cx->key, &wrappedKey);
275 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
276 rv = PK11_WrapSymKey(CKM_AES_KEY_WRAP_KWP0x0000210BUL, NULL((void*)0), wrapKey,
277 cx->exporterSecret, &wrappedExp);
278 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
279
280 keyBytes = &wrappedKey;
281 exporterBytes = &wrappedExp;
282 } else {
283 rv = PK11_ExtractKeyValue(cx->key);
284 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
285 keyBytes = PK11_GetKeyData(cx->key);
286 CHECK_FAIL(!keyBytes)if ((!keyBytes)) { rv = SECFailure; goto cleanup; };
287 PORT_Assert(keyBytes->len == cx->aeadParams->Nk)((keyBytes->len == cx->aeadParams->Nk)?((void)0):PR_Assert
("keyBytes->len == cx->aeadParams->Nk","pk11hpke.c",
287))
;
288
289 rv = PK11_ExtractKeyValue(cx->exporterSecret);
290 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
291 exporterBytes = PK11_GetKeyData(cx->exporterSecret);
292 CHECK_FAIL(!exporterBytes)if ((!exporterBytes)) { rv = SECFailure; goto cleanup; };
293 PORT_Assert(exporterBytes->len == cx->kdfParams->Nh)((exporterBytes->len == cx->kdfParams->Nh)?((void)0)
:PR_Assert("exporterBytes->len == cx->kdfParams->Nh"
,"pk11hpke.c",293))
;
294 }
295
296 allocLen = EXPORTED_CTX_BASE_LEN25 + 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_AllocItemSECITEM_AllocItem_Util(NULL((void*)0), NULL((void*)0), allocLen);
301 CHECK_FAIL(!serializedCx)if ((!serializedCx)) { rv = SECFailure; goto cleanup; };
302
303 walker = &serializedCx->data[0];
304 *(walker)++ = (PRUint8)SERIALIZATION_VERSION2;
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_Memcpymemcpy(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_Memcpymemcpy(walker, cx->baseNonce->data, cx->baseNonce->len);
320 walker += cx->baseNonce->len;
321
322 /* key. */
323 walker = encodeNumber(keyBytes->len, walker, 2);
324 PORT_Memcpymemcpy(walker, keyBytes->data, keyBytes->len);
325 walker += keyBytes->len;
326
327 /* exporter_secret. */
328 walker = encodeNumber(exporterBytes->len, walker, 2);
329 PORT_Memcpymemcpy(walker, exporterBytes->data, exporterBytes->len);
330 walker += exporterBytes->len;
331
332 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; }
333 SEC_ERROR_LIBRARY_FAILURE)if ((serializedCx->len - (walker - serializedCx->data) !=
0)) { PORT_SetError_Util((SEC_ERROR_LIBRARY_FAILURE)); rv = SECFailure
; goto cleanup; }
;
334 *serialized = serializedCx;
335
336CLEANUP((rv == SECSuccess)?((void)0):PR_Assert("rv == SECSuccess","pk11hpke.c"
,336)); cleanup
:
337 if (rv != SECSuccess) {
338 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(serializedCx, PR_TRUE1);
339 }
340 return rv;
341}
342
343HpkeContext *
344PK11_HPKE_ImportContext(const SECItem *serialized, PK11SymKey *wrapKey)
345{
346 SECStatus rv = SECSuccess;
347 HpkeContext *cx = NULL((void*)0);
348 PRUint8 *walker;
349 PRUint64 tmpn;
350 PRUint8 tmp8;
351 HpkeKemId kem;
352 HpkeKdfId kdf;
353 HpkeAeadId aead;
354 PK11SlotInfo *slot = NULL((void*)0);
355 PK11SymKey *tmpKey = NULL((void*)0);
356 SECItem tmpItem = { siBuffer, NULL((void*)0), 0 };
357 SECItem emptyItem = { siBuffer, NULL((void*)0), 0 };
358
359 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; }
360 SEC_ERROR_INVALID_ARGS)if (((!serialized || !serialized->data || serialized->len
== 0))) { PORT_SetError_Util((SEC_ERROR_INVALID_ARGS)); rv =
SECFailure; goto cleanup; }
;
361 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; }
;
362
363 walker = serialized->data;
364
365 tmp8 = *(walker++);
366 CHECK_FAIL_ERR((tmp8 != SERIALIZATION_VERSION), SEC_ERROR_BAD_DATA)if (((tmp8 != 2))) { PORT_SetError_Util((SEC_ERROR_BAD_DATA))
; rv = SECFailure; goto cleanup; }
;
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((void*)0), NULL((void*)0));
380 CHECK_FAIL(!cx)if ((!cx)) { rv = SECFailure; goto cleanup; };
381
382 walker = decodeNumber(&tmpn, walker, 2);
383 CHECK_FAIL_ERR((tmpn != HpkeModeBase && tmpn != HpkeModePsk),if (((tmpn != HpkeModeBase && tmpn != HpkeModePsk))) {
PORT_SetError_Util((SEC_ERROR_BAD_DATA)); rv = SECFailure; goto
cleanup; }
384 SEC_ERROR_BAD_DATA)if (((tmpn != HpkeModeBase && tmpn != HpkeModePsk))) {
PORT_SetError_Util((SEC_ERROR_BAD_DATA)); rv = SECFailure; goto
cleanup; }
;
385 cx->mode = (HpkeModeId)tmpn;
386
387 walker = decodeNumber(&cx->sequenceNumber, walker, 8);
388 slot = PK11_GetBestSlot(CKM_HKDF_DERIVE0x0000402aUL, NULL((void*)0));
389 CHECK_FAIL(!slot)if ((!slot)) { rv = SECFailure; goto cleanup; };
390
391 /* Import sender public key (serialized). */
392 walker = decodeNumber(&tmpn, walker, 2);
393 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; }
394 SEC_ERROR_BAD_DATA)if ((tmpn >= serialized->len - (walker - serialized->
data))) { PORT_SetError_Util((SEC_ERROR_BAD_DATA)); rv = SECFailure
; goto cleanup; }
;
395 tmpItem.data = walker;
396 tmpItem.len = tmpn;
397 cx->encapPubKey = SECITEM_DupItemSECITEM_DupItem_Util(&tmpItem);
398 CHECK_FAIL(!cx->encapPubKey)if ((!cx->encapPubKey)) { rv = SECFailure; goto cleanup; };
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)if ((tmpn != cx->aeadParams->Nn)) { PORT_SetError_Util(
(SEC_ERROR_BAD_DATA)); rv = SECFailure; goto cleanup; }
;
404 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; }
405 SEC_ERROR_BAD_DATA)if ((tmpn >= serialized->len - (walker - serialized->
data))) { PORT_SetError_Util((SEC_ERROR_BAD_DATA)); rv = SECFailure
; goto cleanup; }
;
406 tmpItem.data = walker;
407 tmpItem.len = tmpn;
408 cx->baseNonce = SECITEM_DupItemSECITEM_DupItem_Util(&tmpItem);
409 CHECK_FAIL(!cx->baseNonce)if ((!cx->baseNonce)) { rv = SECFailure; goto cleanup; };
410 walker += tmpItem.len;
411
412 /* Import key */
413 walker = decodeNumber(&tmpn, walker, 2);
414 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; }
415 SEC_ERROR_BAD_DATA)if ((tmpn >= serialized->len - (walker - serialized->
data))) { PORT_SetError_Util((SEC_ERROR_BAD_DATA)); rv = SECFailure
; goto cleanup; }
;
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_KWP0x0000210BUL,
421 NULL((void*)0), &tmpItem, cx->aeadParams->mech,
422 CKA_NSS_MESSAGE0x82000000L | CKA_DECRYPT0x00000105UL, 0);
423 CHECK_FAIL(!cx->key)if ((!cx->key)) { rv = SECFailure; goto cleanup; };
424 } else {
425 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; }
;
426 tmpKey = PK11_ImportSymKey(slot, cx->aeadParams->mech,
427 PK11_OriginUnwrap, CKA_NSS_MESSAGE0x82000000L | CKA_DECRYPT0x00000105UL,
428 &tmpItem, NULL((void*)0));
429 CHECK_FAIL(!tmpKey)if ((!tmpKey)) { rv = SECFailure; goto cleanup; };
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),if ((tmpn != serialized->len - (walker - serialized->data
))) { PORT_SetError_Util((SEC_ERROR_BAD_DATA)); rv = SECFailure
; goto cleanup; }
436 SEC_ERROR_BAD_DATA)if ((tmpn != serialized->len - (walker - serialized->data
))) { PORT_SetError_Util((SEC_ERROR_BAD_DATA)); rv = SECFailure
; goto cleanup; }
;
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_KWP0x0000210BUL,
443 NULL((void*)0), &tmpItem, cx->kdfParams->mech,
444 CKM_HKDF_DERIVE0x0000402aUL, 0);
445 CHECK_FAIL(!cx->exporterSecret)if ((!cx->exporterSecret)) { rv = SECFailure; goto cleanup
; }
;
446 } else {
447 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; }
;
448 tmpKey = PK11_ImportSymKey(slot, CKM_HKDF_DERIVE0x0000402aUL, PK11_OriginUnwrap,
449 CKA_DERIVE0x0000010CUL, &tmpItem, NULL((void*)0));
450 CHECK_FAIL(!tmpKey)if ((!tmpKey)) { rv = SECFailure; goto cleanup; };
451 cx->exporterSecret = tmpKey;
452 }
453
454 cx->aeadContext = PK11_CreateContextBySymKey(cx->aeadParams->mech,
455 CKA_NSS_MESSAGE0x82000000L | CKA_DECRYPT0x00000105UL,
456 cx->key, &emptyItem);
457
458CLEANUP((rv == SECSuccess)?((void)0):PR_Assert("rv == SECSuccess","pk11hpke.c"
,458)); cleanup
:
459 if (rv != SECSuccess) {
460 PK11_FreeSymKey(tmpKey);
461 PK11_HPKE_DestroyContext(cx, PR_TRUE1);
462 cx = NULL((void*)0);
463 }
464 if (slot) {
465 PK11_FreeSlot(slot);
466 }
467
468 return cx;
469}
470
471SECStatus
472PK11_HPKE_Serialize(const SECKEYPublicKey *pk, PRUint8 *buf, unsigned int *len, unsigned int maxLen)
473{
474 if (!pk || !len || pk->keyType != ecKey) {
475 PORT_SetErrorPORT_SetError_Util(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_SetErrorPORT_SetError_Util(SEC_ERROR_INPUT_LEN);
488 return SECFailure;
489 }
490
491 PORT_Memcpymemcpy(buf, pk->u.ec.publicValue.data, pk->u.ec.publicValue.len);
492 *len = pk->u.ec.publicValue.len;
493 return SECSuccess;
494};
495
496SECStatus
497PK11_HPKE_Deserialize(const HpkeContext *cx, const PRUint8 *enc,
498 unsigned int encLen, SECKEYPublicKey **outPubKey)
499{
500 SECStatus rv;
501 SECKEYPublicKey *pubKey = NULL((void*)0);
502 SECOidData *oidData = NULL((void*)0);
503 PLArenaPool *arena;
504
505 if (!cx || !enc || encLen == 0 || !outPubKey) {
506 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
507 return SECFailure;
508 }
509
510 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
511 CHECK_FAIL(!arena)if ((!arena)) { rv = SECFailure; goto cleanup; };
512 pubKey = PORT_ArenaZNew(arena, SECKEYPublicKey)(SECKEYPublicKey *)PORT_ArenaZAlloc_Util(arena, sizeof(SECKEYPublicKey
))
;
513 CHECK_FAIL(!pubKey)if ((!pubKey)) { rv = SECFailure; goto cleanup; };
514
515 pubKey->arena = arena;
516 pubKey->keyType = ecKey;
517 pubKey->pkcs11Slot = NULL((void*)0);
518 pubKey->pkcs11ID = CK_INVALID_HANDLE0;
519
520 rv = SECITEM_MakeItem(pubKey->arena, &pubKey->u.ec.publicValue,
521 enc, encLen);
522 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
523 pubKey->u.ec.encoding = ECPoint_Undefined;
524 pubKey->u.ec.size = 0;
525
526 oidData = SECOID_FindOIDByTagSECOID_FindOIDByTag_Util(cx->kemParams->oidTag);
527 CHECK_FAIL_ERR(!oidData, SEC_ERROR_INVALID_ALGORITHM)if ((!oidData)) { PORT_SetError_Util((SEC_ERROR_INVALID_ALGORITHM
)); rv = SECFailure; goto cleanup; }
;
528
529 // Create parameters.
530 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; }
531 2 + oidData->oid.len))if ((!SECITEM_AllocItem_Util(pubKey->arena, &pubKey->
u.ec.DEREncodedParams, 2 + oidData->oid.len))) { rv = SECFailure
; goto cleanup; }
;
532
533 // Set parameters.
534 pubKey->u.ec.DEREncodedParams.data[0] = SEC_ASN1_OBJECT_ID0x06;
535 pubKey->u.ec.DEREncodedParams.data[1] = oidData->oid.len;
536 PORT_Memcpymemcpy(pubKey->u.ec.DEREncodedParams.data + 2, oidData->oid.data, oidData->oid.len);
537 *outPubKey = pubKey;
538
539CLEANUP((rv == SECSuccess)?((void)0):PR_Assert("rv == SECSuccess","pk11hpke.c"
,539)); cleanup
:
540 if (rv != SECSuccess) {
541 SECKEY_DestroyPublicKey(pubKey);
542 }
543 return rv;
544};
545
546static SECStatus
547pk11_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_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_KEY);
554 return SECFailure;
555 }
556 pkTag = SECKEY_GetECCOid(&pk->u.ec.DEREncodedParams);
557 if (pkTag != cx->kemParams->oidTag) {
558 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_KEY);
559 return SECFailure;
560 }
561 for (i = 0; i < PR_ARRAY_SIZE(kemParams)(sizeof(kemParams)/sizeof((kemParams)[0])); i++) {
562 if (cx->kemParams->oidTag == kemParams[i].oidTag) {
563 return SECSuccess;
564 }
565 }
566
567 return SECFailure;
568}
569
570static SECStatus
571pk11_hpke_GenerateKeyPair(const HpkeContext *cx, SECKEYPublicKey **pkE,
572 SECKEYPrivateKey **skE)
573{
574 SECStatus rv = SECSuccess;
575 SECKEYPrivateKey *privKey = NULL((void*)0);
576 SECKEYPublicKey *pubKey = NULL((void*)0);
577 SECOidData *oidData = NULL((void*)0);
578 SECKEYECParams ecp;
579 PK11SlotInfo *slot = NULL((void*)0);
580 ecp.data = NULL((void*)0);
581 PORT_Assert(cx && skE && pkE)((cx && skE && pkE)?((void)0):PR_Assert("cx && skE && pkE"
,"pk11hpke.c",581))
;
582
583 oidData = SECOID_FindOIDByTagSECOID_FindOIDByTag_Util(cx->kemParams->oidTag);
584 CHECK_FAIL_ERR(!oidData, SEC_ERROR_INVALID_ALGORITHM)if ((!oidData)) { PORT_SetError_Util((SEC_ERROR_INVALID_ALGORITHM
)); rv = SECFailure; goto cleanup; }
;
585 ecp.data = PORT_AllocPORT_Alloc_Util(2 + oidData->oid.len);
586 CHECK_FAIL(!ecp.data)if ((!ecp.data)) { rv = SECFailure; goto cleanup; };
587
588 ecp.len = 2 + oidData->oid.len;
589 ecp.type = siDEROID;
590 ecp.data[0] = SEC_ASN1_OBJECT_ID0x06;
591 ecp.data[1] = oidData->oid.len;
592 PORT_Memcpymemcpy(&ecp.data[2], oidData->oid.data, oidData->oid.len);
593
594 slot = PK11_GetBestSlot(CKM_EC_KEY_PAIR_GEN0x00001040UL, NULL((void*)0));
595 CHECK_FAIL(!slot)if ((!slot)) { rv = SECFailure; goto cleanup; };
596
597 privKey = PK11_GenerateKeyPair(slot, CKM_EC_KEY_PAIR_GEN0x00001040UL, &ecp, &pubKey,
598 PR_FALSE0, PR_TRUE1, NULL((void*)0));
599 CHECK_FAIL_ERR((!privKey || !pubKey), SEC_ERROR_KEYGEN_FAIL)if (((!privKey || !pubKey))) { PORT_SetError_Util((SEC_ERROR_KEYGEN_FAIL
)); rv = SECFailure; goto cleanup; }
;
600 PORT_Assert(rv == SECSuccess)((rv == SECSuccess)?((void)0):PR_Assert("rv == SECSuccess","pk11hpke.c"
,600))
;
601 *skE = privKey;
602 *pkE = pubKey;
603
604CLEANUP((rv == SECSuccess)?((void)0):PR_Assert("rv == SECSuccess","pk11hpke.c"
,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_FreePORT_Free_Util(ecp.data);
613 return rv;
614}
615
616static inline SECItem *
617pk11_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((void*)0);
622 PRUint8 *walker;
623 out = SECITEM_AllocItemSECITEM_AllocItem_Util(NULL((void*)0), NULL((void*)0), prefixLen + labelLen + suiteId->len + (ikm ? ikm->len : 0));
624 if (!out) {
625 return NULL((void*)0);
626 }
627
628 walker = out->data;
629 PORT_Memcpymemcpy(walker, prefix, prefixLen);
630 walker += prefixLen;
631 PORT_Memcpymemcpy(walker, suiteId->data, suiteId->len);
632 walker += suiteId->len;
633 PORT_Memcpymemcpy(walker, label, labelLen);
634 walker += labelLen;
635 if (ikm && ikm->data) {
636 PORT_Memcpymemcpy(walker, ikm->data, ikm->len);
637 }
638
639 return out;
640}
641
642static SECStatus
643pk11_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((void*)0);
650 PK11SymKey *prk = NULL((void*)0);
651 PK11SlotInfo *slot = NULL((void*)0);
652 SECItem *borrowed;
653 SECItem *outDerived = NULL((void*)0);
654 SECItem *labeledIkm;
655 SECItem paramsItem = { siBuffer, (unsigned char *)&params,
656 sizeof(params) };
657 PORT_Assert(cx && ikm && label && labelLen && out && suiteId)((cx && ikm && label && labelLen &&
out && suiteId)?((void)0):PR_Assert("cx && ikm && label && labelLen && out && suiteId"
,"pk11hpke.c",657))
;
658
659 labeledIkm = pk11_hpke_MakeExtractLabel(V1_LABEL, strlen(V1_LABEL), label, labelLen, suiteId, ikm);
660 CHECK_FAIL(!labeledIkm)if ((!labeledIkm)) { rv = SECFailure; goto cleanup; };
661 params.bExtract = CK_TRUE1;
662 params.bExpand = CK_FALSE0;
663 params.prfHashMechanism = cx->kdfParams->mech;
664 params.ulSaltType = salt ? CKF_HKDF_SALT_DATA0x00000002UL : CKF_HKDF_SALT_NULL0x00000001UL;
665 params.pSalt = salt ? (CK_BYTE_PTR)salt->data : NULL((void*)0);
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_GEN0x00001040UL, NULL((void*)0));
671 CHECK_FAIL(!slot)if ((!slot)) { rv = SECFailure; goto cleanup; };
672
673 importedIkm = PK11_ImportDataKey(slot, CKM_HKDF_DATA0x0000402bUL, PK11_OriginUnwrap,
674 CKA_DERIVE0x0000010CUL, labeledIkm, NULL((void*)0));
675 CHECK_FAIL(!importedIkm)if ((!importedIkm)) { rv = SECFailure; goto cleanup; };
676 prk = PK11_Derive(importedIkm, CKM_HKDF_DATA0x0000402bUL, &paramsItem,
677 CKM_HKDF_DERIVE0x0000402aUL, CKA_DERIVE0x0000010CUL, 0);
678 CHECK_FAIL(!prk)if ((!prk)) { rv = SECFailure; goto cleanup; };
679 rv = PK11_ExtractKeyValue(prk);
680 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
681 borrowed = PK11_GetKeyData(prk);
682 CHECK_FAIL(!borrowed)if ((!borrowed)) { rv = SECFailure; goto cleanup; };
683 outDerived = SECITEM_DupItemSECITEM_DupItem_Util(borrowed);
684 CHECK_FAIL(!outDerived)if ((!outDerived)) { rv = SECFailure; goto cleanup; };
685
686 *out = outDerived;
687
688CLEANUP((rv == SECSuccess)?((void)0):PR_Assert("rv == SECSuccess","pk11hpke.c"
,688)); cleanup
:
689 PK11_FreeSymKey(importedIkm);
690 PK11_FreeSymKey(prk);
691 SECITEM_FreeItemSECITEM_FreeItem_Util(labeledIkm, PR_TRUE1);
692 if (slot) {
693 PK11_FreeSlot(slot);
694 }
695 return rv;
696}
697
698static SECStatus
699pk11_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((void*)0);
705 PK11SymKey *labeledIkm = NULL((void*)0);
706 PK11SymKey *prk = NULL((void*)0);
707 CK_HKDF_PARAMS params = { 0 };
708 CK_KEY_DERIVATION_STRING_DATA labelData;
709 SECItem labelDataItem = { siBuffer, NULL((void*)0), 0 };
710 SECItem paramsItem = { siBuffer, (unsigned char *)&params,
711 sizeof(params) };
712 PORT_Assert(cx && ikm && label && labelLen && out && suiteId)((cx && ikm && label && labelLen &&
out && suiteId)?((void)0):PR_Assert("cx && ikm && label && labelLen && out && suiteId"
,"pk11hpke.c",712))
;
713
714 innerLabel = pk11_hpke_MakeExtractLabel(V1_LABEL, strlen(V1_LABEL), label, labelLen, suiteId, NULL((void*)0));
715 CHECK_FAIL(!innerLabel)if ((!innerLabel)) { rv = SECFailure; goto cleanup; };
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_BASE0x00000363UL,
721 &labelDataItem, CKM_GENERIC_SECRET_KEY_GEN0x00000350UL, CKA_DERIVE0x0000010CUL, 0);
722 CHECK_FAIL(!labeledIkm)if ((!labeledIkm)) { rv = SECFailure; goto cleanup; };
723
724 params.bExtract = CK_TRUE1;
725 params.bExpand = CK_FALSE0;
726 params.prfHashMechanism = hashMech;
727 params.ulSaltType = salt ? CKF_HKDF_SALT_KEY0x00000004UL : CKF_HKDF_SALT_NULL0x00000001UL;
728 params.hSaltKey = salt ? PK11_GetSymKeyHandle(salt) : CK_INVALID_HANDLE0;
729
730 prk = PK11_Derive(labeledIkm, CKM_HKDF_DERIVE0x0000402aUL, &paramsItem,
731 CKM_HKDF_DERIVE0x0000402aUL, CKA_DERIVE0x0000010CUL, 0);
732 CHECK_FAIL(!prk)if ((!prk)) { rv = SECFailure; goto cleanup; };
733 *out = prk;
734
735CLEANUP((rv == SECSuccess)?((void)0):PR_Assert("rv == SECSuccess","pk11hpke.c"
,735)); cleanup
:
736 PK11_FreeSymKey(labeledIkm);
737 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(innerLabel, PR_TRUE1);
738 return rv;
739}
740
741static SECStatus
742pk11_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((void*)0);
752 SECItem *labeledInfoItem = NULL((void*)0);
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))((cx && prk && label && (!!outKey != !
!outItem))?((void)0):PR_Assert("cx && prk && label && (!!outKey != !!outItem)"
,"pk11hpke.c",759))
;
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_AllocItemSECITEM_AllocItem_Util(NULL((void*)0), NULL((void*)0), len);
765 CHECK_FAIL(!labeledInfoItem)if ((!labeledInfoItem)) { rv = SECFailure; goto cleanup; };
766
767 walker = labeledInfoItem->data;
768 PORT_Memcpymemcpy(walker, encodedL, sizeof(encodedL));
769 walker += sizeof(encodedL);
770 PORT_Memcpymemcpy(walker, V1_LABEL, strlen(V1_LABEL));
771 walker += strlen(V1_LABEL);
772 PORT_Memcpymemcpy(walker, suiteId->data, suiteId->len);
773 walker += suiteId->len;
774 PORT_Memcpymemcpy(walker, label, labelLen);
775 walker += labelLen;
776 if (info) {
777 PORT_Memcpymemcpy(walker, info->data, info->len);
778 }
779
780 params.bExtract = CK_FALSE0;
781 params.bExpand = CK_TRUE1;
782 params.prfHashMechanism = hashMech;
783 params.ulSaltType = CKF_HKDF_SALT_NULL0x00000001UL;
784 params.pInfo = labeledInfoItem->data;
785 params.ulInfoLen = labeledInfoItem->len;
786 deriveMech = outItem ? CKM_HKDF_DATA0x0000402bUL : CKM_HKDF_DERIVE0x0000402aUL;
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_DERIVE0x0000402aUL;
789
790 derivedKey = PK11_Derive(prk, deriveMech, &paramsItem, keyMech, CKA_DERIVE0x0000010CUL, L);
791 CHECK_FAIL(!derivedKey)if ((!derivedKey)) { rv = SECFailure; goto cleanup; };
792
793 if (outItem) {
794 /* Don't allow export of real keys. */
795 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; }
;
796 rv = PK11_ExtractKeyValue(derivedKey);
797 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
798 derivedKeyData = PK11_GetKeyData(derivedKey);
799 CHECK_FAIL_ERR((!derivedKeyData), SEC_ERROR_NO_KEY)if (((!derivedKeyData))) { PORT_SetError_Util((SEC_ERROR_NO_KEY
)); rv = SECFailure; goto cleanup; }
;
800 *outItem = SECITEM_DupItemSECITEM_DupItem_Util(derivedKeyData);
801 CHECK_FAIL(!*outItem)if ((!*outItem)) { rv = SECFailure; goto cleanup; };
802 PK11_FreeSymKey(derivedKey);
803 } else {
804 *outKey = derivedKey;
805 }
806
807CLEANUP((rv == SECSuccess)?((void)0):PR_Assert("rv == SECSuccess","pk11hpke.c"
,807)); cleanup
:
808 if (rv != SECSuccess) {
809 PK11_FreeSymKey(derivedKey);
810 }
811 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(labeledInfoItem, PR_TRUE1);
812 return rv;
813}
814
815static SECStatus
816pk11_hpke_ExtractAndExpand(const HpkeContext *cx, PK11SymKey *ikm,
817 const SECItem *kemContext, PK11SymKey **out)
818{
819 SECStatus rv;
820 PK11SymKey *eaePrk = NULL((void*)0);
821 PK11SymKey *sharedSecret = NULL((void*)0);
822 PRUint8 suiteIdBuf[5];
823 PRUint8 *walker;
824 PORT_Memcpymemcpy(suiteIdBuf, KEM_LABEL, strlen(KEM_LABEL));
825 SECItem suiteIdItem = { siBuffer, suiteIdBuf, sizeof(suiteIdBuf) };
826 PORT_Assert(cx && ikm && kemContext && out)((cx && ikm && kemContext && out)?((void
)0):PR_Assert("cx && ikm && kemContext && out"
,"pk11hpke.c",826))
;
827
828 walker = &suiteIdBuf[3];
829 walker = encodeNumber(cx->kemParams->id, walker, 2);
Value stored to 'walker' is never read
830
831 rv = pk11_hpke_LabeledExtract(cx, NULL((void*)0), &suiteIdItem, EAE_PRK_LABEL,
832 cx->kemParams->hashMech, strlen(EAE_PRK_LABEL),
833 ikm, &eaePrk);
834 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
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((void*)0));
839 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
840 *out = sharedSecret;
841
842CLEANUP((rv == SECSuccess)?((void)0):PR_Assert("rv == SECSuccess","pk11hpke.c"
,842)); cleanup
:
843 if (rv != SECSuccess) {
844 PK11_FreeSymKey(sharedSecret);
845 }
846 PK11_FreeSymKey(eaePrk);
847 return rv;
848}
849
850static SECStatus
851pk11_hpke_Encap(HpkeContext *cx, const SECKEYPublicKey *pkE, SECKEYPrivateKey *skE,
852 SECKEYPublicKey *pkR)
853{
854 SECStatus rv;
855 PK11SymKey *dh = NULL((void*)0);
856 SECItem *kemContext = NULL((void*)0);
857 SECItem *encPkR = NULL((void*)0);
858 unsigned int tmpLen;
859
860 PORT_Assert(cx && skE && pkE && pkR)((cx && skE && pkE && pkR)?((void)0):
PR_Assert("cx && skE && pkE && pkR","pk11hpke.c"
,860))
;
861
862 rv = pk11_hpke_CheckKeys(cx, pkE, skE);
863 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
864 rv = pk11_hpke_CheckKeys(cx, pkR, NULL((void*)0));
865 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
866
867 dh = PK11_PubDeriveWithKDF(skE, pkR, PR_FALSE0, NULL((void*)0), NULL((void*)0), CKM_ECDH1_DERIVE0x00001050UL,
868 CKM_SHA512_HMAC0x00000271UL /* unused */, CKA_DERIVE0x0000010CUL, 0,
869 CKD_NULL0x00000001UL, NULL((void*)0), NULL((void*)0));
870 CHECK_FAIL(!dh)if ((!dh)) { rv = SECFailure; goto cleanup; };
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((void*)0), &tmpLen, 0);
876 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
877 cx->encapPubKey = SECITEM_AllocItemSECITEM_AllocItem_Util(NULL((void*)0), NULL((void*)0), tmpLen);
878 CHECK_FAIL(!cx->encapPubKey)if ((!cx->encapPubKey)) { rv = SECFailure; goto cleanup; };
879 rv = PK11_HPKE_Serialize(pkE, cx->encapPubKey->data,
880 &cx->encapPubKey->len, cx->encapPubKey->len);
881 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
882
883 rv = PK11_HPKE_Serialize(pkR, NULL((void*)0), &tmpLen, 0);
884 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
885
886 kemContext = SECITEM_AllocItemSECITEM_AllocItem_Util(NULL((void*)0), NULL((void*)0), cx->encapPubKey->len + tmpLen);
887 CHECK_FAIL(!kemContext)if ((!kemContext)) { rv = SECFailure; goto cleanup; };
888
889 PORT_Memcpymemcpy(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)if ((rv) != SECSuccess) { goto cleanup; };
892
893 rv = pk11_hpke_ExtractAndExpand(cx, dh, kemContext, &cx->sharedSecret);
894 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
895
896CLEANUP((rv == SECSuccess)?((void)0):PR_Assert("rv == SECSuccess","pk11hpke.c"
,896)); cleanup
:
897 if (rv != SECSuccess) {
898 PK11_FreeSymKey(cx->sharedSecret);
899 cx->sharedSecret = NULL((void*)0);
900 }
901 SECITEM_FreeItemSECITEM_FreeItem_Util(encPkR, PR_TRUE1);
902 SECITEM_FreeItemSECITEM_FreeItem_Util(kemContext, PR_TRUE1);
903 PK11_FreeSymKey(dh);
904 return rv;
905}
906
907SECStatus
908PK11_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_Memcpymemcpy(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_SetErrorPORT_SetError_Util(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((void*)0));
933 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
934 *out = exported;
935
936CLEANUP((rv == SECSuccess)?((void)0):PR_Assert("rv == SECSuccess","pk11hpke.c"
,936)); cleanup
:
937 return rv;
938}
939
940static SECStatus
941pk11_hpke_Decap(HpkeContext *cx, const SECKEYPublicKey *pkR, SECKEYPrivateKey *skR,
942 const SECItem *encS)
943{
944 SECStatus rv;
945 PK11SymKey *dh = NULL((void*)0);
946 SECItem *encR = NULL((void*)0);
947 SECItem *kemContext = NULL((void*)0);
948 SECKEYPublicKey *pkS = NULL((void*)0);
949 unsigned int tmpLen;
950
951 if (!cx || !skR || !pkR || !encS || !encS->data || !encS->len) {
952 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
953 return SECFailure;
954 }
955
956 rv = PK11_HPKE_Deserialize(cx, encS->data, encS->len, &pkS);
957 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
958
959 rv = pk11_hpke_CheckKeys(cx, pkR, skR);
960 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
961 rv = pk11_hpke_CheckKeys(cx, pkS, NULL((void*)0));
962 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
963
964 dh = PK11_PubDeriveWithKDF(skR, pkS, PR_FALSE0, NULL((void*)0), NULL((void*)0), CKM_ECDH1_DERIVE0x00001050UL,
965 CKM_SHA512_HMAC0x00000271UL /* unused */, CKA_DERIVE0x0000010CUL, 0,
966 CKD_NULL0x00000001UL, NULL((void*)0), NULL((void*)0));
967 CHECK_FAIL(!dh)if ((!dh)) { rv = SECFailure; goto cleanup; };
968
969 /* kem_context = concat(enc, pkRm) */
970 rv = PK11_HPKE_Serialize(pkR, NULL((void*)0), &tmpLen, 0);
971 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
972
973 kemContext = SECITEM_AllocItemSECITEM_AllocItem_Util(NULL((void*)0), NULL((void*)0), encS->len + tmpLen);
974 CHECK_FAIL(!kemContext)if ((!kemContext)) { rv = SECFailure; goto cleanup; };
975
976 PORT_Memcpymemcpy(kemContext->data, encS->data, encS->len);
977 rv = PK11_HPKE_Serialize(pkR, &kemContext->data[encS->len], &tmpLen,
978 kemContext->len - encS->len);
979 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
980 rv = pk11_hpke_ExtractAndExpand(cx, dh, kemContext, &cx->sharedSecret);
981 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
982
983 /* Store the sender serialized public key, which
984 * may be required by application use cases. */
985 cx->encapPubKey = SECITEM_DupItemSECITEM_DupItem_Util(encS);
986 CHECK_FAIL(!cx->encapPubKey)if ((!cx->encapPubKey)) { rv = SECFailure; goto cleanup; };
987
988CLEANUP((rv == SECSuccess)?((void)0):PR_Assert("rv == SECSuccess","pk11hpke.c"
,988)); cleanup
:
989 if (rv != SECSuccess) {
990 PK11_FreeSymKey(cx->sharedSecret);
991 cx->sharedSecret = NULL((void*)0);
992 }
993 PK11_FreeSymKey(dh);
994 SECKEY_DestroyPublicKey(pkS);
995 SECITEM_FreeItemSECITEM_FreeItem_Util(encR, PR_TRUE1);
996 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(kemContext, PR_TRUE1);
997 return rv;
998}
999
1000const SECItem *
1001PK11_HPKE_GetEncapPubKey(const HpkeContext *cx)
1002{
1003 if (!cx) {
1004 return NULL((void*)0);
1005 }
1006 return cx->encapPubKey;
1007}
1008
1009static SECStatus
1010pk11_hpke_KeySchedule(HpkeContext *cx, const SECItem *info)
1011{
1012 SECStatus rv;
1013 SECItem contextItem = { siBuffer, NULL((void*)0), 0 };
1014 unsigned int len;
1015 unsigned int off;
1016 PK11SymKey *secret = NULL((void*)0);
1017 SECItem *pskIdHash = NULL((void*)0);
1018 SECItem *infoHash = NULL((void*)0);
1019 PRUint8 suiteIdBuf[10];
1020 PRUint8 *walker;
1021 PORT_Memcpymemcpy(suiteIdBuf, HPKE_LABEL, strlen(HPKE_LABEL));
1022 SECItem suiteIdItem = { siBuffer, suiteIdBuf, sizeof(suiteIdBuf) };
1023 PORT_Assert(cx && info && cx->psk && cx->pskId)((cx && info && cx->psk && cx->
pskId)?((void)0):PR_Assert("cx && info && cx->psk && cx->pskId"
,"pk11hpke.c",1023))
;
1024
1025 walker = &suiteIdBuf[4];
1026 walker = encodeNumber(cx->kemParams->id, walker, 2);
1027 walker = encodeNumber(cx->kdfParams->id, walker, 2);
1028 walker = encodeNumber(cx->aeadParams->id, walker, 2);
1029
1030 rv = pk11_hpke_LabeledExtractData(cx, NULL((void*)0), &suiteIdItem, PSK_ID_LABEL,
1031 strlen(PSK_ID_LABEL), cx->pskId, &pskIdHash);
1032 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
1033 rv = pk11_hpke_LabeledExtractData(cx, NULL((void*)0), &suiteIdItem, INFO_LABEL,
1034 strlen(INFO_LABEL), info, &infoHash);
1035 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
1036
1037 // Make the context string
1038 len = sizeof(cx->mode) + pskIdHash->len + infoHash->len;
1039 CHECK_FAIL(!SECITEM_AllocItem(NULL, &contextItem, len))if ((!SECITEM_AllocItem_Util(((void*)0), &contextItem, len
))) { rv = SECFailure; goto cleanup; }
;
1040 off = 0;
1041 PORT_Memcpymemcpy(&contextItem.data[off], &cx->mode, sizeof(cx->mode));
1042 off += sizeof(cx->mode);
1043 PORT_Memcpymemcpy(&contextItem.data[off], pskIdHash->data, pskIdHash->len);
1044 off += pskIdHash->len;
1045 PORT_Memcpymemcpy(&contextItem.data[off], infoHash->data, infoHash->len);
1046 off += infoHash->len;
1047
1048 // Compute the keys
1049 rv = pk11_hpke_LabeledExtract(cx, cx->sharedSecret, &suiteIdItem, SECRET_LABEL,
1050 cx->kdfParams->mech, strlen(SECRET_LABEL),
1051 cx->psk, &secret);
1052 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
1053 rv = pk11_hpke_LabeledExpand(cx, secret, &suiteIdItem, KEY_LABEL, strlen(KEY_LABEL),
1054 &contextItem, cx->aeadParams->Nk, cx->kdfParams->mech,
1055 &cx->key, NULL((void*)0));
1056 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
1057 rv = pk11_hpke_LabeledExpand(cx, secret, &suiteIdItem, NONCE_LABEL, strlen(NONCE_LABEL),
1058 &contextItem, cx->aeadParams->Nn, cx->kdfParams->mech,
1059 NULL((void*)0), &cx->baseNonce);
1060 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
1061 rv = pk11_hpke_LabeledExpand(cx, secret, &suiteIdItem, EXP_LABEL, strlen(EXP_LABEL),
1062 &contextItem, cx->kdfParams->Nh, cx->kdfParams->mech,
1063 &cx->exporterSecret, NULL((void*)0));
1064 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
1065
1066CLEANUP((rv == SECSuccess)?((void)0):PR_Assert("rv == SECSuccess","pk11hpke.c"
,1066)); cleanup
:
1067 /* If !SECSuccess, callers will tear down the context. */
1068 PK11_FreeSymKey(secret);
1069 SECITEM_FreeItemSECITEM_FreeItem_Util(&contextItem, PR_FALSE0);
1070 SECITEM_FreeItemSECITEM_FreeItem_Util(infoHash, PR_TRUE1);
1071 SECITEM_FreeItemSECITEM_FreeItem_Util(pskIdHash, PR_TRUE1);
1072 return rv;
1073}
1074
1075SECStatus
1076PK11_HPKE_SetupR(HpkeContext *cx, const SECKEYPublicKey *pkR, SECKEYPrivateKey *skR,
1077 const SECItem *enc, const SECItem *info)
1078{
1079 SECStatus rv;
1080 SECItem empty = { siBuffer, NULL((void*)0), 0 };
1081
1082 CHECK_FAIL_ERR((!cx || !skR || !info || !enc || !enc->data || !enc->len),if (((!cx || !skR || !info || !enc || !enc->data || !enc->
len))) { PORT_SetError_Util((SEC_ERROR_INVALID_ARGS)); rv = SECFailure
; goto cleanup; }
1083 SEC_ERROR_INVALID_ARGS)if (((!cx || !skR || !info || !enc || !enc->data || !enc->
len))) { PORT_SetError_Util((SEC_ERROR_INVALID_ARGS)); rv = SECFailure
; goto cleanup; }
;
1084 /* Already setup */
1085 CHECK_FAIL_ERR((cx->aeadContext), SEC_ERROR_INVALID_STATE)if (((cx->aeadContext))) { PORT_SetError_Util((SEC_ERROR_INVALID_STATE
)); rv = SECFailure; goto cleanup; }
;
1086
1087 rv = pk11_hpke_Decap(cx, pkR, skR, enc);
1088 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
1089 rv = pk11_hpke_KeySchedule(cx, info);
1090 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
1091
1092 /* Store the key context for subsequent calls to Open().
1093 * PK11_CreateContextBySymKey refs the key internally. */
1094 PORT_Assert(cx->key)((cx->key)?((void)0):PR_Assert("cx->key","pk11hpke.c",1094
))
;
1095 cx->aeadContext = PK11_CreateContextBySymKey(cx->aeadParams->mech,
1096 CKA_NSS_MESSAGE0x82000000L | CKA_DECRYPT0x00000105UL,
1097 cx->key, &empty);
1098 CHECK_FAIL_ERR((!cx->aeadContext), SEC_ERROR_LIBRARY_FAILURE)if (((!cx->aeadContext))) { PORT_SetError_Util((SEC_ERROR_LIBRARY_FAILURE
)); rv = SECFailure; goto cleanup; }
;
1099
1100CLEANUP((rv == SECSuccess)?((void)0):PR_Assert("rv == SECSuccess","pk11hpke.c"
,1100)); cleanup
:
1101 if (rv != SECSuccess) {
1102 /* Clear everything past NewContext. */
1103 PK11_HPKE_DestroyContext(cx, PR_FALSE0);
1104 }
1105 return rv;
1106}
1107
1108SECStatus
1109PK11_HPKE_SetupS(HpkeContext *cx, const SECKEYPublicKey *pkE, SECKEYPrivateKey *skE,
1110 SECKEYPublicKey *pkR, const SECItem *info)
1111{
1112 SECStatus rv;
1113 SECItem empty = { siBuffer, NULL((void*)0), 0 };
1114 SECKEYPublicKey *tmpPkE = NULL((void*)0);
1115 SECKEYPrivateKey *tmpSkE = NULL((void*)0);
1116 CHECK_FAIL_ERR((!cx || !pkR || !info || (!!skE != !!pkE)), SEC_ERROR_INVALID_ARGS)if (((!cx || !pkR || !info || (!!skE != !!pkE)))) { PORT_SetError_Util
((SEC_ERROR_INVALID_ARGS)); rv = SECFailure; goto cleanup; }
;
1117 /* Already setup */
1118 CHECK_FAIL_ERR((cx->aeadContext), SEC_ERROR_INVALID_STATE)if (((cx->aeadContext))) { PORT_SetError_Util((SEC_ERROR_INVALID_STATE
)); rv = SECFailure; goto cleanup; }
;
1119
1120 /* If NULL was passed for the local keypair, generate one. */
1121 if (skE == NULL((void*)0)) {
1122 rv = pk11_hpke_GenerateKeyPair(cx, &tmpPkE, &tmpSkE);
1123 if (rv != SECSuccess) {
1124 /* Code set */
1125 return SECFailure;
1126 }
1127 rv = pk11_hpke_Encap(cx, tmpPkE, tmpSkE, pkR);
1128 } else {
1129 rv = pk11_hpke_Encap(cx, pkE, skE, pkR);
1130 }
1131 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
1132
1133 SECItem defaultInfo = { siBuffer, NULL((void*)0), 0 };
1134 if (!info || !info->data) {
1135 info = &defaultInfo;
1136 }
1137 rv = pk11_hpke_KeySchedule(cx, info);
1138 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
1139
1140 PORT_Assert(cx->key)((cx->key)?((void)0):PR_Assert("cx->key","pk11hpke.c",1140
))
;
1141 cx->aeadContext = PK11_CreateContextBySymKey(cx->aeadParams->mech,
1142 CKA_NSS_MESSAGE0x82000000L | CKA_ENCRYPT0x00000104UL,
1143 cx->key, &empty);
1144 CHECK_FAIL_ERR((!cx->aeadContext), SEC_ERROR_LIBRARY_FAILURE)if (((!cx->aeadContext))) { PORT_SetError_Util((SEC_ERROR_LIBRARY_FAILURE
)); rv = SECFailure; goto cleanup; }
;
1145
1146CLEANUP((rv == SECSuccess)?((void)0):PR_Assert("rv == SECSuccess","pk11hpke.c"
,1146)); cleanup
:
1147 if (rv != SECSuccess) {
1148 /* Clear everything past NewContext. */
1149 PK11_HPKE_DestroyContext(cx, PR_FALSE0);
1150 }
1151 SECKEY_DestroyPrivateKey(tmpSkE);
1152 SECKEY_DestroyPublicKey(tmpPkE);
1153 return rv;
1154}
1155
1156SECStatus
1157PK11_HPKE_Seal(HpkeContext *cx, const SECItem *aad, const SECItem *pt,
1158 SECItem **out)
1159{
1160 SECStatus rv;
1161 PRUint8 ivOut[12] = { 0 };
1162 SECItem *ct = NULL((void*)0);
1163 size_t maxOut;
1164 unsigned char tagBuf[HASH_LENGTH_MAX64];
1165 size_t tagLen;
1166 unsigned int fixedBits;
1167
1168 /* aad may be NULL, PT may be zero-length but not NULL. */
1169 if (!cx || !cx->aeadContext ||
1170 (aad && aad->len && !aad->data) ||
1171 !pt || (pt->len && !pt->data) ||
1172 !out) {
1173 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
1174 return SECFailure;
1175 }
1176
1177 PORT_Assert(cx->baseNonce->len == sizeof(ivOut))((cx->baseNonce->len == sizeof(ivOut))?((void)0):PR_Assert
("cx->baseNonce->len == sizeof(ivOut)","pk11hpke.c",1177
))
;
1178 PORT_Memcpymemcpy(ivOut, cx->baseNonce->data, cx->baseNonce->len);
1179
1180 tagLen = cx->aeadParams->tagLen;
1181 maxOut = pt->len + tagLen;
1182 fixedBits = (cx->baseNonce->len - 8) * 8;
1183 ct = SECITEM_AllocItemSECITEM_AllocItem_Util(NULL((void*)0), NULL((void*)0), maxOut);
1184 CHECK_FAIL(!ct)if ((!ct)) { rv = SECFailure; goto cleanup; };
1185
1186 rv = PK11_AEADOp(cx->aeadContext,
1187 CKG_GENERATE_COUNTER_XOR0x00000004UL, fixedBits,
1188 ivOut, sizeof(ivOut),
1189 aad ? aad->data : NULL((void*)0),
1190 aad ? aad->len : 0,
1191 ct->data, (int *)&ct->len, maxOut,
1192 tagBuf, tagLen,
1193 pt->data, pt->len);
1194 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
1195 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;
}
;
1196
1197 /* Append the tag to the ciphertext. */
1198 PORT_Memcpymemcpy(&ct->data[ct->len], tagBuf, tagLen);
1199 ct->len += tagLen;
1200 *out = ct;
1201
1202CLEANUP((rv == SECSuccess)?((void)0):PR_Assert("rv == SECSuccess","pk11hpke.c"
,1202)); cleanup
:
1203 if (rv != SECSuccess) {
1204 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(ct, PR_TRUE1);
1205 }
1206 return rv;
1207}
1208
1209/* PKCS #11 defines the IV generator function to be ignored on
1210 * decrypt (i.e. it uses the nonce input, as provided, as the IV).
1211 * The sequence number is kept independently on each endpoint and
1212 * the XORed IV is not transmitted, so we have to do our own IV
1213 * construction XOR outside of the token. */
1214static SECStatus
1215pk11_hpke_makeIv(HpkeContext *cx, PRUint8 *iv, size_t ivLen)
1216{
1217 unsigned int counterLen = sizeof(cx->sequenceNumber);
1218 PORT_Assert(cx->baseNonce->len == ivLen)((cx->baseNonce->len == ivLen)?((void)0):PR_Assert("cx->baseNonce->len == ivLen"
,"pk11hpke.c",1218))
;
1219 PORT_Assert(counterLen == 8)((counterLen == 8)?((void)0):PR_Assert("counterLen == 8","pk11hpke.c"
,1219))
;
1220 if (cx->sequenceNumber == PR_UINT64(0xffffffffffffffff)0xffffffffffffffffUL) {
1221 /* Overflow */
1222 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_KEY);
1223 return SECFailure;
1224 }
1225
1226 PORT_Memcpymemcpy(iv, cx->baseNonce->data, cx->baseNonce->len);
1227 for (size_t i = 0; i < counterLen; i++) {
1228 iv[cx->baseNonce->len - 1 - i] ^=
1229 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)))
1230 counterLen - 1 - i, counterLen)((unsigned char)(((counterLen) - (counterLen - 1 - i)-1) >=
sizeof(cx->sequenceNumber) ? 0 : (((cx->sequenceNumber
) >> (((counterLen) - (counterLen - 1 - i)-1) * 8)) &
0xff)))
;
1231 }
1232 return SECSuccess;
1233}
1234
1235SECStatus
1236PK11_HPKE_Open(HpkeContext *cx, const SECItem *aad,
1237 const SECItem *ct, SECItem **out)
1238{
1239 SECStatus rv;
1240 PRUint8 constructedNonce[12] = { 0 };
1241 unsigned int tagLen;
1242 SECItem *pt = NULL((void*)0);
1243
1244 /* aad may be NULL, CT may be zero-length but not NULL. */
1245 if ((!cx || !cx->aeadContext || !ct || !out) ||
1246 (aad && aad->len && !aad->data) ||
1247 (!ct->data || (ct->data && !ct->len))) {
1248 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
1249 return SECFailure;
1250 }
1251 tagLen = cx->aeadParams->tagLen;
1252 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; }
;
1253
1254 pt = SECITEM_AllocItemSECITEM_AllocItem_Util(NULL((void*)0), NULL((void*)0), ct->len);
1255 CHECK_FAIL(!pt)if ((!pt)) { rv = SECFailure; goto cleanup; };
1256
1257 rv = pk11_hpke_makeIv(cx, constructedNonce, sizeof(constructedNonce));
1258 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
1259
1260 rv = PK11_AEADOp(cx->aeadContext, CKG_NO_GENERATE0x00000000UL, 0,
1261 constructedNonce, sizeof(constructedNonce),
1262 aad ? aad->data : NULL((void*)0),
1263 aad ? aad->len : 0,
1264 pt->data, (int *)&pt->len, pt->len,
1265 &ct->data[ct->len - tagLen], tagLen,
1266 ct->data, ct->len - tagLen);
1267 CHECK_RV(rv)if ((rv) != SECSuccess) { goto cleanup; };
1268 cx->sequenceNumber++;
1269 *out = pt;
1270
1271CLEANUP((rv == SECSuccess)?((void)0):PR_Assert("rv == SECSuccess","pk11hpke.c"
,1271)); cleanup
:
1272 if (rv != SECSuccess) {
1273 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(pt, PR_TRUE1);
1274 }
1275 return rv;
1276}