[PATCH v3 10/14] KEYS: Calculate key digest and get signature of the key

Roberto Sassu
2024-09-11T12:31:53Z

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

Calculate the digest of the signature, according to the RFC 9580 section
5.2.4, get the last suitable signature with types 0x10 (Generic
certification of a User ID and Public-Key packet) or 0x13 (Positive
certification of a User ID and Public Key packet), and store it in the
asym_auth field of the key payload, so that it is available for validating
a restriction on a keyring.

Type 0x10 is included despite not giving the strongest trust guarantees,
since it is the one used by most common PGP implementations (including
gpg).

The rationale of taking the last signature is that, if there are multiple
signatures, that would be of a different issuer (not a self-signature),
that likely has more chances to be useful for the restriction verification.
If there is one (the self-signature), that will be used.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
crypto/asymmetric_keys/pgp_public_key.c | 81 +++++++++++++++++++++++++
1 file changed, 81 insertions(+)

diff --git a/crypto/asymmetric_keys/pgp_public_key.c b/crypto/asymmetric_keys/pgp_public_key.c
index 22f4a40c7eb7..2dc8b5d321e9 100644
--- a/crypto/asymmetric_keys/pgp_public_key.c
+++ b/crypto/asymmetric_keys/pgp_public_key.c
@@ -14,6 +14,7 @@
#include <keys/asymmetric-parser.h>
#include <crypto/hash.h>
#include <crypto/public_key.h>
+#include <crypto/pgp.h>

#include "pgp_parser.h"

@@ -56,6 +57,8 @@ struct pgp_key_data_parse_context {
size_t raw_fingerprint_len;
const char *user_id;
size_t user_id_len;
+ const char *key_pkt;
+ size_t key_pkt_len;
};

/*
@@ -216,6 +219,12 @@ static int pgp_process_public_key(struct pgp_parse_context *context,
return -EBADMSG;
}

+ /* Pointer refers to data being processed. */
+ if (type == PGP_PKT_PUBLIC_KEY) {
+ ctx->key_pkt = data;
+ ctx->key_pkt_len = datalen;
+ }
+
pub = kzalloc(sizeof(*pub), GFP_KERNEL);
if (!pub)
return -ENOMEM;
@@ -306,6 +315,77 @@ pgp_key_generate_id(struct pgp_key_data_parse_context *ctx)
return NULL;
}

+/*
+ * Calculate the digest of the signature according to the RFC 9580, section
+ * 5.2.4 (packet types 0x10 and 0x13).
+ */
+static int pgp_key_add_sig_data(struct pgp_key_data_parse_context *ctx,
+ struct pgp_sig_verify *sig_ctx)
+{
+ loff_t offset = 0;
+ u8 *data;
+
+ if (!ctx->key_pkt_len || !ctx->user_id_len)
+ return 0;
+
+ /* 0x99 + key pkt len + key pkt + 0xb4 + user ID len + user ID */
+ data = kmalloc(1 + sizeof(u16) + ctx->key_pkt_len +
+ 1 + sizeof(u32) + ctx->user_id_len, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data[offset++] = 0x99;
+ data[offset++] = ctx->key_pkt_len >> 8;
+ data[offset++] = ctx->key_pkt_len;
+
+ memcpy(data + offset, ctx->key_pkt, ctx->key_pkt_len);
+ offset += ctx->key_pkt_len;
+
+ if (pgp_sig_get_version(sig_ctx) == PGP_SIG_VERSION_4) {
+ data[offset++] = 0xb4;
+ data[offset++] = ctx->user_id_len >> 24;
+ data[offset++] = ctx->user_id_len >> 16;
+ data[offset++] = ctx->user_id_len >> 8;
+ data[offset++] = ctx->user_id_len;
+ }
+
+ memcpy(data + offset, ctx->user_id, ctx->user_id_len);
+ offset += ctx->user_id_len;
+
+ pgp_sig_add_data(sig_ctx, data, offset);
+ kfree(data);
+ return 0;
+}
+
+static struct public_key_signature *
+pgp_key_get_sig(struct key_preparsed_payload *prep,
+ struct pgp_key_data_parse_context *ctx)
+{
+ struct public_key_signature *sig = NULL;
+ struct pgp_sig_verify *sig_ctx;
+ bool keep_sig = false;
+ int ret;
+
+ sig_ctx = pgp_sig_parse(prep->data, prep->datalen);
+ if (IS_ERR(sig_ctx))
+ return NULL;
+
+ ret = pgp_key_add_sig_data(ctx, sig_ctx);
+ if (ret < 0)
+ goto out;
+
+ sig = pgp_sig_get_sig(sig_ctx, true);
+ if (IS_ERR(sig)) {
+ sig = NULL;
+ goto out;
+ }
+
+ keep_sig = true;
+out:
+ pgp_sig_verify_cancel(sig_ctx, keep_sig);
+ return sig;
+}
+
/*
* Attempt to parse the instantiation data blob for a key as a PGP packet
* message holding a key.
@@ -370,6 +450,7 @@ static int pgp_key_parse(struct key_preparsed_payload *prep)
prep->payload.data[asym_subtype] = &public_key_subtype;
prep->payload.data[asym_key_ids] = pgp_key_generate_id(&ctx);
prep->payload.data[asym_crypto] = ctx.pub;
+ prep->payload.data[asym_auth] = pgp_key_get_sig(prep, &ctx);
prep->quotalen = 100;
return 0;

--
2.34.1