Coverage Report

Created: 2024-11-21 07:03

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