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