Coverage Report

Created: 2025-07-27 06:09

/src/nss/lib/freebl/ecl/ecp_secp521r1.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
#ifdef FREEBL_NO_DEPEND
6
#include "../stubs.h"
7
#endif
8
9
#include "ecl-priv.h"
10
#include "secitem.h"
11
#include "secerr.h"
12
#include "secmpi.h"
13
#include "../verified/Hacl_P521.h"
14
15
/*
16
 * Point Validation for P-521.
17
 */
18
19
SECStatus
20
ec_secp521r1_pt_validate(const SECItem *pt)
21
0
{
22
0
    SECStatus res = SECSuccess;
23
0
    if (!pt || !pt->data) {
24
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
25
0
        res = SECFailure;
26
0
        return res;
27
0
    }
28
29
0
    if (pt->len != 133) {
30
0
        PORT_SetError(SEC_ERROR_BAD_KEY);
31
0
        res = SECFailure;
32
0
        return res;
33
0
    }
34
35
0
    if (pt->data[0] != EC_POINT_FORM_UNCOMPRESSED) {
36
0
        PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
37
0
        res = SECFailure;
38
0
        return res;
39
0
    }
40
41
0
#ifndef UNSAFE_FUZZER_MODE
42
0
    bool b = Hacl_P521_validate_public_key(pt->data + 1);
43
#else
44
    bool b = PR_TRUE;
45
#endif
46
47
0
    if (!b) {
48
0
        PORT_SetError(SEC_ERROR_BAD_KEY);
49
0
        res = SECFailure;
50
0
    }
51
0
    return res;
52
0
}
53
54
/*
55
 * Scalar Validation for P-521.
56
 */
57
58
SECStatus
59
ec_secp521r1_scalar_validate(const SECItem *scalar)
60
0
{
61
0
    SECStatus res = SECSuccess;
62
0
    if (!scalar || !scalar->data) {
63
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
64
0
        res = SECFailure;
65
0
        return res;
66
0
    }
67
68
0
    if (scalar->len != 66) {
69
0
        PORT_SetError(SEC_ERROR_BAD_KEY);
70
0
        res = SECFailure;
71
0
        return res;
72
0
    }
73
74
0
#ifndef UNSAFE_FUZZER_MODE
75
0
    bool b = Hacl_P521_validate_private_key(scalar->data);
76
#else
77
    bool b = PR_TRUE;
78
#endif
79
80
0
    if (!b) {
81
0
        PORT_SetError(SEC_ERROR_BAD_KEY);
82
0
        res = SECFailure;
83
0
    }
84
0
    return res;
85
0
}
86
87
/*
88
 * Scalar multiplication for P-521.
89
 * If P == NULL, the base point is used.
90
 * Returns X = k*P
91
 */
92
93
SECStatus
94
ec_secp521r1_pt_mul(SECItem *X, SECItem *k, SECItem *P)
95
0
{
96
0
    SECStatus res = SECSuccess;
97
0
    if (!P) {
98
0
        uint8_t derived[132] = { 0 };
99
100
0
        if (!X || !k || !X->data || !k->data ||
101
0
            X->len < 133 || k->len != 66) {
102
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
103
0
            res = SECFailure;
104
0
            return res;
105
0
        }
106
107
0
#ifndef UNSAFE_FUZZER_MODE
108
0
        bool b = Hacl_P521_dh_initiator(derived, k->data);
109
#else
110
        bool b = PR_TRUE;
111
#endif
112
113
0
        if (!b) {
114
0
            PORT_SetError(SEC_ERROR_BAD_KEY);
115
0
            res = SECFailure;
116
0
            return res;
117
0
        }
118
119
0
        X->len = 133;
120
0
        X->data[0] = EC_POINT_FORM_UNCOMPRESSED;
121
0
        memcpy(X->data + 1, derived, 132);
122
123
0
    } else {
124
0
        uint8_t full_key[66] = { 0 };
125
0
        uint8_t *key;
126
0
        uint8_t derived[132] = { 0 };
127
128
0
        if (!X || !k || !P || !X->data || !k->data || !P->data ||
129
0
            X->len < 66 || P->len != 133 ||
130
0
            P->data[0] != EC_POINT_FORM_UNCOMPRESSED) {
131
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
132
0
            res = SECFailure;
133
0
            return res;
134
0
        }
135
136
        /* We consider keys of up to size 66, or of size 67 with a single leading 0 */
137
0
        if (k->len < 66) {
138
0
            memcpy(full_key + 66 - k->len, k->data, k->len);
139
0
            key = full_key;
140
0
        } else if (k->len == 66) {
141
0
            key = k->data;
142
0
        } else if (k->len == 67 && k->data[0] == 0) {
143
0
            key = k->data + 1;
144
0
        } else {
145
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
146
0
            res = SECFailure;
147
0
            return res;
148
0
        }
149
150
0
#ifndef UNSAFE_FUZZER_MODE
151
0
        bool b = Hacl_P521_dh_responder(derived, P->data + 1, key);
152
#else
153
        bool b = key != NULL; /* Avoiding unused variable warnings */
154
#endif
155
156
0
        if (!b) {
157
0
            PORT_SetError(SEC_ERROR_BAD_KEY);
158
0
            res = SECFailure;
159
0
            return res;
160
0
        }
161
162
0
        X->len = 66;
163
0
        memcpy(X->data, derived, 66);
164
0
    }
165
166
0
    return res;
167
0
}
168
169
/*
170
 * ECDSA Signature for P-521
171
 */
172
173
SECStatus
174
ec_secp521r1_sign_digest(ECPrivateKey *ecPrivKey, SECItem *signature,
175
                         const SECItem *digest, const unsigned char *kb,
176
                         const unsigned int kblen)
177
0
{
178
0
    SECStatus res = SECSuccess;
179
180
0
    if (!ecPrivKey || !signature || !digest || !kb ||
181
0
        !ecPrivKey->privateValue.data ||
182
0
        !signature->data || !digest->data ||
183
0
        ecPrivKey->ecParams.name != ECCurve_NIST_P521) {
184
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
185
0
        return SECFailure;
186
0
    }
187
188
0
    if (kblen == 0 || digest->len == 0 || signature->len < 132) {
189
0
        PORT_SetError(SEC_ERROR_INPUT_LEN);
190
0
        return SECFailure;
191
0
    }
192
193
    // Private keys should be 66 bytes, but some software trims leading zeros,
194
    // and some software produces 67 byte keys with a leading zero. We'll
195
    // accept these variants.
196
0
    uint8_t padded_key_data[66] = { 0 };
197
0
    uint8_t *key;
198
0
    SECItem *privKey = &ecPrivKey->privateValue;
199
0
    if (privKey->len == 66) {
200
0
        key = privKey->data;
201
0
    } else if (privKey->len == 67 && privKey->data[0] == 0) {
202
0
        key = privKey->data + 1;
203
0
    } else if (privKey->len < 66) {
204
0
        memcpy(padded_key_data + 66 - privKey->len, privKey->data, privKey->len);
205
0
        key = padded_key_data;
206
0
    } else {
207
0
        PORT_SetError(SEC_ERROR_INPUT_LEN);
208
0
        return SECFailure;
209
0
    }
210
211
0
    uint8_t hash[66] = { 0 };
212
0
    if (digest->len < 66) {
213
0
        memcpy(hash + 66 - digest->len, digest->data, digest->len);
214
0
    } else {
215
        // SEC 1 takes the most significant ceil(log(n)) bits of hash output when the hash output is longer than log(n).
216
0
        hash[0] = digest->data[0] >> 7;
217
0
        for (size_t i = 1; i < 66; i++) {
218
0
            hash[i] = (digest->data[i - 1] << 1) | (digest->data[i] >> 7);
219
0
        }
220
0
    }
221
222
0
    uint8_t nonce[66] = { 0 };
223
0
    if (kblen < 66) {
224
0
        memcpy(nonce + 66 - kblen, kb, kblen);
225
0
    } else {
226
0
        memcpy(nonce, kb, 66);
227
0
    }
228
229
0
#ifndef UNSAFE_FUZZER_MODE
230
0
    bool b = Hacl_P521_ecdsa_sign_p521_without_hash(
231
0
        signature->data, 66, hash, key, nonce);
232
#else
233
    bool b = key != NULL;     /* Avoiding unused variable warnings */
234
#endif
235
236
0
    if (!b) {
237
0
        PORT_SetError(SEC_ERROR_BAD_KEY);
238
0
        res = SECFailure;
239
0
        return res;
240
0
    }
241
242
0
    signature->len = 132;
243
0
    return res;
244
0
}
245
246
/*
247
 * ECDSA Signature Verification for P-521
248
 */
249
250
SECStatus
251
ec_secp521r1_verify_digest(ECPublicKey *key, const SECItem *signature,
252
                           const SECItem *digest)
253
0
{
254
0
    SECStatus res = SECSuccess;
255
256
0
    if (!key || !signature || !digest ||
257
0
        !key->publicValue.data ||
258
0
        !signature->data || !digest->data ||
259
0
        key->ecParams.name != ECCurve_NIST_P521) {
260
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
261
0
        res = SECFailure;
262
0
        return res;
263
0
    }
264
265
0
    if (signature->len == 0 || signature->len % 2 != 0 ||
266
0
        signature->len > 132 || digest->len == 0 ||
267
0
        key->publicValue.len != 133) {
268
0
        PORT_SetError(SEC_ERROR_INPUT_LEN);
269
0
        res = SECFailure;
270
0
        return res;
271
0
    }
272
273
0
    if (key->publicValue.data[0] != EC_POINT_FORM_UNCOMPRESSED) {
274
0
        PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
275
0
        res = SECFailure;
276
0
        return res;
277
0
    }
278
279
    // Signatures should be 132 bytes, but some software produces short signatures.
280
    // Pad components with zeros if necessary.
281
0
    uint8_t paddedSigData[132] = { 0 };
282
0
    uint8_t *sig;
283
0
    if (signature->len != 132) {
284
0
        size_t split = signature->len / 2;
285
286
0
        memcpy(paddedSigData + 66 - split, signature->data, split);
287
0
        memcpy(paddedSigData + 132 - split, signature->data + split, split);
288
289
0
        sig = paddedSigData;
290
0
    } else {
291
0
        sig = signature->data;
292
0
    }
293
294
0
    uint8_t hash[66] = { 0 };
295
0
    if (digest->len < 66) {
296
0
        memcpy(hash + 66 - digest->len, digest->data, digest->len);
297
0
    } else {
298
        // SEC 1 takes the most significant ceil(log(n)) bits of hash output when the hash output is longer than log(n).
299
0
        hash[0] = digest->data[0] >> 7;
300
0
        for (size_t i = 1; i < 66; i++) {
301
0
            hash[i] = (digest->data[i - 1] << 1) | (digest->data[i] >> 7);
302
0
        }
303
0
    }
304
305
0
#ifndef UNSAFE_FUZZER_MODE
306
0
    bool b = Hacl_P521_ecdsa_verif_without_hash(
307
0
        66, hash, key->publicValue.data + 1, sig, sig + 66);
308
#else
309
    bool b = sig != NULL;     /* Avoiding unused variable warnings */
310
#endif
311
312
0
    if (!b) {
313
0
        PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
314
0
        res = SECFailure;
315
0
        return res;
316
0
    }
317
318
0
    return res;
319
0
}