linux-security-module.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Roberto Sassu <roberto.sassu@huaweicloud.com>
To: dhowells@redhat.com, dwmw2@infradead.org,
	herbert@gondor.apana.org.au, davem@davemloft.net,
	jarkko@kernel.org, zohar@linux.ibm.com,
	dmitry.kasatkin@gmail.com, paul@paul-moore.com,
	jmorris@namei.org, serge@hallyn.com
Cc: linux-kernel@vger.kernel.org, keyrings@vger.kernel.org,
	linux-crypto@vger.kernel.org, linux-integrity@vger.kernel.org,
	linux-security-module@vger.kernel.org, pbrobinson@gmail.com,
	zbyszek@in.waw.pl, wiktor@metacode.biz,
	devel@lists.sequoia-pgp.org, gnupg-devel@gnupg.org,
	ebiggers@kernel.org, Jason@zx2c4.com, mail@maciej.szmigiero.name,
	antony@vennard.ch, konstantin@linuxfoundation.org,
	James.Bottomley@HansenPartnership.com,
	Roberto Sassu <roberto.sassu@huawei.com>
Subject: [RFC][GNUPG][PATCH v3 2/2] Convert PGP signatures to the user asymmetric key signatures format
Date: Thu, 20 Jul 2023 17:32:47 +0200	[thread overview]
Message-ID: <20230720153247.3755856-12-roberto.sassu@huaweicloud.com> (raw)
In-Reply-To: <20230720153247.3755856-1-roberto.sassu@huaweicloud.com>

From: Roberto Sassu <roberto.sassu@huawei.com>

Enhance the gpg command --conv-kernel to also support converting PGP
signatures to the user asymmetric key signatures format.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 g10/conv-packet.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++
 g10/conv-packet.h |   7 ++
 g10/mainproc.c    |   1 +
 3 files changed, 208 insertions(+)

diff --git a/g10/conv-packet.c b/g10/conv-packet.c
index 8f2fc40b980..be7eb3c80f8 100644
--- a/g10/conv-packet.c
+++ b/g10/conv-packet.c
@@ -28,6 +28,8 @@
 #include <linux/uasym_parser.h>
 #include <asm/byteorder.h>
 #include <linux/pub_key_info.h>
+#include <linux/sig_enc_info.h>
+#include <linux/hash_info.h>
 
 #include "gpg.h"
 #include "../common/util.h"
@@ -38,6 +40,16 @@
 
 static estream_t listfp;
 
+static const enum hash_algo pgp_hash_algorithms[DIGEST_ALGO_SHA224 + 1] = {
+  [DIGEST_ALGO_MD5]                = HASH_ALGO_MD5,
+  [DIGEST_ALGO_SHA1]               = HASH_ALGO_SHA1,
+  [DIGEST_ALGO_RMD160]             = HASH_ALGO_RIPE_MD_160,
+  [DIGEST_ALGO_SHA256]             = HASH_ALGO_SHA256,
+  [DIGEST_ALGO_SHA384]             = HASH_ALGO_SHA384,
+  [DIGEST_ALGO_SHA512]             = HASH_ALGO_SHA512,
+  [DIGEST_ALGO_SHA224]             = HASH_ALGO_SHA224,
+};
+
 static void init_output(void)
 {
   if (!listfp)
@@ -282,3 +294,191 @@ out:
   xfree(buffer);
   return 0;
 }
+
+/* Taken from sig_check.c */
+static int get_sig_data(PKT_signature * sig, __u8 **buf, __u32 *buf_len)
+{
+  __u8 *buf_ptr;
+
+  *buf = xmalloc_clear(4 + 2 + sig->hashed->len + 6);
+  if (!*buf)
+    return -ENOMEM;
+
+  buf_ptr = *buf;
+
+  if (sig->version >= 4)
+    *buf_ptr++ = sig->version;
+
+  *buf_ptr++ = sig->sig_class;
+  if (sig->version < 4)
+    {
+      u32 a = sig->timestamp;
+      *buf_ptr++ = ((a >> 24) & 0xff);
+      *buf_ptr++ = ((a >> 16) & 0xff);
+      *buf_ptr++ = ((a >>  8) & 0xff);
+      *buf_ptr++ = (a & 0xff);
+    }
+  else
+    {
+      size_t n;
+      *buf_ptr++ = sig->pubkey_algo;
+      *buf_ptr++ = sig->digest_algo;
+      if (sig->hashed)
+        {
+          n = sig->hashed->len;
+          *buf_ptr++ = n >> 8;
+          *buf_ptr++ = n;
+          memcpy(buf_ptr, sig->hashed->data, n);
+          buf_ptr += n;
+          n += 6;
+	}
+      else
+        {
+	  /* Two octets for the (empty) length of the hashed
+           * section. */
+          *buf_ptr++ = 0;
+	  *buf_ptr++ = 0;
+	  n = 6;
+	}
+      /* Add some magic per Section 5.2.4 of RFC 4880.  */
+      *buf_ptr++ = sig->version;
+      *buf_ptr++ = 0xff;
+      *buf_ptr++ = n >> 24;
+      *buf_ptr++ = n >> 16;
+      *buf_ptr++ = n >>  8;
+      *buf_ptr++ = n;
+    }
+
+    *buf_len = buf_ptr - *buf;
+    return 0;
+}
+
+int write_kernel_signature(PKT_signature *sig)
+{
+  unsigned char *buffer = NULL;
+  size_t buffer_len = 0, buffer_len_padded = 0;
+  struct tlv_hdr hdr = { 0 };
+  struct tlv_entry e_key_algo = { 0 };
+  struct tlv_entry e_hash_algo = { 0 };
+  struct tlv_entry e_sig_encoding = { 0 };
+  struct tlv_entry e_sig_kid0 = { 0 };
+  struct tlv_entry e_sig_pub = { 0 };
+  struct tlv_entry e_sig_data = { 0 };
+  __u8 pkey_algo;
+  __u8 hash_algo;
+  __u8 sig_encoding = SIG_ENC_PKCS1;
+  __u8 *sig_data = NULL;
+  __u32 _keyid, sig_data_len;
+  __u64 total_len = 0;
+  gpg_error_t err;
+  int ret = 0;
+
+  init_output();
+
+  ret = pgp_to_kernel_algo(sig->pubkey_algo, NULL, &pkey_algo);
+  if (ret < 0)
+    return ret;
+
+  if (pkey_algo == PKEY_ALGO_ECDSA)
+    sig_encoding = SIG_ENC_X962;
+
+  hash_algo = pgp_hash_algorithms[sig->digest_algo];
+
+  /* sig key algo */
+  e_key_algo.field = __cpu_to_be64(SIG_KEY_ALGO);
+  e_key_algo.length = __cpu_to_be64(sizeof(pkey_algo));
+  total_len += sizeof(e_key_algo) + sizeof(pkey_algo);
+
+  /* sig hash algo */
+  e_hash_algo.field = __cpu_to_be64(SIG_HASH_ALGO);
+  e_hash_algo.length = __cpu_to_be64(sizeof(hash_algo));
+  total_len += sizeof(e_hash_algo) + sizeof(hash_algo);
+
+  /* sig encoding */
+  e_sig_encoding.field = __cpu_to_be64(SIG_ENC);
+  e_sig_encoding.length = __cpu_to_be64(sizeof(sig_encoding));
+  total_len += sizeof(e_sig_encoding) + sizeof(sig_encoding);
+
+  /* sig kid0 */
+  e_sig_kid0.field = __cpu_to_be64(SIG_KID0);
+  e_sig_kid0.length = __cpu_to_be64(2 * sizeof(*sig->keyid));
+  total_len += sizeof(e_sig_kid0) + 2 * sizeof(*sig->keyid);
+
+  /* sig data */
+  e_sig_data.field = __cpu_to_be64(SIG_DATA_END);
+  ret = get_sig_data(sig, &sig_data, &sig_data_len);
+  if (ret < 0)
+    goto out;
+
+  e_sig_data.length = __cpu_to_be64(sig_data_len);
+  total_len += sizeof(e_sig_data) + sig_data_len;
+
+  switch (sig->pubkey_algo) {
+  case PUBKEY_ALGO_ECDSA:
+    ret = mpis_to_asn1_sequence(sig->data, 2, &buffer, &buffer_len_padded);
+    break;
+  case PUBKEY_ALGO_RSA:
+    err = gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &buffer_len, sig->data[0]);
+    if (err) {
+      ret = -EINVAL;
+      break;
+    }
+
+    buffer_len_padded = ((buffer_len + 7) / 8) * 8;
+    buffer = xmalloc_clear(buffer_len_padded);
+    if (!buffer) {
+      ret = -ENOMEM;
+      break;
+    }
+
+    err = gcry_mpi_print(GCRYMPI_FMT_USG,
+                         buffer + buffer_len_padded - buffer_len, buffer_len,
+                         &buffer_len, sig->data[0]);
+    if (err)
+      ret = -EINVAL;
+    break;
+  default:
+    ret = -EOPNOTSUPP;
+    break;
+  }
+
+  if (ret < 0)
+    goto out;
+
+  /* key blob */
+  e_sig_pub.field = __cpu_to_be64(SIG_S);
+  e_sig_pub.length = __cpu_to_be64(buffer_len_padded);
+  total_len += sizeof(e_sig_pub) + buffer_len_padded;
+
+  hdr.data_type = __cpu_to_be64(TYPE_SIG);
+  hdr.num_fields = __cpu_to_be64(6);
+  hdr.total_len = __cpu_to_be64(total_len);
+
+  es_write(listfp, &hdr, sizeof(hdr), NULL);
+
+  es_write(listfp, &e_key_algo, sizeof(e_key_algo), NULL);
+  es_write(listfp, &pkey_algo, sizeof(pkey_algo), NULL);
+
+  es_write(listfp, &e_hash_algo, sizeof(e_hash_algo), NULL);
+  es_write(listfp, &hash_algo, sizeof(hash_algo), NULL);
+
+  es_write(listfp, &e_sig_encoding, sizeof(e_sig_encoding), NULL);
+  es_write(listfp, &sig_encoding, sizeof(sig_encoding), NULL);
+
+  es_write(listfp, &e_sig_kid0, sizeof(e_sig_kid0), NULL);
+  _keyid = __cpu_to_be32(sig->keyid[0]);
+  es_write(listfp, &_keyid, sizeof(_keyid), NULL);
+  _keyid = __cpu_to_be32(sig->keyid[1]);
+  es_write(listfp, &_keyid, sizeof(_keyid), NULL);
+
+  es_write(listfp, &e_sig_pub, sizeof(e_sig_pub), NULL);
+  es_write(listfp, buffer, buffer_len_padded, NULL);
+
+  es_write(listfp, &e_sig_data, sizeof(e_sig_data), NULL);
+  es_write(listfp, sig_data, sig_data_len, NULL);
+
+out:
+  xfree(sig_data);
+  xfree(buffer);
+  return 0;
+}
diff --git a/g10/conv-packet.h b/g10/conv-packet.h
index d35acb985fc..ef718de0a7a 100644
--- a/g10/conv-packet.h
+++ b/g10/conv-packet.h
@@ -26,6 +26,7 @@
 
 #ifdef UASYM_KEYS_SIGS
 int write_kernel_key(PKT_public_key *pk);
+int write_kernel_signature(PKT_signature *sig);
 #else
 static inline int write_kernel_key(PKT_public_key *pk)
 {
@@ -33,5 +34,11 @@ static inline int write_kernel_key(PKT_public_key *pk)
    return 0;
 }
 
+static inline int write_kernel_signature(PKT_signature *sig)
+{
+   (void)sig;
+   return 0;
+}
+
 #endif /* UASYM_KEYS_SIGS */
 #endif /*G10_CONV_PACKET_H*/
diff --git a/g10/mainproc.c b/g10/mainproc.c
index edef9907127..1cb08d82000 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -502,6 +502,7 @@ proc_conv (PACKET *pkt)
   switch (pkt->pkttype)
     {
     case PKT_PUBLIC_KEY: write_kernel_key(pkt->pkt.public_key); break;
+    case PKT_SIGNATURE: write_kernel_signature(pkt->pkt.signature); break;
     default: break;
     }
   free_packet(pkt, NULL);
-- 
2.34.1


  parent reply	other threads:[~2023-07-20 15:37 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-07-20 15:32 [RFC][PATCH v3 0/9] KEYS: Introduce user asymmetric keys and signatures Roberto Sassu
2023-07-20 15:32 ` [RFC][PATCH v3 1/9] lib: Add TLV parser Roberto Sassu
2023-07-20 15:32 ` [RFC][PATCH v3 2/9] crypto: Export public key algorithm information Roberto Sassu
2023-07-20 15:32 ` [RFC][PATCH v3 3/9] crypto: Export signature encoding information Roberto Sassu
2023-07-20 15:32 ` [RFC][PATCH v3 4/9] KEYS: asymmetric: Introduce the user asymmetric key parser Roberto Sassu
2023-07-20 15:32 ` [RFC][PATCH v3 5/9] KEYS: asymmetric: Introduce the user asymmetric key signature parser Roberto Sassu
2023-07-20 15:32 ` [RFC][PATCH v3 6/9] verification: Add verify_uasym_signature() and verify_uasym_sig_message() Roberto Sassu
2023-07-20 15:32 ` [RFC][PATCH v3 7/9] KEYS: asymmetric: Preload user asymmetric keys from a keyring blob Roberto Sassu
2023-07-20 15:32 ` [RFC][PATCH v3 8/9] KEYS: Introduce load_uasym_keyring() Roberto Sassu
2023-07-20 15:32 ` [RFC][PATCH v3 9/9] ima: Support non-PKCS#7 modsig types Roberto Sassu
2023-07-20 15:32 ` [RFC][GNUPG][PATCH v3 1/2] Convert PGP keys to the user asymmetric keys format Roberto Sassu
2023-07-20 15:32 ` Roberto Sassu [this message]
2023-07-20 17:38 ` [RFC][PATCH v3 0/9] KEYS: Introduce user asymmetric keys and signatures Jarkko Sakkinen
2023-07-21  7:04   ` Roberto Sassu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230720153247.3755856-12-roberto.sassu@huaweicloud.com \
    --to=roberto.sassu@huaweicloud.com \
    --cc=James.Bottomley@HansenPartnership.com \
    --cc=Jason@zx2c4.com \
    --cc=antony@vennard.ch \
    --cc=davem@davemloft.net \
    --cc=devel@lists.sequoia-pgp.org \
    --cc=dhowells@redhat.com \
    --cc=dmitry.kasatkin@gmail.com \
    --cc=dwmw2@infradead.org \
    --cc=ebiggers@kernel.org \
    --cc=gnupg-devel@gnupg.org \
    --cc=herbert@gondor.apana.org.au \
    --cc=jarkko@kernel.org \
    --cc=jmorris@namei.org \
    --cc=keyrings@vger.kernel.org \
    --cc=konstantin@linuxfoundation.org \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-integrity@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=mail@maciej.szmigiero.name \
    --cc=paul@paul-moore.com \
    --cc=pbrobinson@gmail.com \
    --cc=roberto.sassu@huawei.com \
    --cc=serge@hallyn.com \
    --cc=wiktor@metacode.biz \
    --cc=zbyszek@in.waw.pl \
    --cc=zohar@linux.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).