[PATCH] scd: RSA_CRT and RSA_CRT_N support

Jonas Borgström jonas at borgstrom.se
Wed Aug 28 12:28:51 CEST 2013


Hi,

the attached patches for master and STABLE-BRANCH-2-0 adds support for
the RSA_CRT and RSA_CRT_N key format as per the openpgp-card-2.0
specification.

The patch has been used to successfully import keys to a yubikey neo[1]
card running the ykneo-openpgp[2] applet. The latest firmware is needed
for key import.

[1]: http://www.yubico.com/yubikey-neo
[2]: https://github.com/jborg/ykneo-openpgp

Cheers,
Jonas
-------------- next part --------------
>From 9bb45e86f0d2951356a35a254bdcfcd712c481b9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20Borgstr=C3=B6m?= <jonas at borgstrom.se>
Date: Wed, 28 Aug 2013 11:21:10 +0200
Subject: [PATCH] scd: add support for RSA_CRT and RSA_CRT_N key import.

 * scd/app-openpgp.c (do_writekey): Added RSA_CRT and RSA_CRT_N support.
---
 scd/app-openpgp.c |   75 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 68 insertions(+), 7 deletions(-)

diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index 011c248..75a5787 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -2508,10 +2508,13 @@ build_privkey_template (app_t app, int keyno,
                         const unsigned char *rsa_e, size_t rsa_e_len,
                         const unsigned char *rsa_p, size_t rsa_p_len,
                         const unsigned char *rsa_q, size_t rsa_q_len,
+                        const unsigned char *rsa_u, size_t rsa_u_len,
+                        const unsigned char *rsa_dp, size_t rsa_dp_len,
+                        const unsigned char *rsa_dq, size_t rsa_dq_len,
                         unsigned char **result, size_t *resultlen)
 {
   size_t rsa_e_reqlen;
-  unsigned char privkey[7*(1+3)];
+  unsigned char privkey[7*(1+3+3)];
   size_t privkey_len;
   unsigned char exthdr[2+2+3];
   size_t exthdr_len;
@@ -2529,17 +2532,16 @@ build_privkey_template (app_t app, int keyno,
     {
     case RSA_STD:
     case RSA_STD_N:
-      break;
     case RSA_CRT:
     case RSA_CRT_N:
-      return gpg_error (GPG_ERR_NOT_SUPPORTED);
+      break;
 
     default:
       return gpg_error (GPG_ERR_INV_VALUE);
     }
 
-  /* Get the required length for E.  */
-  rsa_e_reqlen = app->app_local->keyattr[keyno].rsa.e_bits/8;
+  /* Get the required length for E. Rounded up to the nearest byte  */
+  rsa_e_reqlen = (app->app_local->keyattr[keyno].rsa.e_bits + 7) / 8;
   assert (rsa_e_len <= rsa_e_reqlen);
 
   /* Build the 7f48 cardholder private key template.  */
@@ -2555,6 +2557,17 @@ build_privkey_template (app_t app, int keyno,
   tp += add_tlv (tp, 0x93, rsa_q_len);
   datalen += rsa_q_len;
 
+  if (app->app_local->keyattr[keyno].rsa.format == RSA_CRT
+      || app->app_local->keyattr[keyno].rsa.format == RSA_CRT_N)
+    {
+      tp += add_tlv (tp, 0x94, rsa_u_len);
+      datalen += rsa_u_len;
+      tp += add_tlv (tp, 0x95, rsa_dp_len);
+      datalen += rsa_dp_len;
+      tp += add_tlv (tp, 0x96, rsa_dq_len);
+      datalen += rsa_dq_len;
+    }
+
   if (app->app_local->keyattr[keyno].rsa.format == RSA_STD_N
       || app->app_local->keyattr[keyno].rsa.format == RSA_CRT_N)
     {
@@ -2608,6 +2621,17 @@ build_privkey_template (app_t app, int keyno,
   memcpy (tp, rsa_q, rsa_q_len);
   tp += rsa_q_len;
 
+  if (app->app_local->keyattr[keyno].rsa.format == RSA_CRT
+      || app->app_local->keyattr[keyno].rsa.format == RSA_CRT_N)
+    {
+      memcpy (tp, rsa_u, rsa_u_len);
+      tp += rsa_u_len;
+      memcpy (tp, rsa_dp, rsa_dp_len);
+      tp += rsa_dp_len;
+      memcpy (tp, rsa_dq, rsa_dq_len);
+      tp += rsa_dq_len;
+    }
+
   if (app->app_local->keyattr[keyno].rsa.format == RSA_STD_N
       || app->app_local->keyattr[keyno].rsa.format == RSA_CRT_N)
     {
@@ -2954,16 +2978,53 @@ do_writekey (app_t app, ctrl_t ctrl,
 
   if (app->app_local->extcap.is_v2)
     {
-      /* Build the private key template as described in section 4.3.3.7 of
-         the OpenPGP card specs version 2.0.  */
+      unsigned char *rsa_u, *rsa_dp, rsa_dq;
+      size_t rsa_u_len, rsa_dp_len, rsa_dq_len;
+      gcry_mpi_t mpi_e, mpi_p, mpi_q;
+      gcry_mpi_t mpi_u = gcry_mpi_snew (0);
+      gcry_mpi_t mpi_dp = gcry_mpi_snew (0);
+      gcry_mpi_t mpi_dq = gcry_mpi_snew (0);
+      gcry_mpi_t mpi_tmp = gcry_mpi_snew (0);
       int exmode;
 
+      /* Calculate the u, dp and dq components needed by RSA_CRT cards */
+      gcry_mpi_scan (&mpi_e, GCRYMPI_FMT_USG, rsa_e, rsa_e_len, NULL);
+      gcry_mpi_scan (&mpi_p, GCRYMPI_FMT_USG, rsa_p, rsa_p_len, NULL);
+      gcry_mpi_scan (&mpi_q, GCRYMPI_FMT_USG, rsa_q, rsa_q_len, NULL);
+
+      gcry_mpi_invm (mpi_u, mpi_q, mpi_p);
+      gcry_mpi_sub_ui (mpi_tmp, mpi_p, 1);
+      gcry_mpi_invm (mpi_dp, mpi_e, mpi_tmp);
+      gcry_mpi_sub_ui (mpi_tmp, mpi_q, 1);
+      gcry_mpi_invm (mpi_dq, mpi_e, mpi_tmp);
+
+      gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_u, &rsa_u_len, mpi_u);
+      gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_dp, &rsa_dp_len, mpi_dp);
+      gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_dq, &rsa_dq_len, mpi_dq);
+
+      gcry_mpi_release (mpi_e);
+      gcry_mpi_release (mpi_p);
+      gcry_mpi_release (mpi_q);
+      gcry_mpi_release (mpi_u);
+      gcry_mpi_release (mpi_dp);
+      gcry_mpi_release (mpi_dq);
+      gcry_mpi_release (mpi_tmp);
+
+      /* Build the private key template as described in section 4.3.3.7 of
+         the OpenPGP card specs version 2.0.  */
       err = build_privkey_template (app, keyno,
                                     rsa_n, rsa_n_len,
                                     rsa_e, rsa_e_len,
                                     rsa_p, rsa_p_len,
                                     rsa_q, rsa_q_len,
+                                    rsa_u, rsa_u_len,
+                                    rsa_dp, rsa_dp_len,
+                                    rsa_dq, rsa_dq_len,
                                     &template, &template_len);
+      xfree(rsa_u);
+      xfree(rsa_dp);
+      xfree(rsa_dq);
+
       if (err)
         goto leave;
 
-- 
1.7.9.6 (Apple Git-31.1)

-------------- next part --------------
>From 24cb29c308261a9b060bcc62ac325f184f237a80 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jonas=20Borgstr=C3=B6m?= <jonas at borgstrom.se>
Date: Wed, 28 Aug 2013 11:21:10 +0200
Subject: [PATCH] scd: add support for RSA_CRT and RSA_CRT_N key import.

 * scd/app-openpgp.c (do_writekey): Added RSA_CRT and RSA_CRT_N support.
---
 scd/app-openpgp.c |   75 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 68 insertions(+), 7 deletions(-)

diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index 9186e18..20fd2de 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -2380,10 +2380,13 @@ build_privkey_template (app_t app, int keyno,
                         const unsigned char *rsa_e, size_t rsa_e_len,
                         const unsigned char *rsa_p, size_t rsa_p_len,
                         const unsigned char *rsa_q, size_t rsa_q_len,
+                        const unsigned char *rsa_u, size_t rsa_u_len,
+                        const unsigned char *rsa_dp, size_t rsa_dp_len,
+                        const unsigned char *rsa_dq, size_t rsa_dq_len,
                         unsigned char **result, size_t *resultlen)
 {
   size_t rsa_e_reqlen;
-  unsigned char privkey[7*(1+3)];
+  unsigned char privkey[7*(1+3+3)];
   size_t privkey_len;
   unsigned char exthdr[2+2+3];
   size_t exthdr_len;
@@ -2401,17 +2404,16 @@ build_privkey_template (app_t app, int keyno,
     {
     case RSA_STD:
     case RSA_STD_N:
-      break;
     case RSA_CRT:
     case RSA_CRT_N:
-      return gpg_error (GPG_ERR_NOT_SUPPORTED);
+      break;
 
     default:
       return gpg_error (GPG_ERR_INV_VALUE);
     }
 
-  /* Get the required length for E.  */
-  rsa_e_reqlen = app->app_local->keyattr[keyno].e_bits/8;
+  /* Get the required length for E. Rounded up to the nearest byte  */
+  rsa_e_reqlen = (app->app_local->keyattr[keyno].e_bits + 7) / 8;
   assert (rsa_e_len <= rsa_e_reqlen);
 
   /* Build the 7f48 cardholder private key template.  */
@@ -2427,6 +2429,17 @@ build_privkey_template (app_t app, int keyno,
   tp += add_tlv (tp, 0x93, rsa_q_len);
   datalen += rsa_q_len;
 
+  if (app->app_local->keyattr[keyno].format == RSA_CRT
+      || app->app_local->keyattr[keyno].format == RSA_CRT_N)
+    {
+      tp += add_tlv (tp, 0x94, rsa_u_len);
+      datalen += rsa_u_len;
+      tp += add_tlv (tp, 0x95, rsa_dp_len);
+      datalen += rsa_dp_len;
+      tp += add_tlv (tp, 0x96, rsa_dq_len);
+      datalen += rsa_dq_len;
+    }
+
   if (app->app_local->keyattr[keyno].format == RSA_STD_N
       || app->app_local->keyattr[keyno].format == RSA_CRT_N)
     {
@@ -2480,6 +2493,17 @@ build_privkey_template (app_t app, int keyno,
   memcpy (tp, rsa_q, rsa_q_len);
   tp += rsa_q_len;
 
+  if (app->app_local->keyattr[keyno].format == RSA_CRT
+      || app->app_local->keyattr[keyno].format == RSA_CRT_N)
+    {
+      memcpy (tp, rsa_u, rsa_u_len);
+      tp += rsa_u_len;
+      memcpy (tp, rsa_dp, rsa_dp_len);
+      tp += rsa_dp_len;
+      memcpy (tp, rsa_dq, rsa_dq_len);
+      tp += rsa_dq_len;
+    }
+
   if (app->app_local->keyattr[keyno].format == RSA_STD_N
       || app->app_local->keyattr[keyno].format == RSA_CRT_N)
     {
@@ -2826,16 +2850,53 @@ do_writekey (app_t app, ctrl_t ctrl,
 
   if (app->app_local->extcap.is_v2)
     {
-      /* Build the private key template as described in section 4.3.3.7 of
-         the OpenPGP card specs version 2.0.  */
+      unsigned char *rsa_u, *rsa_dp, rsa_dq;
+      size_t rsa_u_len, rsa_dp_len, rsa_dq_len;
+      gcry_mpi_t mpi_e, mpi_p, mpi_q;
+      gcry_mpi_t mpi_u = gcry_mpi_snew (0);
+      gcry_mpi_t mpi_dp = gcry_mpi_snew (0);
+      gcry_mpi_t mpi_dq = gcry_mpi_snew (0);
+      gcry_mpi_t mpi_tmp = gcry_mpi_snew (0);
       int exmode;
 
+      /* Calculate the u, dp and dq components needed by RSA_CRT cards */
+      gcry_mpi_scan (&mpi_e, GCRYMPI_FMT_USG, rsa_e, rsa_e_len, NULL);
+      gcry_mpi_scan (&mpi_p, GCRYMPI_FMT_USG, rsa_p, rsa_p_len, NULL);
+      gcry_mpi_scan (&mpi_q, GCRYMPI_FMT_USG, rsa_q, rsa_q_len, NULL);
+
+      gcry_mpi_invm (mpi_u, mpi_q, mpi_p);
+      gcry_mpi_sub_ui (mpi_tmp, mpi_p, 1);
+      gcry_mpi_invm (mpi_dp, mpi_e, mpi_tmp);
+      gcry_mpi_sub_ui (mpi_tmp, mpi_q, 1);
+      gcry_mpi_invm (mpi_dq, mpi_e, mpi_tmp);
+
+      gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_u, &rsa_u_len, mpi_u);
+      gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_dp, &rsa_dp_len, mpi_dp);
+      gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_dq, &rsa_dq_len, mpi_dq);
+
+      gcry_mpi_release (mpi_e);
+      gcry_mpi_release (mpi_p);
+      gcry_mpi_release (mpi_q);
+      gcry_mpi_release (mpi_u);
+      gcry_mpi_release (mpi_dp);
+      gcry_mpi_release (mpi_dq);
+      gcry_mpi_release (mpi_tmp);
+
+      /* Build the private key template as described in section 4.3.3.7 of
+         the OpenPGP card specs version 2.0.  */
       err = build_privkey_template (app, keyno,
                                     rsa_n, rsa_n_len,
                                     rsa_e, rsa_e_len,
                                     rsa_p, rsa_p_len,
                                     rsa_q, rsa_q_len,
+                                    rsa_u, rsa_u_len,
+                                    rsa_dp, rsa_dp_len,
+                                    rsa_dq, rsa_dq_len,
                                     &template, &template_len);
+      xfree(rsa_u);
+      xfree(rsa_dp);
+      xfree(rsa_dq);
+
       if (err)
         goto leave;
 
-- 
1.7.9.6 (Apple Git-31.1)



More information about the Gnupg-devel mailing list