diff options
author | tb <> | 2024-10-30 18:16:34 +0000 |
---|---|---|
committer | tb <> | 2024-10-30 18:16:34 +0000 |
commit | f953655e6861bda2cfd07fa49af0ecd20b4507c2 (patch) | |
tree | 4305dbdabff19dba57f0176ca9be0a859323868b /src/lib | |
parent | 8c30fb7d85e73088455141bfbd758b3a43c931df (diff) | |
download | openbsd-f953655e6861bda2cfd07fa49af0ecd20b4507c2.tar.gz openbsd-f953655e6861bda2cfd07fa49af0ecd20b4507c2.tar.bz2 openbsd-f953655e6861bda2cfd07fa49af0ecd20b4507c2.zip |
Move the GFp-specific point <-> octets functions to ec_convert.c
discussed with jsing
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/libcrypto/ec/ec_convert.c | 296 | ||||
-rw-r--r-- | src/lib/libcrypto/ec/ecp_oct.c | 296 |
2 files changed, 296 insertions, 296 deletions
diff --git a/src/lib/libcrypto/ec/ec_convert.c b/src/lib/libcrypto/ec/ec_convert.c index fd0182f420..123cf90ef9 100644 --- a/src/lib/libcrypto/ec/ec_convert.c +++ b/src/lib/libcrypto/ec/ec_convert.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ec_convert.c,v 1.1 2024/10/30 18:14:49 tb Exp $ */ | 1 | /* $OpenBSD: ec_convert.c,v 1.2 2024/10/30 18:16:34 tb Exp $ */ |
2 | /* | 2 | /* |
3 | * Originally written by Bodo Moeller for the OpenSSL project. | 3 | * Originally written by Bodo Moeller for the OpenSSL project. |
4 | */ | 4 | */ |
@@ -69,6 +69,300 @@ | |||
69 | #include "asn1_local.h" | 69 | #include "asn1_local.h" |
70 | #include "ec_local.h" | 70 | #include "ec_local.h" |
71 | 71 | ||
72 | /* | ||
73 | * Only the last three bits of the leading octet of a point should be set. | ||
74 | * Bits 3 and 2 encode the conversion form for all points except the point | ||
75 | * at infinity. In compressed and hybrid form bit 1 indicates if the even | ||
76 | * or the odd solution of the quadratic equation for y should be used. | ||
77 | * | ||
78 | * The public point_conversion_t enum lacks the point at infinity, so we | ||
79 | * ignore it except at the API boundary. | ||
80 | */ | ||
81 | |||
82 | #define EC_OCT_YBIT 0x01 | ||
83 | |||
84 | #define EC_OCT_POINT_AT_INFINITY 0x00 | ||
85 | #define EC_OCT_POINT_COMPRESSED 0x02 | ||
86 | #define EC_OCT_POINT_UNCOMPRESSED 0x04 | ||
87 | #define EC_OCT_POINT_HYBRID 0x06 | ||
88 | #define EC_OCT_POINT_CONVERSION_MASK 0x06 | ||
89 | |||
90 | static int | ||
91 | ec_oct_conversion_form_is_valid(uint8_t form) | ||
92 | { | ||
93 | return (form & EC_OCT_POINT_CONVERSION_MASK) == form; | ||
94 | } | ||
95 | |||
96 | static int | ||
97 | ec_oct_check_hybrid_ybit_is_consistent(uint8_t form, int ybit, const BIGNUM *y) | ||
98 | { | ||
99 | if (form == EC_OCT_POINT_HYBRID && ybit != BN_is_odd(y)) { | ||
100 | ECerror(EC_R_INVALID_ENCODING); | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | return 1; | ||
105 | } | ||
106 | |||
107 | /* Nonzero y-bit only makes sense with compressed or hybrid encoding. */ | ||
108 | static int | ||
109 | ec_oct_nonzero_ybit_allowed(uint8_t form) | ||
110 | { | ||
111 | return form == EC_OCT_POINT_COMPRESSED || form == EC_OCT_POINT_HYBRID; | ||
112 | } | ||
113 | |||
114 | static int | ||
115 | ec_oct_add_leading_octet_cbb(CBB *cbb, uint8_t form, int ybit) | ||
116 | { | ||
117 | if (ec_oct_nonzero_ybit_allowed(form) && ybit != 0) | ||
118 | form |= EC_OCT_YBIT; | ||
119 | |||
120 | return CBB_add_u8(cbb, form); | ||
121 | } | ||
122 | |||
123 | static int | ||
124 | ec_oct_get_leading_octet_cbs(CBS *cbs, uint8_t *out_form, int *out_ybit) | ||
125 | { | ||
126 | uint8_t octet; | ||
127 | |||
128 | if (!CBS_get_u8(cbs, &octet)) { | ||
129 | ECerror(EC_R_BUFFER_TOO_SMALL); | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | *out_ybit = octet & EC_OCT_YBIT; | ||
134 | *out_form = octet & ~EC_OCT_YBIT; | ||
135 | |||
136 | if (!ec_oct_conversion_form_is_valid(*out_form)) { | ||
137 | ECerror(EC_R_INVALID_ENCODING); | ||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | if (*out_ybit != 0 && !ec_oct_nonzero_ybit_allowed(*out_form)) { | ||
142 | ECerror(EC_R_INVALID_ENCODING); | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | return 1; | ||
147 | } | ||
148 | |||
149 | static int | ||
150 | ec_oct_encoded_length(const EC_GROUP *group, uint8_t form, size_t *out_len) | ||
151 | { | ||
152 | switch (form) { | ||
153 | case EC_OCT_POINT_AT_INFINITY: | ||
154 | *out_len = 1; | ||
155 | return 1; | ||
156 | case EC_OCT_POINT_COMPRESSED: | ||
157 | *out_len = 1 + BN_num_bytes(&group->field); | ||
158 | return 1; | ||
159 | case EC_OCT_POINT_UNCOMPRESSED: | ||
160 | case EC_OCT_POINT_HYBRID: | ||
161 | *out_len = 1 + 2 * BN_num_bytes(&group->field); | ||
162 | return 1; | ||
163 | default: | ||
164 | return 0; | ||
165 | } | ||
166 | } | ||
167 | |||
168 | static int | ||
169 | ec_oct_field_element_is_valid(const EC_GROUP *group, const BIGNUM *bn) | ||
170 | { | ||
171 | /* Ensure bn is in the range [0, field). */ | ||
172 | return !BN_is_negative(bn) && BN_cmp(&group->field, bn) > 0; | ||
173 | } | ||
174 | |||
175 | static int | ||
176 | ec_oct_add_field_element_cbb(CBB *cbb, const EC_GROUP *group, const BIGNUM *bn) | ||
177 | { | ||
178 | uint8_t *buf = NULL; | ||
179 | int buf_len = BN_num_bytes(&group->field); | ||
180 | |||
181 | if (!ec_oct_field_element_is_valid(group, bn)) { | ||
182 | ECerror(EC_R_BIGNUM_OUT_OF_RANGE); | ||
183 | return 0; | ||
184 | } | ||
185 | if (!CBB_add_space(cbb, &buf, buf_len)) { | ||
186 | ECerror(ERR_R_MALLOC_FAILURE); | ||
187 | return 0; | ||
188 | } | ||
189 | if (BN_bn2binpad(bn, buf, buf_len) != buf_len) { | ||
190 | ECerror(ERR_R_MALLOC_FAILURE); | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | return 1; | ||
195 | } | ||
196 | |||
197 | static int | ||
198 | ec_oct_get_field_element_cbs(CBS *cbs, const EC_GROUP *group, BIGNUM *bn) | ||
199 | { | ||
200 | CBS field_element; | ||
201 | |||
202 | if (!CBS_get_bytes(cbs, &field_element, BN_num_bytes(&group->field))) { | ||
203 | ECerror(EC_R_INVALID_ENCODING); | ||
204 | return 0; | ||
205 | } | ||
206 | if (!BN_bin2bn(CBS_data(&field_element), CBS_len(&field_element), bn)) { | ||
207 | ECerror(ERR_R_MALLOC_FAILURE); | ||
208 | return 0; | ||
209 | } | ||
210 | if (!ec_oct_field_element_is_valid(group, bn)) { | ||
211 | ECerror(EC_R_BIGNUM_OUT_OF_RANGE); | ||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | return 1; | ||
216 | } | ||
217 | |||
218 | size_t | ||
219 | ec_GFp_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, | ||
220 | point_conversion_form_t conversion_form, unsigned char *buf, size_t len, | ||
221 | BN_CTX *ctx) | ||
222 | { | ||
223 | CBB cbb; | ||
224 | uint8_t form; | ||
225 | BIGNUM *x, *y; | ||
226 | size_t encoded_length; | ||
227 | size_t ret = 0; | ||
228 | |||
229 | if (conversion_form > UINT8_MAX) { | ||
230 | ECerror(EC_R_INVALID_FORM); | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | form = conversion_form; | ||
235 | |||
236 | /* | ||
237 | * Established behavior is to reject a request for the form 0 for the | ||
238 | * point at infinity even if it is valid. | ||
239 | */ | ||
240 | if (form == 0 || !ec_oct_conversion_form_is_valid(form)) { | ||
241 | ECerror(EC_R_INVALID_FORM); | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | if (EC_POINT_is_at_infinity(group, point)) | ||
246 | form = EC_OCT_POINT_AT_INFINITY; | ||
247 | |||
248 | if (!ec_oct_encoded_length(group, form, &encoded_length)) { | ||
249 | ECerror(EC_R_INVALID_FORM); | ||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | if (buf == NULL) | ||
254 | return encoded_length; | ||
255 | |||
256 | if (len < encoded_length) { | ||
257 | ECerror(EC_R_BUFFER_TOO_SMALL); | ||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | BN_CTX_start(ctx); | ||
262 | if (!CBB_init_fixed(&cbb, buf, len)) | ||
263 | goto err; | ||
264 | |||
265 | if (form == EC_OCT_POINT_AT_INFINITY) { | ||
266 | if (!ec_oct_add_leading_octet_cbb(&cbb, form, 0)) | ||
267 | goto err; | ||
268 | |||
269 | goto done; | ||
270 | } | ||
271 | |||
272 | if ((x = BN_CTX_get(ctx)) == NULL) | ||
273 | goto err; | ||
274 | if ((y = BN_CTX_get(ctx)) == NULL) | ||
275 | goto err; | ||
276 | if (!EC_POINT_get_affine_coordinates(group, point, x, y, ctx)) | ||
277 | goto err; | ||
278 | |||
279 | if (!ec_oct_add_leading_octet_cbb(&cbb, form, BN_is_odd(y))) | ||
280 | goto err; | ||
281 | |||
282 | if (form == EC_OCT_POINT_COMPRESSED) { | ||
283 | if (!ec_oct_add_field_element_cbb(&cbb, group, x)) | ||
284 | goto err; | ||
285 | } else { | ||
286 | if (!ec_oct_add_field_element_cbb(&cbb, group, x)) | ||
287 | goto err; | ||
288 | if (!ec_oct_add_field_element_cbb(&cbb, group, y)) | ||
289 | goto err; | ||
290 | } | ||
291 | |||
292 | done: | ||
293 | if (!CBB_finish(&cbb, NULL, &ret)) | ||
294 | goto err; | ||
295 | |||
296 | if (ret != encoded_length) { | ||
297 | ret = 0; | ||
298 | goto err; | ||
299 | } | ||
300 | |||
301 | err: | ||
302 | CBB_cleanup(&cbb); | ||
303 | BN_CTX_end(ctx); | ||
304 | |||
305 | return ret; | ||
306 | } | ||
307 | |||
308 | int | ||
309 | ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point, | ||
310 | const unsigned char *buf, size_t len, BN_CTX *ctx) | ||
311 | { | ||
312 | CBS cbs; | ||
313 | uint8_t form; | ||
314 | int ybit; | ||
315 | BIGNUM *x, *y; | ||
316 | int ret = 0; | ||
317 | |||
318 | BN_CTX_start(ctx); | ||
319 | CBS_init(&cbs, buf, len); | ||
320 | |||
321 | if (!ec_oct_get_leading_octet_cbs(&cbs, &form, &ybit)) | ||
322 | goto err; | ||
323 | |||
324 | if (form == EC_OCT_POINT_AT_INFINITY) { | ||
325 | if (!EC_POINT_set_to_infinity(group, point)) | ||
326 | goto err; | ||
327 | |||
328 | goto done; | ||
329 | } | ||
330 | |||
331 | if ((x = BN_CTX_get(ctx)) == NULL) | ||
332 | goto err; | ||
333 | if ((y = BN_CTX_get(ctx)) == NULL) | ||
334 | goto err; | ||
335 | |||
336 | if (form == EC_OCT_POINT_COMPRESSED) { | ||
337 | if (!ec_oct_get_field_element_cbs(&cbs, group, x)) | ||
338 | goto err; | ||
339 | if (!EC_POINT_set_compressed_coordinates(group, point, x, ybit, ctx)) | ||
340 | goto err; | ||
341 | } else { | ||
342 | if (!ec_oct_get_field_element_cbs(&cbs, group, x)) | ||
343 | goto err; | ||
344 | if (!ec_oct_get_field_element_cbs(&cbs, group, y)) | ||
345 | goto err; | ||
346 | if (!ec_oct_check_hybrid_ybit_is_consistent(form, ybit, y)) | ||
347 | goto err; | ||
348 | if (!EC_POINT_set_affine_coordinates(group, point, x, y, ctx)) | ||
349 | goto err; | ||
350 | } | ||
351 | |||
352 | done: | ||
353 | if (CBS_len(&cbs) > 0) { | ||
354 | ECerror(EC_R_INVALID_ENCODING); | ||
355 | goto err; | ||
356 | } | ||
357 | |||
358 | ret = 1; | ||
359 | |||
360 | err: | ||
361 | BN_CTX_end(ctx); | ||
362 | |||
363 | return ret; | ||
364 | } | ||
365 | |||
72 | int | 366 | int |
73 | ec_point_to_octets(const EC_GROUP *group, const EC_POINT *point, int form, | 367 | ec_point_to_octets(const EC_GROUP *group, const EC_POINT *point, int form, |
74 | unsigned char **out_buf, size_t *out_len, BN_CTX *ctx) | 368 | unsigned char **out_buf, size_t *out_len, BN_CTX *ctx) |
diff --git a/src/lib/libcrypto/ec/ecp_oct.c b/src/lib/libcrypto/ec/ecp_oct.c index ce63bfadc4..0f4d8cb551 100644 --- a/src/lib/libcrypto/ec/ecp_oct.c +++ b/src/lib/libcrypto/ec/ecp_oct.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ecp_oct.c,v 1.29 2024/10/25 18:06:42 tb Exp $ */ | 1 | /* $OpenBSD: ecp_oct.c,v 1.30 2024/10/30 18:16:34 tb Exp $ */ |
2 | /* Includes code written by Lenka Fibikova <fibikova@exp-math.uni-essen.de> | 2 | /* Includes code written by Lenka Fibikova <fibikova@exp-math.uni-essen.de> |
3 | * for the OpenSSL project. | 3 | * for the OpenSSL project. |
4 | * Includes code written by Bodo Moeller for the OpenSSL project. | 4 | * Includes code written by Bodo Moeller for the OpenSSL project. |
@@ -184,297 +184,3 @@ ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, | |||
184 | 184 | ||
185 | return ret; | 185 | return ret; |
186 | } | 186 | } |
187 | |||
188 | /* | ||
189 | * Only the last three bits of the leading octet of a point should be set. | ||
190 | * Bits 3 and 2 encode the conversion form for all points except the point | ||
191 | * at infinity. In compressed and hybrid form bit 1 indicates if the even | ||
192 | * or the odd solution of the quadratic equation for y should be used. | ||
193 | * | ||
194 | * The public point_conversion_t enum lacks the point at infinity, so we | ||
195 | * ignore it except at the API boundary. | ||
196 | */ | ||
197 | |||
198 | #define EC_OCT_YBIT 0x01 | ||
199 | |||
200 | #define EC_OCT_POINT_AT_INFINITY 0x00 | ||
201 | #define EC_OCT_POINT_COMPRESSED 0x02 | ||
202 | #define EC_OCT_POINT_UNCOMPRESSED 0x04 | ||
203 | #define EC_OCT_POINT_HYBRID 0x06 | ||
204 | #define EC_OCT_POINT_CONVERSION_MASK 0x06 | ||
205 | |||
206 | static int | ||
207 | ec_oct_conversion_form_is_valid(uint8_t form) | ||
208 | { | ||
209 | return (form & EC_OCT_POINT_CONVERSION_MASK) == form; | ||
210 | } | ||
211 | |||
212 | static int | ||
213 | ec_oct_check_hybrid_ybit_is_consistent(uint8_t form, int ybit, const BIGNUM *y) | ||
214 | { | ||
215 | if (form == EC_OCT_POINT_HYBRID && ybit != BN_is_odd(y)) { | ||
216 | ECerror(EC_R_INVALID_ENCODING); | ||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | return 1; | ||
221 | } | ||
222 | |||
223 | /* Nonzero y-bit only makes sense with compressed or hybrid encoding. */ | ||
224 | static int | ||
225 | ec_oct_nonzero_ybit_allowed(uint8_t form) | ||
226 | { | ||
227 | return form == EC_OCT_POINT_COMPRESSED || form == EC_OCT_POINT_HYBRID; | ||
228 | } | ||
229 | |||
230 | static int | ||
231 | ec_oct_add_leading_octet_cbb(CBB *cbb, uint8_t form, int ybit) | ||
232 | { | ||
233 | if (ec_oct_nonzero_ybit_allowed(form) && ybit != 0) | ||
234 | form |= EC_OCT_YBIT; | ||
235 | |||
236 | return CBB_add_u8(cbb, form); | ||
237 | } | ||
238 | |||
239 | static int | ||
240 | ec_oct_get_leading_octet_cbs(CBS *cbs, uint8_t *out_form, int *out_ybit) | ||
241 | { | ||
242 | uint8_t octet; | ||
243 | |||
244 | if (!CBS_get_u8(cbs, &octet)) { | ||
245 | ECerror(EC_R_BUFFER_TOO_SMALL); | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | *out_ybit = octet & EC_OCT_YBIT; | ||
250 | *out_form = octet & ~EC_OCT_YBIT; | ||
251 | |||
252 | if (!ec_oct_conversion_form_is_valid(*out_form)) { | ||
253 | ECerror(EC_R_INVALID_ENCODING); | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | if (*out_ybit != 0 && !ec_oct_nonzero_ybit_allowed(*out_form)) { | ||
258 | ECerror(EC_R_INVALID_ENCODING); | ||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | return 1; | ||
263 | } | ||
264 | |||
265 | static int | ||
266 | ec_oct_encoded_length(const EC_GROUP *group, uint8_t form, size_t *out_len) | ||
267 | { | ||
268 | switch (form) { | ||
269 | case EC_OCT_POINT_AT_INFINITY: | ||
270 | *out_len = 1; | ||
271 | return 1; | ||
272 | case EC_OCT_POINT_COMPRESSED: | ||
273 | *out_len = 1 + BN_num_bytes(&group->field); | ||
274 | return 1; | ||
275 | case EC_OCT_POINT_UNCOMPRESSED: | ||
276 | case EC_OCT_POINT_HYBRID: | ||
277 | *out_len = 1 + 2 * BN_num_bytes(&group->field); | ||
278 | return 1; | ||
279 | default: | ||
280 | return 0; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | static int | ||
285 | ec_oct_field_element_is_valid(const EC_GROUP *group, const BIGNUM *bn) | ||
286 | { | ||
287 | /* Ensure bn is in the range [0, field). */ | ||
288 | return !BN_is_negative(bn) && BN_cmp(&group->field, bn) > 0; | ||
289 | } | ||
290 | |||
291 | static int | ||
292 | ec_oct_add_field_element_cbb(CBB *cbb, const EC_GROUP *group, const BIGNUM *bn) | ||
293 | { | ||
294 | uint8_t *buf = NULL; | ||
295 | int buf_len = BN_num_bytes(&group->field); | ||
296 | |||
297 | if (!ec_oct_field_element_is_valid(group, bn)) { | ||
298 | ECerror(EC_R_BIGNUM_OUT_OF_RANGE); | ||
299 | return 0; | ||
300 | } | ||
301 | if (!CBB_add_space(cbb, &buf, buf_len)) { | ||
302 | ECerror(ERR_R_MALLOC_FAILURE); | ||
303 | return 0; | ||
304 | } | ||
305 | if (BN_bn2binpad(bn, buf, buf_len) != buf_len) { | ||
306 | ECerror(ERR_R_MALLOC_FAILURE); | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | return 1; | ||
311 | } | ||
312 | |||
313 | static int | ||
314 | ec_oct_get_field_element_cbs(CBS *cbs, const EC_GROUP *group, BIGNUM *bn) | ||
315 | { | ||
316 | CBS field_element; | ||
317 | |||
318 | if (!CBS_get_bytes(cbs, &field_element, BN_num_bytes(&group->field))) { | ||
319 | ECerror(EC_R_INVALID_ENCODING); | ||
320 | return 0; | ||
321 | } | ||
322 | if (!BN_bin2bn(CBS_data(&field_element), CBS_len(&field_element), bn)) { | ||
323 | ECerror(ERR_R_MALLOC_FAILURE); | ||
324 | return 0; | ||
325 | } | ||
326 | if (!ec_oct_field_element_is_valid(group, bn)) { | ||
327 | ECerror(EC_R_BIGNUM_OUT_OF_RANGE); | ||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | return 1; | ||
332 | } | ||
333 | |||
334 | size_t | ||
335 | ec_GFp_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, | ||
336 | point_conversion_form_t conversion_form, unsigned char *buf, size_t len, | ||
337 | BN_CTX *ctx) | ||
338 | { | ||
339 | CBB cbb; | ||
340 | uint8_t form; | ||
341 | BIGNUM *x, *y; | ||
342 | size_t encoded_length; | ||
343 | size_t ret = 0; | ||
344 | |||
345 | if (conversion_form > UINT8_MAX) { | ||
346 | ECerror(EC_R_INVALID_FORM); | ||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | form = conversion_form; | ||
351 | |||
352 | /* | ||
353 | * Established behavior is to reject a request for the form 0 for the | ||
354 | * point at infinity even if it is valid. | ||
355 | */ | ||
356 | if (form == 0 || !ec_oct_conversion_form_is_valid(form)) { | ||
357 | ECerror(EC_R_INVALID_FORM); | ||
358 | return 0; | ||
359 | } | ||
360 | |||
361 | if (EC_POINT_is_at_infinity(group, point)) | ||
362 | form = EC_OCT_POINT_AT_INFINITY; | ||
363 | |||
364 | if (!ec_oct_encoded_length(group, form, &encoded_length)) { | ||
365 | ECerror(EC_R_INVALID_FORM); | ||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | if (buf == NULL) | ||
370 | return encoded_length; | ||
371 | |||
372 | if (len < encoded_length) { | ||
373 | ECerror(EC_R_BUFFER_TOO_SMALL); | ||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | BN_CTX_start(ctx); | ||
378 | if (!CBB_init_fixed(&cbb, buf, len)) | ||
379 | goto err; | ||
380 | |||
381 | if (form == EC_OCT_POINT_AT_INFINITY) { | ||
382 | if (!ec_oct_add_leading_octet_cbb(&cbb, form, 0)) | ||
383 | goto err; | ||
384 | |||
385 | goto done; | ||
386 | } | ||
387 | |||
388 | if ((x = BN_CTX_get(ctx)) == NULL) | ||
389 | goto err; | ||
390 | if ((y = BN_CTX_get(ctx)) == NULL) | ||
391 | goto err; | ||
392 | if (!EC_POINT_get_affine_coordinates(group, point, x, y, ctx)) | ||
393 | goto err; | ||
394 | |||
395 | if (!ec_oct_add_leading_octet_cbb(&cbb, form, BN_is_odd(y))) | ||
396 | goto err; | ||
397 | |||
398 | if (form == EC_OCT_POINT_COMPRESSED) { | ||
399 | if (!ec_oct_add_field_element_cbb(&cbb, group, x)) | ||
400 | goto err; | ||
401 | } else { | ||
402 | if (!ec_oct_add_field_element_cbb(&cbb, group, x)) | ||
403 | goto err; | ||
404 | if (!ec_oct_add_field_element_cbb(&cbb, group, y)) | ||
405 | goto err; | ||
406 | } | ||
407 | |||
408 | done: | ||
409 | if (!CBB_finish(&cbb, NULL, &ret)) | ||
410 | goto err; | ||
411 | |||
412 | if (ret != encoded_length) { | ||
413 | ret = 0; | ||
414 | goto err; | ||
415 | } | ||
416 | |||
417 | err: | ||
418 | CBB_cleanup(&cbb); | ||
419 | BN_CTX_end(ctx); | ||
420 | |||
421 | return ret; | ||
422 | } | ||
423 | |||
424 | int | ||
425 | ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point, | ||
426 | const unsigned char *buf, size_t len, BN_CTX *ctx) | ||
427 | { | ||
428 | CBS cbs; | ||
429 | uint8_t form; | ||
430 | int ybit; | ||
431 | BIGNUM *x, *y; | ||
432 | int ret = 0; | ||
433 | |||
434 | BN_CTX_start(ctx); | ||
435 | CBS_init(&cbs, buf, len); | ||
436 | |||
437 | if (!ec_oct_get_leading_octet_cbs(&cbs, &form, &ybit)) | ||
438 | goto err; | ||
439 | |||
440 | if (form == EC_OCT_POINT_AT_INFINITY) { | ||
441 | if (!EC_POINT_set_to_infinity(group, point)) | ||
442 | goto err; | ||
443 | |||
444 | goto done; | ||
445 | } | ||
446 | |||
447 | if ((x = BN_CTX_get(ctx)) == NULL) | ||
448 | goto err; | ||
449 | if ((y = BN_CTX_get(ctx)) == NULL) | ||
450 | goto err; | ||
451 | |||
452 | if (form == EC_OCT_POINT_COMPRESSED) { | ||
453 | if (!ec_oct_get_field_element_cbs(&cbs, group, x)) | ||
454 | goto err; | ||
455 | if (!EC_POINT_set_compressed_coordinates(group, point, x, ybit, ctx)) | ||
456 | goto err; | ||
457 | } else { | ||
458 | if (!ec_oct_get_field_element_cbs(&cbs, group, x)) | ||
459 | goto err; | ||
460 | if (!ec_oct_get_field_element_cbs(&cbs, group, y)) | ||
461 | goto err; | ||
462 | if (!ec_oct_check_hybrid_ybit_is_consistent(form, ybit, y)) | ||
463 | goto err; | ||
464 | if (!EC_POINT_set_affine_coordinates(group, point, x, y, ctx)) | ||
465 | goto err; | ||
466 | } | ||
467 | |||
468 | done: | ||
469 | if (CBS_len(&cbs) > 0) { | ||
470 | ECerror(EC_R_INVALID_ENCODING); | ||
471 | goto err; | ||
472 | } | ||
473 | |||
474 | ret = 1; | ||
475 | |||
476 | err: | ||
477 | BN_CTX_end(ctx); | ||
478 | |||
479 | return ret; | ||
480 | } | ||