Align EVP_PKEY Ed25519 API with upstream.

Rather than adding a new mode to EVP_PKEY_CTX, upstream chose to tie
single-shot signing to EVP_MD_CTX, adding functions which combine
EVP_Digest*Update and EVP_Digest*Final. This adds a weird vestigial
EVP_MD_CTX and makes the signing digest parameter non-uniform, slightly
complicating things. But it means APIs like X509_sign_ctx can work
without modification.

Align with upstream's APIs. This required a bit of fiddling around
evp_test.cc. For consistency and to avoid baking details of parameter
input order, I made it eagerly read all inputs before calling
SetupContext. Otherwise which attributes are present depend a lot on the
shape of the API we use---notably the NO_DEFAULT_DIGEST tests for RSA
switch to failing before consuming an input, which is odd.

(This only matters because we have some tests which expect the operation
to abort the operation early with parameter errors and match against
Error. Those probably should not use FileTest to begin with, but I'll
tease that apart a later time.)

Upstream also named NID_Ed25519 as NID_ED25519, even though the
algorithm is normally stylized as "Ed25519". Switch it to match.

Change-Id: Id6c8f5715930038e754de50338924d044e908045
Reviewed-on: https://boringssl-review.googlesource.com/17044
Commit-Queue: Steven Valdez <svaldez@google.com>
Reviewed-by: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/crypto/evp/digestsign.c b/crypto/evp/digestsign.c
index 299ca5e..de41f87 100644
--- a/crypto/evp/digestsign.c
+++ b/crypto/evp/digestsign.c
@@ -61,14 +61,24 @@
 #include "../fipsmodule/digest/internal.h"
 
 
+enum evp_sign_verify_t {
+  evp_sign,
+  evp_verify,
+};
+
 static const struct evp_md_pctx_ops md_pctx_ops = {
   EVP_PKEY_CTX_free,
   EVP_PKEY_CTX_dup,
 };
 
+static int uses_prehash(EVP_MD_CTX *ctx, enum evp_sign_verify_t op) {
+  return (op == evp_sign) ? (ctx->pctx->pmeth->sign != NULL)
+                          : (ctx->pctx->pmeth->verify != NULL);
+}
+
 static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
                           const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey,
-                          int is_verify) {
+                          enum evp_sign_verify_t op) {
   if (ctx->pctx == NULL) {
     ctx->pctx = EVP_PKEY_CTX_new(pkey, e);
   }
@@ -77,12 +87,7 @@
   }
   ctx->pctx_ops = &md_pctx_ops;
 
-  if (type == NULL) {
-    OPENSSL_PUT_ERROR(EVP, EVP_R_NO_DEFAULT_DIGEST);
-    return 0;
-  }
-
-  if (is_verify) {
+  if (op == evp_verify) {
     if (!EVP_PKEY_verify_init(ctx->pctx)) {
       return 0;
     }
@@ -91,38 +96,63 @@
       return 0;
     }
   }
-  if (!EVP_PKEY_CTX_set_signature_md(ctx->pctx, type)) {
+
+  if (type != NULL &&
+      !EVP_PKEY_CTX_set_signature_md(ctx->pctx, type)) {
     return 0;
   }
+
+  if (uses_prehash(ctx, op)) {
+    if (type == NULL) {
+      OPENSSL_PUT_ERROR(EVP, EVP_R_NO_DEFAULT_DIGEST);
+      return 0;
+    }
+    if (!EVP_DigestInit_ex(ctx, type, e)) {
+      return 0;
+    }
+  }
+
   if (pctx) {
     *pctx = ctx->pctx;
   }
-  if (!EVP_DigestInit_ex(ctx, type, e)) {
-    return 0;
-  }
   return 1;
 }
 
 int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type,
                        ENGINE *e, EVP_PKEY *pkey) {
-  return do_sigver_init(ctx, pctx, type, e, pkey, 0);
+  return do_sigver_init(ctx, pctx, type, e, pkey, evp_sign);
 }
 
 int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
                          const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey) {
-  return do_sigver_init(ctx, pctx, type, e, pkey, 1);
+  return do_sigver_init(ctx, pctx, type, e, pkey, evp_verify);
 }
 
 int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) {
+  if (!uses_prehash(ctx, evp_sign)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return 0;
+  }
+
   return EVP_DigestUpdate(ctx, data, len);
 }
 
 int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) {
+  if (!uses_prehash(ctx, evp_verify)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return 0;
+  }
+
   return EVP_DigestUpdate(ctx, data, len);
 }
 
 int EVP_DigestSignFinal(EVP_MD_CTX *ctx, uint8_t *out_sig,
                         size_t *out_sig_len) {
+  if (!uses_prehash(ctx, evp_sign)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return 0;
+  }
+
   if (out_sig) {
     EVP_MD_CTX tmp_ctx;
     int ret;
@@ -144,6 +174,11 @@
 
 int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig,
                           size_t sig_len) {
+  if (!uses_prehash(ctx, evp_verify)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return 0;
+  }
+
   EVP_MD_CTX tmp_ctx;
   int ret;
   uint8_t md[EVP_MAX_MD_SIZE];
@@ -157,3 +192,40 @@
 
   return ret;
 }
+
+int EVP_DigestSign(EVP_MD_CTX *ctx, uint8_t *out_sig, size_t *out_sig_len,
+                   const uint8_t *data, size_t data_len) {
+  if (uses_prehash(ctx, evp_sign)) {
+    /* If |out_sig| is NULL, the caller is only querying the maximum output
+     * length. |data| should only be incorporated in the final call. */
+    if (out_sig != NULL &&
+        !EVP_DigestSignUpdate(ctx, data, data_len)) {
+      return 0;
+    }
+
+    return EVP_DigestSignFinal(ctx, out_sig, out_sig_len);
+  }
+
+  if (ctx->pctx->pmeth->sign_message == NULL) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return 0;
+  }
+
+  return ctx->pctx->pmeth->sign_message(ctx->pctx, out_sig, out_sig_len, data,
+                                        data_len);
+}
+
+int EVP_DigestVerify(EVP_MD_CTX *ctx, const uint8_t *sig, size_t sig_len,
+                     const uint8_t *data, size_t len) {
+  if (uses_prehash(ctx, evp_verify)) {
+    return EVP_DigestVerifyUpdate(ctx, data, len) &&
+           EVP_DigestVerifyFinal(ctx, sig, sig_len);
+  }
+
+  if (ctx->pctx->pmeth->verify_message == NULL) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+    return 0;
+  }
+
+  return ctx->pctx->pmeth->verify_message(ctx->pctx, sig, sig_len, data, len);
+}
diff --git a/crypto/evp/evp_ctx.c b/crypto/evp/evp_ctx.c
index 3108cfb..8d092ee 100644
--- a/crypto/evp/evp_ctx.c
+++ b/crypto/evp/evp_ctx.c
@@ -236,50 +236,6 @@
   return ctx->pmeth->sign(ctx, sig, sig_len, digest, digest_len);
 }
 
-static const EVP_MD *get_signature_md(EVP_PKEY_CTX *ctx) {
-  const EVP_MD *md;
-  if (!EVP_PKEY_CTX_get_signature_md(ctx, &md)) {
-    return NULL;
-  }
-
-  if (md == NULL) {
-    OPENSSL_PUT_ERROR(EVP, EVP_R_NO_DEFAULT_DIGEST);
-    return NULL;
-  }
-
-  return md;
-}
-
-int EVP_PKEY_sign_message(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *sig_len,
-                          const uint8_t *data, size_t data_len) {
-  if (ctx == NULL || ctx->pmeth == NULL ||
-      (ctx->pmeth->sign == NULL && ctx->pmeth->sign_message == NULL)) {
-    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
-    return 0;
-  }
-  if (ctx->operation != EVP_PKEY_OP_SIGN) {
-    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
-    return 0;
-  }
-
-  if (ctx->pmeth->sign_message != NULL) {
-    return ctx->pmeth->sign_message(ctx, sig, sig_len, data, data_len);
-  }
-
-  /* Don't bother digesting if we are only sampling the length. */
-  if (sig == NULL) {
-    *sig_len = EVP_PKEY_size(EVP_PKEY_CTX_get0_pkey(ctx));
-    return 1;
-  }
-
-  uint8_t digest[EVP_MAX_MD_SIZE];
-  unsigned digest_len;
-  const EVP_MD *md = get_signature_md(ctx);
-  return md != NULL &&
-         EVP_Digest(data, data_len, digest, &digest_len, md, NULL) &&
-         EVP_PKEY_sign(ctx, sig, sig_len, digest, digest_len);
-}
-
 int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx) {
   if (ctx == NULL || ctx->pmeth == NULL ||
       (ctx->pmeth->verify == NULL && ctx->pmeth->verify_message == NULL)) {
@@ -303,31 +259,6 @@
   return ctx->pmeth->verify(ctx, sig, sig_len, digest, digest_len);
 }
 
-int EVP_PKEY_verify_message(EVP_PKEY_CTX *ctx, const uint8_t *sig,
-                            size_t sig_len, const uint8_t *data,
-                            size_t data_len) {
-  if (ctx == NULL || ctx->pmeth == NULL ||
-      (ctx->pmeth->verify == NULL && ctx->pmeth->verify_message == NULL)) {
-    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
-    return 0;
-  }
-  if (ctx->operation != EVP_PKEY_OP_VERIFY) {
-    OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED);
-    return 0;
-  }
-
-  if (ctx->pmeth->verify_message != NULL) {
-    return ctx->pmeth->verify_message(ctx, sig, sig_len, data, data_len);
-  }
-
-  uint8_t digest[EVP_MAX_MD_SIZE];
-  unsigned digest_len;
-  const EVP_MD *md = get_signature_md(ctx);
-  return md != NULL &&
-         EVP_Digest(data, data_len, digest, &digest_len, md, NULL) &&
-         EVP_PKEY_verify(ctx, sig, sig_len, digest, digest_len);
-}
-
 int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx) {
   if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
diff --git a/crypto/evp/evp_extra_test.cc b/crypto/evp/evp_extra_test.cc
index 73a5c89..2698663 100644
--- a/crypto/evp/evp_extra_test.cc
+++ b/crypto/evp/evp_extra_test.cc
@@ -621,4 +621,20 @@
   ASSERT_TRUE(pubkey2);
   EXPECT_FALSE(EVP_PKEY_cmp(pubkey.get(), pubkey2.get()));
   EXPECT_FALSE(EVP_PKEY_cmp(privkey.get(), pubkey2.get()));
+
+  // Ed25519 may not be used streaming.
+  bssl::ScopedEVP_MD_CTX ctx;
+  ASSERT_TRUE(
+      EVP_DigestSignInit(ctx.get(), nullptr, nullptr, nullptr, privkey.get()));
+  EXPECT_FALSE(EVP_DigestSignUpdate(ctx.get(), nullptr, 0));
+  size_t len;
+  EXPECT_FALSE(EVP_DigestSignFinal(ctx.get(), nullptr, &len));
+  ERR_clear_error();
+
+  ctx.Reset();
+  ASSERT_TRUE(EVP_DigestVerifyInit(ctx.get(), nullptr, nullptr, nullptr,
+                                   privkey.get()));
+  EXPECT_FALSE(EVP_DigestVerifyUpdate(ctx.get(), nullptr, 0));
+  EXPECT_FALSE(EVP_DigestVerifyFinal(ctx.get(), nullptr, 0));
+  ERR_clear_error();
 }
diff --git a/crypto/evp/evp_test.cc b/crypto/evp/evp_test.cc
index d06fa43..de72107 100644
--- a/crypto/evp/evp_test.cc
+++ b/crypto/evp/evp_test.cc
@@ -185,6 +185,30 @@
   return true;
 }
 
+// SetupContext configures |ctx| based on attributes in |t|, with the exception
+// of the signing digest which must be configured externally.
+static bool SetupContext(FileTest *t, EVP_PKEY_CTX *ctx) {
+  if (t->HasAttribute("RSAPadding")) {
+    int padding;
+    if (!GetRSAPadding(t, &padding, t->GetAttributeOrDie("RSAPadding")) ||
+        !EVP_PKEY_CTX_set_rsa_padding(ctx, padding)) {
+      return false;
+    }
+  }
+  if (t->HasAttribute("PSSSaltLength") &&
+      !EVP_PKEY_CTX_set_rsa_pss_saltlen(
+          ctx, atoi(t->GetAttributeOrDie("PSSSaltLength").c_str()))) {
+    return false;
+  }
+  if (t->HasAttribute("MGF1Digest")) {
+    const EVP_MD *digest = GetDigest(t, t->GetAttributeOrDie("MGF1Digest"));
+    if (digest == nullptr || !EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, digest)) {
+      return false;
+    }
+  }
+  return true;
+}
+
 static bool TestEVP(FileTest *t, KeyMap *key_map) {
   if (t->GetType() == "PrivateKey") {
     return ImportKey(t, key_map, EVP_parse_private_key,
@@ -195,26 +219,26 @@
     return ImportKey(t, key_map, EVP_parse_public_key, EVP_marshal_public_key);
   }
 
-  int (*key_op_init)(EVP_PKEY_CTX *ctx);
+  int (*key_op_init)(EVP_PKEY_CTX *ctx) = nullptr;
   int (*key_op)(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *out_len,
                 const uint8_t *in, size_t in_len) = nullptr;
-  int (*verify_op)(EVP_PKEY_CTX * ctx, const uint8_t *sig, size_t sig_len,
-                   const uint8_t *in, size_t in_len) = nullptr;
+  int (*md_op_init)(EVP_MD_CTX * ctx, EVP_PKEY_CTX * *pctx, const EVP_MD *type,
+                    ENGINE *e, EVP_PKEY *pkey) = nullptr;
+  bool is_verify = false;
   if (t->GetType() == "Decrypt") {
     key_op_init = EVP_PKEY_decrypt_init;
     key_op = EVP_PKEY_decrypt;
   } else if (t->GetType() == "Sign") {
     key_op_init = EVP_PKEY_sign_init;
     key_op = EVP_PKEY_sign;
-  } else if (t->GetType() == "SignMessage") {
-    key_op_init = EVP_PKEY_sign_init;
-    key_op = EVP_PKEY_sign_message;
   } else if (t->GetType() == "Verify") {
     key_op_init = EVP_PKEY_verify_init;
-    verify_op = EVP_PKEY_verify;
+    is_verify = true;
+  } else if (t->GetType() == "SignMessage") {
+    md_op_init = EVP_DigestSignInit;
   } else if (t->GetType() == "VerifyMessage") {
-    key_op_init = EVP_PKEY_verify_init;
-    verify_op = EVP_PKEY_verify_message;
+    md_op_init = EVP_DigestVerifyInit;
+    is_verify = true;
   } else {
     ADD_FAILURE() << "Unknown test " << t->GetType();
     return false;
@@ -228,67 +252,75 @@
   }
   EVP_PKEY *key = (*key_map)[key_name].get();
 
-  std::vector<uint8_t> input;
-  if (!t->GetBytes(&input, "Input")) {
-    return false;
-  }
-
-  // Set up the EVP_PKEY_CTX.
-  bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(key, nullptr));
-  if (!ctx || !key_op_init(ctx.get())) {
-    return false;
-  }
+  const EVP_MD *digest = nullptr;
   if (t->HasAttribute("Digest")) {
-    const EVP_MD *digest = GetDigest(t, t->GetAttributeOrDie("Digest"));
-    if (digest == nullptr ||
-        !EVP_PKEY_CTX_set_signature_md(ctx.get(), digest)) {
-      return false;
-    }
-  }
-  if (t->HasAttribute("RSAPadding")) {
-    int padding;
-    if (!GetRSAPadding(t, &padding, t->GetAttributeOrDie("RSAPadding")) ||
-        !EVP_PKEY_CTX_set_rsa_padding(ctx.get(), padding)) {
-      return false;
-    }
-  }
-  if (t->HasAttribute("PSSSaltLength") &&
-      !EVP_PKEY_CTX_set_rsa_pss_saltlen(
-          ctx.get(), atoi(t->GetAttributeOrDie("PSSSaltLength").c_str()))) {
-    return false;
-  }
-  if (t->HasAttribute("MGF1Digest")) {
-    const EVP_MD *digest = GetDigest(t, t->GetAttributeOrDie("MGF1Digest"));
-    if (digest == nullptr ||
-        !EVP_PKEY_CTX_set_rsa_mgf1_md(ctx.get(), digest)) {
+    digest = GetDigest(t, t->GetAttributeOrDie("Digest"));
+    if (digest == nullptr) {
       return false;
     }
   }
 
-  if (verify_op != nullptr) {
-    std::vector<uint8_t> output;
-    if (!t->GetBytes(&output, "Output") ||
-        !verify_op(ctx.get(), output.data(), output.size(), input.data(),
-                   input.size())) {
+  // For verify tests, the "output" is the signature. Read it now so that, for
+  // tests which expect a failure in SetupContext, the attribute is still
+  // consumed.
+  std::vector<uint8_t> input, actual, output;
+  if (!t->GetBytes(&input, "Input") ||
+      (is_verify && !t->GetBytes(&output, "Output"))) {
+    return false;
+  }
+
+  if (md_op_init) {
+    bssl::ScopedEVP_MD_CTX ctx;
+    EVP_PKEY_CTX *pctx;
+    if (!md_op_init(ctx.get(), &pctx, digest, nullptr, key) ||
+        !SetupContext(t, pctx)) {
       return false;
     }
+
+    if (is_verify) {
+      return !!EVP_DigestVerify(ctx.get(), output.data(), output.size(),
+                                input.data(), input.size());
+    }
+
+    size_t len;
+    if (!EVP_DigestSign(ctx.get(), nullptr, &len, input.data(), input.size())) {
+      return false;
+    }
+    actual.resize(len);
+    if (!EVP_DigestSign(ctx.get(), actual.data(), &len, input.data(),
+                        input.size()) ||
+        !t->GetBytes(&output, "Output")) {
+      return false;
+    }
+    actual.resize(len);
+    EXPECT_EQ(Bytes(output), Bytes(actual));
     return true;
   }
 
+  bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(key, nullptr));
+  if (!ctx ||
+      !key_op_init(ctx.get()) ||
+      (digest != nullptr &&
+       !EVP_PKEY_CTX_set_signature_md(ctx.get(), digest)) ||
+      !SetupContext(t, ctx.get())) {
+    return false;
+  }
+
+  if (is_verify) {
+    return !!EVP_PKEY_verify(ctx.get(), output.data(), output.size(),
+                             input.data(), input.size());
+  }
+
   size_t len;
-  std::vector<uint8_t> actual, output;
   if (!key_op(ctx.get(), nullptr, &len, input.data(), input.size())) {
     return false;
   }
   actual.resize(len);
-  if (!key_op(ctx.get(), actual.data(), &len, input.data(), input.size())) {
+  if (!key_op(ctx.get(), actual.data(), &len, input.data(), input.size()) ||
+      !t->GetBytes(&output, "Output")) {
     return false;
   }
   actual.resize(len);
-  if (!t->GetBytes(&output, "Output")) {
-    return false;
-  }
-
   EXPECT_EQ(Bytes(output), Bytes(actual));
   return true;
 }
@@ -301,8 +333,9 @@
       ASSERT_FALSE(result) << "Operation unexpectedly succeeded.";
       uint32_t err = ERR_peek_error();
       EXPECT_EQ(t->GetAttributeOrDie("Error"), ERR_reason_error_string(err));
-    } else {
-      ASSERT_TRUE(result) << "Operation unexpectedly failed.";
+    } else if (!result) {
+      ADD_FAILURE() << "Operation unexpectedly failed.";
+      ERR_print_errors_fp(stdout);
     }
   });
 }
diff --git a/crypto/obj/obj_dat.h b/crypto/obj/obj_dat.h
index 5f36d40..b3da0e8 100644
--- a/crypto/obj/obj_dat.h
+++ b/crypto/obj/obj_dat.h
@@ -56,6 +56,7 @@
 
 /* This file is generated by crypto/obj/objects.go. */
 
+
 #define NUM_NID 950
 
 static const uint8_t kObjectData[] = {
@@ -1811,7 +1812,7 @@
     0x2b, 0x81, 0x04, 0x01, 0x0e, 0x02,
     /* NID_dhSinglePass_cofactorDH_sha512kdf_scheme */
     0x2b, 0x81, 0x04, 0x01, 0x0e, 0x03,
-    /* NID_Ed25519 */
+    /* NID_ED25519 */
     0x2b, 0x65, 0x70,
 };
 
@@ -3442,7 +3443,7 @@
     {"dh-std-kdf", "dh-std-kdf", NID_dh_std_kdf, 0, NULL, 0},
     {"dh-cofactor-kdf", "dh-cofactor-kdf", NID_dh_cofactor_kdf, 0, NULL, 0},
     {"X25519", "X25519", NID_X25519, 0, NULL, 0},
-    {"Ed25519", "Ed25519", NID_Ed25519, 3, &kObjectData[6175], 0},
+    {"ED25519", "ED25519", NID_ED25519, 3, &kObjectData[6175], 0},
 };
 
 static const unsigned kNIDsInShortNameOrder[] = {
@@ -3531,7 +3532,7 @@
     70 /* DSA-SHA1-old */,
     67 /* DSA-old */,
     297 /* DVCS */,
-    949 /* Ed25519 */,
+    949 /* ED25519 */,
     99 /* GN */,
     855 /* HMAC */,
     780 /* HMAC-MD5 */,
@@ -4404,7 +4405,7 @@
     382 /* Directory */,
     392 /* Domain */,
     132 /* E-mail Protection */,
-    949 /* Ed25519 */,
+    949 /* ED25519 */,
     389 /* Enterprises */,
     384 /* Experimental */,
     372 /* Extended OCSP Status */,
@@ -5332,27 +5333,39 @@
 };
 
 static const unsigned kNIDsInOIDOrder[] = {
-    434 /* 0.9 (OBJ_data) */, 182 /* 1.2 (OBJ_member_body) */,
-    379 /* 1.3 (OBJ_org) */, 676 /* 1.3 (OBJ_identified_organization) */,
-    11 /* 2.5 (OBJ_X500) */, 647 /* 2.23 (OBJ_international_organizations) */,
-    380 /* 1.3.6 (OBJ_dod) */, 12 /* 2.5.4 (OBJ_X509) */,
-    378 /* 2.5.8 (OBJ_X500algorithms) */, 81 /* 2.5.29 (OBJ_id_ce) */,
-    512 /* 2.23.42 (OBJ_id_set) */, 678 /* 2.23.43 (OBJ_wap) */,
-    435 /* 0.9.2342 (OBJ_pss) */, 183 /* 1.2.840 (OBJ_ISO_US) */,
-    381 /* 1.3.6.1 (OBJ_iana) */, 949 /* 1.3.101.112 (OBJ_Ed25519) */,
+    434 /* 0.9 (OBJ_data) */,
+    182 /* 1.2 (OBJ_member_body) */,
+    379 /* 1.3 (OBJ_org) */,
+    676 /* 1.3 (OBJ_identified_organization) */,
+    11 /* 2.5 (OBJ_X500) */,
+    647 /* 2.23 (OBJ_international_organizations) */,
+    380 /* 1.3.6 (OBJ_dod) */,
+    12 /* 2.5.4 (OBJ_X509) */,
+    378 /* 2.5.8 (OBJ_X500algorithms) */,
+    81 /* 2.5.29 (OBJ_id_ce) */,
+    512 /* 2.23.42 (OBJ_id_set) */,
+    678 /* 2.23.43 (OBJ_wap) */,
+    435 /* 0.9.2342 (OBJ_pss) */,
+    183 /* 1.2.840 (OBJ_ISO_US) */,
+    381 /* 1.3.6.1 (OBJ_iana) */,
+    949 /* 1.3.101.112 (OBJ_ED25519) */,
     677 /* 1.3.132 (OBJ_certicom_arc) */,
     394 /* 2.5.1.5 (OBJ_selected_attribute_types) */,
-    13 /* 2.5.4.3 (OBJ_commonName) */, 100 /* 2.5.4.4 (OBJ_surname) */,
-    105 /* 2.5.4.5 (OBJ_serialNumber) */, 14 /* 2.5.4.6 (OBJ_countryName) */,
+    13 /* 2.5.4.3 (OBJ_commonName) */,
+    100 /* 2.5.4.4 (OBJ_surname) */,
+    105 /* 2.5.4.5 (OBJ_serialNumber) */,
+    14 /* 2.5.4.6 (OBJ_countryName) */,
     15 /* 2.5.4.7 (OBJ_localityName) */,
     16 /* 2.5.4.8 (OBJ_stateOrProvinceName) */,
     660 /* 2.5.4.9 (OBJ_streetAddress) */,
     17 /* 2.5.4.10 (OBJ_organizationName) */,
     18 /* 2.5.4.11 (OBJ_organizationalUnitName) */,
-    106 /* 2.5.4.12 (OBJ_title) */, 107 /* 2.5.4.13 (OBJ_description) */,
+    106 /* 2.5.4.12 (OBJ_title) */,
+    107 /* 2.5.4.13 (OBJ_description) */,
     859 /* 2.5.4.14 (OBJ_searchGuide) */,
     860 /* 2.5.4.15 (OBJ_businessCategory) */,
-    861 /* 2.5.4.16 (OBJ_postalAddress) */, 661 /* 2.5.4.17 (OBJ_postalCode) */,
+    861 /* 2.5.4.16 (OBJ_postalAddress) */,
+    661 /* 2.5.4.17 (OBJ_postalCode) */,
     862 /* 2.5.4.18 (OBJ_postOfficeBox) */,
     863 /* 2.5.4.19 (OBJ_physicalDeliveryOfficeName) */,
     864 /* 2.5.4.20 (OBJ_telephoneNumber) */,
@@ -5366,15 +5379,18 @@
     872 /* 2.5.4.28 (OBJ_preferredDeliveryMethod) */,
     873 /* 2.5.4.29 (OBJ_presentationAddress) */,
     874 /* 2.5.4.30 (OBJ_supportedApplicationContext) */,
-    875 /* 2.5.4.31 (OBJ_member) */, 876 /* 2.5.4.32 (OBJ_owner) */,
-    877 /* 2.5.4.33 (OBJ_roleOccupant) */, 878 /* 2.5.4.34 (OBJ_seeAlso) */,
+    875 /* 2.5.4.31 (OBJ_member) */,
+    876 /* 2.5.4.32 (OBJ_owner) */,
+    877 /* 2.5.4.33 (OBJ_roleOccupant) */,
+    878 /* 2.5.4.34 (OBJ_seeAlso) */,
     879 /* 2.5.4.35 (OBJ_userPassword) */,
     880 /* 2.5.4.36 (OBJ_userCertificate) */,
     881 /* 2.5.4.37 (OBJ_cACertificate) */,
     882 /* 2.5.4.38 (OBJ_authorityRevocationList) */,
     883 /* 2.5.4.39 (OBJ_certificateRevocationList) */,
     884 /* 2.5.4.40 (OBJ_crossCertificatePair) */,
-    173 /* 2.5.4.41 (OBJ_name) */, 99 /* 2.5.4.42 (OBJ_givenName) */,
+    173 /* 2.5.4.41 (OBJ_name) */,
+    99 /* 2.5.4.42 (OBJ_givenName) */,
     101 /* 2.5.4.43 (OBJ_initials) */,
     509 /* 2.5.4.44 (OBJ_generationQualifier) */,
     503 /* 2.5.4.45 (OBJ_x500UniqueIdentifier) */,
@@ -5386,7 +5402,8 @@
     889 /* 2.5.4.51 (OBJ_houseIdentifier) */,
     890 /* 2.5.4.52 (OBJ_supportedAlgorithms) */,
     891 /* 2.5.4.53 (OBJ_deltaRevocationList) */,
-    892 /* 2.5.4.54 (OBJ_dmdName) */, 510 /* 2.5.4.65 (OBJ_pseudonym) */,
+    892 /* 2.5.4.54 (OBJ_dmdName) */,
+    510 /* 2.5.4.65 (OBJ_pseudonym) */,
     400 /* 2.5.4.72 (OBJ_role) */,
     769 /* 2.5.29.9 (OBJ_subject_directory_attributes) */,
     82 /* 2.5.29.14 (OBJ_subject_key_identifier) */,
@@ -5395,7 +5412,8 @@
     85 /* 2.5.29.17 (OBJ_subject_alt_name) */,
     86 /* 2.5.29.18 (OBJ_issuer_alt_name) */,
     87 /* 2.5.29.19 (OBJ_basic_constraints) */,
-    88 /* 2.5.29.20 (OBJ_crl_number) */, 141 /* 2.5.29.21 (OBJ_crl_reason) */,
+    88 /* 2.5.29.20 (OBJ_crl_number) */,
+    141 /* 2.5.29.21 (OBJ_crl_reason) */,
     430 /* 2.5.29.23 (OBJ_hold_instruction_code) */,
     142 /* 2.5.29.24 (OBJ_invalidity_date) */,
     140 /* 2.5.29.27 (OBJ_delta_crl) */,
@@ -5411,16 +5429,26 @@
     857 /* 2.5.29.46 (OBJ_freshest_crl) */,
     748 /* 2.5.29.54 (OBJ_inhibit_any_policy) */,
     402 /* 2.5.29.55 (OBJ_target_information) */,
-    403 /* 2.5.29.56 (OBJ_no_rev_avail) */, 513 /* 2.23.42.0 (OBJ_set_ctype) */,
-    514 /* 2.23.42.1 (OBJ_set_msgExt) */, 515 /* 2.23.42.3 (OBJ_set_attr) */,
-    516 /* 2.23.42.5 (OBJ_set_policy) */, 517 /* 2.23.42.7 (OBJ_set_certExt) */,
-    518 /* 2.23.42.8 (OBJ_set_brand) */, 679 /* 2.23.43.1 (OBJ_wap_wsg) */,
-    382 /* 1.3.6.1.1 (OBJ_Directory) */, 383 /* 1.3.6.1.2 (OBJ_Management) */,
-    384 /* 1.3.6.1.3 (OBJ_Experimental) */, 385 /* 1.3.6.1.4 (OBJ_Private) */,
-    386 /* 1.3.6.1.5 (OBJ_Security) */, 387 /* 1.3.6.1.6 (OBJ_SNMPv2) */,
-    388 /* 1.3.6.1.7 (OBJ_Mail) */, 376 /* 1.3.14.3.2 (OBJ_algorithm) */,
-    395 /* 2.5.1.5.55 (OBJ_clearance) */, 19 /* 2.5.8.1.1 (OBJ_rsa) */,
-    96 /* 2.5.8.3.100 (OBJ_mdc2WithRSA) */, 95 /* 2.5.8.3.101 (OBJ_mdc2) */,
+    403 /* 2.5.29.56 (OBJ_no_rev_avail) */,
+    513 /* 2.23.42.0 (OBJ_set_ctype) */,
+    514 /* 2.23.42.1 (OBJ_set_msgExt) */,
+    515 /* 2.23.42.3 (OBJ_set_attr) */,
+    516 /* 2.23.42.5 (OBJ_set_policy) */,
+    517 /* 2.23.42.7 (OBJ_set_certExt) */,
+    518 /* 2.23.42.8 (OBJ_set_brand) */,
+    679 /* 2.23.43.1 (OBJ_wap_wsg) */,
+    382 /* 1.3.6.1.1 (OBJ_Directory) */,
+    383 /* 1.3.6.1.2 (OBJ_Management) */,
+    384 /* 1.3.6.1.3 (OBJ_Experimental) */,
+    385 /* 1.3.6.1.4 (OBJ_Private) */,
+    386 /* 1.3.6.1.5 (OBJ_Security) */,
+    387 /* 1.3.6.1.6 (OBJ_SNMPv2) */,
+    388 /* 1.3.6.1.7 (OBJ_Mail) */,
+    376 /* 1.3.14.3.2 (OBJ_algorithm) */,
+    395 /* 2.5.1.5.55 (OBJ_clearance) */,
+    19 /* 2.5.8.1.1 (OBJ_rsa) */,
+    96 /* 2.5.8.3.100 (OBJ_mdc2WithRSA) */,
+    95 /* 2.5.8.3.101 (OBJ_mdc2) */,
     746 /* 2.5.29.32.0 (OBJ_any_policy) */,
     910 /* 2.5.29.37.0 (OBJ_anyExtendedKeyUsage) */,
     519 /* 2.23.42.0.0 (OBJ_setct_PANData) */,
@@ -5535,22 +5563,27 @@
     638 /* 2.23.42.8.34 (OBJ_set_brand_AmericanExpress) */,
     639 /* 2.23.42.8.35 (OBJ_set_brand_JCB) */,
     805 /* 1.2.643.2.2 (OBJ_cryptopro) */,
-    806 /* 1.2.643.2.9 (OBJ_cryptocom) */, 184 /* 1.2.840.10040 (OBJ_X9_57) */,
+    806 /* 1.2.643.2.9 (OBJ_cryptocom) */,
+    184 /* 1.2.840.10040 (OBJ_X9_57) */,
     405 /* 1.2.840.10045 (OBJ_ansi_X9_62) */,
     389 /* 1.3.6.1.4.1 (OBJ_Enterprises) */,
     504 /* 1.3.6.1.7.1 (OBJ_mime_mhs) */,
     104 /* 1.3.14.3.2.3 (OBJ_md5WithRSA) */,
-    29 /* 1.3.14.3.2.6 (OBJ_des_ecb) */, 31 /* 1.3.14.3.2.7 (OBJ_des_cbc) */,
+    29 /* 1.3.14.3.2.6 (OBJ_des_ecb) */,
+    31 /* 1.3.14.3.2.7 (OBJ_des_cbc) */,
     45 /* 1.3.14.3.2.8 (OBJ_des_ofb64) */,
     30 /* 1.3.14.3.2.9 (OBJ_des_cfb64) */,
     377 /* 1.3.14.3.2.11 (OBJ_rsaSignature) */,
-    67 /* 1.3.14.3.2.12 (OBJ_dsa_2) */, 66 /* 1.3.14.3.2.13 (OBJ_dsaWithSHA) */,
+    67 /* 1.3.14.3.2.12 (OBJ_dsa_2) */,
+    66 /* 1.3.14.3.2.13 (OBJ_dsaWithSHA) */,
     42 /* 1.3.14.3.2.15 (OBJ_shaWithRSAEncryption) */,
-    32 /* 1.3.14.3.2.17 (OBJ_des_ede_ecb) */, 41 /* 1.3.14.3.2.18 (OBJ_sha) */,
+    32 /* 1.3.14.3.2.17 (OBJ_des_ede_ecb) */,
+    41 /* 1.3.14.3.2.18 (OBJ_sha) */,
     64 /* 1.3.14.3.2.26 (OBJ_sha1) */,
     70 /* 1.3.14.3.2.27 (OBJ_dsaWithSHA1_2) */,
     115 /* 1.3.14.3.2.29 (OBJ_sha1WithRSA) */,
-    117 /* 1.3.36.3.2.1 (OBJ_ripemd160) */, 143 /* 1.3.101.1.4.1 (OBJ_sxnet) */,
+    117 /* 1.3.36.3.2.1 (OBJ_ripemd160) */,
+    143 /* 1.3.101.1.4.1 (OBJ_sxnet) */,
     721 /* 1.3.132.0.1 (OBJ_sect163k1) */,
     722 /* 1.3.132.0.2 (OBJ_sect163r1) */,
     728 /* 1.3.132.0.3 (OBJ_sect239k1) */,
@@ -5614,7 +5647,8 @@
     816 /* 1.2.643.2.2.23 (OBJ_id_GostR3411_94_prf) */,
     817 /* 1.2.643.2.2.98 (OBJ_id_GostR3410_2001DH) */,
     818 /* 1.2.643.2.2.99 (OBJ_id_GostR3410_94DH) */,
-    1 /* 1.2.840.113549 (OBJ_rsadsi) */, 185 /* 1.2.840.10040.4 (OBJ_X9cm) */,
+    1 /* 1.2.840.113549 (OBJ_rsadsi) */,
+    185 /* 1.2.840.10040.4 (OBJ_X9cm) */,
     127 /* 1.3.6.1.5.5.7 (OBJ_id_pkix) */,
     505 /* 1.3.6.1.7.1.1 (OBJ_mime_mhs_headings) */,
     506 /* 1.3.6.1.7.1.2 (OBJ_mime_mhs_bodies) */,
diff --git a/crypto/obj/obj_mac.num b/crypto/obj/obj_mac.num
index 2f2a557..572a01b 100644
--- a/crypto/obj/obj_mac.num
+++ b/crypto/obj/obj_mac.num
@@ -937,4 +937,4 @@
 dh_std_kdf		946
 dh_cofactor_kdf		947
 X25519		948
-Ed25519		949
+ED25519		949
diff --git a/crypto/obj/obj_xref.c b/crypto/obj/obj_xref.c
index 1baed0e..6136e99 100644
--- a/crypto/obj/obj_xref.c
+++ b/crypto/obj/obj_xref.c
@@ -88,7 +88,7 @@
     /* The following algorithms use more complex (or simpler) parameters. The
      * digest "undef" indicates the caller should handle this explicitly. */
     {NID_rsassaPss, NID_undef, NID_rsaEncryption},
-    {NID_Ed25519, NID_undef, NID_Ed25519},
+    {NID_ED25519, NID_undef, NID_ED25519},
 };
 
 int OBJ_find_sigid_algs(int sign_nid, int *out_digest_nid, int *out_pkey_nid) {
diff --git a/crypto/obj/objects.txt b/crypto/obj/objects.txt
index 22f24e4..03056de 100644
--- a/crypto/obj/objects.txt
+++ b/crypto/obj/objects.txt
@@ -1335,4 +1335,4 @@
  : X25519
 
 # See draft-ietf-curdle-pkix-04.
-1 3 101 112 : Ed25519
+1 3 101 112 : ED25519
diff --git a/crypto/x509/a_sign.c b/crypto/x509/a_sign.c
index 13a3ac2..b3ea1de 100644
--- a/crypto/x509/a_sign.c
+++ b/crypto/x509/a_sign.c
@@ -104,8 +104,7 @@
         goto err;
     }
 
-    if (!EVP_DigestSignUpdate(ctx, buf_in, inl)
-        || !EVP_DigestSignFinal(ctx, buf_out, &outl)) {
+    if (!EVP_DigestSign(ctx, buf_out, &outl, buf_in, inl)) {
         outl = 0;
         OPENSSL_PUT_ERROR(X509, ERR_R_EVP_LIB);
         goto err;
diff --git a/crypto/x509/a_verify.c b/crypto/x509/a_verify.c
index 400cdd1..d203fba 100644
--- a/crypto/x509/a_verify.c
+++ b/crypto/x509/a_verify.c
@@ -73,6 +73,7 @@
 int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a,
                      ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey)
 {
+    EVP_MD_CTX ctx;
     uint8_t *buf_in = NULL;
     int ret = 0, inl = 0;
 
@@ -86,9 +87,9 @@
         return 0;
     }
 
-    EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
-    if (ctx == NULL ||
-        !x509_digest_verify_init(ctx, a)) {
+    EVP_MD_CTX_init(&ctx);
+
+    if (!x509_digest_verify_init(&ctx, a, pkey)) {
         goto err;
     }
 
@@ -99,19 +100,19 @@
         goto err;
     }
 
-    if (!EVP_PKEY_verify_message(ctx, signature->data,
-                                 (size_t)signature->length, buf_in, inl)) {
+    if (!EVP_DigestVerify(&ctx, signature->data, (size_t)signature->length,
+                          buf_in, inl)) {
         OPENSSL_PUT_ERROR(X509, ERR_R_EVP_LIB);
         goto err;
     }
 
     ret = 1;
 
- err:
+err:
     if (buf_in != NULL) {
-        OPENSSL_cleanse(buf_in, (unsigned int)inl);
+        OPENSSL_cleanse(buf_in, inl);
         OPENSSL_free(buf_in);
     }
-    EVP_PKEY_CTX_free(ctx);
+    EVP_MD_CTX_cleanup(&ctx);
     return ret;
 }
diff --git a/crypto/x509/algorithm.c b/crypto/x509/algorithm.c
index 6e0f3f2..8f53fff 100644
--- a/crypto/x509/algorithm.c
+++ b/crypto/x509/algorithm.c
@@ -66,9 +66,8 @@
 
 
 int x509_digest_sign_algorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor) {
-  const EVP_MD *digest = EVP_MD_CTX_md(ctx);
   EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx);
-  if (digest == NULL || pkey == NULL) {
+  if (pkey == NULL) {
     OPENSSL_PUT_ERROR(ASN1, ASN1_R_CONTEXT_NOT_INITIALISED);
     return 0;
   }
@@ -84,8 +83,18 @@
     }
   }
 
+  if (EVP_PKEY_id(pkey) == EVP_PKEY_ED25519) {
+    return X509_ALGOR_set0(algor, OBJ_nid2obj(NID_ED25519), V_ASN1_UNDEF, NULL);
+  }
+
   /* Default behavior: look up the OID for the algorithm/hash pair and encode
    * that. */
+  const EVP_MD *digest = EVP_MD_CTX_md(ctx);
+  if (digest == NULL) {
+    OPENSSL_PUT_ERROR(ASN1, ASN1_R_CONTEXT_NOT_INITIALISED);
+    return 0;
+  }
+
   int sign_nid;
   if (!OBJ_find_sigid_by_algs(&sign_nid, EVP_MD_type(digest),
                               EVP_PKEY_id(pkey))) {
@@ -101,11 +110,8 @@
   return 1;
 }
 
-int x509_digest_verify_init(EVP_PKEY_CTX *ctx, X509_ALGOR *sigalg) {
-  if (!EVP_PKEY_verify_init(ctx)) {
-    return 0;
-  }
-
+int x509_digest_verify_init(EVP_MD_CTX *ctx, X509_ALGOR *sigalg,
+                            EVP_PKEY *pkey) {
   /* Convert the signature OID into digest and public key OIDs. */
   int sigalg_nid = OBJ_obj2nid(sigalg->algorithm);
   int digest_nid, pkey_nid;
@@ -115,7 +121,6 @@
   }
 
   /* Check the public key OID matches the public key type. */
-  EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
   if (pkey_nid != EVP_PKEY_id(pkey)) {
     OPENSSL_PUT_ERROR(ASN1, ASN1_R_WRONG_PUBLIC_KEY_TYPE);
     return 0;
@@ -124,14 +129,14 @@
   /* NID_undef signals that there are custom parameters to set. */
   if (digest_nid == NID_undef) {
     if (sigalg_nid == NID_rsassaPss) {
-      return x509_rsa_pss_to_ctx(ctx, sigalg);
+      return x509_rsa_pss_to_ctx(ctx, sigalg, pkey);
     }
-    if (sigalg_nid == NID_Ed25519) {
+    if (sigalg_nid == NID_ED25519) {
       if (sigalg->parameter != NULL) {
         OPENSSL_PUT_ERROR(X509, X509_R_INVALID_PARAMETER);
         return 0;
       }
-      return 1; /* Nothing to configure. */
+      return EVP_DigestVerifyInit(ctx, NULL, NULL, NULL, pkey);
     }
     OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
     return 0;
@@ -144,5 +149,5 @@
     return 0;
   }
 
-  return EVP_PKEY_CTX_set_signature_md(ctx, digest);
+  return EVP_DigestVerifyInit(ctx, NULL, digest, NULL, pkey);
 }
diff --git a/crypto/x509/internal.h b/crypto/x509/internal.h
index f7101af..4957c1e 100644
--- a/crypto/x509/internal.h
+++ b/crypto/x509/internal.h
@@ -28,8 +28,9 @@
 
 /* x509_rsa_pss_to_ctx configures |ctx| for an RSA-PSS operation based on
  * signature algorithm parameters in |sigalg| (which must have type
- * |NID_rsassaPss|). It returns one on success and zero on error. */
-int x509_rsa_pss_to_ctx(EVP_PKEY_CTX *ctx, X509_ALGOR *sigalg);
+ * |NID_rsassaPss|) and key |pkey|. It returns one on success and zero on
+ * error. */
+int x509_rsa_pss_to_ctx(EVP_MD_CTX *ctx, X509_ALGOR *sigalg, EVP_PKEY *pkey);
 
 /* x509_rsa_pss_to_ctx sets |algor| to the signature algorithm parameters for
  * |ctx|, which must have been configured for an RSA-PSS signing operation. It
@@ -51,9 +52,11 @@
 int x509_digest_sign_algorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor);
 
 /* x509_digest_verify_init sets up |ctx| for a signature verification operation
- * with parameters from |algor|. The |ctx| argument must have been constructed
- * with the public key. It returns one on success, or zero on error. */
-int x509_digest_verify_init(EVP_PKEY_CTX *ctx, X509_ALGOR *sigalg);
+ * with public key |pkey| and parameters from |algor|. The |ctx| argument must
+ * have been initialised with |EVP_MD_CTX_init|. It returns one on success, or
+ * zero on error. */
+int x509_digest_verify_init(EVP_MD_CTX *ctx, X509_ALGOR *sigalg,
+                            EVP_PKEY *pkey);
 
 
 #if defined(__cplusplus)
diff --git a/crypto/x509/rsa_pss.c b/crypto/x509/rsa_pss.c
index 9c286c6..9230934 100644
--- a/crypto/x509/rsa_pss.c
+++ b/crypto/x509/rsa_pss.c
@@ -242,7 +242,7 @@
   return ret;
 }
 
-int x509_rsa_pss_to_ctx(EVP_PKEY_CTX *ctx, X509_ALGOR *sigalg) {
+int x509_rsa_pss_to_ctx(EVP_MD_CTX *ctx, X509_ALGOR *sigalg, EVP_PKEY *pkey) {
   assert(OBJ_obj2nid(sigalg->algorithm) == NID_rsassaPss);
 
   /* Decode PSS parameters */
@@ -279,10 +279,11 @@
     goto err;
   }
 
-  if (!EVP_PKEY_CTX_set_signature_md(ctx, md) ||
-      !EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) ||
-      !EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, saltlen) ||
-      !EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, mgf1md)) {
+  EVP_PKEY_CTX *pctx;
+  if (!EVP_DigestVerifyInit(ctx, &pctx, md, NULL, pkey) ||
+      !EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) ||
+      !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, saltlen) ||
+      !EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1md)) {
     goto err;
   }
 
diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc
index 3832fdd..1b34578 100644
--- a/crypto/x509/x509_test.cc
+++ b/crypto/x509/x509_test.cc
@@ -19,6 +19,7 @@
 
 #include <openssl/bio.h>
 #include <openssl/bytestring.h>
+#include <openssl/curve25519.h>
 #include <openssl/crypto.h>
 #include <openssl/digest.h>
 #include <openssl/err.h>
@@ -714,7 +715,7 @@
   return !!X509_verify(cert.get(), pkey);
 }
 
-TEST(X509Test, TestSignCtx) {
+TEST(X509Test, RSASign) {
   bssl::UniquePtr<EVP_PKEY> pkey(PrivateKeyFromPEM(kRSAKey));
   ASSERT_TRUE(pkey);
   // Test PKCS#1 v1.5.
@@ -733,6 +734,21 @@
   ASSERT_TRUE(SignatureRoundTrips(md_ctx.get(), pkey.get()));
 }
 
+TEST(X509Test, Ed25519Sign) {
+  uint8_t pub_bytes[32], priv_bytes[64];
+  ED25519_keypair(pub_bytes, priv_bytes);
+
+  bssl::UniquePtr<EVP_PKEY> pub(EVP_PKEY_new_ed25519_public(pub_bytes));
+  ASSERT_TRUE(pub);
+  bssl::UniquePtr<EVP_PKEY> priv(EVP_PKEY_new_ed25519_private(priv_bytes));
+  ASSERT_TRUE(priv);
+
+  bssl::ScopedEVP_MD_CTX md_ctx;
+  ASSERT_TRUE(
+      EVP_DigestSignInit(md_ctx.get(), nullptr, nullptr, nullptr, priv.get()));
+  ASSERT_TRUE(SignatureRoundTrips(md_ctx.get(), pub.get()));
+}
+
 static bool PEMToDER(bssl::UniquePtr<uint8_t> *out, size_t *out_len,
                      const char *pem) {
   bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem, strlen(pem)));
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index 4527109..f3e96b1 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -171,7 +171,7 @@
 #define EVP_PKEY_RSA NID_rsaEncryption
 #define EVP_PKEY_DSA NID_dsa
 #define EVP_PKEY_EC NID_X9_62_id_ecPublicKey
-#define EVP_PKEY_ED25519 NID_Ed25519
+#define EVP_PKEY_ED25519 NID_ED25519
 
 /* EVP_PKEY_assign sets the underlying key of |pkey| to |key|, which must be of
  * the given type. The |type| argument should be one of the |EVP_PKEY_*|
@@ -238,9 +238,9 @@
  * operation will be written to |*pctx|; this can be used to set alternative
  * signing options.
  *
- * This function performs a streaming signing operation and will fail for
- * signature algorithms which do not support this. Use |EVP_PKEY_sign_message|
- * for a single-shot operation.
+ * For single-shot signing algorithms which do not use a pre-hash, such as
+ * Ed25519, |type| should be NULL. The |EVP_MD_CTX| itself is unused but is
+ * present so the API is uniform. See |EVP_DigestSign|.
  *
  * It returns one on success, or zero on error. */
 OPENSSL_EXPORT int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
@@ -248,7 +248,11 @@
                                       EVP_PKEY *pkey);
 
 /* EVP_DigestSignUpdate appends |len| bytes from |data| to the data which will
- * be signed in |EVP_DigestSignFinal|. It returns one. */
+ * be signed in |EVP_DigestSignFinal|. It returns one.
+ *
+ * This function performs a streaming signing operation and will fail for
+ * signature algorithms which do not support this. Use |EVP_DigestSign| for a
+ * single-shot operation. */
 OPENSSL_EXPORT int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *data,
                                         size_t len);
 
@@ -259,10 +263,25 @@
  * is successful, the signature is written to |out_sig| and |*out_sig_len| is
  * set to its length.
  *
+ * This function performs a streaming signing operation and will fail for
+ * signature algorithms which do not support this. Use |EVP_DigestSign| for a
+ * single-shot operation.
+ *
  * It returns one on success, or zero on error. */
 OPENSSL_EXPORT int EVP_DigestSignFinal(EVP_MD_CTX *ctx, uint8_t *out_sig,
                                        size_t *out_sig_len);
 
+/* EVP_DigestSign signs |data_len| bytes from |data| using |ctx|. If |out_sig|
+ * is NULL then |*out_sig_len| is set to the maximum number of output
+ * bytes. Otherwise, on entry, |*out_sig_len| must contain the length of the
+ * |out_sig| buffer. If the call is successful, the signature is written to
+ * |out_sig| and |*out_sig_len| is set to its length.
+ *
+ * It returns one on success and zero on error. */
+OPENSSL_EXPORT int EVP_DigestSign(EVP_MD_CTX *ctx, uint8_t *out_sig,
+                                  size_t *out_sig_len, const uint8_t *data,
+                                  size_t data_len);
+
 
 /* Verifying */
 
@@ -272,9 +291,9 @@
  * operation will be written to |*pctx|; this can be used to set alternative
  * signing options.
  *
- * This function performs streaming signature verification and will fail for
- * signature algorithms which do not support this. Use |EVP_PKEY_verify_message|
- * for a single-shot verification.
+ * For single-shot signing algorithms which do not use a pre-hash, such as
+ * Ed25519, |type| should be NULL. The |EVP_MD_CTX| itself is unused but is
+ * present so the API is uniform. See |EVP_DigestVerify|.
  *
  * It returns one on success, or zero on error. */
 OPENSSL_EXPORT int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
@@ -282,16 +301,30 @@
                                         EVP_PKEY *pkey);
 
 /* EVP_DigestVerifyUpdate appends |len| bytes from |data| to the data which
- * will be verified by |EVP_DigestVerifyFinal|. It returns one. */
+ * will be verified by |EVP_DigestVerifyFinal|. It returns one.
+ *
+ * This function performs streaming signature verification and will fail for
+ * signature algorithms which do not support this. Use |EVP_PKEY_verify_message|
+ * for a single-shot verification. */
 OPENSSL_EXPORT int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data,
                                           size_t len);
 
 /* EVP_DigestVerifyFinal verifies that |sig_len| bytes of |sig| are a valid
  * signature for the data that has been included by one or more calls to
- * |EVP_DigestVerifyUpdate|. It returns one on success and zero otherwise. */
+ * |EVP_DigestVerifyUpdate|. It returns one on success and zero otherwise.
+ *
+ * This function performs streaming signature verification and will fail for
+ * signature algorithms which do not support this. Use |EVP_PKEY_verify_message|
+ * for a single-shot verification. */
 OPENSSL_EXPORT int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig,
                                          size_t sig_len);
 
+/* EVP_DigestVerify verifies that |sig_len| bytes from |sig| are a valid
+ * signature for |data|. It returns one on success or zero on error. */
+OPENSSL_EXPORT int EVP_DigestVerify(EVP_MD_CTX *ctx, const uint8_t *sig,
+                                    size_t sig_len, const uint8_t *data,
+                                    size_t len);
+
 
 /* Signing (old functions) */
 
@@ -439,8 +472,8 @@
  * |sig| and |*sig_len| updated with the true length.
  *
  * This function expects a pre-hashed input and will fail for signature
- * algorithms which do not support this. Use |EVP_PKEY_sign_message| or
- * |EVP_DigestSignInit| to sign an unhashed input.
+ * algorithms which do not support this. Use |EVP_DigestSignInit| to sign an
+ * unhashed input.
  *
  * WARNING: Setting |sig| to NULL only gives the maximum size of the
  * signature. The actual signature may be smaller.
@@ -451,21 +484,6 @@
                                  size_t *sig_len, const uint8_t *digest,
                                  size_t digest_len);
 
-/* EVP_PKEY_sign_message signs |data_len| bytes from |data| using |ctx|. If
- * |sig| is NULL, the maximum size of the signature is written to |out_sig_len|.
- * Otherwise, |*sig_len| must contain the number of bytes of space available at
- * |sig|. If sufficient, the signature will be written to |sig| and |*sig_len|
- * updated with the true length.
- *
- * WARNING: Setting |sig| to NULL only gives the maximum size of the
- * signature. The actual signature may be smaller.
- *
- * It returns one on success or zero on error. (Note: this differs from
- * OpenSSL, which can also return negative values to indicate an error. ) */
-OPENSSL_EXPORT int EVP_PKEY_sign_message(EVP_PKEY_CTX *ctx, uint8_t *sig,
-                                         size_t *sig_len, const uint8_t *data,
-                                         size_t data_len);
-
 /* EVP_PKEY_verify_init initialises an |EVP_PKEY_CTX| for a signature
  * verification operation. It should be called before |EVP_PKEY_verify|.
  *
@@ -476,21 +494,14 @@
  * signature for |digest|.
  *
  * This function expects a pre-hashed input and will fail for signature
- * algorithms which do not support this. Use |EVP_PKEY_verify_message| or
- * |EVP_DigestVerifyInit| to verify a signature given the unhashed input.
+ * algorithms which do not support this. Use |EVP_DigestVerifyInit| to verify a
+ * signature given the unhashed input.
  *
  * It returns one on success or zero on error. */
 OPENSSL_EXPORT int EVP_PKEY_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig,
                                    size_t sig_len, const uint8_t *digest,
                                    size_t digest_len);
 
-/* EVP_PKEY_verify_message verifies that |sig_len| bytes from |sig| are a valid
- * signature for |data|. It returns one on success or zero on error. */
-OPENSSL_EXPORT int EVP_PKEY_verify_message(EVP_PKEY_CTX *ctx,
-                                           const uint8_t *sig, size_t sig_len,
-                                           const uint8_t *data,
-                                           size_t data_len);
-
 /* EVP_PKEY_encrypt_init initialises an |EVP_PKEY_CTX| for an encryption
  * operation. It should be called before |EVP_PKEY_encrypt|.
  *
diff --git a/include/openssl/nid.h b/include/openssl/nid.h
index f023c1f..bc0ee33 100644
--- a/include/openssl/nid.h
+++ b/include/openssl/nid.h
@@ -65,6 +65,7 @@
 extern "C" {
 #endif
 
+
 /* The nid library provides numbered values for ASN.1 object identifiers and
  * other symbols. These values are used by other libraries to identify
  * cryptographic primitives.
@@ -78,6 +79,7 @@
  * These values should not be used outside of a single process; they are not
  * stable identifiers. */
 
+
 #define SN_undef "UNDEF"
 #define LN_undef "undefined"
 #define NID_undef 0
@@ -4192,9 +4194,9 @@
 #define SN_X25519 "X25519"
 #define NID_X25519 948
 
-#define SN_Ed25519 "Ed25519"
-#define NID_Ed25519 949
-#define OBJ_Ed25519 1L, 3L, 101L, 112L
+#define SN_ED25519 "ED25519"
+#define NID_ED25519 949
+#define OBJ_ED25519 1L, 3L, 101L, 112L
 
 
 #if defined(__cplusplus)
diff --git a/ssl/ssl_privkey.c b/ssl/ssl_privkey.c
index f429c1d..8492748 100644
--- a/ssl/ssl_privkey.c
+++ b/ssl/ssl_privkey.c
@@ -373,21 +373,27 @@
   return 1;
 }
 
-static int setup_ctx(SSL *ssl, EVP_PKEY_CTX *ctx, uint16_t sigalg) {
-  if (!pkey_supports_algorithm(ssl, EVP_PKEY_CTX_get0_pkey(ctx), sigalg)) {
+static int setup_ctx(SSL *ssl, EVP_MD_CTX *ctx, EVP_PKEY *pkey, uint16_t sigalg,
+                     int is_verify) {
+  if (!pkey_supports_algorithm(ssl, pkey, sigalg)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_SIGNATURE_TYPE);
     return 0;
   }
 
   const SSL_SIGNATURE_ALGORITHM *alg = get_signature_algorithm(sigalg);
-  if (alg->digest_func != NULL &&
-      !EVP_PKEY_CTX_set_signature_md(ctx, alg->digest_func())) {
+  const EVP_MD *digest = alg->digest_func != NULL ? alg->digest_func() : NULL;
+  EVP_PKEY_CTX *pctx;
+  if (is_verify) {
+    if (!EVP_DigestVerifyInit(ctx, &pctx, digest, NULL, pkey)) {
+      return 0;
+    }
+  } else if (!EVP_DigestSignInit(ctx, &pctx, digest, NULL, pkey)) {
     return 0;
   }
 
   if (alg->is_rsa_pss) {
-    if (!EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) ||
-        !EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, -1 /* salt len = hash len */)) {
+    if (!EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) ||
+        !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1 /* salt len = hash len */)) {
       return 0;
     }
   }
@@ -430,24 +436,22 @@
   }
 
   *out_len = max_out;
-  EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(ssl->cert->privatekey, NULL);
-  int ret = ctx != NULL &&
-            EVP_PKEY_sign_init(ctx) &&
-            setup_ctx(ssl, ctx, sigalg) &&
-            EVP_PKEY_sign_message(ctx, out, out_len, in, in_len);
-  EVP_PKEY_CTX_free(ctx);
+  EVP_MD_CTX ctx;
+  EVP_MD_CTX_init(&ctx);
+  int ret = setup_ctx(ssl, &ctx, ssl->cert->privatekey, sigalg, 0 /* sign */) &&
+            EVP_DigestSign(&ctx, out, out_len, in, in_len);
+  EVP_MD_CTX_cleanup(&ctx);
   return ret ? ssl_private_key_success : ssl_private_key_failure;
 }
 
 int ssl_public_key_verify(SSL *ssl, const uint8_t *signature,
-                          size_t signature_len, uint16_t signature_algorithm,
-                          EVP_PKEY *pkey, const uint8_t *in, size_t in_len) {
-  EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
-  int ret = ctx != NULL &&
-            EVP_PKEY_verify_init(ctx) &&
-            setup_ctx(ssl, ctx, signature_algorithm) &&
-            EVP_PKEY_verify_message(ctx, signature, signature_len, in, in_len);
-  EVP_PKEY_CTX_free(ctx);
+                          size_t signature_len, uint16_t sigalg, EVP_PKEY *pkey,
+                          const uint8_t *in, size_t in_len) {
+  EVP_MD_CTX ctx;
+  EVP_MD_CTX_init(&ctx);
+  int ret = setup_ctx(ssl, &ctx, pkey, sigalg, 1 /* verify */) &&
+            EVP_DigestVerify(&ctx, signature, signature_len, in, in_len);
+  EVP_MD_CTX_cleanup(&ctx);
   return ret;
 }
 
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc
index 3b08a98..f9b6553 100644
--- a/ssl/test/bssl_shim.cc
+++ b/ssl/test/bssl_shim.cc
@@ -295,13 +295,6 @@
     abort();
   }
 
-  bssl::UniquePtr<EVP_PKEY_CTX> ctx(
-      EVP_PKEY_CTX_new(test_state->private_key.get(), nullptr));
-  if (!ctx ||
-      !EVP_PKEY_sign_init(ctx.get())) {
-    return ssl_private_key_failure;
-  }
-
   // Determine the hash.
   const EVP_MD *md;
   switch (signature_algorithm) {
@@ -336,8 +329,10 @@
       return ssl_private_key_failure;
   }
 
-  if (md != nullptr &&
-      !EVP_PKEY_CTX_set_signature_md(ctx.get(), md)) {
+  bssl::ScopedEVP_MD_CTX ctx;
+  EVP_PKEY_CTX *pctx;
+  if (!EVP_DigestSignInit(ctx.get(), &pctx, md, nullptr,
+                          test_state->private_key.get())) {
     return ssl_private_key_failure;
   }
 
@@ -346,8 +341,8 @@
     case SSL_SIGN_RSA_PSS_SHA256:
     case SSL_SIGN_RSA_PSS_SHA384:
     case SSL_SIGN_RSA_PSS_SHA512:
-      if (!EVP_PKEY_CTX_set_rsa_padding(ctx.get(), RSA_PKCS1_PSS_PADDING) ||
-          !EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx.get(),
+      if (!EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) ||
+          !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx,
                                             -1 /* salt len = hash len */)) {
         return ssl_private_key_failure;
       }
@@ -355,12 +350,12 @@
 
   // Write the signature into |test_state|.
   size_t len = 0;
-  if (!EVP_PKEY_sign_message(ctx.get(), nullptr, &len, in, in_len)) {
+  if (!EVP_DigestSign(ctx.get(), nullptr, &len, in, in_len)) {
     return ssl_private_key_failure;
   }
   test_state->private_key_result.resize(len);
-  if (!EVP_PKEY_sign_message(ctx.get(), test_state->private_key_result.data(),
-                             &len, in, in_len)) {
+  if (!EVP_DigestSign(ctx.get(), test_state->private_key_result.data(), &len,
+                      in, in_len)) {
     return ssl_private_key_failure;
   }
   test_state->private_key_result.resize(len);
diff --git a/tool/sign.cc b/tool/sign.cc
index 74b84f1..a511e8d 100644
--- a/tool/sign.cc
+++ b/tool/sign.cc
@@ -46,24 +46,19 @@
     return false;
   }
 
-  // Setup the signing operation.
-  bssl::UniquePtr<EVP_PKEY_CTX> ctx(EVP_PKEY_CTX_new(key.get(), nullptr));
-  if (!ctx ||
-      !EVP_PKEY_sign_init(ctx.get())) {
-    return false;
-  }
-
+  const EVP_MD *md = nullptr;
   if (args_map.count("-digest")) {
-    const EVP_MD *md = EVP_get_digestbyname(args_map["-digest"].c_str());
+    md = EVP_get_digestbyname(args_map["-digest"].c_str());
     if (md == nullptr) {
       fprintf(stderr, "Unknown digest algorithm: %s\n",
               args_map["-digest"].c_str());
       return false;
     }
+  }
 
-    if (!EVP_PKEY_CTX_set_signature_md(ctx.get(), md)) {
-      return false;
-    }
+  bssl::ScopedEVP_MD_CTX ctx;
+  if (!EVP_DigestSignInit(ctx.get(), nullptr, md, nullptr, key.get())) {
+    return false;
   }
 
   std::vector<uint8_t> data;
@@ -74,8 +69,8 @@
 
   size_t sig_len = EVP_PKEY_size(key.get());
   std::unique_ptr<uint8_t[]> sig(new uint8_t[sig_len]);
-  if (!EVP_PKEY_sign_message(ctx.get(), sig.get(), &sig_len, data.data(),
-                             data.size())) {
+  if (!EVP_DigestSign(ctx.get(), sig.get(), &sig_len, data.data(),
+                      data.size())) {
     return false;
   }