- long err = ERR_peek_error();
- if (ERR_GET_LIB(err) == ERR_LIB_EVP
- && ERR_GET_REASON(err) == EVP_R_UNSUPPORTED_ALGORITHM) {
- ERR_clear_error();
- return 1;
- }
- return 0;
-}
-
-static int process_test(struct evp_test *t, char *buf, int verbose)
-{
- char *keyword = NULL, *value = NULL;
- int rv = 0, add_key = 0;
- long save_pos = 0;
- struct key_list **lst = NULL, *key = NULL;
- EVP_PKEY *pk = NULL;
- const struct evp_test_method *tmeth = NULL;
- if (verbose)
- fputs(buf, stdout);
- if (!parse_line(&keyword, &value, buf))
- return 1;
- if (strcmp(keyword, "PrivateKey") == 0) {
- save_pos = ftell(t->in);
- pk = PEM_read_PrivateKey(t->in, NULL, 0, NULL);
- if (pk == NULL && !check_unsupported()) {
- fprintf(stderr, "Error reading private key %s\n", value);
- ERR_print_errors_fp(stderr);
- return 0;
- }
- lst = &t->private;
- add_key = 1;
- }
- if (strcmp(keyword, "PublicKey") == 0) {
- save_pos = ftell(t->in);
- pk = PEM_read_PUBKEY(t->in, NULL, 0, NULL);
- if (pk == NULL && !check_unsupported()) {
- fprintf(stderr, "Error reading public key %s\n", value);
- ERR_print_errors_fp(stderr);
- return 0;
- }
- lst = &t->public;
- add_key = 1;
- }
- /* If we have a key add to list */
- if (add_key) {
- char tmpbuf[80];
- if (find_key(NULL, value, *lst)) {
- fprintf(stderr, "Duplicate key %s\n", value);
- return 0;
- }
- key = OPENSSL_malloc(sizeof(*key));
- if (!key)
- return 0;
- key->name = OPENSSL_strdup(value);
- key->key = pk;
- key->next = *lst;
- *lst = key;
- /* Rewind input, read to end and update line numbers */
- fseek(t->in, save_pos, SEEK_SET);
- while (fgets(tmpbuf, sizeof(tmpbuf), t->in)) {
- t->line++;
- if (strncmp(tmpbuf, "-----END", 8) == 0)
- return 1;
- }
- fprintf(stderr, "Can't find key end\n");
- return 0;
- }
-
- /* See if keyword corresponds to a test start */
- tmeth = evp_find_test(keyword);
- if (tmeth) {
- if (!setup_test(t, tmeth))
- return 0;
- t->start_line = t->line;
- t->skip = 0;
- if (!tmeth->init(t, value)) {
- fprintf(stderr, "Unknown %s: %s\n", keyword, value);
- return 0;
- }
- return 1;
- } else if (t->skip) {
- return 1;
- } else if (strcmp(keyword, "Result") == 0) {
- if (t->expected_err) {
- fprintf(stderr, "Line %d: multiple result lines\n", t->line);
- return 0;
- }
- t->expected_err = OPENSSL_strdup(value);
- if (!t->expected_err)
- return 0;
- } else {
- /* Must be test specific line: try to parse it */
- if (t->meth)
- rv = t->meth->parse(t, keyword, value);
-
- if (rv == 0)
- fprintf(stderr, "line %d: unexpected keyword %s\n",
- t->line, keyword);
-
- if (rv < 0)
- fprintf(stderr, "line %d: error processing keyword %s\n",
- t->line, keyword);
- if (rv <= 0)
- return 0;
- }
- return 1;
-}
-
-static int check_var_length_output(struct evp_test *t,
- const unsigned char *expected,
- size_t expected_len,
- const unsigned char *received,
- size_t received_len)
-{
- if (expected_len == received_len &&
- memcmp(expected, received, expected_len) == 0) {
- return 0;
- }
-
- /* The result printing code expects a non-NULL buffer. */
- t->out_expected = OPENSSL_memdup(expected, expected_len ? expected_len : 1);
- t->out_expected_len = expected_len;
- t->out_received = OPENSSL_memdup(received, received_len ? received_len : 1);
- t->out_received_len = received_len;
- if (t->out_expected == NULL || t->out_received == NULL) {
- fprintf(stderr, "Memory allocation error!\n");
- exit(1);
- }
- return 1;
-}
-
-static int check_output(struct evp_test *t,
- const unsigned char *expected,
- const unsigned char *received,
- size_t len)
-{
- return check_var_length_output(t, expected, len, received, len);
-}
-
-int main(int argc, char **argv)
-{
- FILE *in = NULL;
- char buf[10240];
- struct evp_test t;
-
- if (argc != 2) {
- fprintf(stderr, "usage: evp_test testfile.txt\n");
- return 1;
- }
-
- CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
-
- memset(&t, 0, sizeof(t));
- t.start_line = -1;
- in = fopen(argv[1], "r");
- t.in = in;
- while (fgets(buf, sizeof(buf), in)) {
- t.line++;
- if (!process_test(&t, buf, 0))
- exit(1);
- }
- /* Run any final test we have */
- if (!setup_test(&t, NULL))
- exit(1);
- fprintf(stderr, "%d tests completed with %d errors, %d skipped\n",
- t.ntests, t.errors, t.nskip);
- free_key_list(t.public);
- free_key_list(t.private);
- fclose(in);
-
-#ifndef OPENSSL_NO_CRYPTO_MDEBUG
- if (CRYPTO_mem_leaks_fp(stderr) <= 0)
- return 1;
-#endif
- if (t.errors)
- return 1;
- return 0;
-}
-
-static void test_free(void *d)
-{
- OPENSSL_free(d);
-}
-
-/* Message digest tests */
-
-struct digest_data {
- /* Digest this test is for */
- const EVP_MD *digest;
- /* Input to digest */
- unsigned char *input;
- size_t input_len;
- /* Repeat count for input */
- size_t nrpt;
- /* Expected output */
- unsigned char *output;
- size_t output_len;
-};
-
-static int digest_test_init(struct evp_test *t, const char *alg)
-{
- const EVP_MD *digest;
- struct digest_data *mdat;
- digest = EVP_get_digestbyname(alg);
- if (!digest) {
- /* If alg has an OID assume disabled algorithm */
- if (OBJ_sn2nid(alg) != NID_undef || OBJ_ln2nid(alg) != NID_undef) {
- t->skip = 1;
- return 1;
- }
- return 0;
- }
- mdat = OPENSSL_malloc(sizeof(*mdat));
- mdat->digest = digest;
- mdat->input = NULL;
- mdat->output = NULL;
- mdat->nrpt = 1;
- t->data = mdat;
- return 1;
-}
-
-static void digest_test_cleanup(struct evp_test *t)
-{
- struct digest_data *mdat = t->data;
- test_free(mdat->input);
- test_free(mdat->output);
-}
-
-static int digest_test_parse(struct evp_test *t,
- const char *keyword, const char *value)
-{
- struct digest_data *mdata = t->data;
- if (strcmp(keyword, "Input") == 0)
- return test_bin(value, &mdata->input, &mdata->input_len);
- if (strcmp(keyword, "Output") == 0)
- return test_bin(value, &mdata->output, &mdata->output_len);
- if (strcmp(keyword, "Count") == 0) {
- long nrpt = atoi(value);
- if (nrpt <= 0)
- return 0;
- mdata->nrpt = (size_t)nrpt;
- return 1;
- }
- return 0;
-}
-
-static int digest_test_run(struct evp_test *t)
-{
- struct digest_data *mdata = t->data;
- size_t i;
- const char *err = "INTERNAL_ERROR";
- EVP_MD_CTX *mctx;
- unsigned char md[EVP_MAX_MD_SIZE];
- unsigned int md_len;
- mctx = EVP_MD_CTX_new();
- if (!mctx)
- goto err;
- err = "DIGESTINIT_ERROR";
- if (!EVP_DigestInit_ex(mctx, mdata->digest, NULL))
- goto err;
- err = "DIGESTUPDATE_ERROR";
- for (i = 0; i < mdata->nrpt; i++) {
- 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:
- EVP_MD_CTX_free(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;
- /* EVP_CIPH_GCM_MODE, EVP_CIPH_CCM_MODE or EVP_CIPH_OCB_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) {
- /* If alg has an OID assume disabled algorithm */
- if (OBJ_sn2nid(alg) != NID_undef || OBJ_ln2nid(alg) != NID_undef) {
- t->skip = 1;
- return 1;
- }
- return 0;
- }
- cdat = OPENSSL_malloc(sizeof(*cdat));
- 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_OCB_MODE
- || EVP_CIPHER_mode(cipher) == EVP_CIPH_CCM_MODE)
- cdat->aead = EVP_CIPHER_mode(cipher);
- else if (EVP_CIPHER_flags(cipher) & EVP_CIPH_FLAG_AEAD_CIPHER)
- cdat->aead = -1;
- 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") == 0)
- return test_bin(value, &cdat->key, &cdat->key_len);
- if (strcmp(keyword, "IV") == 0)
- return test_bin(value, &cdat->iv, &cdat->iv_len);
- if (strcmp(keyword, "Plaintext") == 0)
- return test_bin(value, &cdat->plaintext, &cdat->plaintext_len);
- if (strcmp(keyword, "Ciphertext") == 0)
- return test_bin(value, &cdat->ciphertext, &cdat->ciphertext_len);
- if (cdat->aead) {
- if (strcmp(keyword, "AAD") == 0)
- return test_bin(value, &cdat->aad, &cdat->aad_len);
- if (strcmp(keyword, "Tag") == 0)
- return test_bin(value, &cdat->tag, &cdat->tag_len);