+static int dsa_digest_signverify_init(void *vpdsactx, const char *mdname,
+ const char *props, void *vdsa)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+ EVP_MD *md;
+
+ if (!dsa_signature_init(vpdsactx, vdsa))
+ return 0;
+
+ md = EVP_MD_fetch(pdsactx->libctx, mdname, props);
+ if (md == NULL)
+ return 0;
+ pdsactx->md = md;
+ pdsactx->mdsize = EVP_MD_size(md);
+ pdsactx->mdctx = EVP_MD_CTX_new();
+ if (pdsactx->mdctx == NULL)
+ return 0;
+
+ if (!EVP_DigestInit_ex(pdsactx->mdctx, md, NULL))
+ return 0;
+
+ return 1;
+}
+
+int dsa_digest_signverify_update(void *vpdsactx, const unsigned char *data,
+ size_t datalen)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+
+ if (pdsactx == NULL || pdsactx->mdctx == NULL)
+ return 0;
+
+ return EVP_DigestUpdate(pdsactx->mdctx, data, datalen);
+}
+
+int dsa_digest_sign_final(void *vpdsactx, unsigned char *sig, size_t *siglen,
+ size_t sigsize)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ unsigned int dlen = 0;
+
+ if (pdsactx == NULL || pdsactx->mdctx == NULL)
+ return 0;
+
+ /*
+ * If sig is NULL then we're just finding out the sig size. Other fields
+ * are ignored. Defer to dsa_sign.
+ */
+ if (sig != NULL) {
+ /*
+ * TODO(3.0): There is the possibility that some externally provided
+ * digests exceed EVP_MAX_MD_SIZE. We should probably handle that somehow -
+ * but that problem is much larger than just in DSA.
+ */
+ if (!EVP_DigestFinal_ex(pdsactx->mdctx, digest, &dlen))
+ return 0;
+ }
+
+ return dsa_sign(vpdsactx, sig, siglen, sigsize, digest, (size_t)dlen);
+}
+
+
+int dsa_digest_verify_final(void *vpdsactx, const unsigned char *sig,
+ size_t siglen)
+{
+ PROV_DSA_CTX *pdsactx = (PROV_DSA_CTX *)vpdsactx;
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ unsigned int dlen = 0;
+
+ if (pdsactx == NULL || pdsactx->mdctx == NULL)
+ return 0;
+
+ /*
+ * TODO(3.0): There is the possibility that some externally provided
+ * digests exceed EVP_MAX_MD_SIZE. We should probably handle that somehow -
+ * but that problem is much larger than just in DSA.
+ */
+ if (!EVP_DigestFinal_ex(pdsactx->mdctx, digest, &dlen))
+ return 0;
+
+ return dsa_verify(vpdsactx, sig, siglen, digest, (size_t)dlen);
+}