+static int test_contexts_digest_or_legacy_mac(const EVP_MD *type, int mac)
+{
+ int ret = 0, test = 0;
+ unsigned char K[32] = {1};
+
+ /* produce base digest */
+ EVP_MD_CTX *ctx, *save;
+ unsigned char pt[TEST_SIZE] = {1};
+ unsigned char b[EVP_MAX_MD_SIZE] = {0};
+ unsigned char c[EVP_MAX_MD_SIZE];
+ unsigned int outlen, tmplen;
+
+ /* Simply digest whole input. */
+ T(ctx = EVP_MD_CTX_new());
+ T(EVP_DigestInit_ex(ctx, type, NULL));
+ if (mac)
+ T(EVP_MD_CTX_ctrl(ctx, EVP_MD_CTRL_SET_KEY, sizeof(K), (void *)K));
+ T(EVP_DigestUpdate(ctx, pt, sizeof(pt)));
+ T(EVP_DigestFinal_ex(ctx, b, &tmplen));
+ save = ctx; /* will be not freed while cloning */
+
+ /* cloned digest */
+ EVP_MD_CTX_reset(ctx); /* test double reset */
+ EVP_MD_CTX_reset(ctx);
+ T(EVP_DigestInit_ex(ctx, type, NULL));
+ if (mac)
+ T(EVP_MD_CTX_ctrl(ctx, EVP_MD_CTRL_SET_KEY, sizeof(K), (void *)K));
+ printf(" cloned contexts: ");
+ memset(c, 0, sizeof(c));
+ int i;
+ for (i = 0; i < TEST_SIZE / STEP_SIZE; i++) {
+ /* Clone and continue digesting next part of input. */
+ EVP_MD_CTX *copy;
+ T(copy = EVP_MD_CTX_new());
+ T(EVP_MD_CTX_copy_ex(copy, ctx));
+
+ /* rolling */
+ if (save != ctx)
+ EVP_MD_CTX_free(ctx);
+ ctx = copy;
+
+ T(EVP_DigestUpdate(ctx, pt + STEP_SIZE * i, STEP_SIZE));
+ }
+ outlen = i * STEP_SIZE;
+ T(EVP_DigestFinal_ex(ctx, c, &tmplen));
+ /* Should be same as the simple digest. */
+ TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, EVP_MAX_MD_SIZE));
+ EVP_MD_CTX_free(ctx);
+ if (test) {
+ printf(" b[%d] = ", outlen);
+ hexdump(b, outlen);
+ printf(" c[%d] = ", outlen);
+ hexdump(c, outlen);
+ }
+ ret |= test;
+
+ /* Resume original context, what if it's damaged? */
+ printf(" base context: ");
+ memset(c, 0, sizeof(c));
+ T(EVP_DigestUpdate(save, pt, sizeof(pt)));
+ T(EVP_DigestFinal_ex(save, c, &tmplen));
+ TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, EVP_MAX_MD_SIZE));
+ EVP_MD_CTX_free(save);
+ if (test) {
+ printf(" b[%d] = ", outlen);
+ hexdump(b, outlen);
+ printf(" c[%d] = ", outlen);
+ hexdump(c, outlen);
+ }
+ ret |= test;
+
+ return ret;
+}
+
+static int test_contexts_digest(const char *name)
+{
+ EVP_MD *type;
+ ERR_set_mark();
+ T((type = (EVP_MD *)EVP_get_digestbyname(name))
+ || (type = EVP_MD_fetch(NULL, name, NULL)));
+ ERR_pop_to_mark();
+
+ printf(cBLUE "Digest test for %s" cNORM "\n", name);
+ int ret = test_contexts_digest_or_legacy_mac(type, 0);
+ EVP_MD_free(type);
+ return ret;
+}
+
+static int test_contexts_mac(const char *name)
+{
+ int ret = 0, test = 0;
+ unsigned char K[32] = {1};
+ const EVP_MD *type = EVP_get_digestbyname(name);
+ EVP_MAC *mac;
+
+ if (type) {
+ printf(cBLUE "Mac via EVP_MD test for %s" cNORM "\n", name);
+ return test_contexts_digest_or_legacy_mac(type, 1);
+ }
+
+ T(mac = EVP_MAC_fetch(NULL, name, NULL));
+ printf(cBLUE "Mac test for %s" cNORM "\n", name);
+
+ /* produce base mac */
+ EVP_MAC_CTX *ctx;
+ unsigned char pt[TEST_SIZE] = {1};
+ unsigned char b[EVP_MAX_MD_SIZE] = {0};
+ unsigned char c[EVP_MAX_MD_SIZE] = {0};
+ size_t outlen, tmplen;
+
+ /* Simply mac whole input. */
+ T(ctx = EVP_MAC_CTX_new(mac));
+ T(EVP_MAC_init(ctx, K, sizeof(K), NULL));
+ T(EVP_MAC_update(ctx, pt, sizeof(pt)));
+ T(EVP_MAC_final(ctx, b, &tmplen, sizeof(b)));
+ EVP_MAC_CTX_free(ctx);
+
+ /* Mac with rolling input. */
+ printf(" cloned contexts: ");
+ T(ctx = EVP_MAC_CTX_new(mac));
+ T(EVP_MAC_init(ctx, K, sizeof(K), NULL));
+ int i;
+ for (i = 0; i < TEST_SIZE / STEP_SIZE; i++) {
+ T(EVP_MAC_update(ctx, pt + STEP_SIZE * i, STEP_SIZE));
+ }
+ outlen = i * STEP_SIZE;
+ T(EVP_MAC_final(ctx, c, &tmplen, sizeof(c)));
+ EVP_MAC_CTX_free(ctx);
+ EVP_MAC_free(mac);
+
+ /* Rolling mac should give the same result as the simple mac. */
+ TEST_ASSERT(outlen != TEST_SIZE || memcmp(c, b, EVP_MAX_MD_SIZE));
+
+ if (test) {
+ printf(" b[%d] = ", (int)outlen);
+ hexdump(b, outlen);
+ printf(" c[%d] = ", (int)outlen);
+ hexdump(c, outlen);
+ }
+ ret |= test;
+
+ return ret;
+}
+
+static struct testcase_cipher {
+ const char *name;