+/*-
+ * random 256-bit explicit parameters curve, cofactor absent
+ * order: 0x0c38d96a9f892b88772ec2e39614a82f4f (132 bit)
+ * cofactor: 0x12bc94785251297abfafddf1565100da (125 bit)
+ */
+static const unsigned char params_cf_pass[] = {
+ 0x30, 0x81, 0xcd, 0x02, 0x01, 0x01, 0x30, 0x2c, 0x06, 0x07, 0x2a, 0x86,
+ 0x48, 0xce, 0x3d, 0x01, 0x01, 0x02, 0x21, 0x00, 0xe5, 0x00, 0x1f, 0xc5,
+ 0xca, 0x71, 0x9d, 0x8e, 0xf7, 0x07, 0x4b, 0x48, 0x37, 0xf9, 0x33, 0x2d,
+ 0x71, 0xbf, 0x79, 0xe7, 0xdc, 0x91, 0xc2, 0xff, 0xb6, 0x7b, 0xc3, 0x93,
+ 0x44, 0x88, 0xe6, 0x91, 0x30, 0x44, 0x04, 0x20, 0xe5, 0x00, 0x1f, 0xc5,
+ 0xca, 0x71, 0x9d, 0x8e, 0xf7, 0x07, 0x4b, 0x48, 0x37, 0xf9, 0x33, 0x2d,
+ 0x71, 0xbf, 0x79, 0xe7, 0xdc, 0x91, 0xc2, 0xff, 0xb6, 0x7b, 0xc3, 0x93,
+ 0x44, 0x88, 0xe6, 0x8e, 0x04, 0x20, 0x18, 0x8c, 0x59, 0x57, 0xc4, 0xbc,
+ 0x85, 0x57, 0xc3, 0x66, 0x9f, 0x89, 0xd5, 0x92, 0x0d, 0x7e, 0x42, 0x27,
+ 0x07, 0x64, 0xaa, 0x26, 0xed, 0x89, 0xc4, 0x09, 0x05, 0x4d, 0xc7, 0x23,
+ 0x47, 0xda, 0x04, 0x41, 0x04, 0x1b, 0x6b, 0x41, 0x0b, 0xf9, 0xfb, 0x77,
+ 0xfd, 0x50, 0xb7, 0x3e, 0x23, 0xa3, 0xec, 0x9a, 0x3b, 0x09, 0x31, 0x6b,
+ 0xfa, 0xf6, 0xce, 0x1f, 0xff, 0xeb, 0x57, 0x93, 0x24, 0x70, 0xf3, 0xf4,
+ 0xba, 0x7e, 0xfa, 0x86, 0x6e, 0x19, 0x89, 0xe3, 0x55, 0x6d, 0x5a, 0xe9,
+ 0xc0, 0x3d, 0xbc, 0xfb, 0xaf, 0xad, 0xd4, 0x7e, 0xa6, 0xe5, 0xfa, 0x1a,
+ 0x58, 0x07, 0x9e, 0x8f, 0x0d, 0x3b, 0xf7, 0x38, 0xca, 0x02, 0x11, 0x0c,
+ 0x38, 0xd9, 0x6a, 0x9f, 0x89, 0x2b, 0x88, 0x77, 0x2e, 0xc2, 0xe3, 0x96,
+ 0x14, 0xa8, 0x2f, 0x4f
+};
+
+/*-
+ * random 256-bit explicit parameters curve, cofactor absent
+ * order: 0x045a75c0c17228ebd9b169a10e34a22101 (131 bit)
+ * cofactor: 0x2e134b4ede82649f67a2e559d361e5fe (126 bit)
+ */
+static const unsigned char params_cf_fail[] = {
+ 0x30, 0x81, 0xcd, 0x02, 0x01, 0x01, 0x30, 0x2c, 0x06, 0x07, 0x2a, 0x86,
+ 0x48, 0xce, 0x3d, 0x01, 0x01, 0x02, 0x21, 0x00, 0xc8, 0x95, 0x27, 0x37,
+ 0xe8, 0xe1, 0xfd, 0xcc, 0xf9, 0x6e, 0x0c, 0xa6, 0x21, 0xc1, 0x7d, 0x6b,
+ 0x9d, 0x44, 0x42, 0xea, 0x73, 0x4e, 0x04, 0xb6, 0xac, 0x62, 0x50, 0xd0,
+ 0x33, 0xc2, 0xea, 0x13, 0x30, 0x44, 0x04, 0x20, 0xc8, 0x95, 0x27, 0x37,
+ 0xe8, 0xe1, 0xfd, 0xcc, 0xf9, 0x6e, 0x0c, 0xa6, 0x21, 0xc1, 0x7d, 0x6b,
+ 0x9d, 0x44, 0x42, 0xea, 0x73, 0x4e, 0x04, 0xb6, 0xac, 0x62, 0x50, 0xd0,
+ 0x33, 0xc2, 0xea, 0x10, 0x04, 0x20, 0xbf, 0xa6, 0xa8, 0x05, 0x1d, 0x09,
+ 0xac, 0x70, 0x39, 0xbb, 0x4d, 0xb2, 0x90, 0x8a, 0x15, 0x41, 0x14, 0x1d,
+ 0x11, 0x86, 0x9f, 0x13, 0xa2, 0x63, 0x1a, 0xda, 0x95, 0x22, 0x4d, 0x02,
+ 0x15, 0x0a, 0x04, 0x41, 0x04, 0xaf, 0x16, 0x71, 0xf9, 0xc4, 0xc8, 0x59,
+ 0x1d, 0xa3, 0x6f, 0xe7, 0xc3, 0x57, 0xa1, 0xfa, 0x9f, 0x49, 0x7c, 0x11,
+ 0x27, 0x05, 0xa0, 0x7f, 0xff, 0xf9, 0xe0, 0xe7, 0x92, 0xdd, 0x9c, 0x24,
+ 0x8e, 0xc7, 0xb9, 0x52, 0x71, 0x3f, 0xbc, 0x7f, 0x6a, 0x9f, 0x35, 0x70,
+ 0xe1, 0x27, 0xd5, 0x35, 0x8a, 0x13, 0xfa, 0xa8, 0x33, 0x3e, 0xd4, 0x73,
+ 0x1c, 0x14, 0x58, 0x9e, 0xc7, 0x0a, 0x87, 0x65, 0x8d, 0x02, 0x11, 0x04,
+ 0x5a, 0x75, 0xc0, 0xc1, 0x72, 0x28, 0xeb, 0xd9, 0xb1, 0x69, 0xa1, 0x0e,
+ 0x34, 0xa2, 0x21, 0x01
+};
+
+/*-
+ * Test two random 256-bit explicit parameters curves with absent cofactor.
+ * The two curves are chosen to roughly straddle the bounds at which the lib
+ * can compute the cofactor automatically, roughly 4*sqrt(p). So test that:
+ *
+ * - params_cf_pass: order is sufficiently close to p to compute cofactor
+ * - params_cf_fail: order is too far away from p to compute cofactor
+ *
+ * For standards-compliant curves, cofactor is chosen as small as possible.
+ * So you can see neither of these curves are fit for cryptographic use.
+ *
+ * Some standards even mandate an upper bound on the cofactor, e.g. SECG1 v2:
+ * h <= 2**(t/8) where t is the security level of the curve, for which the lib
+ * will always succeed in computing the cofactor. Neither of these curves
+ * conform to that -- this is just robustness testing.
+ */
+static int cofactor_range_test(void)
+{
+ EC_GROUP *group = NULL;
+ BIGNUM *cf = NULL;
+ int ret = 0;
+ const unsigned char *b1 = (const unsigned char *)params_cf_fail;
+ const unsigned char *b2 = (const unsigned char *)params_cf_pass;
+
+ if (!TEST_ptr(group = d2i_ECPKParameters(NULL, &b1, sizeof(params_cf_fail)))
+ || !TEST_BN_eq_zero(EC_GROUP_get0_cofactor(group))
+ || !TEST_ptr(group = d2i_ECPKParameters(&group, &b2,
+ sizeof(params_cf_pass)))
+ || !TEST_int_gt(BN_hex2bn(&cf, "12bc94785251297abfafddf1565100da"), 0)
+ || !TEST_BN_eq(cf, EC_GROUP_get0_cofactor(group)))
+ goto err;
+ ret = 1;
+ err:
+ BN_free(cf);
+ EC_GROUP_free(group);
+ return ret;
+}
+
+/*-
+ * For named curves, test that:
+ * - the lib correctly computes the cofactor if passed a NULL or zero cofactor
+ * - a nonsensical cofactor throws an error (negative test)
+ * - nonsensical orders throw errors (negative tests)
+ */
+static int cardinality_test(int n)
+{
+ int ret = 0;
+ int nid = curves[n].nid;
+ BN_CTX *ctx = NULL;
+ EC_GROUP *g1 = NULL, *g2 = NULL;
+ EC_POINT *g2_gen = NULL;
+ BIGNUM *g1_p = NULL, *g1_a = NULL, *g1_b = NULL, *g1_x = NULL, *g1_y = NULL,
+ *g1_order = NULL, *g1_cf = NULL, *g2_cf = NULL;
+
+ TEST_info("Curve %s cardinality test", OBJ_nid2sn(nid));
+
+ if (!TEST_ptr(ctx = BN_CTX_new())
+ || !TEST_ptr(g1 = EC_GROUP_new_by_curve_name(nid))
+ || !TEST_ptr(g2 = EC_GROUP_new(EC_GROUP_method_of(g1)))) {
+ EC_GROUP_free(g1);
+ EC_GROUP_free(g2);
+ BN_CTX_free(ctx);
+ return 0;
+ }
+
+ BN_CTX_start(ctx);
+ g1_p = BN_CTX_get(ctx);
+ g1_a = BN_CTX_get(ctx);
+ g1_b = BN_CTX_get(ctx);
+ g1_x = BN_CTX_get(ctx);
+ g1_y = BN_CTX_get(ctx);
+ g1_order = BN_CTX_get(ctx);
+ g1_cf = BN_CTX_get(ctx);
+
+ if (!TEST_ptr(g2_cf = BN_CTX_get(ctx))
+ /* pull out the explicit curve parameters */
+ || !TEST_true(EC_GROUP_get_curve(g1, g1_p, g1_a, g1_b, ctx))
+ || !TEST_true(EC_POINT_get_affine_coordinates(g1,
+ EC_GROUP_get0_generator(g1), g1_x, g1_y, ctx))
+ || !TEST_true(BN_copy(g1_order, EC_GROUP_get0_order(g1)))
+ || !TEST_true(EC_GROUP_get_cofactor(g1, g1_cf, ctx))
+ /* construct g2 manually with g1 parameters */
+ || !TEST_true(EC_GROUP_set_curve(g2, g1_p, g1_a, g1_b, ctx))
+ || !TEST_ptr(g2_gen = EC_POINT_new(g2))
+ || !TEST_true(EC_POINT_set_affine_coordinates(g2, g2_gen, g1_x, g1_y, ctx))
+ /* pass NULL cofactor: lib should compute it */
+ || !TEST_true(EC_GROUP_set_generator(g2, g2_gen, g1_order, NULL))
+ || !TEST_true(EC_GROUP_get_cofactor(g2, g2_cf, ctx))
+ || !TEST_BN_eq(g1_cf, g2_cf)
+ /* pass zero cofactor: lib should compute it */
+ || !TEST_true(BN_set_word(g2_cf, 0))
+ || !TEST_true(EC_GROUP_set_generator(g2, g2_gen, g1_order, g2_cf))
+ || !TEST_true(EC_GROUP_get_cofactor(g2, g2_cf, ctx))
+ || !TEST_BN_eq(g1_cf, g2_cf)
+ /* negative test for invalid cofactor */
+ || !TEST_true(BN_set_word(g2_cf, 0))
+ || !TEST_true(BN_sub(g2_cf, g2_cf, BN_value_one()))
+ || !TEST_false(EC_GROUP_set_generator(g2, g2_gen, g1_order, g2_cf))
+ /* negative test for NULL order */
+ || !TEST_false(EC_GROUP_set_generator(g2, g2_gen, NULL, NULL))
+ /* negative test for zero order */
+ || !TEST_true(BN_set_word(g1_order, 0))
+ || !TEST_false(EC_GROUP_set_generator(g2, g2_gen, g1_order, NULL))
+ /* negative test for negative order */
+ || !TEST_true(BN_set_word(g2_cf, 0))
+ || !TEST_true(BN_sub(g2_cf, g2_cf, BN_value_one()))
+ || !TEST_false(EC_GROUP_set_generator(g2, g2_gen, g1_order, NULL))
+ /* negative test for too large order */
+ || !TEST_true(BN_lshift(g1_order, g1_p, 2))
+ || !TEST_false(EC_GROUP_set_generator(g2, g2_gen, g1_order, NULL)))
+ goto err;
+ ret = 1;
+ err:
+ EC_POINT_free(g2_gen);
+ EC_GROUP_free(g1);
+ EC_GROUP_free(g2);
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ return ret;
+}
+