[PATCH setup 2/4] Add support for RSA key signatures

Jon Turney jon.turney@dronecode.org.uk
Mon Feb 24 22:02:00 GMT 2020


---
 crypto.cc | 162 ++++++++++++++++++++++++++++++++++--------------------
 crypto.h  |   5 +-
 2 files changed, 103 insertions(+), 64 deletions(-)

diff --git a/crypto.cc b/crypto.cc
index e2ed7b2..118d4d7 100644
--- a/crypto.cc
+++ b/crypto.cc
@@ -52,7 +52,7 @@ static BoolOption UntrustedKeysOption (false, 'u', "untrusted-keys",
 static BoolOption KeepUntrustedKeysOption (false, 'U', "keep-untrusted-keys",
 			"Use untrusted keys and retain all");
 
-/*  Embedded public half of Cygwin DSA signing key.  */
+/*  Embedded public half of Cygwin signing key.  */
 static const char *cygwin_pubkey_sexpr = 
 #include "cyg-pubkey.h"
 ;
@@ -63,14 +63,21 @@ static const char *dsa_pubkey_templ = "(public-key (dsa (p %m) (q %m) (g %m) (y
 /*  S-expr template for DSA signature.  */
 static const char *dsa_sig_templ = "(sig-val (dsa (r %m) (s %m)))";
 
+/*  S-expr template for RSA signature.  */
+static const char *rsa_sig_templ = "(sig-val (rsa (s %m)))";
+
 /*  S-expr template for data block to be signed.  */
-static const char *data_hash_templ = "(data (flags raw) (value %m))";
+static const char *dsa_data_hash_templ = "(data (flags raw) (value %m))";
+
+/*  S-expr template for RSA data block to be signed.  */
+static const char *rsa_data_hash_templ = "(data (flags pkcs1) (hash %s %b))";
 
 /*  User context data for sig packet walk.  */
 struct sig_data
 {
   /*  MPI values of sig components.  */
   gcry_mpi_t dsa_mpi_r, dsa_mpi_s;
+  gcry_mpi_t rsa_mpi_s;
 
   /*  Hash context.  */
   gcry_md_hd_t md;
@@ -315,8 +322,9 @@ pkt_cb_resp sig_file_walker (struct packet_walker *wlk, unsigned char tag,
       ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, sigdat->sig_type, "unsupported sig type.");
       return pktHALT;
     }
-  // And we only speak DSA.
-  if (sigdat->pk_alg != RFC4880_PK_DSA)
+
+  // We only handle RSA and DSA keys
+  if ((sigdat->pk_alg != RFC4880_PK_DSA) && (sigdat->pk_alg != RFC4880_PK_RSA))
     {
       ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, sigdat->pk_alg, "unsupported pk alg.");
       return pktHALT;
@@ -366,20 +374,35 @@ pkt_cb_resp sig_file_walker (struct packet_walker *wlk, unsigned char tag,
   MESSAGE ("sig type %d, pk_alg %d, hash_alg %d - first $%04x\n", sigdat->sig_type,
 			sigdat->pk_alg, sigdat->hash_alg, hash_first);
 
-  /*    Algorithm-Specific Fields for DSA signatures:
+  /*  Algorithm-Specific Fields for signatures:
 
-     - MPI of DSA value r.
+      for DSA:
+      - MPI of DSA value r
+      - MPI of DSA value s
 
-     - MPI of DSA value s.
+      DSA signatures MUST use hashes that are equal in size to the number of
+      bits of q, the group generated by the DSA key's generator value.
 
-   DSA signatures MUST use hashes that are equal in size to the number
-   of bits of q, the group generated by the DSA key's generator value.  */
+      for RSA:
+      - MPI of RSA value m^d mod n (aka s)
+  */
 
-  if ((pkt_get_mpi (&sigdat->dsa_mpi_r, wlk->pfile) < 0)
-      || (pkt_get_mpi (&sigdat->dsa_mpi_s, wlk->pfile) < 0))
+  if (sigdat->pk_alg == RFC4880_PK_DSA)
     {
-      ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, "unpacking mpi.");
-      return pktHALT;
+      if ((pkt_get_mpi (&sigdat->dsa_mpi_r, wlk->pfile) < 0)
+          || (pkt_get_mpi (&sigdat->dsa_mpi_s, wlk->pfile) < 0))
+        {
+          ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, "unpacking mpi.");
+          return pktHALT;
+        }
+    }
+  else if (sigdat->pk_alg == RFC4880_PK_RSA)
+    {
+      if (pkt_get_mpi (&sigdat->rsa_mpi_s, wlk->pfile) < 0)
+        {
+          ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, "unpacking mpi.");
+          return pktHALT;
+        }
     }
 
   MESSAGE ("Read sig packets succesfully!\n");
@@ -598,55 +621,81 @@ verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, HWND owner)
   sigdat.complete = false;
   sigdat.sign_data = ini_file;
   sigdat.dsa_mpi_r = sigdat.dsa_mpi_s = 0;
+  sigdat.rsa_mpi_s = 0;
   sigdat.md = 0;
   pkt_walk_packets (ini_sig_file, sig_file_walker, owner, 0,
 				ini_sig_file->get_size (), &sigdat);
   if (sigdat.complete)
     {
-      /*  DSA sig coefficients in s-expr format.  */
-      gcry_sexp_t dsa_sig;
+      /*  sig coefficients in s-expr format.  */
+      gcry_sexp_t sig;
 
-      /*  DSA signature hash data in s-expr format.  */
-      gcry_sexp_t dsa_hash;
+      /*  signature hash data in s-expr format.  */
+      gcry_sexp_t hash;
 
       /* So, we have hashed all the data, and found the sig coefficients.
-        Next stages are to finalise the hash, build everything into 
+        Next stages are to finalise the hash, build everything into
         s-exprs, and call the libgcrypt verification routine.  */
 
-      rv = gcry_sexp_build (&dsa_sig, &n, dsa_sig_templ, sigdat.dsa_mpi_r,
-								sigdat.dsa_mpi_s);
-      if (rv != GPG_ERR_NO_ERROR)
-	{
-	  ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "while creating sig s-expr.");
-	  return false;
-	}
-
       gcry_md_final (sigdat.md);
+      MESSAGE("digest length is %d\n",gcry_md_get_algo_dlen (sigdat.algo));
 
-      // Make a temp mpi from the hash output, then an s-expr from that.
-      gcry_mpi_t dsa_mpi_hash = 0;
-      unsigned char *tmpbuf = gcry_md_read (sigdat.md, 0);
-      size_t dlen = gcry_md_get_algo_dlen (sigdat.algo);
-      rv = gcry_mpi_scan (&dsa_mpi_hash, GCRYMPI_FMT_USG, tmpbuf, dlen, 0UL);
-      if (rv != GPG_ERR_NO_ERROR)
-	{
-	  ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "while creating hash MPI.");
-	  return false;
-	}
+      if (sigdat.pk_alg == RFC4880_PK_DSA)
+        {
+          rv = gcry_sexp_build (&sig, &n, dsa_sig_templ, sigdat.dsa_mpi_r,
+                                sigdat.dsa_mpi_s);
+          if (rv != GPG_ERR_NO_ERROR)
+            {
+              ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "while creating sig s-expr.");
+              return false;
+            }
+
+          // Make a temp mpi from the hash output, then an s-expr from that.
+          gcry_mpi_t mpi_hash = 0;
+          unsigned char *tmpbuf = gcry_md_read (sigdat.md, 0);
+          size_t dlen = gcry_md_get_algo_dlen (sigdat.algo);
+          rv = gcry_mpi_scan (&mpi_hash, GCRYMPI_FMT_USG, tmpbuf, dlen, 0UL);
+          if (rv != GPG_ERR_NO_ERROR)
+            {
+              ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "while creating hash MPI.");
+              return false;
+            }
 
-      rv = gcry_sexp_build (&dsa_hash, &n, data_hash_templ, dsa_mpi_hash);
-      if (rv != GPG_ERR_NO_ERROR)
-	{
-	  ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "while creating hash s-expr.");
-	  return false;
-	}
+          rv = gcry_sexp_build (&hash, &n, dsa_data_hash_templ, mpi_hash);
+          if (rv != GPG_ERR_NO_ERROR)
+            {
+              ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "while creating hash s-expr.");
+              return false;
+            }
+
+          gcry_mpi_release (mpi_hash);
+        }
+      else if (sigdat.pk_alg == RFC4880_PK_RSA)
+        {
+          rv = gcry_sexp_build (&sig, &n, rsa_sig_templ, sigdat.rsa_mpi_s);
+          if (rv != GPG_ERR_NO_ERROR)
+            {
+              ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "while creating sig s-expr.");
+              return false;
+            }
+
+          rv = gcry_sexp_build (&hash, &n, rsa_data_hash_templ,
+                                gcry_md_algo_name(sigdat.algo),
+                                gcry_md_get_algo_dlen (sigdat.algo),
+                                gcry_md_read (sigdat.md, 0));
+          if (rv != GPG_ERR_NO_ERROR)
+            {
+              ERRKIND (owner, IDS_CRYPTO_ERROR, rv, "while creating hash s-expr.");
+              return false;
+            }
+        }
 
 #if CRYPTODEBUGGING
-      n = gcry_sexp_sprint (dsa_sig, GCRYSEXP_FMT_ADVANCED, sexprbuf,
-							GPG_KEY_SEXPR_BUF_SIZE);
+      n = gcry_sexp_sprint (sig, GCRYSEXP_FMT_ADVANCED, sexprbuf,
+                            GPG_KEY_SEXPR_BUF_SIZE);
       LogBabblePrintf ("sig:%d\n'%s'", n, sexprbuf);
-      n = gcry_sexp_sprint (dsa_hash, GCRYSEXP_FMT_ADVANCED, sexprbuf,
-							GPG_KEY_SEXPR_BUF_SIZE);
+      n = gcry_sexp_sprint (hash, GCRYSEXP_FMT_ADVANCED, sexprbuf,
+                            GPG_KEY_SEXPR_BUF_SIZE);
       LogBabblePrintf ("hash:%d\n'%s'", n, sexprbuf);
 #endif /* CRYPTODEBUGGING */
 
@@ -656,29 +705,22 @@ verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, HWND owner)
       std::vector<key_info>::iterator it;
       for (it = keys_to_try.begin (); it < keys_to_try.end (); ++it)
         {
-          MESSAGE ("Trying key %s\n", it->name.c_str());
-          rv = gcry_pk_verify (dsa_sig, dsa_hash, it->key);
+          rv = gcry_pk_verify (sig, hash, it->key);
+
+          LogBabblePrintf("signature: tried key %s, returned 0x%08x %s\n",
+                          it->name.c_str(), rv, gcry_strerror(rv));
+
           if (rv != GPG_ERR_NO_ERROR)
             continue;
           // Found it!  This key gets kept!
-          LogBabblePrintf("Valid signature by key %s", it->name.c_str());
           if (!it->builtin)
             add_key_from_sexpr (it->key);
           break;
         }
       sig_ok = (rv == GPG_ERR_NO_ERROR);
 
-#if CRYPTODEBUGGING
-      gcry_err_code_t code;
-      gcry_err_source_t src;
-      code = gcry_err_code (rv);
-      src = gcry_err_source (rv);
-      LogBabblePrintf ("Well, pk verify returned $%08x - code %d src %d\n", rv, code, src);
-#endif /* CRYPTODEBUGGING */
-
-      gcry_mpi_release (dsa_mpi_hash);
-      gcry_sexp_release (dsa_sig);
-      gcry_sexp_release (dsa_hash);
+      gcry_sexp_release (sig);
+      gcry_sexp_release (hash);
     }
 
   // Discard the temp data then.
diff --git a/crypto.h b/crypto.h
index 860df6c..661d86d 100644
--- a/crypto.h
+++ b/crypto.h
@@ -308,12 +308,9 @@ extern bool verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, H
 
 */
 
-// Big enough to dump the coefficients of a DSA
+// Big enough to dump the coefficients of a
 // signing key of any reasonable size in ASCII
 // s-expr representation.
 #define GPG_KEY_SEXPR_BUF_SIZE  (8192)
 
-// As long as you respect this maximum coefficient size.
-#define GPG_KEY_MAX_COEFF_SIZE  (8192)
-
 #endif /* SETUP_CRYPTO_H */
-- 
2.21.0



More information about the Cygwin-apps mailing list