commit 7845f69cba0bad9855db00e1a81be3381ec6af54
Author: Stephan Mueller <stephan.mueller@atsec.com>
Date:   Mon Mar 5 13:28:52 2018 +0100

    Add gcry_pk_sign_md and gcry_pk_verify_md API calls
    
    FIPS 140-2 requires that the library calculates the hash of the input
    data provided by the caller. The new API calls allow the user to specify
    a message digest handle that received already the user's input. By
    extracting the hash algorithm from s_hash, the respective message digest
    is obtained from the message digest handle.
    
    * cipher/pubkey-internal.h: Add _gcry_pk_util_get_algo.
    * cipher/pubkey-util.c: Add _gcry_pk_util_get_algo.
    * cipher/pubkey.c: Add calculate_hash, _gcry_pk_sign_md,
    _gcry_pk_verify_md and turn _gcry_pk_sign/_gcry_pk_verify into a wrapper
    to call _gcry_pk_sign_md / _gcry_pk_verify_md with a NULL message digest
    context
    * src/visibility.c: Add gcry_pk_sign_md, gcry_pk_verify_md APIs
    * src/visibility.h: Add gcry_pk_sign_md, gcry_pk_verify_md APIs
    
    Signed-off-by: Stephan Mueller <smueller@chronox.de>

diff --git a/cipher/pubkey-internal.h b/cipher/pubkey-internal.h
index d31e26f3..2936969f 100644
--- a/cipher/pubkey-internal.h
+++ b/cipher/pubkey-internal.h
@@ -43,6 +43,7 @@ void _gcry_pk_util_free_encoding_ctx (struct pk_encoding_ctx *ctx);
 gcry_err_code_t _gcry_pk_util_data_to_mpi (gcry_sexp_t input,
                                            gcry_mpi_t *ret_mpi,
                                            struct pk_encoding_ctx *ctx);
+gcry_err_code_t _gcry_pk_util_get_algo (gcry_sexp_t input, int *algo);
 
 
 
diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c
index 7ddef7dc..b41135e6 100644
--- a/cipher/pubkey-util.c
+++ b/cipher/pubkey-util.c
@@ -1158,3 +1158,50 @@ _gcry_pk_util_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
 
   return rc;
 }
+
+
+gcry_err_code_t
+_gcry_pk_util_get_algo (gcry_sexp_t input, int *algo)
+{
+  gcry_err_code_t rc = 0;
+  gcry_sexp_t ldata, list = NULL;
+  const char *s;
+  size_t n;
+  int lalgo;
+
+  ldata = sexp_find_token (input, "data", 0);
+  if (!ldata)
+    {
+      rc = GPG_ERR_INV_OBJ;
+      goto leave;
+    }
+
+  list = sexp_find_token (ldata, "hash-algo", 0);
+  if (!list)
+    {
+      rc = GPG_ERR_INV_OBJ;
+      goto leave;
+    }
+
+  s = sexp_nth_data (list, 1, &n);
+  if (!s)
+    {
+      rc = GPG_ERR_NO_OBJ;
+      goto leave;
+    }
+
+  lalgo = get_hash_algo (s, n);
+  if (!lalgo)
+    {
+      rc = GPG_ERR_DIGEST_ALGO;
+      goto leave;
+    }
+
+  *algo = lalgo;
+
+ leave:
+  sexp_release (ldata);
+  sexp_release (list);
+
+  return rc;
+}
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index 4c07e33b..a625094f 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -284,8 +284,34 @@ pubkey_get_nenc (int algo)
   return spec? strlen (spec->elements_enc) : 0;
 }
 
+static gcry_err_code_t
+calculate_hash (gcry_md_hd_t hd, gcry_sexp_t s_hash)
+{
+  gcry_err_code_t rc;
+  const unsigned char *digest;
+  int algo;
+
+  if (!hd)
+    return 0;
+
+  rc = _gcry_pk_util_get_algo (s_hash, &algo);
+  if (rc)
+    return rc;
+
+  digest = _gcry_md_read(hd, algo);
+  if (!digest)
+      return GPG_ERR_DIGEST_ALGO;
+
+  rc = _gcry_sexp_build (s_hash, NULL,
+                         "(data (flags pkcs1)(hash %s %b))",
+                         _gcry_md_algo_name(algo),
+                         (int) _gcry_md_get_algo_dlen(algo),
+                         digest);
+
+  return rc;
+}
+
 
-
 /*
    Do a PK encrypt operation
 
@@ -384,6 +410,35 @@ _gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey)
 }
 
 
+gcry_err_code_t
+_gcry_pk_sign_md (gcry_sexp_t *r_sig, gcry_md_hd_t hd, gcry_sexp_t s_hash,
+                  gcry_sexp_t s_skey)
+{
+  gcry_err_code_t rc;
+  gcry_pk_spec_t *spec;
+  gcry_sexp_t keyparms;
+
+  *r_sig = NULL;
+
+  rc = spec_from_sexp (s_skey, 1, &spec, &keyparms);
+  if (rc)
+    goto leave;
+
+  rc = calculate_hash (hd, s_hash);
+  if (rc)
+    goto leave;
+
+  if (spec->sign)
+    rc = spec->sign (r_sig, s_hash, keyparms);
+  else
+    rc = GPG_ERR_NOT_IMPLEMENTED;
+
+ leave:
+  sexp_release (keyparms);
+  return rc;
+}
+
+
 
 /*
    Create a signature.
@@ -415,19 +470,29 @@ _gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey)
 */
 gcry_err_code_t
 _gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey)
+{
+  return _gcry_pk_sign_md (r_sig, NULL, s_hash, s_skey);
+}
+
+
+gcry_err_code_t
+_gcry_pk_verify_md (gcry_sexp_t s_sig, gcry_md_hd_t hd, gcry_sexp_t s_hash,
+                    gcry_sexp_t s_pkey)
 {
   gcry_err_code_t rc;
   gcry_pk_spec_t *spec;
   gcry_sexp_t keyparms;
 
-  *r_sig = NULL;
+  rc = spec_from_sexp (s_pkey, 0, &spec, &keyparms);
+  if (rc)
+    goto leave;
 
-  rc = spec_from_sexp (s_skey, 1, &spec, &keyparms);
+  rc = calculate_hash (hd, s_hash);
   if (rc)
     goto leave;
 
-  if (spec->sign)
-    rc = spec->sign (r_sig, s_hash, keyparms);
+  if (spec->verify)
+    rc = spec->verify (s_sig, s_hash, keyparms);
   else
     rc = GPG_ERR_NOT_IMPLEMENTED;
 
@@ -447,22 +512,7 @@ _gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey)
 gcry_err_code_t
 _gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey)
 {
-  gcry_err_code_t rc;
-  gcry_pk_spec_t *spec;
-  gcry_sexp_t keyparms;
-
-  rc = spec_from_sexp (s_pkey, 0, &spec, &keyparms);
-  if (rc)
-    goto leave;
-
-  if (spec->verify)
-    rc = spec->verify (s_sig, s_hash, keyparms);
-  else
-    rc = GPG_ERR_NOT_IMPLEMENTED;
-
- leave:
-  sexp_release (keyparms);
-  return rc;
+  return _gcry_pk_verify_md (s_sig, NULL, s_hash, s_pkey);
 }
 
 
diff --git a/src/g10lib.h b/src/g10lib.h
index b0b73852..75f8bd59 100644
--- a/src/g10lib.h
+++ b/src/g10lib.h
@@ -315,6 +315,10 @@ gpg_err_code_t _gcry_generate_fips186_3_prime
 gpg_err_code_t _gcry_fips186_4_prime_check (const gcry_mpi_t x,
                                             unsigned int bits);
 
+gcry_err_code_t _gcry_pk_sign_md (gcry_sexp_t *r_sig, gcry_md_hd_t hd,
+                                  gcry_sexp_t s_hash, gcry_sexp_t s_skey);
+gcry_err_code_t _gcry_pk_verify_md (gcry_sexp_t s_sig, gcry_md_hd_t hd,
+                                    gcry_sexp_t s_hash, gcry_sexp_t s_pkey);
 
 /* Replacements of missing functions (missing-string.c).  */
 #ifndef HAVE_STPCPY
diff --git a/src/visibility.c b/src/visibility.c
index 8cda962c..8c5df8c1 100644
--- a/src/visibility.c
+++ b/src/visibility.c
@@ -991,6 +991,18 @@ gcry_pk_decrypt (gcry_sexp_t *result, gcry_sexp_t data, gcry_sexp_t skey)
   return gpg_error (_gcry_pk_decrypt (result, data, skey));
 }
 
+gcry_error_t
+gcry_pk_sign_md (gcry_sexp_t *result, gcry_md_hd_t hd, gcry_sexp_t data,
+                 gcry_sexp_t skey)
+{
+  if (!fips_is_operational ())
+    {
+      *result = NULL;
+      return gpg_error (fips_not_operational ());
+    }
+  return gpg_error (_gcry_pk_sign_md (result, hd, data, skey));
+}
+
 gcry_error_t
 gcry_pk_sign (gcry_sexp_t *result, gcry_sexp_t data, gcry_sexp_t skey)
 {
@@ -1002,6 +1014,15 @@ gcry_pk_sign (gcry_sexp_t *result, gcry_sexp_t data, gcry_sexp_t skey)
   return gpg_error (_gcry_pk_sign (result, data, skey));
 }
 
+gcry_error_t
+gcry_pk_verify_md (gcry_sexp_t sigval, gcry_md_hd_t hd, gcry_sexp_t data,
+                   gcry_sexp_t pkey)
+{
+  if (!fips_is_operational ())
+    return gpg_error (fips_not_operational ());
+  return gpg_error (_gcry_pk_verify_md (sigval, hd, data, pkey));
+}
+
 gcry_error_t
 gcry_pk_verify (gcry_sexp_t sigval, gcry_sexp_t data, gcry_sexp_t pkey)
 {
diff --git a/src/visibility.h b/src/visibility.h
index b7e8369a..99c6024a 100644
--- a/src/visibility.h
+++ b/src/visibility.h
@@ -361,8 +361,10 @@ MARK_VISIBLEX (_gcry_mpi_get_const)
 #define gcry_pk_get_nbits           _gcry_USE_THE_UNDERSCORED_FUNCTION
 #define gcry_pk_map_name            _gcry_USE_THE_UNDERSCORED_FUNCTION
 #define gcry_pk_sign                _gcry_USE_THE_UNDERSCORED_FUNCTION
+#define gcry_pk_sign_md             _gcry_USE_THE_UNDERSCORED_FUNCTION
 #define gcry_pk_testkey             _gcry_USE_THE_UNDERSCORED_FUNCTION
 #define gcry_pk_verify              _gcry_USE_THE_UNDERSCORED_FUNCTION
+#define gcry_pk_verify_md           _gcry_USE_THE_UNDERSCORED_FUNCTION
 #define gcry_pubkey_get_sexp        _gcry_USE_THE_UNDERSCORED_FUNCTION
 #define gcry_ecc_get_algo_keylen    _gcry_USE_THE_UNDERSCORED_FUNCTION
 #define gcry_ecc_mul_point          _gcry_USE_THE_UNDERSCORED_FUNCTION
