Coverage Report

Created: 2026-02-18 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nss/lib/freebl/ecl/ecp_secp521r1.c
Line
Count
Source
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
2.44k
{
22
2.44k
    SECStatus res = SECSuccess;
23
2.44k
    if (!pt || !pt->data) {
24
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
25
0
        res = SECFailure;
26
0
        return res;
27
0
    }
28
29
2.44k
    if (pt->len != 133) {
30
158
        PORT_SetError(SEC_ERROR_BAD_KEY);
31
158
        res = SECFailure;
32
158
        return res;
33
158
    }
34
35
2.28k
    if (pt->data[0] != EC_POINT_FORM_UNCOMPRESSED) {
36
44
        PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
37
44
        res = SECFailure;
38
44
        return res;
39
44
    }
40
41
#ifndef UNSAFE_FUZZER_MODE
42
1.12k
    bool b = Hacl_P521_validate_public_key(pt->data + 1);
43
#else
44
1.12k
    bool b = PR_TRUE;
45
#endif
46
47
2.24k
    if (!b) {
48
680
        PORT_SetError(SEC_ERROR_BAD_KEY);
49
680
        res = SECFailure;
50
680
    }
51
1.12k
    return res;
52
2.28k
}
ec_secp521r1_pt_validate
Line
Count
Source
21
1.22k
{
22
1.22k
    SECStatus res = SECSuccess;
23
1.22k
    if (!pt || !pt->data) {
24
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
25
0
        res = SECFailure;
26
0
        return res;
27
0
    }
28
29
1.22k
    if (pt->len != 133) {
30
79
        PORT_SetError(SEC_ERROR_BAD_KEY);
31
79
        res = SECFailure;
32
79
        return res;
33
79
    }
34
35
1.14k
    if (pt->data[0] != EC_POINT_FORM_UNCOMPRESSED) {
36
22
        PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
37
22
        res = SECFailure;
38
22
        return res;
39
22
    }
40
41
1.12k
#ifndef UNSAFE_FUZZER_MODE
42
1.14k
    bool b = Hacl_P521_validate_public_key(pt->data + 1);
43
#else
44
    bool b = PR_TRUE;
45
#endif
46
47
1.12k
    if (!b) {
48
340
        PORT_SetError(SEC_ERROR_BAD_KEY);
49
340
        res = SECFailure;
50
340
    }
51
1.12k
    return res;
52
1.14k
}
ec_secp521r1_pt_validate
Line
Count
Source
21
1.22k
{
22
1.22k
    SECStatus res = SECSuccess;
23
1.22k
    if (!pt || !pt->data) {
24
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
25
0
        res = SECFailure;
26
0
        return res;
27
0
    }
28
29
1.22k
    if (pt->len != 133) {
30
79
        PORT_SetError(SEC_ERROR_BAD_KEY);
31
79
        res = SECFailure;
32
79
        return res;
33
79
    }
34
35
1.14k
    if (pt->data[0] != EC_POINT_FORM_UNCOMPRESSED) {
36
22
        PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
37
22
        res = SECFailure;
38
22
        return res;
39
22
    }
40
41
#ifndef UNSAFE_FUZZER_MODE
42
    bool b = Hacl_P521_validate_public_key(pt->data + 1);
43
#else
44
1.14k
    bool b = PR_TRUE;
45
1.12k
#endif
46
47
1.12k
    if (!b) {
48
340
        PORT_SetError(SEC_ERROR_BAD_KEY);
49
340
        res = SECFailure;
50
340
    }
51
1.12k
    return res;
52
1.14k
}
53
54
/*
55
 * Scalar Validation for P-521.
56
 */
57
58
SECStatus
59
ec_secp521r1_scalar_validate(const SECItem *scalar)
60
872
{
61
872
    SECStatus res = SECSuccess;
62
872
    if (!scalar || !scalar->data) {
63
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
64
0
        res = SECFailure;
65
0
        return res;
66
0
    }
67
68
872
    if (scalar->len != 66) {
69
0
        PORT_SetError(SEC_ERROR_BAD_KEY);
70
0
        res = SECFailure;
71
0
        return res;
72
0
    }
73
74
#ifndef UNSAFE_FUZZER_MODE
75
436
    bool b = Hacl_P521_validate_private_key(scalar->data);
76
#else
77
436
    bool b = PR_TRUE;
78
#endif
79
80
872
    if (!b) {
81
0
        PORT_SetError(SEC_ERROR_BAD_KEY);
82
0
        res = SECFailure;
83
0
    }
84
436
    return res;
85
872
}
ec_secp521r1_scalar_validate
Line
Count
Source
60
436
{
61
436
    SECStatus res = SECSuccess;
62
436
    if (!scalar || !scalar->data) {
63
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
64
0
        res = SECFailure;
65
0
        return res;
66
0
    }
67
68
436
    if (scalar->len != 66) {
69
0
        PORT_SetError(SEC_ERROR_BAD_KEY);
70
0
        res = SECFailure;
71
0
        return res;
72
0
    }
73
74
436
#ifndef UNSAFE_FUZZER_MODE
75
436
    bool b = Hacl_P521_validate_private_key(scalar->data);
76
#else
77
    bool b = PR_TRUE;
78
#endif
79
80
436
    if (!b) {
81
0
        PORT_SetError(SEC_ERROR_BAD_KEY);
82
0
        res = SECFailure;
83
0
    }
84
436
    return res;
85
436
}
ec_secp521r1_scalar_validate
Line
Count
Source
60
436
{
61
436
    SECStatus res = SECSuccess;
62
436
    if (!scalar || !scalar->data) {
63
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
64
0
        res = SECFailure;
65
0
        return res;
66
0
    }
67
68
436
    if (scalar->len != 66) {
69
0
        PORT_SetError(SEC_ERROR_BAD_KEY);
70
0
        res = SECFailure;
71
0
        return res;
72
0
    }
73
74
#ifndef UNSAFE_FUZZER_MODE
75
    bool b = Hacl_P521_validate_private_key(scalar->data);
76
#else
77
436
    bool b = PR_TRUE;
78
436
#endif
79
80
436
    if (!b) {
81
0
        PORT_SetError(SEC_ERROR_BAD_KEY);
82
0
        res = SECFailure;
83
0
    }
84
436
    return res;
85
436
}
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
786
{
96
786
    SECStatus res = SECSuccess;
97
786
    if (!P) {
98
656
        uint8_t derived[132] = { 0 };
99
100
656
        if (!X || !k || !X->data || !k->data ||
101
656
            X->len < 133 || k->len != 66) {
102
4
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
103
4
            res = SECFailure;
104
4
            return res;
105
4
        }
106
107
#ifndef UNSAFE_FUZZER_MODE
108
473
        bool b = Hacl_P521_dh_initiator(derived, k->data);
109
#else
110
179
        bool b = PR_TRUE;
111
#endif
112
113
652
        if (!b) {
114
21
            PORT_SetError(SEC_ERROR_BAD_KEY);
115
21
            res = SECFailure;
116
21
            return res;
117
21
        }
118
119
631
        X->len = 133;
120
631
        X->data[0] = EC_POINT_FORM_UNCOMPRESSED;
121
631
        memcpy(X->data + 1, derived, 132);
122
123
631
    } else {
124
130
        uint8_t full_key[66] = { 0 };
125
130
        uint8_t *key;
126
130
        uint8_t derived[132] = { 0 };
127
128
130
        if (!X || !k || !P || !X->data || !k->data || !P->data ||
129
130
            X->len < 66 || P->len != 133 ||
130
130
            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
130
        if (k->len < 66) {
138
0
            memcpy(full_key + 66 - k->len, k->data, k->len);
139
0
            key = full_key;
140
130
        } else if (k->len == 66) {
141
130
            key = k->data;
142
130
        } 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
#ifndef UNSAFE_FUZZER_MODE
151
17
        bool b = Hacl_P521_dh_responder(derived, P->data + 1, key);
152
#else
153
113
        bool b = key != NULL; /* Avoiding unused variable warnings */
154
113
#endif
155
156
130
        if (!b) {
157
0
            PORT_SetError(SEC_ERROR_BAD_KEY);
158
0
            res = SECFailure;
159
0
            return res;
160
0
        }
161
162
130
        X->len = 66;
163
130
        memcpy(X->data, derived, 66);
164
130
    }
165
166
761
    return res;
167
786
}
ec_secp521r1_pt_mul
Line
Count
Source
95
494
{
96
494
    SECStatus res = SECSuccess;
97
494
    if (!P) {
98
477
        uint8_t derived[132] = { 0 };
99
100
477
        if (!X || !k || !X->data || !k->data ||
101
477
            X->len < 133 || k->len != 66) {
102
4
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
103
4
            res = SECFailure;
104
4
            return res;
105
4
        }
106
107
473
#ifndef UNSAFE_FUZZER_MODE
108
477
        bool b = Hacl_P521_dh_initiator(derived, k->data);
109
#else
110
        bool b = PR_TRUE;
111
#endif
112
113
473
        if (!b) {
114
21
            PORT_SetError(SEC_ERROR_BAD_KEY);
115
21
            res = SECFailure;
116
21
            return res;
117
21
        }
118
119
452
        X->len = 133;
120
452
        X->data[0] = EC_POINT_FORM_UNCOMPRESSED;
121
452
        memcpy(X->data + 1, derived, 132);
122
123
452
    } else {
124
17
        uint8_t full_key[66] = { 0 };
125
17
        uint8_t *key;
126
17
        uint8_t derived[132] = { 0 };
127
128
17
        if (!X || !k || !P || !X->data || !k->data || !P->data ||
129
17
            X->len < 66 || P->len != 133 ||
130
17
            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
17
        if (k->len < 66) {
138
0
            memcpy(full_key + 66 - k->len, k->data, k->len);
139
0
            key = full_key;
140
17
        } else if (k->len == 66) {
141
17
            key = k->data;
142
17
        } 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
17
#ifndef UNSAFE_FUZZER_MODE
151
17
        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
17
        if (!b) {
157
0
            PORT_SetError(SEC_ERROR_BAD_KEY);
158
0
            res = SECFailure;
159
0
            return res;
160
0
        }
161
162
17
        X->len = 66;
163
17
        memcpy(X->data, derived, 66);
164
17
    }
165
166
469
    return res;
167
494
}
ec_secp521r1_pt_mul
Line
Count
Source
95
292
{
96
292
    SECStatus res = SECSuccess;
97
292
    if (!P) {
98
179
        uint8_t derived[132] = { 0 };
99
100
179
        if (!X || !k || !X->data || !k->data ||
101
179
            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
#ifndef UNSAFE_FUZZER_MODE
108
        bool b = Hacl_P521_dh_initiator(derived, k->data);
109
#else
110
179
        bool b = PR_TRUE;
111
179
#endif
112
113
179
        if (!b) {
114
0
            PORT_SetError(SEC_ERROR_BAD_KEY);
115
0
            res = SECFailure;
116
0
            return res;
117
0
        }
118
119
179
        X->len = 133;
120
179
        X->data[0] = EC_POINT_FORM_UNCOMPRESSED;
121
179
        memcpy(X->data + 1, derived, 132);
122
123
179
    } else {
124
113
        uint8_t full_key[66] = { 0 };
125
113
        uint8_t *key;
126
113
        uint8_t derived[132] = { 0 };
127
128
113
        if (!X || !k || !P || !X->data || !k->data || !P->data ||
129
113
            X->len < 66 || P->len != 133 ||
130
113
            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
113
        if (k->len < 66) {
138
0
            memcpy(full_key + 66 - k->len, k->data, k->len);
139
0
            key = full_key;
140
113
        } else if (k->len == 66) {
141
113
            key = k->data;
142
113
        } 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
#ifndef UNSAFE_FUZZER_MODE
151
        bool b = Hacl_P521_dh_responder(derived, P->data + 1, key);
152
#else
153
113
        bool b = key != NULL; /* Avoiding unused variable warnings */
154
113
#endif
155
156
113
        if (!b) {
157
0
            PORT_SetError(SEC_ERROR_BAD_KEY);
158
0
            res = SECFailure;
159
0
            return res;
160
0
        }
161
162
113
        X->len = 66;
163
113
        memcpy(X->data, derived, 66);
164
113
    }
165
166
292
    return res;
167
292
}
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
82
{
178
82
    SECStatus res = SECSuccess;
179
180
82
    if (!ecPrivKey || !signature || !digest || !kb ||
181
82
        !ecPrivKey->privateValue.data ||
182
82
        !signature->data || !digest->data ||
183
82
        ecPrivKey->ecParams.name != ECCurve_NIST_P521) {
184
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
185
0
        return SECFailure;
186
0
    }
187
188
82
    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
82
    uint8_t padded_key_data[66] = { 0 };
197
82
    uint8_t *key;
198
82
    SECItem *privKey = &ecPrivKey->privateValue;
199
82
    if (privKey->len == 66) {
200
82
        key = privKey->data;
201
82
    } 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
82
    uint8_t hash[66] = { 0 };
212
82
    if (digest->len < 66) {
213
72
        memcpy(hash + 66 - digest->len, digest->data, digest->len);
214
72
    } 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
10
        hash[0] = digest->data[0] >> 7;
217
660
        for (size_t i = 1; i < 66; i++) {
218
650
            hash[i] = (digest->data[i - 1] << 1) | (digest->data[i] >> 7);
219
650
        }
220
10
    }
221
222
82
    uint8_t nonce[66] = { 0 };
223
82
    if (kblen < 66) {
224
39
        memcpy(nonce + 66 - kblen, kb, kblen);
225
43
    } else {
226
43
        memcpy(nonce, kb, 66);
227
43
    }
228
229
82
#ifndef UNSAFE_FUZZER_MODE
230
82
    bool b = Hacl_P521_ecdsa_sign_p521_without_hash(
231
82
        signature->data, 66, hash, key, nonce);
232
#else
233
    bool b = key != NULL;     /* Avoiding unused variable warnings */
234
#endif
235
236
82
    if (!b) {
237
11
        PORT_SetError(SEC_ERROR_BAD_KEY);
238
11
        res = SECFailure;
239
11
        return res;
240
11
    }
241
242
71
    signature->len = 132;
243
71
    return res;
244
82
}
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
232
{
254
232
    SECStatus res = SECSuccess;
255
256
232
    if (!key || !signature || !digest ||
257
232
        !key->publicValue.data ||
258
232
        !signature->data || !digest->data ||
259
232
        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
232
    if (signature->len == 0 || signature->len % 2 != 0 ||
266
232
        signature->len > 132 || digest->len == 0 ||
267
232
        key->publicValue.len != 133) {
268
0
        PORT_SetError(SEC_ERROR_INPUT_LEN);
269
0
        res = SECFailure;
270
0
        return res;
271
0
    }
272
273
232
    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
232
    uint8_t paddedSigData[132] = { 0 };
282
232
    uint8_t *sig;
283
232
    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
232
    } else {
291
232
        sig = signature->data;
292
232
    }
293
294
232
    uint8_t hash[66] = { 0 };
295
232
    if (digest->len < 66) {
296
221
        memcpy(hash + 66 - digest->len, digest->data, digest->len);
297
221
    } 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
11
        hash[0] = digest->data[0] >> 7;
300
726
        for (size_t i = 1; i < 66; i++) {
301
715
            hash[i] = (digest->data[i - 1] << 1) | (digest->data[i] >> 7);
302
715
        }
303
11
    }
304
305
232
#ifndef UNSAFE_FUZZER_MODE
306
232
    bool b = Hacl_P521_ecdsa_verif_without_hash(
307
232
        66, hash, key->publicValue.data + 1, sig, sig + 66);
308
#else
309
    bool b = sig != NULL;     /* Avoiding unused variable warnings */
310
#endif
311
312
232
    if (!b) {
313
151
        PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
314
151
        res = SECFailure;
315
151
        return res;
316
151
    }
317
318
81
    return res;
319
232
}
320
321
/*
322
    Point decompression for P-521.
323
324
    publicCompressed must be 67 bytes (1 byte for a sign and 66 bytes for the x coordinate.
325
    publicUncompressed must be 132 bytes (66 * 2).
326
    The function returns SECSuccess if the decompression was success and the decompresse
327
    point is a valid P-521 curve point.
328
*/
329
330
SECStatus
331
ec_secp521r1_decompress(const SECItem *publicCompressed, SECItem *publicUncompressed)
332
33
{
333
33
    if (!publicCompressed || !publicCompressed->data) {
334
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
335
0
        return SECFailure;
336
0
    }
337
338
33
    if (publicCompressed->len != 67) {
339
33
        PORT_SetError(SEC_ERROR_BAD_KEY);
340
33
        return SECFailure;
341
33
    }
342
343
0
    if (!publicUncompressed || !publicUncompressed->data) {
344
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
345
0
        return SECFailure;
346
0
    }
347
348
0
    if (publicUncompressed->len != 133) {
349
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
350
0
        return SECFailure;
351
0
    }
352
353
0
    if (publicCompressed->data[0] != EC_POINT_FORM_COMPRESSED_Y0 &&
354
0
        publicCompressed->data[0] != EC_POINT_FORM_COMPRESSED_Y1) {
355
0
        PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM);
356
0
        return SECFailure;
357
0
    }
358
359
0
    bool b = Hacl_P521_compressed_to_raw(publicCompressed->data, publicUncompressed->data + 1);
360
361
0
    if (!b) {
362
0
        PORT_SetError(SEC_ERROR_BAD_KEY);
363
0
        return SECFailure;
364
0
    }
365
366
0
    publicUncompressed->data[0] = EC_POINT_FORM_UNCOMPRESSED;
367
0
    return SECSuccess;
368
0
}