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

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

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

Jon TURNEY
Jon Turney (4):
  Convert msg under CRYPTODEBUGGING to LogBabblePrintf
  Add support for RSA key signatures
  Teach gpg-key-to-s-expr.sh to handle RSA pubkeys
  Teach --pubkey option to handle RSA keys

 crypto.cc            | 278 ++++++++++++++++++++++++++-----------------
 crypto.h             |   5 +-
 gpg-key-to-s-expr.sh |  49 +++++---
 3 files changed, 208 insertions(+), 124 deletions(-)

--
2.21.0

Reply | Threaded
Open this post in threaded view
|

[PATCH setup 1/4] Convert msg under CRYPTODEBUGGING to LogBabblePrintf

Jon TURNEY
Convert msg under CRYPTODEBUGGING to LogBabblePrintf, missed in 6f2a7375.
---
 crypto.cc | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/crypto.cc b/crypto.cc
index fabd097..e2ed7b2 100644
--- a/crypto.cc
+++ b/crypto.cc
@@ -161,7 +161,7 @@ pkt_cb_resp key_file_walker (struct packet_walker *wlk, unsigned char tag,
       char sexprbuf[GPG_KEY_SEXPR_BUF_SIZE];
       n = gcry_sexp_sprint (new_key, GCRYSEXP_FMT_ADVANCED, sexprbuf,
  GPG_KEY_SEXPR_BUF_SIZE);
-      msg ("key:%d\n'%s'", n, sexprbuf);
+      LogBabblePrintf ("key:%d\n'%s'", n, sexprbuf);
 #endif /* CRYPTODEBUGGING */
 
       // Return it to caller in the vector.
@@ -474,7 +474,7 @@ verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, HWND owner)
 #if CRYPTODEBUGGING
   char sexprbuf[GPG_KEY_SEXPR_BUF_SIZE];
   n = gcry_sexp_sprint (dsa_key, GCRYSEXP_FMT_ADVANCED, sexprbuf, GPG_KEY_SEXPR_BUF_SIZE);
-  msg ("key:%d\n'%s'", n, sexprbuf);
+  LogBabblePrintf ("key:%d\n'%s'", n, sexprbuf);
 #endif /* CRYPTODEBUGGING */
 
 
@@ -549,7 +549,7 @@ verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, HWND owner)
   // +1 because we want to include the nul-terminator.
   n = fold_lfs_and_spaces (sexprbuf, n + 1);
   ExtraKeysSetting::instance().add_key (sexprbuf);
-  msg ("key2:%d\n'%s'", n, sexprbuf);
+  LogBabblePrintf ("key2:%d\n'%s'", n, sexprbuf);
 #endif /* CRYPTODEBUGGING */
   keys_to_try.push_back (key_info ("from command-line option --sexpr-pubkey", false, dsa_key2));
  }
@@ -584,7 +584,7 @@ verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, HWND owner)
       // +1 because we want to include the nul-terminator.
       n = fold_lfs_and_spaces (sexprbuf, n + 1);
       ExtraKeysSetting::instance().add_key (sexprbuf);
-      msg ("key3:%d\n'%s'", n, sexprbuf);
+      LogBabblePrintf ("key3:%d\n'%s'", n, sexprbuf);
 #endif /* CRYPTODEBUGGING */
       keys_to_try.push_back (key_info ("from command-line option --pubkey", false, kdat.keys.back ()));
       kdat.keys.pop_back ();
@@ -644,10 +644,10 @@ verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, HWND owner)
 #if CRYPTODEBUGGING
       n = gcry_sexp_sprint (dsa_sig, GCRYSEXP_FMT_ADVANCED, sexprbuf,
  GPG_KEY_SEXPR_BUF_SIZE);
-      msg ("sig:%d\n'%s'", n, sexprbuf);
+      LogBabblePrintf ("sig:%d\n'%s'", n, sexprbuf);
       n = gcry_sexp_sprint (dsa_hash, GCRYSEXP_FMT_ADVANCED, sexprbuf,
  GPG_KEY_SEXPR_BUF_SIZE);
-      msg ("hash:%d\n'%s'", n, sexprbuf);
+      LogBabblePrintf ("hash:%d\n'%s'", n, sexprbuf);
 #endif /* CRYPTODEBUGGING */
 
       // Well, we're actually there!
@@ -673,7 +673,7 @@ verify_ini_file_sig (io_stream *ini_file, io_stream *ini_sig_file, HWND owner)
       gcry_err_source_t src;
       code = gcry_err_code (rv);
       src = gcry_err_source (rv);
-      msg ("Well, pk verify returned $%08x - code %d src %d\n", rv, code, src);
+      LogBabblePrintf ("Well, pk verify returned $%08x - code %d src %d\n", rv, code, src);
 #endif /* CRYPTODEBUGGING */
 
       gcry_mpi_release (dsa_mpi_hash);
--
2.21.0

Reply | Threaded
Open this post in threaded view
|

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

Jon TURNEY
In reply to this post by Jon TURNEY
---
 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

Reply | Threaded
Open this post in threaded view
|

[PATCH setup 3/4] Teach gpg-key-to-s-expr.sh to handle RSA pubkeys

Jon TURNEY
In reply to this post by Jon TURNEY
---
 gpg-key-to-s-expr.sh | 49 +++++++++++++++++++++++++++++++-------------
 1 file changed, 35 insertions(+), 14 deletions(-)

diff --git a/gpg-key-to-s-expr.sh b/gpg-key-to-s-expr.sh
index 1938bbf..f5c6799 100755
--- a/gpg-key-to-s-expr.sh
+++ b/gpg-key-to-s-expr.sh
@@ -13,7 +13,7 @@
 # Written by Dave Korn <[hidden email]>
 #
 #
-# Converts a gpg dsa pub key file to a text s-expr for
+# Converts a gpg pub key file to a text s-expr for
 # building into setup.exe's signature verification.
 # Relies on having pgpdump installed.
 #
@@ -28,11 +28,10 @@
 # output on a single line.  Only one option should be
 # specified or the behaviour is undefined.
 
-
-# Usage: find_a_line DSACOEFFICIENT PGPDUMPFILE
-# Returns the hex data for the named DSA coefficeint..
+# Usage: find_a_line ALG COEFFICIENT PGPDUMPFILE
+# Returns the hex data for the named coefficient..
 function find_a_line() {
-  grep "DSA $1([0-9]* bits) -" < "$2" \
+  grep -m1 "$1 $2([0-9]* bits) -" < "$3" \
     | sed -e 's/^.*- //g' | tr -d ' '
 }
 
@@ -105,17 +104,36 @@ pgpdump -milpu "$1" >"$TMPFILE" || exit 1
 # bunch of bashes, greps and seds.  No, I don't care.  Don't bug
 # me about it until we have to run this script a million times a day!
 
-dsa_p=`find_a_line p $TMPFILE`
-dsa_q=`find_a_line q $TMPFILE`
-dsa_g=`find_a_line g $TMPFILE`
-dsa_y=`find_a_line y $TMPFILE`
+alg=`grep -m1 "Pub alg" $TMPFILE | sed -E -e 's/^.*pub (.*)\)/\1/g'`
+
+case $alg in
+    1)
+    rsa_n=`find_a_line RSA n $TMPFILE`
+    rsa_e=`find_a_line RSA e $TMPFILE`
+
+    rsa_n=`line_to_sexpr "$rsa_n"`
+    rsa_e=`line_to_sexpr "$rsa_e"`
+
+    echo -e $header$quotes"(public-key $escapes$nl\
+$starts$ind$mid(rsa $escapes$nl\
+$starts$ind$ind$mid(n $rsa_n) $escapes$nl\
+$starts$ind$ind$mid(e $rsa_e) $escapes$nl\
+$starts$ind$mid)$escapes$nl\
+$starts$mid)$quotes$nl";
+    ;;
 
-dsa_p=`line_to_sexpr "$dsa_p"`
-dsa_q=`line_to_sexpr "$dsa_q"`
-dsa_g=`line_to_sexpr "$dsa_g"`
-dsa_y=`line_to_sexpr "$dsa_y"`
+    17)
+    dsa_p=`find_a_line DSA p $TMPFILE`
+    dsa_q=`find_a_line DSA q $TMPFILE`
+    dsa_g=`find_a_line DSA g $TMPFILE`
+    dsa_y=`find_a_line DSA y $TMPFILE`
 
-echo -e $header$quotes"(public-key $escapes$nl\
+    dsa_p=`line_to_sexpr "$dsa_p"`
+    dsa_q=`line_to_sexpr "$dsa_q"`
+    dsa_g=`line_to_sexpr "$dsa_g"`
+    dsa_y=`line_to_sexpr "$dsa_y"`
+
+    echo -e $header$quotes"(public-key $escapes$nl\
 $starts$ind$mid(dsa $escapes$nl\
 $starts$ind$ind$mid(p $dsa_p) $escapes$nl\
 $starts$ind$ind$mid(q $dsa_q) $escapes$nl\
@@ -124,4 +142,7 @@ $starts$ind$ind$mid(y $dsa_y)$escapes$nl\
 $starts$ind$mid)$escapes$nl\
 $starts$mid)$quotes$nl";
 
+    ;;
+esac
+
 rm "$TMPFILE"
--
2.21.0

Reply | Threaded
Open this post in threaded view
|

[PATCH setup 4/4] Teach --pubkey option to handle RSA keys

Jon TURNEY
In reply to this post by Jon TURNEY
---
 crypto.cc | 106 +++++++++++++++++++++++++++++++++---------------------
 1 file changed, 65 insertions(+), 41 deletions(-)

diff --git a/crypto.cc b/crypto.cc
index 118d4d7..9a84376 100644
--- a/crypto.cc
+++ b/crypto.cc
@@ -42,10 +42,10 @@
 
 /*  Command-line options for specifying and controlling extra keys.  */
 static StringArrayOption ExtraKeyOption ('K', "pubkey",
- "URL of extra public key file (gpg format)");
+                                         "URL or absolute path of extra public key file (RFC4880 format)");
 
 static StringArrayOption SexprExtraKeyOption ('S', "sexpr-pubkey",
- "Extra public key in s-expr format");
+                                              "Extra DSA public key in s-expr format");
 
 static BoolOption UntrustedKeysOption (false, 'u', "untrusted-keys",
  "Use untrusted saved extra keys");
@@ -60,6 +60,9 @@ static const char *cygwin_pubkey_sexpr =
 /*  S-expr template for DSA pubkey.  */
 static const char *dsa_pubkey_templ = "(public-key (dsa (p %m) (q %m) (g %m) (y %m)))";
 
+/*  S-expr template for RSA pubkey.  */
+static const char *rsa_pubkey_templ = "(public-key (rsa (n %m) (e %m)))";
+
 /*  S-expr template for DSA signature.  */
 static const char *dsa_sig_templ = "(sig-val (dsa (r %m) (s %m)))";
 
@@ -104,17 +107,17 @@ struct key_data
 };
 
 /*  Callback hook for walking packets in gpg key file.  Extracts
-  the DSA coefficients from any public key packets encountered and
+  the key coefficients from any public key packets encountered and
   converts them into s-expr pubkey format, returning the public
   keys thus found to the caller in a vector in the userdata context.  */
 static enum
 pkt_cb_resp key_file_walker (struct packet_walker *wlk, unsigned char tag,
- size_t packetsize, size_t hdrpos)
+                             size_t packetsize, size_t hdrpos)
 {
   struct key_data *kdat = (struct key_data *)(wlk->userdata);
 
   MESSAGE ("key packet %d size %d at offs $%04x kdat $%08x\n", tag,
- packetsize, hdrpos, kdat);
+           packetsize, hdrpos, kdat);
 
   if (tag != RFC4880_PT_PUBLIC_KEY)
     return pktCONTINUE;
@@ -136,54 +139,75 @@ pkt_cb_resp key_file_walker (struct packet_walker *wlk, unsigned char tag,
     }
 
   char pkalg = pkt_getch (wlk->pfile);
-  if (pkalg != RFC4880_PK_DSA)
+  if ((pkalg != RFC4880_PK_DSA) && (pkalg != RFC4880_PK_RSA))
     {
       ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, pkalg, "unsupported key alg.");
       return pktCONTINUE;
     }
 
-  // Next, the four MPIs should be present.  Read them out,
-  // convert to an s-expr and add that to the list.
-  gcry_mpi_t p, q, g, y;
-  p = q = g = y = 0;
+  // Next, the key coefficient MPIs should be present.  Read them out, convert
+  // to an s-expr and add that to the list of keys.
+  size_t n;
+  gcry_sexp_t new_key;
 
-  if ((pkt_get_mpi (&p, wlk->pfile) >= 0)
- && (pkt_get_mpi (&q, wlk->pfile) >= 0)
- && (pkt_get_mpi (&g, wlk->pfile) >= 0)
- && (pkt_get_mpi (&y, wlk->pfile) >= 0))
+  if (pkalg == RFC4880_PK_DSA)
     {
-      // Convert to s-expr.
-      gcry_sexp_t new_key;
-      size_t n;
+      gcry_mpi_t p, q, g, y;
+      p = q = g = y = 0;
 
-      gcry_error_t rv = gcry_sexp_build (&new_key, &n, dsa_pubkey_templ, p, q, g, y);
-      if (rv != GPG_ERR_NO_ERROR)
- {
-  ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, rv, "while creating sig s-expr.");
-  return pktCONTINUE;
- }
+      if ((pkt_get_mpi (&p, wlk->pfile) >= 0)
+            && (pkt_get_mpi (&q, wlk->pfile) >= 0)
+            && (pkt_get_mpi (&g, wlk->pfile) >= 0)
+            && (pkt_get_mpi (&y, wlk->pfile) >= 0))
+        {
+          gcry_error_t rv = gcry_sexp_build (&new_key, &n, dsa_pubkey_templ, p, q, g, y);
+          if (rv != GPG_ERR_NO_ERROR)
+            {
+              ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, rv, "while creating sig s-expr.");
+              return pktCONTINUE;
+            }
+        }
 
-#if CRYPTODEBUGGING
-      // Debugging
-      char sexprbuf[GPG_KEY_SEXPR_BUF_SIZE];
-      n = gcry_sexp_sprint (new_key, GCRYSEXP_FMT_ADVANCED, sexprbuf,
- GPG_KEY_SEXPR_BUF_SIZE);
-      LogBabblePrintf ("key:%d\n'%s'", n, sexprbuf);
-#endif /* CRYPTODEBUGGING */
+      // Release temps and continue.
+      if (p)
+        gcry_mpi_release (p);
+      if (q)
+        gcry_mpi_release (q);
+      if (g)
+        gcry_mpi_release (g);
+      if (y)
+        gcry_mpi_release (y);
+    }
+  else if (pkalg == RFC4880_PK_RSA)
+    {
+      gcry_mpi_t n, e;
+      n = e = 0;
+
+      if ((pkt_get_mpi (&n, wlk->pfile) >= 0)
+          && (pkt_get_mpi (&e, wlk->pfile) >= 0))
+        {
+          gcry_sexp_t new_key;
+          size_t n;
 
-      // Return it to caller in the vector.
-      kdat->keys.push_back (new_key);
+          gcry_error_t rv = gcry_sexp_build (&new_key, &n, rsa_pubkey_templ, n, e);
+          if (rv != GPG_ERR_NO_ERROR)
+            {
+              ERRKIND (wlk->owner, IDS_CRYPTO_ERROR, rv, "while creating sig s-expr.");
+              return pktCONTINUE;
+            }
+        }
     }
 
-  // Release temps and continue.
-  if (p)
-    gcry_mpi_release (p);
-  if (q)
-    gcry_mpi_release (q);
-  if (g)
-    gcry_mpi_release (g);
-  if (y)
-    gcry_mpi_release (y);
+#if CRYPTODEBUGGING
+  // Debugging
+  char sexprbuf[GPG_KEY_SEXPR_BUF_SIZE];
+  n = gcry_sexp_sprint (new_key, GCRYSEXP_FMT_ADVANCED, sexprbuf,
+                        GPG_KEY_SEXPR_BUF_SIZE);
+  LogBabblePrintf ("key:%d\n'%s'", n, sexprbuf);
+#endif /* CRYPTODEBUGGING */
+
+  // Return it to caller in the vector.
+  kdat->keys.push_back (new_key);
 
   return pktCONTINUE;
 }
--
2.21.0