cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pkcs8_parser.c (4005B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/* PKCS#8 Private Key parser [RFC 5208].
      3 *
      4 * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
      5 * Written by David Howells (dhowells@redhat.com)
      6 */
      7
      8#define pr_fmt(fmt) "PKCS8: "fmt
      9#include <linux/module.h>
     10#include <linux/kernel.h>
     11#include <linux/export.h>
     12#include <linux/slab.h>
     13#include <linux/err.h>
     14#include <linux/oid_registry.h>
     15#include <keys/asymmetric-subtype.h>
     16#include <keys/asymmetric-parser.h>
     17#include <crypto/public_key.h>
     18#include "pkcs8.asn1.h"
     19
     20struct pkcs8_parse_context {
     21	struct public_key *pub;
     22	unsigned long	data;			/* Start of data */
     23	enum OID	last_oid;		/* Last OID encountered */
     24	enum OID	algo_oid;		/* Algorithm OID */
     25	u32		key_size;
     26	const void	*key;
     27};
     28
     29/*
     30 * Note an OID when we find one for later processing when we know how to
     31 * interpret it.
     32 */
     33int pkcs8_note_OID(void *context, size_t hdrlen,
     34		   unsigned char tag,
     35		   const void *value, size_t vlen)
     36{
     37	struct pkcs8_parse_context *ctx = context;
     38
     39	ctx->last_oid = look_up_OID(value, vlen);
     40	if (ctx->last_oid == OID__NR) {
     41		char buffer[50];
     42
     43		sprint_oid(value, vlen, buffer, sizeof(buffer));
     44		pr_info("Unknown OID: [%lu] %s\n",
     45			(unsigned long)value - ctx->data, buffer);
     46	}
     47	return 0;
     48}
     49
     50/*
     51 * Note the version number of the ASN.1 blob.
     52 */
     53int pkcs8_note_version(void *context, size_t hdrlen,
     54		       unsigned char tag,
     55		       const void *value, size_t vlen)
     56{
     57	if (vlen != 1 || ((const u8 *)value)[0] != 0) {
     58		pr_warn("Unsupported PKCS#8 version\n");
     59		return -EBADMSG;
     60	}
     61	return 0;
     62}
     63
     64/*
     65 * Note the public algorithm.
     66 */
     67int pkcs8_note_algo(void *context, size_t hdrlen,
     68		    unsigned char tag,
     69		    const void *value, size_t vlen)
     70{
     71	struct pkcs8_parse_context *ctx = context;
     72
     73	if (ctx->last_oid != OID_rsaEncryption)
     74		return -ENOPKG;
     75
     76	ctx->pub->pkey_algo = "rsa";
     77	return 0;
     78}
     79
     80/*
     81 * Note the key data of the ASN.1 blob.
     82 */
     83int pkcs8_note_key(void *context, size_t hdrlen,
     84		   unsigned char tag,
     85		   const void *value, size_t vlen)
     86{
     87	struct pkcs8_parse_context *ctx = context;
     88
     89	ctx->key = value;
     90	ctx->key_size = vlen;
     91	return 0;
     92}
     93
     94/*
     95 * Parse a PKCS#8 private key blob.
     96 */
     97static struct public_key *pkcs8_parse(const void *data, size_t datalen)
     98{
     99	struct pkcs8_parse_context ctx;
    100	struct public_key *pub;
    101	long ret;
    102
    103	memset(&ctx, 0, sizeof(ctx));
    104
    105	ret = -ENOMEM;
    106	ctx.pub = kzalloc(sizeof(struct public_key), GFP_KERNEL);
    107	if (!ctx.pub)
    108		goto error;
    109
    110	ctx.data = (unsigned long)data;
    111
    112	/* Attempt to decode the private key */
    113	ret = asn1_ber_decoder(&pkcs8_decoder, &ctx, data, datalen);
    114	if (ret < 0)
    115		goto error_decode;
    116
    117	ret = -ENOMEM;
    118	pub = ctx.pub;
    119	pub->key = kmemdup(ctx.key, ctx.key_size, GFP_KERNEL);
    120	if (!pub->key)
    121		goto error_decode;
    122
    123	pub->keylen = ctx.key_size;
    124	pub->key_is_private = true;
    125	return pub;
    126
    127error_decode:
    128	kfree(ctx.pub);
    129error:
    130	return ERR_PTR(ret);
    131}
    132
    133/*
    134 * Attempt to parse a data blob for a key as a PKCS#8 private key.
    135 */
    136static int pkcs8_key_preparse(struct key_preparsed_payload *prep)
    137{
    138	struct public_key *pub;
    139
    140	pub = pkcs8_parse(prep->data, prep->datalen);
    141	if (IS_ERR(pub))
    142		return PTR_ERR(pub);
    143
    144	pr_devel("Cert Key Algo: %s\n", pub->pkey_algo);
    145	pub->id_type = "PKCS8";
    146
    147	/* We're pinning the module by being linked against it */
    148	__module_get(public_key_subtype.owner);
    149	prep->payload.data[asym_subtype] = &public_key_subtype;
    150	prep->payload.data[asym_key_ids] = NULL;
    151	prep->payload.data[asym_crypto] = pub;
    152	prep->payload.data[asym_auth] = NULL;
    153	prep->quotalen = 100;
    154	return 0;
    155}
    156
    157static struct asymmetric_key_parser pkcs8_key_parser = {
    158	.owner	= THIS_MODULE,
    159	.name	= "pkcs8",
    160	.parse	= pkcs8_key_preparse,
    161};
    162
    163/*
    164 * Module stuff
    165 */
    166static int __init pkcs8_key_init(void)
    167{
    168	return register_asymmetric_key_parser(&pkcs8_key_parser);
    169}
    170
    171static void __exit pkcs8_key_exit(void)
    172{
    173	unregister_asymmetric_key_parser(&pkcs8_key_parser);
    174}
    175
    176module_init(pkcs8_key_init);
    177module_exit(pkcs8_key_exit);
    178
    179MODULE_DESCRIPTION("PKCS#8 certificate parser");
    180MODULE_LICENSE("GPL");