Add EVP_DigestVerifyInitFromAlgorithm and EVP_DigestSignAlgorithm.

Factor the AlgorithmIdentifier portions of ASN1_item_sign and ASN1_item_verify
out. This makes it possible to initialize a signature context from an
AlgorithmIdentifier without needing the data parsed into an ASN1_ITEM/void*
pair and reserialized.

Change-Id: Idc2e06b1310a3f801aa25de323d39d2b7a44ef50
Reviewed-on: https://boringssl-review.googlesource.com/1916
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/evp/CMakeLists.txt b/crypto/evp/CMakeLists.txt
index c3d8d8a..43e351a 100644
--- a/crypto/evp/CMakeLists.txt
+++ b/crypto/evp/CMakeLists.txt
@@ -5,6 +5,7 @@
 
 	OBJECT
 
+	algorithm.c
 	asn1.c
 	digestsign.c
 	evp.c
diff --git a/crypto/evp/algorithm.c b/crypto/evp/algorithm.c
new file mode 100644
index 0000000..4ec111b
--- /dev/null
+++ b/crypto/evp/algorithm.c
@@ -0,0 +1,162 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/evp.h>
+
+#include <assert.h>
+
+#include <openssl/asn1.h>
+#include <openssl/err.h>
+#include <openssl/obj.h>
+#include <openssl/x509.h>
+
+#include "internal.h"
+
+
+/* These functions use error codes under the ASN1 and X509 namespaces for
+ * compatibility with OpenSSL. */
+
+int EVP_DigestSignAlgorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor) {
+  const EVP_MD *digest;
+  EVP_PKEY *pkey;
+  int sign_nid, paramtype;
+
+  digest = EVP_MD_CTX_md(ctx);
+  pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx);
+  if (!digest || !pkey) {
+    OPENSSL_PUT_ERROR(EVP, EVP_DigestSignAlgorithm,
+                      EVP_R_CONTEXT_NOT_INITIALISED);
+    return 0;
+  }
+
+  if (pkey->ameth->digest_sign_algorithm) {
+    switch (pkey->ameth->digest_sign_algorithm(ctx, algor)) {
+      case EVP_DIGEST_SIGN_ALGORITHM_ERROR:
+        return 0;
+      case EVP_DIGEST_SIGN_ALGORITHM_SUCCESS:
+        return 1;
+      case EVP_DIGEST_SIGN_ALGORITHM_DEFAULT:
+        /* Use default behavior. */
+        break;
+      default:
+        assert(0);
+    }
+  }
+
+  /* Default behavior: look up the OID for the algorithm/hash pair and encode
+   * that. */
+  if (!OBJ_find_sigid_by_algs(&sign_nid, EVP_MD_type(digest),
+                              pkey->ameth->pkey_id)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_DigestSignAlgorithm,
+                      X509_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
+    return 0;
+  }
+
+  if (pkey->ameth->pkey_flags & ASN1_PKEY_SIGPARAM_NULL) {
+    paramtype = V_ASN1_NULL;
+  } else {
+    paramtype = V_ASN1_UNDEF;
+  }
+
+  X509_ALGOR_set0(algor, OBJ_nid2obj(sign_nid), paramtype, NULL);
+  return 1;
+}
+
+int EVP_DigestVerifyInitFromAlgorithm(EVP_MD_CTX *ctx,
+                                      X509_ALGOR *algor,
+                                      EVP_PKEY *pkey) {
+  int digest_nid, pkey_nid;
+  const EVP_PKEY_ASN1_METHOD *ameth;
+  const EVP_MD *digest;
+
+  /* Convert signature OID into digest and public key OIDs */
+  if (!OBJ_find_sigid_algs(OBJ_obj2nid(algor->algorithm), &digest_nid,
+                           &pkey_nid)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_DigestVerifyInitFromAlgorithm,
+                      ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
+    return 0;
+  }
+
+  /* Check public key OID matches public key type */
+  ameth = EVP_PKEY_asn1_find(NULL, pkey_nid);
+  if (ameth == NULL || ameth->pkey_id != pkey->ameth->pkey_id) {
+    OPENSSL_PUT_ERROR(EVP, EVP_DigestVerifyInitFromAlgorithm,
+                      ASN1_R_WRONG_PUBLIC_KEY_TYPE);
+    return 0;
+  }
+
+  /* NID_undef signals that there are custom parameters to set. */
+  if (digest_nid == NID_undef) {
+    if (!pkey->ameth || !pkey->ameth->digest_verify_init_from_algorithm) {
+      OPENSSL_PUT_ERROR(EVP, EVP_DigestVerifyInitFromAlgorithm,
+                        ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
+      return 0;
+    }
+
+    return pkey->ameth->digest_verify_init_from_algorithm(ctx, algor, pkey);
+  }
+
+  /* Otherwise, initialize with the digest from the OID. */
+  digest = EVP_get_digestbynid(digest_nid);
+  if (digest == NULL) {
+    OPENSSL_PUT_ERROR(EVP, EVP_DigestVerifyInitFromAlgorithm,
+                      ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
+    return 0;
+  }
+
+  return EVP_DigestVerifyInit(ctx, NULL, digest, NULL, pkey);
+}
+
diff --git a/crypto/evp/evp_error.c b/crypto/evp/evp_error.c
index 76a802a..fae1aa7 100644
--- a/crypto/evp/evp_error.c
+++ b/crypto/evp/evp_error.c
@@ -17,6 +17,8 @@
 #include <openssl/evp.h>
 
 const ERR_STRING_DATA EVP_error_string_data[] = {
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_DigestSignAlgorithm, 0), "EVP_DigestSignAlgorithm"},
+  {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_DigestVerifyInitFromAlgorithm, 0), "EVP_DigestVerifyInitFromAlgorithm"},
   {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_CTX_ctrl, 0), "EVP_PKEY_CTX_ctrl"},
   {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_copy_parameters, 0), "EVP_PKEY_copy_parameters"},
   {ERR_PACK(ERR_LIB_EVP, EVP_F_EVP_PKEY_decrypt, 0), "EVP_PKEY_decrypt"},
@@ -74,6 +76,7 @@
   {ERR_PACK(ERR_LIB_EVP, EVP_F_rsa_pub_decode, 0), "rsa_pub_decode"},
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_BUFFER_TOO_SMALL), "BUFFER_TOO_SMALL"},
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_COMMAND_NOT_SUPPORTED), "COMMAND_NOT_SUPPORTED"},
+  {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_CONTEXT_NOT_INITIALISED), "CONTEXT_NOT_INITIALISED"},
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DECODE_ERROR), "DECODE_ERROR"},
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DIFFERENT_KEY_TYPES), "DIFFERENT_KEY_TYPES"},
   {ERR_PACK(ERR_LIB_EVP, 0, EVP_R_DIFFERENT_PARAMETERS), "DIFFERENT_PARAMETERS"},
diff --git a/crypto/evp/internal.h b/crypto/evp/internal.h
index 36755f0..d92c9e5 100644
--- a/crypto/evp/internal.h
+++ b/crypto/evp/internal.h
@@ -67,8 +67,25 @@
 /* These values are flags for EVP_PKEY_ASN1_METHOD.flags. */
 #define ASN1_PKEY_ALIAS 0x1
 #define ASN1_PKEY_DYNAMIC 0x2
+
+/* ASN1_PKEY_SIGPARAM_NULL controls whether the default behavior of
+ * EVP_DigestSignAlgorithm writes an explicit NULL parameter in the
+ * AlgorithmIdentifier. */
 #define ASN1_PKEY_SIGPARAM_NULL 0x4
 
+/* evp_digest_sign_algorithm_result_t is the return value of the
+ * digest_sign_algorithm function in EVP_PKEY_ASN1_METHOD. */
+typedef enum {
+  /* EVP_DIGEST_SIGN_ALGORITHM_ERROR signals an error. */
+  EVP_DIGEST_SIGN_ALGORITHM_ERROR = 0,
+  /* EVP_DIGEST_SIGN_ALGORITHM_SUCCESS signals that the parameters were
+   * serialized in the AlgorithmIdentifier. */
+  EVP_DIGEST_SIGN_ALGORITHM_SUCCESS = 1,
+  /* EVP_DIGEST_SIGN_ALGORITHM_DEFAULT signals that the parameters are
+   * serialized using the default behavior. */
+  EVP_DIGEST_SIGN_ALGORITHM_DEFAULT = 2,
+} evp_digest_sign_algorithm_result_t;
+
 struct evp_pkey_asn1_method_st {
   int pkey_id;
   int pkey_base_id;
@@ -113,11 +130,14 @@
   int (*old_priv_decode)(EVP_PKEY *pkey, const unsigned char **pder,
                          int derlen);
   int (*old_priv_encode)(const EVP_PKEY *pkey, unsigned char **pder);
-  /* Custom ASN1 signature verification */
-  int (*item_verify)(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
-                     X509_ALGOR *a, ASN1_BIT_STRING *sig, EVP_PKEY *pkey);
-  int (*item_sign)(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
-                   X509_ALGOR *alg1, X509_ALGOR *alg2, ASN1_BIT_STRING *sig);
+
+  /* Converting parameters to/from AlgorithmIdentifier (X509_ALGOR). */
+  int (*digest_verify_init_from_algorithm)(EVP_MD_CTX *ctx,
+                                           X509_ALGOR *algor,
+                                           EVP_PKEY *pkey);
+  evp_digest_sign_algorithm_result_t (*digest_sign_algorithm)(
+      EVP_MD_CTX *ctx,
+      X509_ALGOR *algor);
 
 } /* EVP_PKEY_ASN1_METHOD */;
 
diff --git a/crypto/evp/p_rsa_asn1.c b/crypto/evp/p_rsa_asn1.c
index 1bb69f3..ab83a8e 100644
--- a/crypto/evp/p_rsa_asn1.c
+++ b/crypto/evp/p_rsa_asn1.c
@@ -649,54 +649,37 @@
   return ret;
 }
 
-/* Customised RSA item verification routine. This is called
- * when a signature is encountered requiring special handling. We
- * currently only handle PSS. */
-static int rsa_item_verify(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
-                           X509_ALGOR *sigalg, ASN1_BIT_STRING *sig,
-                           EVP_PKEY *pkey) {
+/* Customised RSA AlgorithmIdentifier handling. This is called when a signature
+ * is encountered requiring special handling. We currently only handle PSS. */
+static int rsa_digest_verify_init_from_algorithm(EVP_MD_CTX *ctx,
+                                                 X509_ALGOR *sigalg,
+                                                 EVP_PKEY *pkey) {
   /* Sanity check: make sure it is PSS */
   if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss) {
     OPENSSL_PUT_ERROR(EVP, rsa_item_verify, EVP_R_UNSUPPORTED_SIGNATURE_TYPE);
-    return -1;
+    return 0;
   }
-  if (rsa_pss_to_ctx(ctx, sigalg, pkey)) {
-    /* Carry on */
-    return 2;
-  }
-
-  return -1;
+  return rsa_pss_to_ctx(ctx, sigalg, pkey);
 }
 
-static int rsa_item_sign(EVP_MD_CTX *ctx, const ASN1_ITEM *it, void *asn,
-                         X509_ALGOR *alg1, X509_ALGOR *alg2,
-                         ASN1_BIT_STRING *sig) {
+static evp_digest_sign_algorithm_result_t rsa_digest_sign_algorithm(
+    EVP_MD_CTX *ctx, X509_ALGOR *sigalg) {
   int pad_mode;
   EVP_PKEY_CTX *pkctx = ctx->pctx;
   if (EVP_PKEY_CTX_get_rsa_padding(pkctx, &pad_mode) <= 0) {
-    return 0;
-  }
-  if (pad_mode == RSA_PKCS1_PADDING) {
-    return 2;
+    return EVP_DIGEST_SIGN_ALGORITHM_ERROR;
   }
   if (pad_mode == RSA_PKCS1_PSS_PADDING) {
     ASN1_STRING *os1 = rsa_ctx_to_pss(pkctx);
     if (!os1) {
-      return 0;
+      return EVP_DIGEST_SIGN_ALGORITHM_ERROR;
     }
-    /* Duplicate parameters if we have to */
-    if (alg2) {
-      ASN1_STRING *os2 = ASN1_STRING_dup(os1);
-      if (!os2) {
-        ASN1_STRING_free(os1);
-        return 0;
-      }
-      X509_ALGOR_set0(alg2, OBJ_nid2obj(NID_rsassaPss), V_ASN1_SEQUENCE, os2);
-    }
-    X509_ALGOR_set0(alg1, OBJ_nid2obj(NID_rsassaPss), V_ASN1_SEQUENCE, os1);
-    return 3;
+    X509_ALGOR_set0(sigalg, OBJ_nid2obj(NID_rsassaPss), V_ASN1_SEQUENCE, os1);
+    return EVP_DIGEST_SIGN_ALGORITHM_SUCCESS;
   }
-  return 2;
+
+  /* Other padding schemes use the default behavior. */
+  return EVP_DIGEST_SIGN_ALGORITHM_DEFAULT;
 }
 
 const EVP_PKEY_ASN1_METHOD rsa_asn1_meth = {
@@ -730,8 +713,8 @@
   old_rsa_priv_decode,
   old_rsa_priv_encode,
 
-  rsa_item_verify,
-  rsa_item_sign,
+  rsa_digest_verify_init_from_algorithm,
+  rsa_digest_sign_algorithm,
 };
 
 const EVP_PKEY_ASN1_METHOD rsa_asn1_meth_2 = {
diff --git a/crypto/x509/a_sign.c b/crypto/x509/a_sign.c
index a6bf715..f219c23 100644
--- a/crypto/x509/a_sign.c
+++ b/crypto/x509/a_sign.c
@@ -84,65 +84,20 @@
 		X509_ALGOR *algor1, X509_ALGOR *algor2,
 	     	ASN1_BIT_STRING *signature, void *asn, EVP_MD_CTX *ctx)
 	{
-	const EVP_MD *type;
 	EVP_PKEY *pkey;
 	unsigned char *buf_in=NULL,*buf_out=NULL;
 	size_t inl=0,outl=0,outll=0;
-	int signid, paramtype;
-	int rv;
 
-	type = EVP_MD_CTX_md(ctx);
 	pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx);
 
-	if (!type || !pkey)
+	/* Write out the requested copies of the AlgorithmIdentifier. */
+	if (algor1 && !EVP_DigestSignAlgorithm(ctx, algor1))
 		{
-		OPENSSL_PUT_ERROR(X509, ASN1_item_sign_ctx, X509_R_CONTEXT_NOT_INITIALISED);
-		return 0;
+		goto err;
 		}
-
-	if (pkey->ameth->item_sign)
+	if (algor2 && !EVP_DigestSignAlgorithm(ctx, algor2))
 		{
-		rv = pkey->ameth->item_sign(ctx, it, asn, algor1, algor2,
-						signature);
-		if (rv == 1)
-			outl = signature->length;
-		/* Return value meanings:
-		 * <=0: error.
-		 *   1: method does everything.
-		 *   2: carry on as normal.
-		 *   3: ASN1 method sets algorithm identifiers: just sign.
-		 */
-		if (rv <= 0)
-			OPENSSL_PUT_ERROR(X509, ASN1_item_sign_ctx, ERR_R_EVP_LIB);
-		if (rv <= 1)
-			goto err;
-		}
-	else
-		rv = 2;
-
-	if (rv == 2)
-		{
-		/* TODO(fork): EVP_MD_FLAG_PKEY_METHOD_SIGNATURE seems to mean
-		 * "is SHA". */
-		if (!pkey->ameth ||
-			!OBJ_find_sigid_by_algs(&signid,
-						EVP_MD_type(type),
-						pkey->ameth->pkey_id))
-			{
-			OPENSSL_PUT_ERROR(X509, ASN1_item_sign_ctx, X509_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED);
-			return 0;
-			}
-
-		if (pkey->ameth->pkey_flags & ASN1_PKEY_SIGPARAM_NULL)
-			paramtype = V_ASN1_NULL;
-		else
-			paramtype = V_ASN1_UNDEF;
-
-		if (algor1)
-			X509_ALGOR_set0(algor1, OBJ_nid2obj(signid), paramtype, NULL);
-		if (algor2)
-			X509_ALGOR_set0(algor2, OBJ_nid2obj(signid), paramtype, NULL);
-
+		goto err;
 		}
 
 	inl=ASN1_item_i2d(asn,&buf_in, it);
diff --git a/crypto/x509/a_verify.c b/crypto/x509/a_verify.c
index 51f0fd6..e728863 100644
--- a/crypto/x509/a_verify.c
+++ b/crypto/x509/a_verify.c
@@ -75,69 +75,21 @@
 		ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey)
 	{
 	EVP_MD_CTX ctx;
-	unsigned char *buf_in=NULL;
-	int ret= -1,inl;
-	const EVP_PKEY_ASN1_METHOD *ameth;
-
-	int mdnid, pknid;
+	uint8_t *buf_in = NULL;
+	int ret = 0, inl;
 
 	if (!pkey)
 		{
 		OPENSSL_PUT_ERROR(X509, ASN1_item_verify, ERR_R_PASSED_NULL_PARAMETER);
-		return 1;
+		return 0;
 		}
 
 	EVP_MD_CTX_init(&ctx);
 
-	/* Convert signature OID into digest and public key OIDs */
-	if (!OBJ_find_sigid_algs(OBJ_obj2nid(a->algorithm), &mdnid, &pknid))
+	if (!EVP_DigestVerifyInitFromAlgorithm(&ctx, a, pkey))
 		{
-		OPENSSL_PUT_ERROR(X509, ASN1_item_verify, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
 		goto err;
 		}
-	if (mdnid == NID_undef)
-		{
-		if (!pkey->ameth || !pkey->ameth->item_verify)
-			{
-			OPENSSL_PUT_ERROR(X509, ASN1_item_verify, ASN1_R_UNKNOWN_SIGNATURE_ALGORITHM);
-			goto err;
-			}
-		ret = pkey->ameth->item_verify(&ctx, it, asn, a,
-							signature, pkey);
-		/* Return value of 2 means carry on, anything else means we
-		 * exit straight away: either a fatal error of the underlying
-		 * verification routine handles all verification.
-		 */
-		if (ret != 2)
-			goto err;
-		ret = -1;
-		}
-	else
-		{
-		const EVP_MD *type;
-		type=EVP_get_digestbynid(mdnid);
-		if (type == NULL)
-			{
-			OPENSSL_PUT_ERROR(X509, ASN1_item_verify, ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM);
-			goto err;
-			}
-
-		/* Check public key OID matches public key type */
-		ameth = EVP_PKEY_asn1_find(NULL, pknid);
-		if (ameth == NULL || ameth->pkey_id != pkey->ameth->pkey_id)
-			{
-			OPENSSL_PUT_ERROR(X509, ASN1_item_verify, ASN1_R_WRONG_PUBLIC_KEY_TYPE);
-			goto err;
-			}
-
-		if (!EVP_DigestVerifyInit(&ctx, NULL, type, NULL, pkey))
-			{
-			OPENSSL_PUT_ERROR(X509, ASN1_item_verify, ERR_R_EVP_LIB);
-			ret=0;
-			goto err;
-			}
-
-		}
 
 	inl = ASN1_item_i2d(asn, &buf_in, it);
 	
@@ -152,7 +104,6 @@
 		OPENSSL_cleanse(buf_in,(unsigned int)inl);
 		OPENSSL_free(buf_in);
 		OPENSSL_PUT_ERROR(X509, ASN1_item_verify, ERR_R_EVP_LIB);
-		ret=0;
 		goto err;
 		}
 
@@ -163,15 +114,14 @@
 			(size_t)signature->length) <= 0)
 		{
 		OPENSSL_PUT_ERROR(X509, ASN1_item_verify, ERR_R_EVP_LIB);
-		ret=0;
 		goto err;
 		}
 	/* we don't need to zero the 'ctx' because we just checked
 	 * public information */
 	/* memset(&ctx,0,sizeof(ctx)); */
-	ret=1;
+	ret = 1;
 err:
 	EVP_MD_CTX_cleanup(&ctx);
-	return(ret);
+	return ret;
 	}
 
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index 091912f..fcbb085 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -247,6 +247,15 @@
 OPENSSL_EXPORT int EVP_DigestSignFinal(EVP_MD_CTX *ctx, uint8_t *out_sig,
                                        size_t *out_sig_len);
 
+/* EVP_DigestSignAlgorithm encodes the signing parameters of |ctx| as an
+ * AlgorithmIdentifer and saves the result in |algor|.
+ *
+ * It returns one on success, or zero on error.
+ *
+ * TODO(davidben): This API should eventually lose the dependency on
+ * crypto/asn1/. */
+OPENSSL_EXPORT int EVP_DigestSignAlgorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor);
+
 
 /* Verifying */
 
@@ -261,6 +270,18 @@
                                         const EVP_MD *type, ENGINE *e,
                                         EVP_PKEY *pkey);
 
+/* EVP_DigestVerifyInitFromAlgorithm sets up |ctx| for a signature verification
+ * operation 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.
+ *
+ * TODO(davidben): This API should eventually lose the dependency on
+ * crypto/asn1/. */
+OPENSSL_EXPORT int EVP_DigestVerifyInitFromAlgorithm(EVP_MD_CTX *ctx,
+                                                     X509_ALGOR *algor,
+                                                     EVP_PKEY *pkey);
+
 /* EVP_DigestVerifyUpdate appends |len| bytes from |data| to the data which
  * will be verified by |EVP_DigestVerifyFinal|. It returns one on success and
  * zero otherwise. */
@@ -813,6 +834,8 @@
 #define EVP_F_pkey_rsa_encrypt 152
 #define EVP_F_pkey_rsa_decrypt 153
 #define EVP_F_hmac_signctx 154
+#define EVP_F_EVP_DigestVerifyInitFromAlgorithm 155
+#define EVP_F_EVP_DigestSignAlgorithm 156
 #define EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE 100
 #define EVP_R_UNSUPPORTED_SIGNATURE_TYPE 101
 #define EVP_R_INVALID_DIGEST_TYPE 102
@@ -859,5 +882,6 @@
 #define EVP_R_DECODE_ERROR 143
 #define EVP_R_INVALID_PSS_SALTLEN 144
 #define EVP_R_UNKNOWN_PUBLIC_KEY_TYPE 145
+#define EVP_R_CONTEXT_NOT_INITIALISED 146
 
 #endif  /* OPENSSL_HEADER_EVP_H */