Add a simple (raw) PKCS#1 padding mode
authorDmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Sun, 22 Dec 2013 13:12:28 +0000 (17:12 +0400)
committerWerner Koch <wk@gnupg.org>
Tue, 4 Mar 2014 10:00:12 +0000 (11:00 +0100)
* src/cipher.h (PUBKEY_ENC_PKCS1_RAW): New.
* cipher/pubkey-util.c (_gcry_pk_util_parse_flaglist): Handle pkcs1-raw
  flag.
* cipher/pubkey-util.c (_gcry_pk_util_data_to_mpi):
  Handle s-exp like (data (flags pkcs1-raw) (value xxxxx))
* cipher/rsa-common.c (_gcry_rsa_pkcs1_encode_raw_for_sig):
  PKCS#1-encode data with embedded hash OID for signature verification.
* tests/basic.c (check_pubkey_sign): Add tests for s-exps with pkcs1-raw
  flag.

--
Allow user to specify (flags pkcs1-raw) to enable pkcs1 padding of raw
value (no hash algorithm is specified). It is up to the user to verify
that the passed value is properly formatted and includes DER-encoded
ASN OID of the used hash function.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
cipher/pubkey-internal.h
cipher/pubkey-util.c
cipher/rsa-common.c
src/cipher.h
tests/basic.c

index 193248c..b8167c7 100644 (file)
@@ -56,6 +56,10 @@ gpg_err_code_t
 _gcry_rsa_pkcs1_decode_for_enc (unsigned char **r_result, size_t *r_resultlen,
                                 unsigned int nbits, gcry_mpi_t value);
 gpg_err_code_t
+_gcry_rsa_pkcs1_encode_raw_for_sig (gcry_mpi_t *r_result, unsigned int nbits,
+                                const unsigned char *value, size_t valuelen);
+
+gpg_err_code_t
 _gcry_rsa_pkcs1_encode_for_sig (gcry_mpi_t *r_result, unsigned int nbits,
                                 const unsigned char *value, size_t valuelen,
                                 int algo);
index 616b499..514f1eb 100644 (file)
@@ -142,6 +142,16 @@ _gcry_pk_util_parse_flaglist (gcry_sexp_t list,
             rc = GPG_ERR_INV_FLAG;
           break;
 
+       case 9:
+          if (!memcmp (s, "pkcs1-raw", 9) && encoding == PUBKEY_ENC_UNKNOWN)
+            {
+              encoding = PUBKEY_ENC_PKCS1_RAW;
+              flags |= PUBKEY_FLAG_FIXEDLEN;
+            }
+          else if (!igninvflag)
+            rc = GPG_ERR_INV_FLAG;
+          break;
+
         case 10:
           if (!memcmp (s, "igninvflag", 10))
             igninvflag = 1;
@@ -850,6 +860,21 @@ _gcry_pk_util_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
                                                  ctx->hash_algo);
         }
     }
+  else if (ctx->encoding == PUBKEY_ENC_PKCS1_RAW && lvalue
+          && (ctx->op == PUBKEY_OP_SIGN || ctx->op == PUBKEY_OP_VERIFY))
+    {
+      const void * value;
+      size_t valuelen;
+
+      if (sexp_length (lvalue) != 2)
+        rc = GPG_ERR_INV_OBJ;
+      else if ( !(value=sexp_nth_data (lvalue, 1, &valuelen))
+                || !valuelen )
+        rc = GPG_ERR_INV_OBJ;
+      else
+        rc = _gcry_rsa_pkcs1_encode_raw_for_sig (ret_mpi, ctx->nbits,
+                                                 value, valuelen);
+    }
   else if (ctx->encoding == PUBKEY_ENC_OAEP && lvalue
           && ctx->op == PUBKEY_OP_ENCRYPT)
     {
index 4f5a659..f56e989 100644 (file)
@@ -319,6 +319,71 @@ _gcry_rsa_pkcs1_encode_for_sig (gcry_mpi_t *r_result, unsigned int nbits,
   return rc;
 }
 
+/* Encode {VALUE,VALUELEN} for an NBITS keys using the pkcs#1 block
+   type 1 padding.  On success the result is stored as a new MPI at
+   R_RESULT.  On error the value at R_RESULT is undefined.
+
+   We encode the value in this way:
+
+     0  1  PAD(n bytes)  0  VALUE(valuelen bytes)
+
+   0   is a marker we unfortunately can't encode because we return an
+       MPI which strips all leading zeroes.
+   1   is the block type.
+   PAD consists of 0xff bytes.
+   0   marks the end of the padding.
+
+   (Note that PGP prior to version 2.3 encoded the message digest as:
+      0   1   MD(16 bytes)   0   PAD(n bytes)   1
+    The MD is always 16 bytes here because it's always MD5.  GnuPG
+    does not not support pre-v2.3 signatures, but I'm including this
+    comment so the information is easily found if needed.)
+*/
+gpg_err_code_t
+_gcry_rsa_pkcs1_encode_raw_for_sig (gcry_mpi_t *r_result, unsigned int nbits,
+                                const unsigned char *value, size_t valuelen)
+{
+  gcry_err_code_t rc = 0;
+  gcry_error_t err;
+  byte *frame = NULL;
+  size_t nframe = (nbits+7) / 8;
+  int i;
+  size_t n;
+
+  if ( !valuelen || valuelen + 4 > nframe)
+    {
+      /* Can't encode an DLEN byte digest MD into an NFRAME byte
+         frame.  */
+      return GPG_ERR_TOO_SHORT;
+    }
+
+  if ( !(frame = xtrymalloc (nframe)) )
+    return gpg_err_code_from_syserror ();
+
+  /* Assemble the pkcs#1 block type 1. */
+  n = 0;
+  frame[n++] = 0;
+  frame[n++] = 1; /* block type */
+  i = nframe - valuelen - 3 ;
+  gcry_assert (i > 1);
+  memset (frame+n, 0xff, i );
+  n += i;
+  frame[n++] = 0;
+  memcpy (frame+n, value, valuelen );
+  n += valuelen;
+  gcry_assert (n == nframe);
+
+  /* Convert it into an MPI. */
+  err = _gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, frame, n, &nframe);
+  if (err)
+    rc = gcry_err_code (err);
+  else if (DBG_CIPHER)
+    log_mpidump ("PKCS#1 block type 1 encoded data", *r_result);
+  xfree (frame);
+
+  return rc;
+}
+
 
 /* Mask generation function for OAEP.  See RFC-3447 B.2.1.  */
 static gcry_err_code_t
index 10bfe0c..26ffddc 100644 (file)
@@ -54,6 +54,7 @@ enum pk_encoding
   {
     PUBKEY_ENC_RAW,
     PUBKEY_ENC_PKCS1,
+    PUBKEY_ENC_PKCS1_RAW,
     PUBKEY_ENC_OAEP,
     PUBKEY_ENC_PSS,
     PUBKEY_ENC_UNKNOWN
index 4474a9d..e21e055 100644 (file)
@@ -5155,6 +5155,10 @@ check_pubkey_sign (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo)
        " (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n",
        GCRY_PK_RSA,
        0 },
+      { "(data\n (flags pkcs1-raw)\n"
+       " (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n",
+       GCRY_PK_RSA,
+       GPG_ERR_CONFLICT },
       { "(data\n (flags oaep)\n"
        " (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n",
        0,
@@ -5187,6 +5191,10 @@ check_pubkey_sign (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo)
        " (value #11223344556677889900AA#))\n",
        GCRY_PK_RSA,
        GPG_ERR_CONFLICT },
+      { "(data\n (flags pkcs1-raw)\n"
+       " (value #11223344556677889900AA#))\n",
+       GCRY_PK_RSA,
+       0 },
       { "(data\n (flags raw foo)\n"
        " (value #11223344556677889900AA#))\n",
        0,