Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* PKCS#8 Private Key parser [RFC 5208].
0003  *
0004  * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
0005  * Written by David Howells (dhowells@redhat.com)
0006  */
0007 
0008 #define pr_fmt(fmt) "PKCS8: "fmt
0009 #include <linux/module.h>
0010 #include <linux/kernel.h>
0011 #include <linux/export.h>
0012 #include <linux/slab.h>
0013 #include <linux/err.h>
0014 #include <linux/oid_registry.h>
0015 #include <keys/asymmetric-subtype.h>
0016 #include <keys/asymmetric-parser.h>
0017 #include <crypto/public_key.h>
0018 #include "pkcs8.asn1.h"
0019 
0020 struct pkcs8_parse_context {
0021     struct public_key *pub;
0022     unsigned long   data;           /* Start of data */
0023     enum OID    last_oid;       /* Last OID encountered */
0024     enum OID    algo_oid;       /* Algorithm OID */
0025     u32     key_size;
0026     const void  *key;
0027 };
0028 
0029 /*
0030  * Note an OID when we find one for later processing when we know how to
0031  * interpret it.
0032  */
0033 int pkcs8_note_OID(void *context, size_t hdrlen,
0034            unsigned char tag,
0035            const void *value, size_t vlen)
0036 {
0037     struct pkcs8_parse_context *ctx = context;
0038 
0039     ctx->last_oid = look_up_OID(value, vlen);
0040     if (ctx->last_oid == OID__NR) {
0041         char buffer[50];
0042 
0043         sprint_oid(value, vlen, buffer, sizeof(buffer));
0044         pr_info("Unknown OID: [%lu] %s\n",
0045             (unsigned long)value - ctx->data, buffer);
0046     }
0047     return 0;
0048 }
0049 
0050 /*
0051  * Note the version number of the ASN.1 blob.
0052  */
0053 int pkcs8_note_version(void *context, size_t hdrlen,
0054                unsigned char tag,
0055                const void *value, size_t vlen)
0056 {
0057     if (vlen != 1 || ((const u8 *)value)[0] != 0) {
0058         pr_warn("Unsupported PKCS#8 version\n");
0059         return -EBADMSG;
0060     }
0061     return 0;
0062 }
0063 
0064 /*
0065  * Note the public algorithm.
0066  */
0067 int pkcs8_note_algo(void *context, size_t hdrlen,
0068             unsigned char tag,
0069             const void *value, size_t vlen)
0070 {
0071     struct pkcs8_parse_context *ctx = context;
0072 
0073     if (ctx->last_oid != OID_rsaEncryption)
0074         return -ENOPKG;
0075 
0076     ctx->pub->pkey_algo = "rsa";
0077     return 0;
0078 }
0079 
0080 /*
0081  * Note the key data of the ASN.1 blob.
0082  */
0083 int pkcs8_note_key(void *context, size_t hdrlen,
0084            unsigned char tag,
0085            const void *value, size_t vlen)
0086 {
0087     struct pkcs8_parse_context *ctx = context;
0088 
0089     ctx->key = value;
0090     ctx->key_size = vlen;
0091     return 0;
0092 }
0093 
0094 /*
0095  * Parse a PKCS#8 private key blob.
0096  */
0097 static struct public_key *pkcs8_parse(const void *data, size_t datalen)
0098 {
0099     struct pkcs8_parse_context ctx;
0100     struct public_key *pub;
0101     long ret;
0102 
0103     memset(&ctx, 0, sizeof(ctx));
0104 
0105     ret = -ENOMEM;
0106     ctx.pub = kzalloc(sizeof(struct public_key), GFP_KERNEL);
0107     if (!ctx.pub)
0108         goto error;
0109 
0110     ctx.data = (unsigned long)data;
0111 
0112     /* Attempt to decode the private key */
0113     ret = asn1_ber_decoder(&pkcs8_decoder, &ctx, data, datalen);
0114     if (ret < 0)
0115         goto error_decode;
0116 
0117     ret = -ENOMEM;
0118     pub = ctx.pub;
0119     pub->key = kmemdup(ctx.key, ctx.key_size, GFP_KERNEL);
0120     if (!pub->key)
0121         goto error_decode;
0122 
0123     pub->keylen = ctx.key_size;
0124     pub->key_is_private = true;
0125     return pub;
0126 
0127 error_decode:
0128     kfree(ctx.pub);
0129 error:
0130     return ERR_PTR(ret);
0131 }
0132 
0133 /*
0134  * Attempt to parse a data blob for a key as a PKCS#8 private key.
0135  */
0136 static int pkcs8_key_preparse(struct key_preparsed_payload *prep)
0137 {
0138     struct public_key *pub;
0139 
0140     pub = pkcs8_parse(prep->data, prep->datalen);
0141     if (IS_ERR(pub))
0142         return PTR_ERR(pub);
0143 
0144     pr_devel("Cert Key Algo: %s\n", pub->pkey_algo);
0145     pub->id_type = "PKCS8";
0146 
0147     /* We're pinning the module by being linked against it */
0148     __module_get(public_key_subtype.owner);
0149     prep->payload.data[asym_subtype] = &public_key_subtype;
0150     prep->payload.data[asym_key_ids] = NULL;
0151     prep->payload.data[asym_crypto] = pub;
0152     prep->payload.data[asym_auth] = NULL;
0153     prep->quotalen = 100;
0154     return 0;
0155 }
0156 
0157 static struct asymmetric_key_parser pkcs8_key_parser = {
0158     .owner  = THIS_MODULE,
0159     .name   = "pkcs8",
0160     .parse  = pkcs8_key_preparse,
0161 };
0162 
0163 /*
0164  * Module stuff
0165  */
0166 static int __init pkcs8_key_init(void)
0167 {
0168     return register_asymmetric_key_parser(&pkcs8_key_parser);
0169 }
0170 
0171 static void __exit pkcs8_key_exit(void)
0172 {
0173     unregister_asymmetric_key_parser(&pkcs8_key_parser);
0174 }
0175 
0176 module_init(pkcs8_key_init);
0177 module_exit(pkcs8_key_exit);
0178 
0179 MODULE_DESCRIPTION("PKCS#8 certificate parser");
0180 MODULE_LICENSE("GPL");