1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* PKCS#8 Private Key parser [RFC 5208].
4 * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
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"
20 struct 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 */
30 * Note an OID when we find one for later processing when we know how to
33 int pkcs8_note_OID(void *context, size_t hdrlen,
35 const void *value, size_t vlen)
37 struct pkcs8_parse_context *ctx = context;
39 ctx->last_oid = look_up_OID(value, vlen);
40 if (ctx->last_oid == OID__NR) {
43 sprint_oid(value, vlen, buffer, sizeof(buffer));
44 pr_info("Unknown OID: [%lu] %s\n",
45 (unsigned long)value - ctx->data, buffer);
51 * Note the version number of the ASN.1 blob.
53 int pkcs8_note_version(void *context, size_t hdrlen,
55 const void *value, size_t vlen)
57 if (vlen != 1 || ((const u8 *)value)[0] != 0) {
58 pr_warn("Unsupported PKCS#8 version\n");
65 * Note the public algorithm.
67 int pkcs8_note_algo(void *context, size_t hdrlen,
69 const void *value, size_t vlen)
71 struct pkcs8_parse_context *ctx = context;
73 if (ctx->last_oid != OID_rsaEncryption)
76 ctx->pub->pkey_algo = "rsa";
81 * Note the key data of the ASN.1 blob.
83 int pkcs8_note_key(void *context, size_t hdrlen,
85 const void *value, size_t vlen)
87 struct pkcs8_parse_context *ctx = context;
95 * Parse a PKCS#8 private key blob.
97 static struct public_key *pkcs8_parse(const void *data, size_t datalen)
99 struct pkcs8_parse_context ctx;
100 struct public_key *pub;
103 memset(&ctx, 0, sizeof(ctx));
106 ctx.pub = kzalloc(sizeof(struct public_key), GFP_KERNEL);
110 ctx.data = (unsigned long)data;
112 /* Attempt to decode the private key */
113 ret = asn1_ber_decoder(&pkcs8_decoder, &ctx, data, datalen);
119 pub->key = kmemdup(ctx.key, ctx.key_size, GFP_KERNEL);
123 pub->keylen = ctx.key_size;
124 pub->key_is_private = true;
134 * Attempt to parse a data blob for a key as a PKCS#8 private key.
136 static int pkcs8_key_preparse(struct key_preparsed_payload *prep)
138 struct public_key *pub;
140 pub = pkcs8_parse(prep->data, prep->datalen);
144 pr_devel("Cert Key Algo: %s\n", pub->pkey_algo);
145 pub->id_type = "PKCS8";
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;
157 static struct asymmetric_key_parser pkcs8_key_parser = {
158 .owner = THIS_MODULE,
160 .parse = pkcs8_key_preparse,
166 static int __init pkcs8_key_init(void)
168 return register_asymmetric_key_parser(&pkcs8_key_parser);
171 static void __exit pkcs8_key_exit(void)
173 unregister_asymmetric_key_parser(&pkcs8_key_parser);
176 module_init(pkcs8_key_init);
177 module_exit(pkcs8_key_exit);
179 MODULE_DESCRIPTION("PKCS#8 certificate parser");
180 MODULE_LICENSE("GPL");