+ *p++ = '\0';
+
+ *pkw = linebuf;
+ *pval = p;
+
+ /* Remove spaces from keyword and value */
+ remove_space(pkw);
+ remove_space(pval);
+
+ return 1;
+}
+
+/* For a hex string "value" convert to a binary allocated buffer */
+static int test_bin(const char *value, unsigned char **buf, size_t *buflen)
+{
+ long len;
+ if (!*value) {
+ /* Don't return NULL for zero length buffer */
+ *buf = OPENSSL_malloc(1);
+ if (!*buf)
+ return 0;
+ **buf = 0;
+ *buflen = 0;
+ return 1;
+ }
+ *buf = string_to_hex(value, &len);
+ if (!*buf) {
+ fprintf(stderr, "Value=%s\n", value);
+ ERR_print_errors_fp(stderr);
+ return -1;
+ }
+ /* Size of input buffer means we'll never overflow */
+ *buflen = len;
+ return 1;
+}
+
+/* Structure holding test information */
+struct evp_test {
+ /* method for this test */
+ const struct evp_test_method *meth;
+ /* current line being processed */
+ unsigned int line;
+ /* start line of current test */
+ unsigned int start_line;
+ /* Error string for test */
+ const char *err;
+ /* Expected error value of test */
+ char *expected_err;
+ /* Number of tests */
+ int ntests;
+ /* Error count */
+ int errors;
+ /* If output mismatch expected and got value */
+ unsigned char *out_got;
+ unsigned char *out_expected;
+ size_t out_len;
+ /* test specific data */
+ void *data;
+};
+/* Test method structure */
+struct evp_test_method {
+ /* Name of test as it appears in file */
+ const char *name;
+ /* Initialise test for "alg" */
+ int (*init) (struct evp_test * t, const char *alg);
+ /* Clean up method */
+ void (*cleanup) (struct evp_test * t);
+ /* Test specific name value pair processing */
+ int (*parse) (struct evp_test * t, const char *name, const char *value);
+ /* Run the test itself */
+ int (*run_test) (struct evp_test * t);
+};
+
+static const struct evp_test_method digest_test_method, cipher_test_method;
+static const struct evp_test_method aead_test_method;
+
+static const struct evp_test_method *evp_test_list[] = {
+ &digest_test_method,
+ &cipher_test_method,
+ NULL,
+};
+
+static const struct evp_test_method *evp_find_test(const char *name)
+{
+ const struct evp_test_method **tt;
+ for (tt = evp_test_list; *tt; tt++) {
+ if (!strcmp(name, (*tt)->name))
+ return *tt;
+ }
+ return NULL;
+}
+
+static void hex_print(const char *name, const unsigned char *buf, size_t len)
+{
+ size_t i;
+ fprintf(stderr, "%s ", name);
+ for (i = 0; i < len; i++)
+ fprintf(stderr, "%02X", buf[i]);
+ fputs("\n", stderr);
+}
+
+static void print_expected(struct evp_test *t)
+{
+ if (t->out_expected == NULL)
+ return;
+ hex_print("Expected:", t->out_expected, t->out_len);
+ hex_print("Got: ", t->out_got, t->out_len);
+ OPENSSL_free(t->out_expected);
+ OPENSSL_free(t->out_got);
+ t->out_expected = NULL;
+ t->out_got = NULL;
+}
+
+static int check_test_error(struct evp_test *t)
+{
+ if (!t->err && !t->expected_err)
+ return 1;
+ if (t->err && !t->expected_err) {
+ fprintf(stderr, "Test line %d: unexpected error %s\n",
+ t->start_line, t->err);
+ print_expected(t);
+ return 0;
+ }
+ if (!t->err && t->expected_err) {
+ fprintf(stderr, "Test line %d: succeeded expecting %s\n",
+ t->start_line, t->expected_err);
+ return 0;
+ }
+ if (!strcmp(t->err, t->expected_err))
+ return 1;
+
+ fprintf(stderr, "Test line %d: expecting %s got %s\n",
+ t->start_line, t->expected_err, t->err);
+ return 0;
+}
+
+/* Setup a new test, run any existing test */
+
+static int setup_test(struct evp_test *t, const struct evp_test_method *tmeth)
+{
+ /* If we already have a test set up run it */
+ if (t->meth) {
+ t->ntests++;
+ t->err = NULL;
+ if (t->meth->run_test(t) != 1) {
+ fprintf(stderr, "%s test error line %d\n",
+ t->meth->name, t->start_line);
+ return 0;
+ }
+ if (!check_test_error(t)) {
+ if (t->err)
+ ERR_print_errors_fp(stderr);
+ t->errors++;
+ }
+ ERR_clear_error();
+ t->meth->cleanup(t);
+ /* If new test type free old data */
+ if (tmeth != t->meth && t->data) {
+ OPENSSL_free(t->data);
+ t->data = NULL;
+ }
+ if (t->expected_err) {
+ OPENSSL_free(t->expected_err);
+ t->expected_err = NULL;
+ }
+ }
+ t->meth = tmeth;
+ return 1;
+}
+
+static int process_test(struct evp_test *t, char *buf, int verbose)
+{
+ char *keyword, *value;
+ int rv = 0;
+ const struct evp_test_method *tmeth;
+ if (verbose)
+ fputs(buf, stdout);
+ if (!parse_line(&keyword, &value, buf))
+ return 1;
+ /* 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;
+ if (!tmeth->init(t, value)) {
+ fprintf(stderr, "Unknown %s: %s\n", keyword, value);
+ return 0;
+ }
+ return 1;
+ } else if (!strcmp(keyword, "Result")) {
+ if (t->expected_err) {
+ fprintf(stderr, "Line %d: multiple result lines\n", t->line);
+ return 0;
+ }
+ t->expected_err = BUF_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;
+ }