xref: /OK3568_Linux_fs/kernel/crypto/asymmetric_keys/pkcs8_parser.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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