#define cDBLUE "\033[0;34m"
#define cNORM "\033[m"
#define TEST_ASSERT(e) {if ((test = (e))) \
- printf(cRED " Test FAILED\n" cNORM); \
+ printf(cRED " Test FAILED" cNORM "\n"); \
else \
- printf(cGREEN " Test passed\n" cNORM);}
+ printf(cGREEN " Test passed" cNORM "\n");}
struct test_param {
unsigned int param; /* NID of EC parameters */
static void print_test_result(int err)
{
if (err == 1)
- printf(cGREEN "correct\n" cNORM);
+ printf(cGREEN "correct" cNORM "\n");
else if (err == 0)
- printf(cRED "incorrect\n" cNORM);
+ printf(cRED "incorrect" cNORM "\n");
else
ERR_print_errors_fp(stderr);
}
+/* copy-paste from crypto/crmf/crmf_lib.c */
+static int X509_PUBKEY_cmp(X509_PUBKEY *a, X509_PUBKEY *b)
+{
+ X509_ALGOR *algA = NULL, *algB = NULL;
+ int res = 0;
+
+ if (a == b)
+ return 0;
+ if (a == NULL || !X509_PUBKEY_get0_param(NULL, NULL, NULL, &algA, a)
+ || algA == NULL)
+ return -1;
+ if (b == NULL || !X509_PUBKEY_get0_param(NULL, NULL, NULL, &algB, b)
+ || algB == NULL)
+ return 1;
+ if ((res = X509_ALGOR_cmp(algA, algB)) != 0)
+ return res;
+ return !EVP_PKEY_cmp(X509_PUBKEY_get0(a), X509_PUBKEY_get0(b));
+}
+
static int test_cert(struct test_cert *tc)
{
- int err = 0;
+ int ret = 0, err;
X509 *x;
const unsigned char *p;
- printf(cBLUE "Test %s (it):\n" cNORM, tc->name);
+ printf(cBLUE "Test %s (it): " cNORM, tc->name);
p = tc->cert;
T(x = d2i_X509(NULL, &p, tc->len));
printf(" (curve %s)\n", OBJ_nid2sn(param_nid));
sk_ASN1_TYPE_pop_free(seq, ASN1_TYPE_free);
+ /*
+ * Conversion tests.
+ */
+ /* Convert cert to DER and back. */
+ BIO *bp;
+ T(bp = BIO_new(BIO_s_mem()));
+ T(i2d_X509_bio(bp, x));
+ X509 *y = NULL;
+ T(d2i_X509_bio(bp, &y));
+ err = X509_cmp(x, y);
+ printf(" d2i_X509_bio\t\t\t");
+ print_test_result(!err);
+ ret |= err;
+ X509_free(y);
+
+ /* Convert cert to PEM and back. */
+ y = NULL;
+ T(PEM_write_bio_X509(bp, x));
+ T(PEM_read_bio_X509(bp, &y, 0, NULL));
+ err = X509_cmp(x, y);
+ printf(" PEM_read_bio_X509\t\t");
+ print_test_result(!err);
+ ret |= err;
+ X509_free(y);
+
+ /* Convert public key to PEM and back. */
+ T(BIO_reset(bp));
+ T(PEM_write_bio_X509_PUBKEY(bp, xk));
+ X509_PUBKEY *tk = NULL;
+ T(PEM_read_bio_X509_PUBKEY(bp, &tk, NULL, NULL));
+ err = X509_PUBKEY_cmp(xk, tk);
+ X509_PUBKEY_free(tk);
+ printf(" PEM_read_bio_X509_PUBKEY\t");
+ print_test_result(!err);
+ ret |= err;
+
+ /* Convert public key to DER and back. */
+ T(BIO_reset(bp));
+ T(i2d_X509_PUBKEY_bio(bp, xk));
+ tk = NULL;
+ T(d2i_X509_PUBKEY_bio(bp, &tk));
+ err = X509_PUBKEY_cmp(xk, tk);
+ X509_PUBKEY_free(tk);
+ printf(" d2i_X509_PUBKEY_bio\t\t");
+ print_test_result(!err);
+ ret |= err;
+ BIO_free(bp);
+
/*
* Verify
*/
- printf(" X509_verify API\t");
+ printf(" X509_verify API\t\t");
fflush(stdout);
EVP_PKEY *pk;
TE(pk = X509_get0_pubkey(x));
/* Similar to: openssl verify -partial_chain -check_ss_sig ... */
+ /* X509_verify uses EVP_DigestVerify internally */
err = X509_verify(x, pk);
print_test_result(err);
+ ret |= err != 1;
- return err != 1;
+ /* Verify manually. */
+ const ASN1_BIT_STRING *signature;
+ X509_get0_signature(&signature, NULL, x);
+ unsigned char *tbs = NULL; /* signed part */
+ int tbs_len;
+ T((tbs_len = i2d_re_X509_tbs(x, &tbs)) > 0);
+ int algnid, hash_nid, pknid;
+ T(algnid = X509_get_signature_nid(x));
+ T(OBJ_find_sigid_algs(algnid, &hash_nid, &pknid));
+
+ printf(" EVP_Verify API\t\t");
+ EVP_MD_CTX *md_ctx;
+ T(md_ctx = EVP_MD_CTX_new());
+ const EVP_MD *mdtype;
+ T(mdtype = EVP_get_digestbynid(hash_nid));
+ T(EVP_VerifyInit(md_ctx, mdtype));
+ T(EVP_VerifyUpdate(md_ctx, tbs, tbs_len));
+ err = EVP_VerifyFinal(md_ctx, signature->data, signature->length, pk);
+ print_test_result(err);
+ EVP_MD_CTX_free(md_ctx);
+ ret |= err != 1;
+
+ X509_free(x);
+ OPENSSL_free(tbs);
+ return ret;
+}
+
+/* Generate EC_KEY with proper parameters using temporary PKEYs.
+ * This emulates fill_GOST_EC_params() call.
+ */
+static int EC_KEY_create(int type, int param_nid, EC_KEY *dst)
+{
+ EVP_PKEY *pkey;
+ T(pkey = EVP_PKEY_new());
+ T(EVP_PKEY_set_type(pkey, type));
+ EVP_PKEY_CTX *ctx;
+ T(ctx = EVP_PKEY_CTX_new(pkey, NULL));
+ T(EVP_PKEY_paramgen_init(ctx));
+ T(EVP_PKEY_CTX_ctrl(ctx, type, -1, EVP_PKEY_CTRL_GOST_PARAMSET, param_nid, NULL));
+ EVP_PKEY *pkey2 = NULL;
+ int err;
+ TE((err = EVP_PKEY_paramgen(ctx, &pkey2)) == 1);
+ T(EC_KEY_copy(dst, EVP_PKEY_get0(pkey2)));
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(pkey);
+ EVP_PKEY_free(pkey2);
+ return err;
}
static int test_param(struct test_param *t)
int hash_nid = 0;
const char *sn = OBJ_nid2sn(t->param);
- printf(cBLUE "Test %s (cp):\n" cNORM, sn);
- //T(pkey = EVP_PKEY_new_raw_public_key(NID_id_GostR3410_2001, NULL, t->pub_key, 64));
+ printf(cBLUE "Test %s (cp):" cNORM "\n", sn);
switch (t->len) {
case 256 / 8:
/* Manually construct public key */
EC_KEY *ec;
T(ec = EC_KEY_new());
- T(fill_GOST_EC_params(ec, t->param));
+ T(EC_KEY_create(type, t->param, ec));
const EC_GROUP *group;
T(group = EC_KEY_get0_group(ec));
unsigned char *pub_key;
T(ctx = EVP_PKEY_CTX_new(pkey, NULL));
unsigned char *sig;
T(sig = OPENSSL_malloc(siglen));
- /* Need to reverse provided signature for unknown reason */
+ /* Need to reverse provided signature for unknown reason,
+ * contrary to how it goes into signature. */
BUF_reverse(sig, t->signature, siglen);
/* Verify using EVP_PKEY_verify API */
- printf(" EVP_PKEY_verify API\t");
+ printf(" EVP_PKEY_verify API\t\t");
T(EVP_PKEY_verify_init(ctx));
err = EVP_PKEY_verify(ctx, sig, siglen, t->hash, t->len);
+ EVP_PKEY_CTX_free(ctx);
print_test_result(err);
ret |= err != 1;
/* Verify using EVP_Verify API */
if (t->data) {
- printf(" EVP_Verify API\t");
+ printf(" EVP_Verify API\t\t");
EVP_MD_CTX *md_ctx;
T(md_ctx = EVP_MD_CTX_new());
const EVP_MD *mdtype;
T(mdtype = EVP_get_digestbynid(hash_nid));
T(EVP_VerifyInit(md_ctx, mdtype));
- T(EVP_VerifyUpdate(md_ctx, t->data, t->data_len));
+ /* Feed byte-by-byte. */
+ int i;
+ for (i = 0; i < t->data_len; i++)
+ T(EVP_VerifyUpdate(md_ctx, &t->data[i], 1));
err = EVP_VerifyFinal(md_ctx, sig, siglen, pkey);
print_test_result(err);
EVP_MD_CTX_free(md_ctx);
ret |= err != 1;
}
+ /* Verify using EVP_DigestVerifyInit API */
+ if (t->data) {
+ printf(" EVP_DigestVerifyInit API\t");
+ EVP_MD_CTX *md_ctx;
+ T(md_ctx = EVP_MD_CTX_new());
+ const EVP_MD *mdtype;
+ T(mdtype = EVP_get_digestbynid(hash_nid));
+ T(EVP_DigestVerifyInit(md_ctx, NULL, mdtype, NULL, pkey));
+ /* Verify in one step. */
+ err = EVP_DigestVerify(md_ctx, sig, siglen, t->data, t->data_len);
+ print_test_result(err);
+ EVP_MD_CTX_free(md_ctx);
+ ret |= err != 1;
+ }
+
OPENSSL_free(sig);
+ EVP_PKEY_free(pkey);
return ret;
}
int ret = 0;
OPENSSL_add_all_algorithms_conf();
- ERR_load_crypto_strings();
- ENGINE *e = ENGINE_new();
- bind_gost(e, "gost");
- ENGINE_register_complete(e);
struct test_param **tpp;
for (tpp = test_params; *tpp; tpp++)
for (tc = test_certs; tc->cert; tc++)
ret |= test_cert(tc);
+ if (ret)
+ printf(cDRED "= Some tests FAILED!" cNORM "\n");
+ else
+ printf(cDGREEN "= All tests passed!" cNORM "\n");
return ret;
}