+}
+
+static int digest_test_run(struct evp_test *t)
+{
+ struct digest_data *mdata = t->data;
+ const char *err = "INTERNAL_ERROR";
+ EVP_MD_CTX *mctx;
+ unsigned char md[EVP_MAX_MD_SIZE];
+ unsigned int md_len;
+ mctx = EVP_MD_CTX_create();
+ if (!mctx)
+ goto err;
+ err = "DIGESTINIT_ERROR";
+ if (!EVP_DigestInit_ex(mctx, mdata->digest, NULL))
+ goto err;
+ err = "DIGESTUPDATE_ERROR";
+ if (!EVP_DigestUpdate(mctx, mdata->input, mdata->input_len))
+ goto err;
+ err = "DIGESTFINAL_ERROR";
+ if (!EVP_DigestFinal(mctx, md, &md_len))
+ goto err;
+ err = "DIGEST_LENGTH_MISMATCH";
+ if (md_len != mdata->output_len)
+ goto err;
+ err = "DIGEST_MISMATCH";
+ if (check_output(t, mdata->output, md, md_len))
+ goto err;
+ err = NULL;
+ err:
+ if (mctx)
+ EVP_MD_CTX_destroy(mctx);
+ t->err = err;
+ return 1;
+}
+
+static const struct evp_test_method digest_test_method = {
+ "Digest",
+ digest_test_init,
+ digest_test_cleanup,
+ digest_test_parse,
+ digest_test_run
+};
+
+/* Cipher tests */
+struct cipher_data {
+ const EVP_CIPHER *cipher;
+ int enc;
+ /* Set to EVP_CIPH_GCM_MODE or EVP_CIPH_CCM_MODE if AEAD */
+ int aead;
+ unsigned char *key;
+ size_t key_len;
+ unsigned char *iv;
+ size_t iv_len;
+ unsigned char *plaintext;
+ size_t plaintext_len;
+ unsigned char *ciphertext;
+ size_t ciphertext_len;
+ /* GCM, CCM only */
+ unsigned char *aad;
+ size_t aad_len;
+ unsigned char *tag;
+ size_t tag_len;
+};
+
+static int cipher_test_init(struct evp_test *t, const char *alg)
+{
+ const EVP_CIPHER *cipher;
+ struct cipher_data *cdat = t->data;
+ cipher = EVP_get_cipherbyname(alg);
+ if (!cipher)
+ return 0;
+ cdat = OPENSSL_malloc(sizeof(struct cipher_data));
+ cdat->cipher = cipher;
+ cdat->enc = -1;
+ cdat->key = NULL;
+ cdat->iv = NULL;
+ cdat->ciphertext = NULL;
+ cdat->plaintext = NULL;
+ cdat->aad = NULL;
+ cdat->tag = NULL;
+ t->data = cdat;
+ if (EVP_CIPHER_mode(cipher) == EVP_CIPH_GCM_MODE
+ || EVP_CIPHER_mode(cipher) == EVP_CIPH_CCM_MODE)
+ cdat->aead = EVP_CIPHER_mode(cipher);
+ else
+ cdat->aead = 0;
+
+ return 1;
+}
+
+static void cipher_test_cleanup(struct evp_test *t)
+{
+ struct cipher_data *cdat = t->data;
+ test_free(cdat->key);
+ test_free(cdat->iv);
+ test_free(cdat->ciphertext);
+ test_free(cdat->plaintext);
+ test_free(cdat->aad);
+ test_free(cdat->tag);
+}
+
+static int cipher_test_parse(struct evp_test *t, const char *keyword,
+ const char *value)
+{
+ struct cipher_data *cdat = t->data;
+ if (!strcmp(keyword, "Key"))
+ return test_bin(value, &cdat->key, &cdat->key_len);
+ if (!strcmp(keyword, "IV"))
+ return test_bin(value, &cdat->iv, &cdat->iv_len);
+ if (!strcmp(keyword, "Plaintext"))
+ return test_bin(value, &cdat->plaintext, &cdat->plaintext_len);
+ if (!strcmp(keyword, "Ciphertext"))
+ return test_bin(value, &cdat->ciphertext, &cdat->ciphertext_len);
+ if (cdat->aead) {
+ if (!strcmp(keyword, "AAD"))
+ return test_bin(value, &cdat->aad, &cdat->aad_len);
+ if (!strcmp(keyword, "Tag"))
+ return test_bin(value, &cdat->tag, &cdat->tag_len);
+ }
+
+ if (!strcmp(keyword, "Operation")) {
+ if (!strcmp(value, "ENCRYPT"))
+ cdat->enc = 1;
+ else if (!strcmp(value, "DECRYPT"))
+ cdat->enc = 0;
+ else
+ return 0;
+ return 1;
+ }
+ return 0;
+}
+
+static int cipher_test_enc(struct evp_test *t, int enc)
+{
+ struct cipher_data *cdat = t->data;
+ unsigned char *in, *out, *tmp = NULL;
+ size_t in_len, out_len;
+ int tmplen, tmpflen;
+ EVP_CIPHER_CTX *ctx = NULL;
+ const char *err;
+ err = "INTERNAL_ERROR";
+ ctx = EVP_CIPHER_CTX_new();
+ if (!ctx)
+ goto err;
+ EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
+ if (enc) {
+ in = cdat->plaintext;
+ in_len = cdat->plaintext_len;
+ out = cdat->ciphertext;
+ out_len = cdat->ciphertext_len;
+ } else {
+ in = cdat->ciphertext;
+ in_len = cdat->ciphertext_len;
+ out = cdat->plaintext;
+ out_len = cdat->plaintext_len;
+ }
+ tmp = OPENSSL_malloc(in_len + 2 * EVP_MAX_BLOCK_LENGTH);
+ if (!tmp)
+ goto err;
+ err = "CIPHERINIT_ERROR";
+ if (!EVP_CipherInit_ex(ctx, cdat->cipher, NULL, NULL, NULL, enc))
+ goto err;
+ err = "INVALID_IV_LENGTH";
+ if (cdat->iv) {
+ if (cdat->aead == EVP_CIPH_GCM_MODE) {
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN,
+ cdat->iv_len, 0))
+ goto err;
+ } else if (cdat->aead == EVP_CIPH_CCM_MODE) {
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN,
+ cdat->iv_len, 0))
+ goto err;
+ } else if (cdat->iv_len != (size_t)EVP_CIPHER_CTX_iv_length(ctx))
+ goto err;
+ }
+ if (cdat->aead) {
+ unsigned char *tag;
+ /*
+ * If encrypting just set tag length. If decrypting set
+ * tag length and value.
+ */
+ if (enc) {
+ err = "TAG_LENGTH_SET_ERROR";
+ tag = NULL;
+ } else {
+ err = "TAG_SET_ERROR";
+ tag = cdat->tag;
+ }
+ if (cdat->aead == EVP_CIPH_GCM_MODE && tag) {
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG,
+ cdat->tag_len, tag))
+ goto err;
+ } else if (cdat->aead == EVP_CIPH_CCM_MODE) {
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG,
+ cdat->tag_len, tag))
+ goto err;
+ }
+ }
+
+ err = "INVALID_KEY_LENGTH";
+ if (!EVP_CIPHER_CTX_set_key_length(ctx, cdat->key_len))
+ goto err;
+ err = "KEY_SET_ERROR";
+ if (!EVP_CipherInit_ex(ctx, NULL, NULL, cdat->key, cdat->iv, -1))
+ goto err;
+
+ if (cdat->aead == EVP_CIPH_CCM_MODE) {
+ if (!EVP_CipherUpdate(ctx, NULL, &tmplen, NULL, out_len)) {
+ err = "CCM_PLAINTEXT_LENGTH_SET_ERROR";
+ goto err;
+ }
+ }
+ if (cdat->aad) {
+ if (!EVP_CipherUpdate(ctx, NULL, &tmplen, cdat->aad, cdat->aad_len)) {
+ err = "AAD_SET_ERROR";
+ goto err;
+ }
+ }
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
+ err = "CIPHERUPDATE_ERROR";
+ if (!EVP_CipherUpdate(ctx, tmp, &tmplen, in, in_len))
+ goto err;
+ if (cdat->aead == EVP_CIPH_CCM_MODE)
+ tmpflen = 0;
+ else {
+ err = "CIPHERFINAL_ERROR";
+ if (!EVP_CipherFinal_ex(ctx, tmp + tmplen, &tmpflen))
+ goto err;
+ }
+ err = "LENGTH_MISMATCH";
+ if (out_len != (size_t)(tmplen + tmpflen))
+ goto err;
+ err = "VALUE_MISMATCH";
+ if (check_output(t, out, tmp, out_len))
+ goto err;
+ if (enc && cdat->aead) {
+ unsigned char rtag[16];
+ if (cdat->tag_len > sizeof(rtag)) {
+ err = "TAG_LENGTH_INTERNAL_ERROR";
+ goto err;
+ }
+ /* EVP_CTRL_CCM_GET_TAG and EVP_CTRL_GCM_GET_TAG are equal. */
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG,
+ cdat->tag_len, rtag)) {
+ err = "TAG_RETRIEVE_ERROR";
+ goto err;
+ }
+ if (check_output(t, cdat->tag, rtag, cdat->tag_len)) {
+ err = "TAG_VALUE_MISMATCH";
+ goto err;
+ }
+ }
+ err = NULL;
+ err:
+ if (tmp)
+ OPENSSL_free(tmp);
+ EVP_CIPHER_CTX_free(ctx);
+ t->err = err;
+ return err ? 0 : 1;
+}
+
+static int cipher_test_run(struct evp_test *t)
+{
+ struct cipher_data *cdat = t->data;
+ int rv;
+ if (!cdat->key) {
+ t->err = "NO_KEY";
+ return 0;
+ }
+ if (!cdat->iv && EVP_CIPHER_iv_length(cdat->cipher)) {
+ /* IV is optional and usually omitted in wrap mode */
+ if (EVP_CIPHER_mode(cdat->cipher) != EVP_CIPH_WRAP_MODE) {
+ t->err = "NO_IV";
+ return 0;
+ }
+ }
+ if (cdat->aead && !cdat->tag) {
+ t->err = "NO_TAG";
+ return 0;
+ }
+ if (cdat->enc) {
+ rv = cipher_test_enc(t, 1);
+ /* Not fatal errors: return */
+ if (rv != 1) {
+ if (rv < 0)
+ return 0;
+ return 1;
+ }
+ }
+ if (cdat->enc != 1) {
+ rv = cipher_test_enc(t, 0);
+ /* Not fatal errors: return */
+ if (rv != 1) {
+ if (rv < 0)
+ return 0;
+ return 1;
+ }
+ }
+ return 1;
+}
+
+static const struct evp_test_method cipher_test_method = {
+ "Cipher",
+ cipher_test_init,
+ cipher_test_cleanup,
+ cipher_test_parse,
+ cipher_test_run
+};
+
+struct mac_data {
+ /* MAC type */
+ int type;
+ /* Algorithm string for this MAC */
+ char *alg;
+ /* MAC key */
+ unsigned char *key;
+ size_t key_len;
+ /* Input to MAC */
+ unsigned char *input;
+ size_t input_len;
+ /* Expected output */
+ unsigned char *output;
+ size_t output_len;
+};
+
+static int mac_test_init(struct evp_test *t, const char *alg)
+{
+ int type;
+ struct mac_data *mdat;
+ if (!strcmp(alg, "HMAC"))
+ type = EVP_PKEY_HMAC;
+ else if (!strcmp(alg, "CMAC"))
+ type = EVP_PKEY_CMAC;
+ else
+ return 0;
+
+ mdat = OPENSSL_malloc(sizeof(struct mac_data));
+ mdat->type = type;
+ mdat->alg = NULL;
+ mdat->key = NULL;
+ mdat->input = NULL;
+ mdat->output = NULL;
+ t->data = mdat;
+ return 1;
+}
+
+static void mac_test_cleanup(struct evp_test *t)
+{
+ struct mac_data *mdat = t->data;
+ test_free(mdat->alg);
+ test_free(mdat->key);
+ test_free(mdat->input);
+ test_free(mdat->output);
+}
+
+static int mac_test_parse(struct evp_test *t,
+ const char *keyword, const char *value)
+{
+ struct mac_data *mdata = t->data;
+ if (!strcmp(keyword, "Key"))
+ return test_bin(value, &mdata->key, &mdata->key_len);
+ if (!strcmp(keyword, "Algorithm")) {
+ mdata->alg = BUF_strdup(value);
+ if (!mdata->alg)
+ return 0;
+ return 1;
+ }
+ if (!strcmp(keyword, "Input"))
+ return test_bin(value, &mdata->input, &mdata->input_len);
+ if (!strcmp(keyword, "Output"))
+ return test_bin(value, &mdata->output, &mdata->output_len);
+ return 0;
+}
+
+static int mac_test_run(struct evp_test *t)
+{
+ struct mac_data *mdata = t->data;
+ const char *err = "INTERNAL_ERROR";
+ EVP_MD_CTX *mctx = NULL;
+ EVP_PKEY_CTX *pctx = NULL, *genctx = NULL;
+ EVP_PKEY *key = NULL;
+ const EVP_MD *md = NULL;
+ unsigned char *mac = NULL;
+ size_t mac_len;
+
+ err = "MAC_PKEY_CTX_ERROR";
+ genctx = EVP_PKEY_CTX_new_id(mdata->type, NULL);
+ if (!genctx)
+ goto err;
+
+ err = "MAC_KEYGEN_INIT_ERROR";
+ if (EVP_PKEY_keygen_init(genctx) <= 0)
+ goto err;
+ if (mdata->type == EVP_PKEY_CMAC) {
+ err = "MAC_ALGORITHM_SET_ERROR";
+ if (EVP_PKEY_CTX_ctrl_str(genctx, "cipher", mdata->alg) <= 0)
+ goto err;
+ }
+
+ err = "MAC_KEY_SET_ERROR";
+ if (EVP_PKEY_CTX_set_mac_key(genctx, mdata->key, mdata->key_len) <= 0)
+ goto err;
+
+ err = "MAC_KEY_GENERATE_ERROR";
+ if (EVP_PKEY_keygen(genctx, &key) <= 0)
+ goto err;
+ if (mdata->type == EVP_PKEY_HMAC) {
+ err = "MAC_ALGORITHM_SET_ERROR";
+ md = EVP_get_digestbyname(mdata->alg);
+ if (!md)
+ goto err;
+ }
+ mctx = EVP_MD_CTX_create();
+ if (!mctx)
+ goto err;
+ err = "DIGESTSIGNINIT_ERROR";
+ if (!EVP_DigestSignInit(mctx, &pctx, md, NULL, key))
+ goto err;
+
+ err = "DIGESTSIGNUPDATE_ERROR";
+ if (!EVP_DigestSignUpdate(mctx, mdata->input, mdata->input_len))
+ goto err;
+ err = "DIGESTSIGNFINAL_LENGTH_ERROR";
+ if (!EVP_DigestSignFinal(mctx, NULL, &mac_len))
+ goto err;
+ mac = OPENSSL_malloc(mac_len);
+ if (!mac) {
+ fprintf(stderr, "Error allocating mac buffer!\n");
+ exit(1);
+ }
+ if (!EVP_DigestSignFinal(mctx, mac, &mac_len))
+ goto err;
+ err = "MAC_LENGTH_MISMATCH";
+ if (mac_len != mdata->output_len)
+ goto err;
+ err = "MAC_MISMATCH";
+ if (check_output(t, mdata->output, mac, mac_len))
+ goto err;
+ err = NULL;
+ err:
+ if (mctx)
+ EVP_MD_CTX_destroy(mctx);
+ if (mac)
+ OPENSSL_free(mac);
+ if (genctx)
+ EVP_PKEY_CTX_free(genctx);
+ if (key)
+ EVP_PKEY_free(key);
+ t->err = err;
+ return 1;
+}
+
+static const struct evp_test_method mac_test_method = {
+ "MAC",
+ mac_test_init,
+ mac_test_cleanup,
+ mac_test_parse,
+ mac_test_run
+};
+
+/*
+ * Public key operations. These are all very similar and can share
+ * a lot of common code.
+ */
+
+struct pkey_data {
+ /* Context for this operation */
+ EVP_PKEY_CTX *ctx;
+ /* Key operation to perform */
+ int (*keyop) (EVP_PKEY_CTX *ctx,
+ unsigned char *sig, size_t *siglen,
+ const unsigned char *tbs, size_t tbslen);
+ /* Input to MAC */
+ unsigned char *input;
+ size_t input_len;
+ /* Expected output */
+ unsigned char *output;
+ size_t output_len;
+};
+
+/*
+ * Perform public key operation setup: lookup key, allocated ctx and call
+ * the appropriate initialisation function
+ */
+static int pkey_test_init(struct evp_test *t, const char *name,
+ int use_public,
+ int (*keyopinit) (EVP_PKEY_CTX *ctx),
+ int (*keyop) (EVP_PKEY_CTX *ctx,
+ unsigned char *sig, size_t *siglen,
+ const unsigned char *tbs,
+ size_t tbslen)
+ )
+{
+ struct pkey_data *kdata;
+ EVP_PKEY *pkey = NULL;
+ kdata = OPENSSL_malloc(sizeof(struct pkey_data));
+ if (!kdata)
+ return 0;
+ kdata->ctx = NULL;
+ kdata->input = NULL;
+ kdata->output = NULL;
+ kdata->keyop = keyop;
+ t->data = kdata;
+ if (use_public)
+ pkey = find_key(name, t->public);
+ if (!pkey)
+ pkey = find_key(name, t->private);
+ if (!pkey)
+ return 0;
+ kdata->ctx = EVP_PKEY_CTX_new(pkey, NULL);
+ if (!kdata->ctx)
+ return 0;
+ if (keyopinit(kdata->ctx) <= 0)
+ return 0;
+ return 1;
+}
+
+static void pkey_test_cleanup(struct evp_test *t)
+{
+ struct pkey_data *kdata = t->data;
+ if (kdata->input)
+ OPENSSL_free(kdata->input);
+ if (kdata->output)
+ OPENSSL_free(kdata->output);
+ if (kdata->ctx)
+ EVP_PKEY_CTX_free(kdata->ctx);
+}
+
+static int pkey_test_parse(struct evp_test *t,
+ const char *keyword, const char *value)
+{
+ struct pkey_data *kdata = t->data;
+ if (!strcmp(keyword, "Input"))
+ return test_bin(value, &kdata->input, &kdata->input_len);
+ if (!strcmp(keyword, "Output"))
+ return test_bin(value, &kdata->output, &kdata->output_len);
+ if (!strcmp(keyword, "Ctrl")) {
+ char *p = strchr(value, ':');
+ if (p)
+ *p++ = 0;
+ if (EVP_PKEY_CTX_ctrl_str(kdata->ctx, value, p) <= 0)
+ return 0;
+ return 1;