Coverage Report

Created: 2024-05-20 06:23

/src/nss/lib/softoken/kem.c
Line
Count
Source (jump to first uncovered line)
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5
#include "blapi.h"
6
#include "kem.h"
7
#include "pkcs11i.h"
8
#include "pkcs11n.h"
9
#include "secitem.h"
10
#include "secport.h"
11
#include "softoken.h"
12
13
KyberParams
14
sftk_kyber_PK11ParamToInternal(CK_NSS_KEM_PARAMETER_SET_TYPE pk11ParamSet)
15
0
{
16
0
    switch (pk11ParamSet) {
17
0
        case CKP_NSS_KYBER_768_ROUND3:
18
0
            return params_kyber768_round3;
19
0
        default:
20
0
            return params_kyber_invalid;
21
0
    }
22
0
}
23
24
SECItem *
25
sftk_kyber_AllocPubKeyItem(KyberParams params, SECItem *pubkey)
26
0
{
27
0
    switch (params) {
28
0
        case params_kyber768_round3:
29
0
        case params_kyber768_round3_test_mode:
30
0
            return SECITEM_AllocItem(NULL, pubkey, KYBER768_PUBLIC_KEY_BYTES);
31
0
        default:
32
0
            return NULL;
33
0
    }
34
0
}
35
36
SECItem *
37
sftk_kyber_AllocPrivKeyItem(KyberParams params, SECItem *privkey)
38
0
{
39
0
    switch (params) {
40
0
        case params_kyber768_round3:
41
0
        case params_kyber768_round3_test_mode:
42
0
            return SECITEM_AllocItem(NULL, privkey, KYBER768_PRIVATE_KEY_BYTES);
43
0
        default:
44
0
            return NULL;
45
0
    }
46
0
}
47
48
SECItem *
49
sftk_kyber_AllocCiphertextItem(KyberParams params, SECItem *ciphertext)
50
0
{
51
0
    switch (params) {
52
0
        case params_kyber768_round3:
53
0
        case params_kyber768_round3_test_mode:
54
0
            return SECITEM_AllocItem(NULL, ciphertext, KYBER768_CIPHERTEXT_BYTES);
55
0
        default:
56
0
            return NULL;
57
0
    }
58
0
}
59
60
static PRBool
61
sftk_kyber_ValidateParams(const CK_NSS_KEM_PARAMETER_SET_TYPE *params)
62
0
{
63
0
    if (!params) {
64
0
        return PR_FALSE;
65
0
    }
66
0
    switch (*params) {
67
0
        case CKP_NSS_KYBER_768_ROUND3:
68
0
            return PR_TRUE;
69
0
        default:
70
0
            return PR_FALSE;
71
0
    }
72
0
}
73
74
static PRBool
75
sftk_kem_ValidateMechanism(CK_MECHANISM_PTR pMechanism)
76
0
{
77
0
    if (!pMechanism) {
78
0
        return PR_FALSE;
79
0
    }
80
0
    switch (pMechanism->mechanism) {
81
0
        case CKM_NSS_KYBER:
82
0
            return pMechanism->ulParameterLen == sizeof(CK_NSS_KEM_PARAMETER_SET_TYPE) && sftk_kyber_ValidateParams(pMechanism->pParameter);
83
0
        default:
84
0
            return PR_FALSE;
85
0
    }
86
0
}
87
88
static CK_ULONG
89
sftk_kem_CiphertextLen(CK_MECHANISM_PTR pMechanism)
90
0
{
91
    /* Assumes pMechanism has been validated with sftk_kem_ValidateMechanism */
92
0
    if (pMechanism->mechanism != CKM_NSS_KYBER) {
93
0
        PORT_Assert(0);
94
0
        return 0;
95
0
    }
96
0
    CK_NSS_KEM_PARAMETER_SET_TYPE *pParameterSet = pMechanism->pParameter;
97
0
    switch (*pParameterSet) {
98
0
        case CKP_NSS_KYBER_768_ROUND3:
99
0
            return KYBER768_CIPHERTEXT_BYTES;
100
0
        default:
101
            /* unreachable if pMechanism has been validated */
102
0
            PORT_Assert(0);
103
0
            return 0;
104
0
    }
105
0
}
106
107
/* C_Encapsulate takes a public encapsulation key hPublicKey, a secret
108
 * phKey, and outputs a ciphertext (i.e. encapsulaton) of this secret in
109
 * pCiphertext. */
110
CK_RV
111
NSC_Encapsulate(CK_SESSION_HANDLE hSession,
112
                CK_MECHANISM_PTR pMechanism,
113
                CK_OBJECT_HANDLE hPublicKey,
114
                CK_ATTRIBUTE_PTR pTemplate,
115
                CK_ULONG ulAttributeCount,
116
                /* out */ CK_OBJECT_HANDLE_PTR phKey,
117
                /* out */ CK_BYTE_PTR pCiphertext,
118
                /* out */ CK_ULONG_PTR pulCiphertextLen)
119
0
{
120
0
    SFTKSession *session = NULL;
121
0
    SFTKSlot *slot = NULL;
122
123
0
    SFTKObject *key = NULL;
124
125
0
    SFTKObject *encapsulationKeyObject = NULL;
126
0
    SFTKAttribute *encapsulationKey = NULL;
127
128
0
    CK_RV crv;
129
0
    SFTKFreeStatus status;
130
131
0
    CHECK_FORK();
132
133
0
    if (!pMechanism || !phKey || !pulCiphertextLen) {
134
0
        return CKR_ARGUMENTS_BAD;
135
0
    }
136
137
0
    if (!sftk_kem_ValidateMechanism(pMechanism)) {
138
0
        return CKR_MECHANISM_INVALID;
139
0
    }
140
141
0
    CK_ULONG ciphertextLen = sftk_kem_CiphertextLen(pMechanism);
142
0
    if (!pCiphertext || *pulCiphertextLen < ciphertextLen) {
143
0
        *pulCiphertextLen = ciphertextLen;
144
0
        return CKR_KEY_SIZE_RANGE;
145
0
    }
146
0
    *phKey = CK_INVALID_HANDLE;
147
148
0
    session = sftk_SessionFromHandle(hSession);
149
0
    if (session == NULL) {
150
0
        return CKR_SESSION_HANDLE_INVALID;
151
0
    }
152
0
    slot = sftk_SlotFromSessionHandle(hSession);
153
0
    if (slot == NULL) {
154
0
        crv = CKR_SESSION_HANDLE_INVALID;
155
0
        goto cleanup;
156
0
    }
157
158
0
    key = sftk_NewObject(slot);
159
0
    if (key == NULL) {
160
0
        crv = CKR_HOST_MEMORY;
161
0
        goto cleanup;
162
0
    }
163
0
    for (unsigned long int i = 0; i < ulAttributeCount; i++) {
164
0
        crv = sftk_AddAttributeType(key, sftk_attr_expand(&pTemplate[i]));
165
0
        if (crv != CKR_OK) {
166
0
            goto cleanup;
167
0
        }
168
0
    }
169
170
0
    encapsulationKeyObject = sftk_ObjectFromHandle(hPublicKey, session);
171
0
    if (encapsulationKeyObject == NULL) {
172
0
        crv = CKR_KEY_HANDLE_INVALID;
173
0
        goto cleanup;
174
0
    }
175
0
    encapsulationKey = sftk_FindAttribute(encapsulationKeyObject, CKA_VALUE);
176
0
    if (encapsulationKey == NULL) {
177
0
        crv = CKR_KEY_HANDLE_INVALID;
178
0
        goto cleanup;
179
0
    }
180
181
0
    SECItem ciphertext = { siBuffer, pCiphertext, ciphertextLen };
182
0
    SECItem pubKey = { siBuffer, encapsulationKey->attrib.pValue, encapsulationKey->attrib.ulValueLen };
183
184
    /* The length of secretBuf can be increased if we ever support other KEMs */
185
0
    uint8_t secretBuf[KYBER_SHARED_SECRET_BYTES] = { 0 };
186
0
    SECItem secret = { siBuffer, secretBuf, sizeof secretBuf };
187
188
0
    switch (pMechanism->mechanism) {
189
0
        case CKM_NSS_KYBER: {
190
0
            PORT_Assert(secret.len == KYBER_SHARED_SECRET_BYTES);
191
0
            CK_NSS_KEM_PARAMETER_SET_TYPE *pParameter = pMechanism->pParameter;
192
0
            KyberParams kyberParams = sftk_kyber_PK11ParamToInternal(*pParameter);
193
0
            SECStatus rv = Kyber_Encapsulate(kyberParams, /* seed */ NULL, &pubKey, &ciphertext, &secret);
194
0
            if (rv != SECSuccess) {
195
0
                crv = CKR_FUNCTION_FAILED;
196
0
                goto cleanup;
197
0
            }
198
199
0
            crv = sftk_forceAttribute(key, CKA_VALUE, sftk_item_expand(&secret));
200
0
            if (crv != CKR_OK) {
201
0
                goto cleanup;
202
0
            }
203
204
0
            crv = sftk_handleObject(key, session);
205
0
            if (crv != CKR_OK) {
206
0
                goto cleanup;
207
0
            }
208
209
            /* We wrote the ciphertext out directly in Kyber_Encapsulate */
210
0
            *phKey = key->handle;
211
0
            *pulCiphertextLen = ciphertext.len;
212
0
            break;
213
0
        }
214
0
        default:
215
0
            crv = CKR_MECHANISM_INVALID;
216
0
            goto cleanup;
217
0
    }
218
219
0
cleanup:
220
0
    if (session) {
221
0
        sftk_FreeSession(session);
222
0
    }
223
0
    if (key) {
224
0
        status = sftk_FreeObject(key);
225
0
        if (status == SFTK_DestroyFailure) {
226
0
            return CKR_DEVICE_ERROR;
227
0
        }
228
0
    }
229
0
    if (encapsulationKeyObject) {
230
0
        status = sftk_FreeObject(encapsulationKeyObject);
231
0
        if (status == SFTK_DestroyFailure) {
232
0
            return CKR_DEVICE_ERROR;
233
0
        }
234
0
    }
235
0
    if (encapsulationKey) {
236
0
        sftk_FreeAttribute(encapsulationKey);
237
0
    }
238
0
    return crv;
239
0
}
240
241
CK_RV
242
NSC_Decapsulate(CK_SESSION_HANDLE hSession,
243
                CK_MECHANISM_PTR pMechanism,
244
                CK_OBJECT_HANDLE hPrivateKey,
245
                CK_BYTE_PTR pCiphertext,
246
                CK_ULONG ulCiphertextLen,
247
                CK_ATTRIBUTE_PTR pTemplate,
248
                CK_ULONG ulAttributeCount,
249
                /* out */ CK_OBJECT_HANDLE_PTR phKey)
250
0
{
251
0
    SFTKSession *session = NULL;
252
0
    SFTKSlot *slot = NULL;
253
254
0
    SFTKObject *key = NULL;
255
256
0
    SFTKObject *decapsulationKeyObject = NULL;
257
0
    SFTKAttribute *decapsulationKey = NULL;
258
259
0
    CK_RV crv;
260
0
    SFTKFreeStatus status;
261
262
0
    CHECK_FORK();
263
264
0
    if (!pMechanism || !pCiphertext || !pTemplate || !phKey) {
265
0
        return CKR_ARGUMENTS_BAD;
266
0
    }
267
268
0
    if (!sftk_kem_ValidateMechanism(pMechanism)) {
269
0
        return CKR_MECHANISM_INVALID;
270
0
    }
271
272
0
    CK_ULONG ciphertextLen = sftk_kem_CiphertextLen(pMechanism);
273
0
    if (ulCiphertextLen < ciphertextLen) {
274
0
        return CKR_ARGUMENTS_BAD;
275
0
    }
276
0
    *phKey = CK_INVALID_HANDLE;
277
278
0
    session = sftk_SessionFromHandle(hSession);
279
0
    if (session == NULL) {
280
0
        return CKR_SESSION_HANDLE_INVALID;
281
0
    }
282
0
    slot = sftk_SlotFromSessionHandle(hSession);
283
0
    if (slot == NULL) {
284
0
        crv = CKR_SESSION_HANDLE_INVALID;
285
0
        goto cleanup;
286
0
    }
287
288
0
    key = sftk_NewObject(slot);
289
0
    if (key == NULL) {
290
0
        crv = CKR_HOST_MEMORY;
291
0
        goto cleanup;
292
0
    }
293
0
    for (unsigned long int i = 0; i < ulAttributeCount; i++) {
294
0
        crv = sftk_AddAttributeType(key, sftk_attr_expand(&pTemplate[i]));
295
0
        if (crv != CKR_OK) {
296
0
            goto cleanup;
297
0
        }
298
0
    }
299
300
0
    decapsulationKeyObject = sftk_ObjectFromHandle(hPrivateKey, session);
301
0
    if (decapsulationKeyObject == NULL) {
302
0
        crv = CKR_KEY_HANDLE_INVALID;
303
0
        goto cleanup;
304
0
    }
305
0
    decapsulationKey = sftk_FindAttribute(decapsulationKeyObject, CKA_VALUE);
306
0
    if (decapsulationKey == NULL) {
307
0
        crv = CKR_KEY_HANDLE_INVALID;
308
0
        goto cleanup;
309
0
    }
310
311
0
    SECItem privKey = { siBuffer, decapsulationKey->attrib.pValue, decapsulationKey->attrib.ulValueLen };
312
0
    SECItem ciphertext = { siBuffer, pCiphertext, ulCiphertextLen };
313
314
    /* The length of secretBuf can be increased if we ever support other KEMs */
315
0
    uint8_t secretBuf[KYBER_SHARED_SECRET_BYTES] = { 0 };
316
0
    SECItem secret = { siBuffer, secretBuf, sizeof secretBuf };
317
318
0
    switch (pMechanism->mechanism) {
319
0
        case CKM_NSS_KYBER: {
320
0
            PORT_Assert(secret.len == KYBER_SHARED_SECRET_BYTES);
321
0
            CK_NSS_KEM_PARAMETER_SET_TYPE *pParameter = pMechanism->pParameter;
322
0
            KyberParams kyberParams = sftk_kyber_PK11ParamToInternal(*pParameter);
323
0
            SECStatus rv = Kyber_Decapsulate(kyberParams, &privKey, &ciphertext, &secret);
324
0
            if (rv != SECSuccess) {
325
0
                crv = CKR_FUNCTION_FAILED;
326
0
                goto cleanup;
327
0
            }
328
329
0
            crv = sftk_forceAttribute(key, CKA_VALUE, sftk_item_expand(&secret));
330
0
            if (crv != CKR_OK) {
331
0
                goto cleanup;
332
0
            }
333
334
0
            crv = sftk_handleObject(key, session);
335
0
            if (crv != CKR_OK) {
336
0
                goto cleanup;
337
0
            }
338
0
            *phKey = key->handle;
339
0
            break;
340
0
        }
341
0
        default:
342
0
            crv = CKR_MECHANISM_INVALID;
343
0
            goto cleanup;
344
0
    }
345
346
0
cleanup:
347
0
    if (session) {
348
0
        sftk_FreeSession(session);
349
0
    }
350
0
    if (key) {
351
0
        status = sftk_FreeObject(key);
352
0
        if (status == SFTK_DestroyFailure) {
353
0
            return CKR_DEVICE_ERROR;
354
0
        }
355
0
    }
356
0
    if (decapsulationKeyObject) {
357
0
        status = sftk_FreeObject(decapsulationKeyObject);
358
0
        if (status == SFTK_DestroyFailure) {
359
0
            return CKR_DEVICE_ERROR;
360
0
        }
361
0
    }
362
0
    if (decapsulationKey) {
363
0
        sftk_FreeAttribute(decapsulationKey);
364
0
    }
365
0
    return crv;
366
0
}