/src/nss/lib/freebl/ecdecode.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 "blapi.h" |
10 | | #include "secoid.h" |
11 | | #include "secitem.h" |
12 | | #include "secerr.h" |
13 | | #include "ec.h" |
14 | | #include "ecl-curve.h" |
15 | | |
16 | | #define CHECK_OK(func) \ |
17 | 0 | if (func == NULL) \ |
18 | 0 | goto cleanup |
19 | | #define CHECK_SEC_OK(func) \ |
20 | 0 | if (SECSuccess != (rv = func)) \ |
21 | 0 | goto cleanup |
22 | | |
23 | | /* Copy all of the fields from srcParams into dstParams |
24 | | */ |
25 | | SECStatus |
26 | | EC_CopyParams(PLArenaPool *arena, ECParams *dstParams, |
27 | | const ECParams *srcParams) |
28 | 0 | { |
29 | 0 | SECStatus rv = SECFailure; |
30 | |
|
31 | 0 | dstParams->arena = arena; |
32 | 0 | dstParams->type = srcParams->type; |
33 | 0 | dstParams->fieldID.size = srcParams->fieldID.size; |
34 | 0 | dstParams->fieldID.type = srcParams->fieldID.type; |
35 | 0 | CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->fieldID.u.prime, |
36 | 0 | &srcParams->fieldID.u.prime)); |
37 | 0 | dstParams->fieldID.k1 = srcParams->fieldID.k1; |
38 | 0 | dstParams->fieldID.k2 = srcParams->fieldID.k2; |
39 | 0 | dstParams->fieldID.k3 = srcParams->fieldID.k3; |
40 | 0 | CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->curve.a, |
41 | 0 | &srcParams->curve.a)); |
42 | 0 | CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->curve.b, |
43 | 0 | &srcParams->curve.b)); |
44 | 0 | CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->curve.seed, |
45 | 0 | &srcParams->curve.seed)); |
46 | 0 | CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->base, |
47 | 0 | &srcParams->base)); |
48 | 0 | CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->order, |
49 | 0 | &srcParams->order)); |
50 | 0 | CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->DEREncoding, |
51 | 0 | &srcParams->DEREncoding)); |
52 | 0 | dstParams->name = srcParams->name; |
53 | 0 | CHECK_SEC_OK(SECITEM_CopyItem(arena, &dstParams->curveOID, |
54 | 0 | &srcParams->curveOID)); |
55 | 0 | dstParams->cofactor = srcParams->cofactor; |
56 | |
|
57 | 0 | return SECSuccess; |
58 | | |
59 | 0 | cleanup: |
60 | 0 | return SECFailure; |
61 | 0 | } |
62 | | |
63 | | static SECStatus |
64 | | gf_populate_params_bytes(ECCurveName name, ECFieldType field_type, ECParams *params) |
65 | 0 | { |
66 | 0 | SECStatus rv = SECFailure; |
67 | 0 | const ECCurveBytes *curveParams; |
68 | |
|
69 | 0 | if ((name < ECCurve_noName) || (name > ECCurve_pastLastCurve)) |
70 | 0 | goto cleanup; |
71 | 0 | params->name = name; |
72 | 0 | curveParams = ecCurve_map[params->name]; |
73 | 0 | CHECK_OK(curveParams); |
74 | 0 | params->fieldID.size = curveParams->size; |
75 | 0 | params->fieldID.type = field_type; |
76 | 0 | if (field_type != ec_field_plain) { |
77 | 0 | return SECFailure; |
78 | 0 | } |
79 | 0 | params->fieldID.u.prime.len = curveParams->scalarSize; |
80 | 0 | params->fieldID.u.prime.data = (unsigned char *)curveParams->irr; |
81 | 0 | params->curve.a.len = curveParams->scalarSize; |
82 | 0 | params->curve.a.data = (unsigned char *)curveParams->curvea; |
83 | 0 | params->curve.b.len = curveParams->scalarSize; |
84 | 0 | params->curve.b.data = (unsigned char *)curveParams->curveb; |
85 | 0 | params->base.len = curveParams->pointSize; |
86 | 0 | params->base.data = (unsigned char *)curveParams->base; |
87 | 0 | params->order.len = curveParams->scalarSize; |
88 | 0 | params->order.data = (unsigned char *)curveParams->order; |
89 | 0 | params->cofactor = curveParams->cofactor; |
90 | |
|
91 | 0 | rv = SECSuccess; |
92 | |
|
93 | 0 | cleanup: |
94 | 0 | return rv; |
95 | 0 | } |
96 | | |
97 | | SECStatus |
98 | | EC_FillParams(PLArenaPool *arena, const SECItem *encodedParams, |
99 | | ECParams *params) |
100 | 0 | { |
101 | 0 | SECStatus rv = SECFailure; |
102 | 0 | SECOidTag tag; |
103 | 0 | SECItem oid = { siBuffer, NULL, 0 }; |
104 | |
|
105 | | #if EC_DEBUG |
106 | | int i; |
107 | | |
108 | | printf("Encoded params in EC_DecodeParams: "); |
109 | | for (i = 0; i < encodedParams->len; i++) { |
110 | | printf("%02x:", encodedParams->data[i]); |
111 | | } |
112 | | printf("\n"); |
113 | | #endif |
114 | |
|
115 | 0 | if ((encodedParams->len != ANSI_X962_CURVE_OID_TOTAL_LEN) && |
116 | 0 | (encodedParams->len != SECG_CURVE_OID_TOTAL_LEN) && |
117 | 0 | (encodedParams->len != PKIX_NEWCURVES_OID_TOTAL_LEN) && |
118 | 0 | (encodedParams->len != ED25519_OID_TOTAL_LEN)) { |
119 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
120 | 0 | return SECFailure; |
121 | 0 | }; |
122 | |
|
123 | 0 | oid.len = encodedParams->len - 2; |
124 | 0 | oid.data = encodedParams->data + 2; |
125 | 0 | if ((encodedParams->data[0] != SEC_ASN1_OBJECT_ID) || |
126 | 0 | ((tag = SECOID_FindOIDTag(&oid)) == SEC_OID_UNKNOWN)) { |
127 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
128 | 0 | return SECFailure; |
129 | 0 | } |
130 | | |
131 | 0 | params->arena = arena; |
132 | 0 | params->cofactor = 0; |
133 | 0 | params->type = ec_params_named; |
134 | 0 | params->name = ECCurve_noName; |
135 | | |
136 | | /* Fill out curveOID */ |
137 | 0 | params->curveOID.len = oid.len; |
138 | 0 | params->curveOID.data = (unsigned char *)PORT_ArenaAlloc(arena, oid.len); |
139 | 0 | if (params->curveOID.data == NULL) |
140 | 0 | goto cleanup; |
141 | 0 | memcpy(params->curveOID.data, oid.data, oid.len); |
142 | |
|
143 | | #if EC_DEBUG |
144 | | printf("Curve: %s\n", SECOID_FindOIDTagDescription(tag)); |
145 | | #endif |
146 | |
|
147 | 0 | switch (tag) { |
148 | 0 | case SEC_OID_ANSIX962_EC_PRIME256V1: |
149 | | /* Populate params for prime256v1 aka secp256r1 |
150 | | * (the NIST P-256 curve) |
151 | | */ |
152 | 0 | CHECK_SEC_OK(gf_populate_params_bytes(ECCurve_X9_62_PRIME_256V1, |
153 | 0 | ec_field_plain, params)); |
154 | 0 | break; |
155 | | |
156 | 0 | case SEC_OID_SECG_EC_SECP384R1: |
157 | | /* Populate params for secp384r1 |
158 | | * (the NIST P-384 curve) |
159 | | */ |
160 | 0 | CHECK_SEC_OK(gf_populate_params_bytes(ECCurve_SECG_PRIME_384R1, |
161 | 0 | ec_field_plain, params)); |
162 | 0 | break; |
163 | | |
164 | 0 | case SEC_OID_SECG_EC_SECP521R1: |
165 | | /* Populate params for secp521r1 |
166 | | * (the NIST P-521 curve) |
167 | | */ |
168 | 0 | CHECK_SEC_OK(gf_populate_params_bytes(ECCurve_SECG_PRIME_521R1, |
169 | 0 | ec_field_plain, params)); |
170 | 0 | break; |
171 | | |
172 | 0 | case SEC_OID_ED25519_PUBLIC_KEY: |
173 | 0 | params->type = ec_params_edwards_named; |
174 | 0 | CHECK_SEC_OK(gf_populate_params_bytes(ECCurve_Ed25519, |
175 | 0 | ec_field_plain, params)); |
176 | | |
177 | 0 | break; |
178 | | |
179 | 0 | case SEC_OID_X25519: |
180 | 0 | case SEC_OID_CURVE25519: |
181 | | /* Populate params for Curve25519 */ |
182 | 0 | params->type = ec_params_montgomery_named; |
183 | 0 | CHECK_SEC_OK(gf_populate_params_bytes(ECCurve25519, |
184 | 0 | ec_field_plain, |
185 | 0 | params)); |
186 | 0 | break; |
187 | | |
188 | 0 | default: |
189 | 0 | break; |
190 | 0 | }; |
191 | |
|
192 | 0 | cleanup: |
193 | 0 | if (!params->cofactor) { |
194 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); |
195 | | #if EC_DEBUG |
196 | | printf("Unrecognized curve, returning NULL params\n"); |
197 | | #endif |
198 | 0 | } |
199 | |
|
200 | 0 | return rv; |
201 | 0 | } |
202 | | |
203 | | SECStatus |
204 | | EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams) |
205 | 0 | { |
206 | 0 | PLArenaPool *arena; |
207 | 0 | ECParams *params; |
208 | 0 | SECStatus rv = SECFailure; |
209 | | |
210 | | /* Initialize an arena for the ECParams structure */ |
211 | 0 | if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE))) |
212 | 0 | return SECFailure; |
213 | | |
214 | 0 | params = (ECParams *)PORT_ArenaZAlloc(arena, sizeof(ECParams)); |
215 | 0 | if (!params) { |
216 | 0 | PORT_FreeArena(arena, PR_TRUE); |
217 | 0 | return SECFailure; |
218 | 0 | } |
219 | | |
220 | | /* Copy the encoded params */ |
221 | 0 | SECITEM_AllocItem(arena, &(params->DEREncoding), |
222 | 0 | encodedParams->len); |
223 | 0 | memcpy(params->DEREncoding.data, encodedParams->data, encodedParams->len); |
224 | | |
225 | | /* Fill out the rest of the ECParams structure based on |
226 | | * the encoded params |
227 | | */ |
228 | 0 | rv = EC_FillParams(arena, encodedParams, params); |
229 | 0 | if (rv == SECFailure) { |
230 | 0 | PORT_FreeArena(arena, PR_TRUE); |
231 | 0 | return SECFailure; |
232 | 0 | } else { |
233 | 0 | *ecparams = params; |
234 | 0 | ; |
235 | 0 | return SECSuccess; |
236 | 0 | } |
237 | 0 | } |
238 | | |
239 | | int |
240 | | EC_GetPointSize(const ECParams *params) |
241 | 0 | { |
242 | 0 | ECCurveName name = params->name; |
243 | 0 | const ECCurveBytes *curveParams; |
244 | |
|
245 | 0 | if ((name < ECCurve_noName) || (name > ECCurve_pastLastCurve) || |
246 | 0 | ((curveParams = ecCurve_map[name]) == NULL)) { |
247 | | /* unknown curve, calculate point size from params. assume standard curves with 2 points |
248 | | * and a point compression indicator byte */ |
249 | 0 | int sizeInBytes = (params->fieldID.size + 7) / 8; |
250 | 0 | return sizeInBytes * 2 + 1; |
251 | 0 | } |
252 | | |
253 | 0 | if (params->type == ec_params_edwards_named || params->type == ec_params_montgomery_named) { |
254 | 0 | return curveParams->scalarSize; |
255 | 0 | } |
256 | | |
257 | 0 | return curveParams->pointSize - 1; |
258 | 0 | } |
259 | | |
260 | | int |
261 | | EC_GetScalarSize(const ECParams *params) |
262 | 0 | { |
263 | 0 | ECCurveName name = params->name; |
264 | 0 | const ECCurveBytes *curveParams; |
265 | |
|
266 | 0 | if ((name < ECCurve_noName) || (name > ECCurve_pastLastCurve) || |
267 | 0 | ((curveParams = ecCurve_map[name]) == NULL)) { |
268 | | /* unknown curve, calculate scalar size from field size in params */ |
269 | 0 | int sizeInBytes = (params->fieldID.size + 7) / 8; |
270 | 0 | return sizeInBytes; |
271 | 0 | } |
272 | 0 | return curveParams->scalarSize; |
273 | 0 | } |