static int test_fips1864_keygen_kat(void) { int ret = 0; RSA *key = NULL; BN_CTX *ctx = NULL; BIGNUM *e, *Xp, *Xp1, *Xp2, *Xq, *Xq1, *Xq2; BIGNUM *p1, *p2, *q1, *q2; BIGNUM *p1_exp, *p2_exp, *q1_exp, *q2_exp; BIGNUM *p_exp, *q_exp, *n_exp, *d_exp; const BIGNUM *p, *q, *n, *d, *e2; if (!(TEST_ptr(key = RSA_new()) && TEST_ptr(ctx = BN_CTX_new()))) goto err; BN_CTX_start(ctx); e = bn_load(ctx, cav_e, sizeof(cav_e)); Xp = bn_load(ctx, cav_Xp, sizeof(cav_Xp)); Xp1 = bn_load(ctx, cav_Xp1, sizeof(cav_Xp1)); Xp2 = bn_load(ctx, cav_Xp2, sizeof(cav_Xp2)); Xq = bn_load(ctx, cav_Xq, sizeof(cav_Xq)); Xq1 = bn_load(ctx, cav_Xq1, sizeof(cav_Xq1)); Xq2 = bn_load(ctx, cav_Xq2, sizeof(cav_Xq2)); p1_exp = bn_load(ctx, cav_p1, sizeof(cav_p1)); p2_exp = bn_load(ctx, cav_p2, sizeof(cav_p2)); q1_exp = bn_load(ctx, cav_q1, sizeof(cav_q1)); q2_exp = bn_load(ctx, cav_q2, sizeof(cav_q2)); p_exp = bn_load(ctx, cav_p, sizeof(cav_p)); q_exp = bn_load(ctx, cav_q, sizeof(cav_q)); n_exp = bn_load(ctx, cav_n, sizeof(cav_n)); d_exp = bn_load(ctx, cav_d, sizeof(cav_d)); p1 = BN_CTX_get(ctx); p2 = BN_CTX_get(ctx); q1 = BN_CTX_get(ctx); q2 = BN_CTX_get(ctx); ret = TEST_ptr(q2) && TEST_true(rsa_fips186_4_gen_prob_primes(key, p1, p2, NULL, Xp, Xp1, Xp2, q1, q2, NULL, Xq, Xq1, Xq2, 2048, e, ctx, NULL)) && TEST_true(rsa_sp800_56b_derive_params_from_pq(key, 2048, e, ctx)) && TEST_BN_eq(p1_exp, p1) && TEST_BN_eq(p2_exp, p2) && TEST_BN_eq(q1_exp, q1) && TEST_BN_eq(q2_exp, q2); if (!ret) goto err; RSA_get0_key(key, &n, &e2, &d); RSA_get0_factors(key, &p, &q); ret = TEST_BN_eq(e, e2) && TEST_BN_eq(p_exp, p) && TEST_BN_eq(q_exp, q) && TEST_BN_eq(n_exp, n) && TEST_BN_eq(d_exp, d); err: RSA_free(key); BN_CTX_end(ctx); BN_CTX_free(ctx); return ret; }
static int test_param_bignum(int n) { unsigned char buf[MAX_LEN], bnbuf[MAX_LEN], le[MAX_LEN]; const size_t len = raw_values[n].len; size_t bnsize; BIGNUM *b = NULL, *c = NULL; OSSL_PARAM param = OSSL_PARAM_DEFN("bn", OSSL_PARAM_UNSIGNED_INTEGER, NULL, 0, NULL); int ret = 0; param.data = bnbuf; param.data_size = len; param.return_size = &bnsize; copy_be_to_native(buf, raw_values[n].value, len); swap_copy(le, raw_values[n].value, len); if (!TEST_ptr(b = BN_bin2bn(raw_values[n].value, (int)len, NULL))) goto err; if (!TEST_true(OSSL_PARAM_set_BN(¶m, b)) || !TEST_mem_eq(bnbuf, bnsize, buf, bnsize)) goto err; param.data_size = *param.return_size; if (!TEST_true(OSSL_PARAM_get_BN(¶m, &c)) || !TEST_BN_eq(b, c)) goto err; ret = 1; err: BN_free(b); BN_free(c); return ret; }
static int check_bn(const char *name, const BIGNUM *bn, const char *hexbn) { BIGNUM *tmp = NULL; int r; if (!TEST_true(BN_hex2bn(&tmp, hexbn))) return 0; if (BN_cmp(bn, tmp) != 0) TEST_error("unexpected %s value", name); r = TEST_BN_eq(bn, tmp); BN_free(tmp); return r; }
/* Test that multiplying all the small primes from 3 to 751 equals a constant. * This test is mainly used to test that both 32 and 64 bit are correct. */ static int test_bn_small_factors(void) { int ret = 0, i; BIGNUM *b = NULL; if (!(TEST_ptr(b = BN_new()) && TEST_true(BN_set_word(b, 3)))) goto err; for (i = 1; i < NUMPRIMES; i++) { prime_t p = primes[i]; if (p > 3 && p <= 751) BN_mul_word(b, p); if (p > 751) break; } ret = TEST_BN_eq(bn_get0_small_factors(), b); err: BN_free(b); return ret; }
static int test_curve(void) { EC_GROUP *group = NULL; EC_POINT *point = NULL; BIGNUM *result = NULL, *expected_result = NULL; int ret = 0; /* * We currently hard-code P-256, though adaptation to other curves. * would be straightforward. */ if (!TEST_ptr(group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)) || !TEST_ptr(point = EC_POINT_dup(EC_GROUP_get0_generator(group), group)) || !TEST_ptr(result = walk_curve(group, point, num_repeats))) return 0; if (print_mode) { BN_print(bio_out, result); BIO_printf(bio_out, "\n"); ret = 1; } else { if (!TEST_true(BN_hex2bn(&expected_result, kP256DefaultResult)) || !TEST_ptr(expected_result) || !TEST_BN_eq(result, expected_result)) goto err; ret = 1; } err: EC_GROUP_free(group); EC_POINT_free(point); BN_free(result); BN_free(expected_result); return ret; }
/* some tests from the X9.62 draft */ static int x9_62_test_internal(int nid, const char *r_in, const char *s_in) { int ret = 0; const char message[] = "abc"; unsigned char digest[20]; unsigned int dgst_len = 0; EVP_MD_CTX *md_ctx; EC_KEY *key = NULL; ECDSA_SIG *signature = NULL; BIGNUM *r = NULL, *s = NULL; BIGNUM *kinv = NULL, *rp = NULL; const BIGNUM *sig_r, *sig_s; if (!TEST_ptr(md_ctx = EVP_MD_CTX_new())) goto x962_int_err; /* get the message digest */ if (!TEST_true(EVP_DigestInit(md_ctx, EVP_sha1())) || !TEST_true(EVP_DigestUpdate(md_ctx, (const void *)message, 3)) || !TEST_true(EVP_DigestFinal(md_ctx, digest, &dgst_len))) goto x962_int_err; TEST_info("testing %s", OBJ_nid2sn(nid)); /* create the key */ if (!TEST_ptr(key = EC_KEY_new_by_curve_name(nid))) goto x962_int_err; use_fake = 1; if (!TEST_true(EC_KEY_generate_key(key))) goto x962_int_err; /* create the signature */ use_fake = 1; /* Use ECDSA_sign_setup to avoid use of ECDSA nonces */ if (!TEST_true(ECDSA_sign_setup(key, NULL, &kinv, &rp))) goto x962_int_err; if (!TEST_ptr(signature = ECDSA_do_sign_ex(digest, 20, kinv, rp, key))) goto x962_int_err; /* compare the created signature with the expected signature */ if (!TEST_ptr(r = BN_new()) || !TEST_ptr(s = BN_new())) goto x962_int_err; if (!TEST_true(BN_dec2bn(&r, r_in)) || !TEST_true(BN_dec2bn(&s, s_in))) goto x962_int_err; ECDSA_SIG_get0(signature, &sig_r, &sig_s); if (!TEST_BN_eq(sig_r, r) || !TEST_BN_eq(sig_s, s)) goto x962_int_err; /* verify the signature */ if (!TEST_int_eq(ECDSA_do_verify(digest, 20, signature, key), 1)) goto x962_int_err; ret = 1; x962_int_err: EC_KEY_free(key); ECDSA_SIG_free(signature); BN_free(r); BN_free(s); EVP_MD_CTX_free(md_ctx); BN_clear_free(kinv); BN_clear_free(rp); return ret; }
static int test_param_construct(void) { static const char *int_names[] = { "int", "long", "int32", "int64" }; static const char *uint_names[] = { "uint", "ulong", "uint32", "uint64", "size_t" }; static const unsigned char bn_val[16] = { 0xac, 0x75, 0x22, 0x7d, 0x81, 0x06, 0x7a, 0x23, 0xa6, 0xed, 0x87, 0xc7, 0xab, 0xf4, 0x73, 0x22 }; OSSL_PARAM params[20]; char buf[100], buf2[100], *bufp, *bufp2; unsigned char ubuf[100]; void *vp, *vpn = NULL, *vp2; OSSL_PARAM *p; const OSSL_PARAM *cp; static const OSSL_PARAM pend = OSSL_PARAM_END; int i, n = 0, ret = 0; unsigned int u; long int l; unsigned long int ul; int32_t i32; uint32_t u32; int64_t i64; uint64_t u64; size_t j, k, s, sz; double d, d2; BIGNUM *bn = NULL, *bn2 = NULL; params[n++] = OSSL_PARAM_construct_int("int", &i, &sz); params[n++] = OSSL_PARAM_construct_uint("uint", &u, &sz); params[n++] = OSSL_PARAM_construct_long("long", &l, &sz); params[n++] = OSSL_PARAM_construct_ulong("ulong", &ul, &sz); params[n++] = OSSL_PARAM_construct_int32("int32", &i32, &sz); params[n++] = OSSL_PARAM_construct_int64("int64", &i64, &sz); params[n++] = OSSL_PARAM_construct_uint32("uint32", &u32, &sz); params[n++] = OSSL_PARAM_construct_uint64("uint64", &u64, &sz); params[n++] = OSSL_PARAM_construct_size_t("size_t", &s, &sz); params[n++] = OSSL_PARAM_construct_double("double", &d, &sz); params[n++] = OSSL_PARAM_construct_BN("bignum", ubuf, sizeof(ubuf), &sz); params[n++] = OSSL_PARAM_construct_utf8_string("utf8str", buf, sizeof(buf), &sz); params[n++] = OSSL_PARAM_construct_octet_string("octstr", buf, sizeof(buf), &sz); params[n++] = OSSL_PARAM_construct_utf8_ptr("utf8ptr", &bufp, &sz); params[n++] = OSSL_PARAM_construct_octet_ptr("octptr", &vp, &sz); params[n] = pend; /* Search failure */ if (!TEST_ptr_null(OSSL_PARAM_locate(params, "fnord"))) goto err; /* All signed integral types */ for (j = 0; j < OSSL_NELEM(int_names); j++) { if (!TEST_ptr(cp = OSSL_PARAM_locate(params, int_names[j])) || !TEST_true(OSSL_PARAM_set_int32(cp, (int32_t)(3 + j))) || !TEST_true(OSSL_PARAM_get_int64(cp, &i64)) || !TEST_size_t_eq(cp->data_size, sz) || !TEST_size_t_eq((size_t)i64, 3 + j)) { TEST_note("iteration %zu var %s", j + 1, int_names[j]); goto err; } } /* All unsigned integral types */ for (j = 0; j < OSSL_NELEM(uint_names); j++) { if (!TEST_ptr(cp = OSSL_PARAM_locate(params, uint_names[j])) || !TEST_true(OSSL_PARAM_set_uint32(cp, (uint32_t)(3 + j))) || !TEST_true(OSSL_PARAM_get_uint64(cp, &u64)) || !TEST_size_t_eq(cp->data_size, sz) || !TEST_size_t_eq((size_t)u64, 3 + j)) { TEST_note("iteration %zu var %s", j + 1, uint_names[j]); goto err; } } /* Real */ if (!TEST_ptr(cp = OSSL_PARAM_locate(params, "double")) || !TEST_true(OSSL_PARAM_set_double(cp, 3.14)) || !TEST_true(OSSL_PARAM_get_double(cp, &d2)) || !TEST_size_t_eq(sz, sizeof(double)) || !TEST_double_eq(d, d2)) goto err; /* UTF8 string */ bufp = NULL; if (!TEST_ptr(cp = OSSL_PARAM_locate(params, "utf8str")) || !TEST_true(OSSL_PARAM_set_utf8_string(cp, "abcdef")) || !TEST_size_t_eq(sz, sizeof("abcdef")) || !TEST_true(OSSL_PARAM_get_utf8_string(cp, &bufp, 0)) || !TEST_str_eq(bufp, "abcdef")) goto err; OPENSSL_free(bufp); bufp = buf2; if (!TEST_true(OSSL_PARAM_get_utf8_string(cp, &bufp, sizeof(buf2))) || !TEST_str_eq(buf2, "abcdef")) goto err; /* UTF8 pointer */ bufp = buf; sz = 0; if (!TEST_ptr(cp = OSSL_PARAM_locate(params, "utf8ptr")) || !TEST_true(OSSL_PARAM_set_utf8_ptr(cp, "tuvwxyz")) || !TEST_size_t_eq(sz, sizeof("tuvwxyz")) || !TEST_str_eq(bufp, "tuvwxyz") || !TEST_true(OSSL_PARAM_get_utf8_ptr(cp, (const char **)&bufp2)) || !TEST_ptr_eq(bufp2, bufp)) goto err; /* OCTET string */ if (!TEST_ptr(p = locate(params, "octstr")) || !TEST_true(OSSL_PARAM_set_octet_string(p, "abcdefghi", sizeof("abcdefghi"))) || !TEST_size_t_eq(sz, sizeof("abcdefghi"))) goto err; /* Match the return size to avoid trailing garbage bytes */ p->data_size = *p->return_size; if (!TEST_true(OSSL_PARAM_get_octet_string(p, &vpn, 0, &s)) || !TEST_size_t_eq(s, sizeof("abcdefghi")) || !TEST_mem_eq(vpn, sizeof("abcdefghi"), "abcdefghi", sizeof("abcdefghi"))) goto err; vp = buf2; if (!TEST_true(OSSL_PARAM_get_octet_string(p, &vp, sizeof(buf2), &s)) || !TEST_size_t_eq(s, sizeof("abcdefghi")) || !TEST_mem_eq(vp, sizeof("abcdefghi"), "abcdefghi", sizeof("abcdefghi"))) goto err; /* OCTET pointer */ vp = &l; sz = 0; if (!TEST_ptr(p = locate(params, "octptr")) || !TEST_true(OSSL_PARAM_set_octet_ptr(p, &ul, sizeof(ul))) || !TEST_size_t_eq(sz, sizeof(ul)) || !TEST_ptr_eq(vp, &ul)) goto err; /* Match the return size to avoid trailing garbage bytes */ p->data_size = *p->return_size; if (!TEST_true(OSSL_PARAM_get_octet_ptr(p, (const void **)&vp2, &k)) || !TEST_size_t_eq(k, sizeof(ul)) || !TEST_ptr_eq(vp2, vp)) goto err; /* BIGNUM */ if (!TEST_ptr(p = locate(params, "bignum")) || !TEST_ptr(bn = BN_lebin2bn(bn_val, (int)sizeof(bn_val), NULL)) || !TEST_true(OSSL_PARAM_set_BN(p, bn)) || !TEST_size_t_eq(sz, sizeof(bn_val))) goto err; /* Match the return size to avoid trailing garbage bytes */ p->data_size = *p->return_size; if(!TEST_true(OSSL_PARAM_get_BN(p, &bn2)) || !TEST_BN_eq(bn, bn2)) goto err; ret = 1; err: OPENSSL_free(vpn); BN_free(bn); BN_free(bn2); return ret; }
static int test_mod_exp(int round) { BN_CTX *ctx; unsigned char c; int ret = 0; BIGNUM *r_mont = NULL; BIGNUM *r_mont_const = NULL; BIGNUM *r_recp = NULL; BIGNUM *r_simple = NULL; BIGNUM *a = NULL; BIGNUM *b = NULL; BIGNUM *m = NULL; if (!TEST_ptr(ctx = BN_CTX_new())) goto err; if (!TEST_ptr(r_mont = BN_new()) || !TEST_ptr(r_mont_const = BN_new()) || !TEST_ptr(r_recp = BN_new()) || !TEST_ptr(r_simple = BN_new()) || !TEST_ptr(a = BN_new()) || !TEST_ptr(b = BN_new()) || !TEST_ptr(m = BN_new())) goto err; RAND_bytes(&c, 1); c = (c % BN_BITS) - BN_BITS2; BN_rand(a, NUM_BITS + c, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY); RAND_bytes(&c, 1); c = (c % BN_BITS) - BN_BITS2; BN_rand(b, NUM_BITS + c, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY); RAND_bytes(&c, 1); c = (c % BN_BITS) - BN_BITS2; BN_rand(m, NUM_BITS + c, BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ODD); if (!TEST_true(BN_mod(a, a, m, ctx)) || !TEST_true(BN_mod(b, b, m, ctx)) || !TEST_true(BN_mod_exp_mont(r_mont, a, b, m, ctx, NULL)) || !TEST_true(BN_mod_exp_recp(r_recp, a, b, m, ctx)) || !TEST_true(BN_mod_exp_simple(r_simple, a, b, m, ctx)) || !TEST_true(BN_mod_exp_mont_consttime(r_mont_const, a, b, m, ctx, NULL))) goto err; if (!TEST_BN_eq(r_simple, r_mont) || !TEST_BN_eq(r_simple, r_recp) || !TEST_BN_eq(r_simple, r_mont_const)) { if (BN_cmp(r_simple, r_mont) != 0) TEST_info("simple and mont results differ"); if (BN_cmp(r_simple, r_mont_const) != 0) TEST_info("simple and mont const time results differ"); if (BN_cmp(r_simple, r_recp) != 0) TEST_info("simple and recp results differ"); BN_print_var(a); BN_print_var(b); BN_print_var(m); BN_print_var(r_simple); BN_print_var(r_recp); BN_print_var(r_mont); BN_print_var(r_mont_const); goto err; } ret = 1; err: BN_free(r_mont); BN_free(r_mont_const); BN_free(r_recp); BN_free(r_simple); BN_free(a); BN_free(b); BN_free(m); BN_CTX_free(ctx); return ret; }
static int run_srp(const char *username, const char *client_pass, const char *server_pass) { int ret = 0; BIGNUM *s = NULL; BIGNUM *v = NULL; BIGNUM *a = NULL; BIGNUM *b = NULL; BIGNUM *u = NULL; BIGNUM *x = NULL; BIGNUM *Apub = NULL; BIGNUM *Bpub = NULL; BIGNUM *Kclient = NULL; BIGNUM *Kserver = NULL; unsigned char rand_tmp[RANDOM_SIZE]; /* use builtin 1024-bit params */ const SRP_gN *GN; if (!TEST_ptr(GN = SRP_get_default_gN("1024"))) return 0; /* Set up server's password entry */ if (!TEST_true(SRP_create_verifier_BN(username, server_pass, &s, &v, GN->N, GN->g))) goto end; showbn("N", GN->N); showbn("g", GN->g); showbn("Salt", s); showbn("Verifier", v); /* Server random */ RAND_bytes(rand_tmp, sizeof(rand_tmp)); b = BN_bin2bn(rand_tmp, sizeof(rand_tmp), NULL); if (!TEST_BN_ne_zero(b)) goto end; showbn("b", b); /* Server's first message */ Bpub = SRP_Calc_B(b, GN->N, GN->g, v); showbn("B", Bpub); if (!TEST_true(SRP_Verify_B_mod_N(Bpub, GN->N))) goto end; /* Client random */ RAND_bytes(rand_tmp, sizeof(rand_tmp)); a = BN_bin2bn(rand_tmp, sizeof(rand_tmp), NULL); if (!TEST_BN_ne_zero(a)) goto end; showbn("a", a); /* Client's response */ Apub = SRP_Calc_A(a, GN->N, GN->g); showbn("A", Apub); if (!TEST_true(SRP_Verify_A_mod_N(Apub, GN->N))) goto end; /* Both sides calculate u */ u = SRP_Calc_u(Apub, Bpub, GN->N); /* Client's key */ x = SRP_Calc_x(s, username, client_pass); Kclient = SRP_Calc_client_key(GN->N, Bpub, GN->g, x, a, u); showbn("Client's key", Kclient); /* Server's key */ Kserver = SRP_Calc_server_key(Apub, v, u, b, GN->N); showbn("Server's key", Kserver); if (!TEST_BN_eq(Kclient, Kserver)) goto end; ret = 1; end: BN_clear_free(Kclient); BN_clear_free(Kserver); BN_clear_free(x); BN_free(u); BN_free(Apub); BN_clear_free(a); BN_free(Bpub); BN_clear_free(b); BN_free(s); BN_clear_free(v); return ret; }
/*- * This function hijacks the RNG to feed it the chosen ECDSA key and nonce. * The ECDSA KATs are from: * - the X9.62 draft (4) * - NIST CAVP (720) * * It uses the low-level ECDSA_sign_setup instead of EVP to control the RNG. * NB: This is not how applications should use ECDSA; this is only for testing. * * Tests the library can successfully: * - generate public keys that matches those KATs * - create ECDSA signatures that match those KATs * - accept those signatures as valid */ static int x9_62_tests(int n) { int nid, md_nid, ret = 0; const char *r_in = NULL, *s_in = NULL, *tbs = NULL; unsigned char *pbuf = NULL, *qbuf = NULL, *message = NULL; unsigned char digest[EVP_MAX_MD_SIZE]; unsigned int dgst_len = 0; long q_len, msg_len = 0; size_t p_len; EVP_MD_CTX *mctx = NULL; EC_KEY *key = NULL; ECDSA_SIG *signature = NULL; BIGNUM *r = NULL, *s = NULL; BIGNUM *kinv = NULL, *rp = NULL; const BIGNUM *sig_r = NULL, *sig_s = NULL; nid = ecdsa_cavs_kats[n].nid; md_nid = ecdsa_cavs_kats[n].md_nid; r_in = ecdsa_cavs_kats[n].r; s_in = ecdsa_cavs_kats[n].s; tbs = ecdsa_cavs_kats[n].msg; numbers[0] = ecdsa_cavs_kats[n].d; numbers[1] = ecdsa_cavs_kats[n].k; TEST_info("ECDSA KATs for curve %s", OBJ_nid2sn(nid)); if (!TEST_ptr(mctx = EVP_MD_CTX_new()) /* get the message digest */ || !TEST_ptr(message = OPENSSL_hexstr2buf(tbs, &msg_len)) || !TEST_true(EVP_DigestInit_ex(mctx, EVP_get_digestbynid(md_nid), NULL)) || !TEST_true(EVP_DigestUpdate(mctx, message, msg_len)) || !TEST_true(EVP_DigestFinal_ex(mctx, digest, &dgst_len)) /* create the key */ || !TEST_ptr(key = EC_KEY_new_by_curve_name(nid)) /* load KAT variables */ || !TEST_ptr(r = BN_new()) || !TEST_ptr(s = BN_new()) || !TEST_true(BN_hex2bn(&r, r_in)) || !TEST_true(BN_hex2bn(&s, s_in)) /* swap the RNG source */ || !TEST_true(change_rand())) goto err; /* public key must match KAT */ use_fake = 1; if (!TEST_true(EC_KEY_generate_key(key)) || !TEST_true(p_len = EC_KEY_key2buf(key, POINT_CONVERSION_UNCOMPRESSED, &pbuf, NULL)) || !TEST_ptr(qbuf = OPENSSL_hexstr2buf(ecdsa_cavs_kats[n].Q, &q_len)) || !TEST_int_eq(q_len, p_len) || !TEST_mem_eq(qbuf, q_len, pbuf, p_len)) goto err; /* create the signature via ECDSA_sign_setup to avoid use of ECDSA nonces */ use_fake = 1; if (!TEST_true(ECDSA_sign_setup(key, NULL, &kinv, &rp)) || !TEST_ptr(signature = ECDSA_do_sign_ex(digest, dgst_len, kinv, rp, key)) /* verify the signature */ || !TEST_int_eq(ECDSA_do_verify(digest, dgst_len, signature, key), 1)) goto err; /* compare the created signature with the expected signature */ ECDSA_SIG_get0(signature, &sig_r, &sig_s); if (!TEST_BN_eq(sig_r, r) || !TEST_BN_eq(sig_s, s)) goto err; ret = 1; err: /* restore the RNG source */ if (!TEST_true(restore_rand())) ret = 0; OPENSSL_free(message); OPENSSL_free(pbuf); OPENSSL_free(qbuf); EC_KEY_free(key); ECDSA_SIG_free(signature); BN_free(r); BN_free(s); EVP_MD_CTX_free(mctx); BN_clear_free(kinv); BN_clear_free(rp); return ret; }