-/* $OpenBSD: ec_asn1_test.c,v 1.6 2024/10/16 23:58:25 tb Exp $ */
+/* $OpenBSD: ec_asn1_test.c,v 1.7 2024/10/18 09:01:44 tb Exp $ */
/*
* Copyright (c) 2017, 2021 Joel Sing <jsing@openbsd.org>
* Copyright (c) 2024 Theo Buehler <tb@openbsd.org>
* From draft-ietf-lwig-curve-representation-23, Appendix E.3
*/
-static const struct {
- const char *oid;
- const char *sn;
- const char *ln;
- const char *p;
- const char *a;
- const char *b;
- const char *order;
- const char *cofactor;
- const char *x;
- const char *y;
-} wei25519 = {
- .oid = "1.3.101.108",
- .sn = "Wei25519",
- .p = "7fffffff" "ffffffff" "ffffffff" "ffffffff"
- "ffffffff" "ffffffff" "ffffffff" "ffffffed",
- .a = "2aaaaaaa" "aaaaaaaa" "aaaaaaaa" "aaaaaaaa"
- "aaaaaaaa" "aaaaaaaa" "aaaaaa98" "4914a144",
- .b = "7b425ed0" "97b425ed" "097b425e" "d097b425"
- "ed097b42" "5ed097b4" "260b5e9c" "7710c864",
- .x = "2aaaaaaa" "aaaaaaaa" "aaaaaaaa" "aaaaaaaa"
- "aaaaaaaa" "aaaaaaaa" "aaaaaaaa" "aaad245a",
- .y = "20ae19a1" "b8a086b4" "e01edd2c" "7748d14c"
- "923d4d7e" "6d7c61b2" "29e9c5a2" "7eced3d9",
- .order = "10000000" "00000000" "00000000" "00000000"
- "14def9de" "a2f79cd6" "5812631a" "5cf5d3ed",
- .cofactor = "8",
-};
-
const uint8_t ec_wei25519_pkparameters_named_curve[] = {
0x06, 0x03, 0x2b, 0x65, 0x6c,
};
0x08,
};
-static int
-ec_weierstrass25519(void)
+struct curve {
+ const char *oid;
+ const char *sn;
+ const char *ln;
+ const char *p;
+ const char *a;
+ const char *b;
+ const char *order;
+ const char *cofactor;
+ const char *x;
+ const char *y;
+ const char *named;
+ size_t named_len;
+ const char *param;
+ size_t param_len;
+};
+
+static const struct curve wei25519 = {
+ .oid = "1.3.101.108",
+ .sn = "Wei25519",
+ .p = "7fffffff" "ffffffff" "ffffffff" "ffffffff"
+ "ffffffff" "ffffffff" "ffffffff" "ffffffed",
+ .a = "2aaaaaaa" "aaaaaaaa" "aaaaaaaa" "aaaaaaaa"
+ "aaaaaaaa" "aaaaaaaa" "aaaaaa98" "4914a144",
+ .b = "7b425ed0" "97b425ed" "097b425e" "d097b425"
+ "ed097b42" "5ed097b4" "260b5e9c" "7710c864",
+ .x = "2aaaaaaa" "aaaaaaaa" "aaaaaaaa" "aaaaaaaa"
+ "aaaaaaaa" "aaaaaaaa" "aaaaaaaa" "aaad245a",
+ .y = "20ae19a1" "b8a086b4" "e01edd2c" "7748d14c"
+ "923d4d7e" "6d7c61b2" "29e9c5a2" "7eced3d9",
+ .order = "10000000" "00000000" "00000000" "00000000"
+ "14def9de" "a2f79cd6" "5812631a" "5cf5d3ed",
+ .cofactor = "8",
+ .named = ec_wei25519_pkparameters_named_curve,
+ .named_len = sizeof(ec_wei25519_pkparameters_named_curve),
+ .param = ec_wei25519_pkparameters_parameters,
+ .param_len = sizeof(ec_wei25519_pkparameters_parameters),
+};
+
+static EC_GROUP *
+ec_group_from_curve_method(const struct curve *curve, const EC_METHOD *method,
+ BN_CTX *ctx)
{
- EC_GROUP *group = NULL, *new_group = NULL;
+ EC_GROUP *group;
EC_POINT *generator = NULL;
- BN_CTX *ctx = NULL;
BIGNUM *p, *a, *b;
- BIGNUM *order, *cofactor, *guessed_cofactor, *x, *y;
- const unsigned char *pder;
- unsigned char *der = NULL;
- long error;
- int der_len = 0;
- int nid;
- int failed = 1;
+ BIGNUM *order, *x, *y;
- ERR_clear_error();
- if ((ctx = BN_CTX_new()) == NULL)
- goto err;
BN_CTX_start(ctx);
- if ((nid = OBJ_create(wei25519.oid, wei25519.sn, NULL)) == NID_undef) {
- fprintf(stderr, "FAIL: %s OBJ_create(wei25519)\n", __func__);
- goto err;
- }
-
if ((p = BN_CTX_get(ctx)) == NULL)
errx(1, "BN_CTX_get");
if ((a = BN_CTX_get(ctx)) == NULL)
errx(1, "BN_CTX_get");
if ((b = BN_CTX_get(ctx)) == NULL)
errx(1, "BN_CTX_get");
+
if ((order = BN_CTX_get(ctx)) == NULL)
errx(1, "BN_CTX_get");
- if ((cofactor = BN_CTX_get(ctx)) == NULL)
- errx(1, "BN_CTX_get");
- if ((guessed_cofactor = BN_CTX_get(ctx)) == NULL)
- errx(1, "BN_CTX_get");
if ((x = BN_CTX_get(ctx)) == NULL)
errx(1, "BN_CTX_get");
if ((y = BN_CTX_get(ctx)) == NULL)
errx(1, "BN_CTX_get");
- if (BN_hex2bn(&p, wei25519.p) == 0)
+ if (BN_hex2bn(&p, curve->p) == 0)
errx(1, "BN_hex2bn(p)");
- if (BN_hex2bn(&a, wei25519.a) == 0)
+ if (BN_hex2bn(&a, curve->a) == 0)
errx(1, "BN_hex2bn(a)");
- if (BN_hex2bn(&b, wei25519.b) == 0)
+ if (BN_hex2bn(&b, curve->b) == 0)
errx(1, "BN_hex2bn(b)");
- /*
- * XXX - this uses the Montgomery method. Consider exercising the
- * simple method as well.
- */
- if ((group = EC_GROUP_new_curve_GFp(p, a, b, ctx)) == NULL) {
- fprintf(stderr, "FAIL: %s EC_GROUP_new_curve_GFp", __func__);
- goto err;
- }
+ if ((group = EC_GROUP_new(method)) == NULL)
+ errx(1, "EC_GROUP_new");
+
+ if (!EC_GROUP_set_curve(group, p, a, b, ctx))
+ errx(1, "EC_GROUP_set_curve");
- if (BN_hex2bn(&x, wei25519.x) == 0)
+ if (BN_hex2bn(&x, curve->x) == 0)
errx(1, "BN_hex2bn(x)");
- if (BN_hex2bn(&x, wei25519.x) == 0)
+ if (BN_hex2bn(&x, curve->x) == 0)
errx(1, "BN_hex2bn(x)");
- if (BN_hex2bn(&y, wei25519.y) == 0)
+ if (BN_hex2bn(&y, curve->y) == 0)
errx(1, "BN_hex2bn(y)");
if ((generator = EC_POINT_new(group)) == NULL)
errx(1, "EC_POINT_new()");
if (!EC_POINT_set_affine_coordinates(group, generator, x, y, ctx)) {
- fprintf(stderr, "FAIL: %s EC_POINT_set_affine_coordinates", __func__);
+ fprintf(stderr, "FAIL: %s EC_POINT_set_affine_coordinates",
+ curve->sn);
ERR_print_errors_fp(stderr);
goto err;
}
- if (BN_hex2bn(&order, wei25519.order) == 0)
+ if (BN_hex2bn(&order, curve->order) == 0)
errx(1, "BN_hex2bn(order)");
- if (BN_hex2bn(&cofactor, wei25519.cofactor) == 0)
- errx(1, "BN_hex2bn(cofactor)");
/* Don't set cofactor to exercise the cofactor guessing code. */
if (!EC_GROUP_set_generator(group, generator, order, NULL)) {
- fprintf(stderr, "FAIL: %s EC_GROUP_set_generator\n", __func__);
+ fprintf(stderr, "FAIL: %s EC_GROUP_set_generator\n", curve->sn);
+ ERR_print_errors_fp(stderr);
+ goto err;
+ }
+
+ EC_POINT_free(generator);
+
+ BN_CTX_end(ctx);
+
+ return group;
+
+ err:
+ BN_CTX_end(ctx);
+
+ EC_POINT_free(generator);
+ EC_GROUP_free(group);
+
+ return NULL;
+}
+
+static EC_GROUP *
+ec_group_new(const struct curve *curve, const EC_METHOD *method, BN_CTX *ctx)
+{
+ EC_GROUP *group = NULL;
+ BIGNUM *cofactor, *guessed_cofactor;
+ int nid;
+
+ BN_CTX_start(ctx);
+
+ if ((nid = OBJ_txt2nid(curve->oid)) == NID_undef)
+ nid = OBJ_create(curve->oid, curve->sn, curve->ln);
+ if (nid == NID_undef) {
+ fprintf(stderr, "FAIL: OBJ_create(%s)\n", curve->sn);
+ goto err;
+ }
+
+ if ((cofactor = BN_CTX_get(ctx)) == NULL)
+ errx(1, "BN_CTX_get");
+ if ((guessed_cofactor = BN_CTX_get(ctx)) == NULL)
+ errx(1, "BN_CTX_get");
+
+ if (BN_hex2bn(&cofactor, curve->cofactor) == 0)
+ errx(1, "BN_hex2bn(cofactor)");
+
+ if ((group = ec_group_from_curve_method(curve, method, ctx)) == NULL) {
+ fprintf(stderr, "FAIL: %s ec_group_from_curve_method\n", curve->sn);
ERR_print_errors_fp(stderr);
goto err;
}
if (!EC_GROUP_get_cofactor(group, guessed_cofactor, ctx)) {
- fprintf(stderr, "FAIL: %s EC_GROUP_get_cofactor\n", __func__);
+ fprintf(stderr, "FAIL: %s EC_GROUP_get_cofactor\n", curve->sn);
ERR_print_errors_fp(stderr);
goto err;
}
if (BN_cmp(cofactor, guessed_cofactor) != 0) {
- fprintf(stderr, "FAIL: %s cofactor: want ", __func__);
+ fprintf(stderr, "FAIL: %s cofactor: want ", curve->sn);
BN_print_fp(stderr, cofactor);
fprintf(stderr, ", got ");
BN_print_fp(stderr, guessed_cofactor);
}
if (!EC_GROUP_check(group, ctx)) {
- fprintf(stderr, "FAIL: %s EC_GROUP_check\n", __func__);
+ fprintf(stderr, "FAIL: %s EC_GROUP_check\n", curve->sn);
ERR_print_errors_fp(stderr);
goto err;
}
- /* Explicit curve parameter encoding should work without NID set. */
- if (EC_GROUP_get_curve_name(group) != NID_undef) {
- fprintf(stderr, "FAIL: %s unexpected curve name %d\n", __func__,
- EC_GROUP_get_curve_name(group));
- ERR_print_errors_fp(stderr);
+ EC_GROUP_set_curve_name(group, nid);
+
+ BN_CTX_end(ctx);
+
+ return group;
+
+ err:
+ BN_CTX_end(ctx);
+
+ EC_GROUP_free(group);
+
+ return NULL;
+}
+
+static int
+ec_group_non_builtin_curve(const struct curve *curve, const EC_METHOD *method,
+ BN_CTX *ctx)
+{
+ EC_GROUP *group = NULL, *new_group = NULL;
+ const unsigned char *pder;
+ unsigned char *der = NULL;
+ long error;
+ int der_len = 0;
+ int nid;
+ int failed = 1;
+
+ ERR_clear_error();
+ BN_CTX_start(ctx);
+
+ if ((group = ec_group_new(curve, method, ctx)) == NULL)
+ goto err;
+
+ if ((nid = EC_GROUP_get_curve_name(group)) == NID_undef) {
+ fprintf(stderr, "FAIL: no curve name set for %s\n", curve->sn);
goto err;
}
- EC_GROUP_set_asn1_flag(group, OPENSSL_EC_EXPLICIT_CURVE);
+ EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
der = NULL;
if ((der_len = i2d_ECPKParameters(group, &der)) <= 0) {
- fprintf(stderr, "FAIL: %s i2d_ECPKParameters (explicit)\n", __func__);
+ fprintf(stderr, "FAIL: %s i2d_ECPKParameters (named)\n",
+ curve->sn);
ERR_print_errors_fp(stderr);
goto err;
}
- if (compare_data("Weierstrass 25519 explicit", der, der_len,
- ec_wei25519_pkparameters_parameters,
- sizeof(ec_wei25519_pkparameters_parameters)) == -1)
+ if (compare_data("Weierstrass 25519 named curve", der, der_len,
+ ec_wei25519_pkparameters_named_curve,
+ sizeof(ec_wei25519_pkparameters_named_curve)) == -1)
goto err;
freezero(der, der_len);
der = NULL;
- EC_GROUP_set_curve_name(group, nid);
- EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
+ /* Explicit curve parameter encoding should work without NID set. */
+ EC_GROUP_set_curve_name(group, NID_undef);
+ EC_GROUP_set_asn1_flag(group, OPENSSL_EC_EXPLICIT_CURVE);
der = NULL;
if ((der_len = i2d_ECPKParameters(group, &der)) <= 0) {
- fprintf(stderr, "FAIL: %s i2d_ECPKParameters (named)\n", __func__);
+ fprintf(stderr, "FAIL: i2d_ECPKParameters (explicit) %s\n",
+ curve->sn);
ERR_print_errors_fp(stderr);
goto err;
}
- if (compare_data("Weierstrass 25519 named curve", der, der_len,
- ec_wei25519_pkparameters_named_curve,
- sizeof(ec_wei25519_pkparameters_named_curve)) == -1)
+ if (compare_data(curve->sn, der, der_len,
+ curve->param, curve->param_len) == -1)
goto err;
freezero(der, der_len);
/* At this point we should have no error on the stack. */
if (ERR_peek_last_error() != 0) {
- fprintf(stderr, "FAIL: %s unexpected error %lu\n", __func__,
+ fprintf(stderr, "FAIL: %s unexpected error %lu\n", curve->sn,
ERR_peek_last_error());
goto err;
}
- pder = ec_wei25519_pkparameters_named_curve;
- der_len = sizeof(ec_wei25519_pkparameters_named_curve);
+ pder = curve->named;
+ der_len = curve->named_len;
if ((new_group = d2i_ECPKParameters(NULL, &pder, der_len)) != NULL) {
- fprintf(stderr, "FAIL: %s managed to decode unknown named curve\n",
- __func__);
+ fprintf(stderr, "FAIL: managed to decode unknown named curve %s\n",
+ curve->sn);
goto err;
}
error = ERR_get_error();
if (ERR_GET_REASON(error) != EC_R_UNKNOWN_GROUP) {
fprintf(stderr, "FAIL: %s unexpected error: want %d, got %d\n",
- __func__, EC_R_UNKNOWN_GROUP, ERR_GET_REASON(error));
+ curve->sn, EC_R_UNKNOWN_GROUP, ERR_GET_REASON(error));
goto err;
}
ERR_clear_error();
- pder = ec_wei25519_pkparameters_parameters;
- der_len = sizeof(ec_wei25519_pkparameters_parameters);
-
+ pder = curve->param;
+ der_len = curve->param_len;
#if 0
if ((new_group = d2i_ECPKParameters(NULL, &pder, der_len)) != NULL) {
- fprintf(stderr, "FAIL: %s managed to decode non-builtin parameters\n",
- __func__);
+ fprintf(stderr, "FAIL: managed to decode non-builtin parameters %s\n",
+ curve->sn);
goto err;
}
error = ERR_peek_last_error();
if (ERR_GET_REASON(error) != EC_R_PKPARAMETERS2GROUP_FAILURE) {
fprintf(stderr, "FAIL: %s unexpected error: want %d, got %d\n",
- __func__, EC_R_UNKNOWN_GROUP, ERR_GET_REASON(error));
+ curve->sn, EC_R_UNKNOWN_GROUP, ERR_GET_REASON(error));
goto err;
}
#else
if ((new_group = d2i_ECPKParameters(NULL, &pder, der_len)) == NULL) {
- fprintf(stderr, "FAIL: %s d2i_ECPKParameters(Wei25519)\n", __func__);
+ fprintf(stderr, "FAIL: d2i_ECPKParameters(%s)\n", curve->sn);
goto err;
}
- if (EC_GROUP_cmp(group, new_group, ctx) != 0) {
+ if (method == EC_GFp_mont_method() &&
+ EC_GROUP_cmp(group, new_group, ctx) != 0) {
fprintf(stderr, "FAIL: %s Weierstrass groups do not match!\n",
- __func__);
+ curve->sn);
goto err;
}
#endif
err:
BN_CTX_end(ctx);
- BN_CTX_free(ctx);
EC_GROUP_free(group);
EC_GROUP_free(new_group);
- EC_POINT_free(generator);
freezero(der, der_len);
return failed;
}
+static int
+ec_group_non_builtin_curves(void)
+{
+ BN_CTX *ctx;
+ int failed = 0;
+
+ if ((ctx = BN_CTX_new()) == NULL)
+ errx(1, "BN_CTX_new");
+
+ failed |= ec_group_non_builtin_curve(&wei25519, EC_GFp_mont_method(), ctx);
+ failed |= ec_group_non_builtin_curve(&wei25519, EC_GFp_simple_method(), ctx);
+
+ BN_CTX_free(ctx);
+
+ return failed;
+}
+
int
main(int argc, char **argv)
{
failed |= ec_group_pkparameters_parameters_test();
failed |= ec_group_pkparameters_correct_padding_test();
failed |= ec_group_roundtrip_builtin_curves();
- failed |= ec_weierstrass25519();
+ failed |= ec_group_non_builtin_curves();
return (failed);
}