summaryrefslogtreecommitdiff
path: root/compat/verification/public_key.c
diff options
context:
space:
mode:
Diffstat (limited to 'compat/verification/public_key.c')
-rw-r--r--compat/verification/public_key.c131
1 files changed, 131 insertions, 0 deletions
diff --git a/compat/verification/public_key.c b/compat/verification/public_key.c
new file mode 100644
index 0000000..83a6935
--- /dev/null
+++ b/compat/verification/public_key.c
@@ -0,0 +1,131 @@
+/*
+ * Adapted from the kernel for simplicity in backports.
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) "PKEY: "fmt
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+#include <linux/scatterlist.h>
+#include <linux/asn1_decoder.h>
+#include <crypto/public_key.h>
+#include "rsapubkey.asn1.h"
+#include "mbedtls/rsa.h"
+#include "mbedtls/md.h"
+
+void public_key_free(struct public_key *key)
+{
+ if (key) {
+ kfree(key->key);
+ kfree(key);
+ }
+}
+
+int rsa_get_n(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ mbedtls_rsa_context *rsa = context;
+
+ /* invalid key provided */
+ if (!value || !vlen)
+ return -EINVAL;
+
+ return mbedtls_mpi_read_binary(&rsa->N, value, vlen) ? -EINVAL : 0;
+}
+
+int rsa_get_e(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ mbedtls_rsa_context *rsa = context;
+
+ /* invalid key provided */
+ if (!value || !vlen)
+ return -EINVAL;
+
+ return mbedtls_mpi_read_binary(&rsa->E, value, vlen) ? -EINVAL : 0;
+}
+
+int public_key_verify_signature(const struct public_key *pkey,
+ const struct public_key_signature *sig)
+{
+ mbedtls_rsa_context rsa;
+ mbedtls_md_type_t md_alg;
+ const u8 *sigdata = sig->s;
+ int s_size = sig->s_size;
+ int ret;
+
+ if (WARN_ON(!pkey))
+ return -EINVAL;
+
+ if (strcmp(sig->pkey_algo, "rsa"))
+ return -ENOTSUPP;
+
+ if (strcmp(sig->hash_algo, "sha1") == 0)
+ md_alg = MBEDTLS_MD_SHA1;
+ else if (strcmp(sig->hash_algo, "sha256") == 0)
+ md_alg = MBEDTLS_MD_SHA256;
+ else
+ return -ENOTSUPP;
+
+ mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0);
+
+ ret = asn1_ber_decoder(&rsapubkey_decoder, &rsa,
+ pkey->key, pkey->keylen);
+ if (ret)
+ goto free;
+
+ rsa.len = (mbedtls_mpi_bitlen(&rsa.N) + 7) >> 3;
+
+ /*
+ * In some cases (from X.509 certificates) we get here with a
+ * BIT_STRING ASN.1 object, in which the first byte indicates
+ * the number of unused bits in the bit string (in case the
+ * string isn't a multiple of 8 long).
+ * Assume here that it's always a multiple of 8, and just skip
+ * the additional byte.
+ */
+ if (s_size == rsa.len + 1 && sigdata[0] == 0) {
+ sigdata = sig->s + 1;
+ s_size -= 1;
+ }
+
+ if (rsa.len != s_size) {
+ ret = -EINVAL;
+ goto free;
+ }
+
+ ret = mbedtls_rsa_pkcs1_verify(&rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC,
+ md_alg, 0, sig->digest, sigdata);
+
+ if (ret)
+ ret = -EKEYREJECTED;
+ else
+ ret = 0;
+
+ free:
+ mbedtls_rsa_free(&rsa);
+
+ return ret;
+}
+
+void public_key_signature_free(struct public_key_signature *sig)
+{
+ int i;
+
+ if (sig) {
+ for (i = 0; i < ARRAY_SIZE(sig->auth_ids); i++)
+ kfree(sig->auth_ids[i]);
+ kfree(sig->s);
+ kfree(sig->digest);
+ kfree(sig);
+ }
+}