162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* PKCS#8 Private Key parser [RFC 5208]. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved. 562306a36Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define pr_fmt(fmt) "PKCS8: "fmt 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/export.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <linux/err.h> 1462306a36Sopenharmony_ci#include <linux/oid_registry.h> 1562306a36Sopenharmony_ci#include <keys/asymmetric-subtype.h> 1662306a36Sopenharmony_ci#include <keys/asymmetric-parser.h> 1762306a36Sopenharmony_ci#include <crypto/public_key.h> 1862306a36Sopenharmony_ci#include "pkcs8.asn1.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistruct pkcs8_parse_context { 2162306a36Sopenharmony_ci struct public_key *pub; 2262306a36Sopenharmony_ci unsigned long data; /* Start of data */ 2362306a36Sopenharmony_ci enum OID last_oid; /* Last OID encountered */ 2462306a36Sopenharmony_ci enum OID algo_oid; /* Algorithm OID */ 2562306a36Sopenharmony_ci u32 key_size; 2662306a36Sopenharmony_ci const void *key; 2762306a36Sopenharmony_ci}; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* 3062306a36Sopenharmony_ci * Note an OID when we find one for later processing when we know how to 3162306a36Sopenharmony_ci * interpret it. 3262306a36Sopenharmony_ci */ 3362306a36Sopenharmony_ciint pkcs8_note_OID(void *context, size_t hdrlen, 3462306a36Sopenharmony_ci unsigned char tag, 3562306a36Sopenharmony_ci const void *value, size_t vlen) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci struct pkcs8_parse_context *ctx = context; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci ctx->last_oid = look_up_OID(value, vlen); 4062306a36Sopenharmony_ci if (ctx->last_oid == OID__NR) { 4162306a36Sopenharmony_ci char buffer[50]; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci sprint_oid(value, vlen, buffer, sizeof(buffer)); 4462306a36Sopenharmony_ci pr_info("Unknown OID: [%lu] %s\n", 4562306a36Sopenharmony_ci (unsigned long)value - ctx->data, buffer); 4662306a36Sopenharmony_ci } 4762306a36Sopenharmony_ci return 0; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* 5162306a36Sopenharmony_ci * Note the version number of the ASN.1 blob. 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ciint pkcs8_note_version(void *context, size_t hdrlen, 5462306a36Sopenharmony_ci unsigned char tag, 5562306a36Sopenharmony_ci const void *value, size_t vlen) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci if (vlen != 1 || ((const u8 *)value)[0] != 0) { 5862306a36Sopenharmony_ci pr_warn("Unsupported PKCS#8 version\n"); 5962306a36Sopenharmony_ci return -EBADMSG; 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci return 0; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* 6562306a36Sopenharmony_ci * Note the public algorithm. 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ciint pkcs8_note_algo(void *context, size_t hdrlen, 6862306a36Sopenharmony_ci unsigned char tag, 6962306a36Sopenharmony_ci const void *value, size_t vlen) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci struct pkcs8_parse_context *ctx = context; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci if (ctx->last_oid != OID_rsaEncryption) 7462306a36Sopenharmony_ci return -ENOPKG; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci ctx->pub->pkey_algo = "rsa"; 7762306a36Sopenharmony_ci return 0; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* 8162306a36Sopenharmony_ci * Note the key data of the ASN.1 blob. 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_ciint pkcs8_note_key(void *context, size_t hdrlen, 8462306a36Sopenharmony_ci unsigned char tag, 8562306a36Sopenharmony_ci const void *value, size_t vlen) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct pkcs8_parse_context *ctx = context; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci ctx->key = value; 9062306a36Sopenharmony_ci ctx->key_size = vlen; 9162306a36Sopenharmony_ci return 0; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/* 9562306a36Sopenharmony_ci * Parse a PKCS#8 private key blob. 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_cistatic struct public_key *pkcs8_parse(const void *data, size_t datalen) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct pkcs8_parse_context ctx; 10062306a36Sopenharmony_ci struct public_key *pub; 10162306a36Sopenharmony_ci long ret; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci memset(&ctx, 0, sizeof(ctx)); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci ret = -ENOMEM; 10662306a36Sopenharmony_ci ctx.pub = kzalloc(sizeof(struct public_key), GFP_KERNEL); 10762306a36Sopenharmony_ci if (!ctx.pub) 10862306a36Sopenharmony_ci goto error; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci ctx.data = (unsigned long)data; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* Attempt to decode the private key */ 11362306a36Sopenharmony_ci ret = asn1_ber_decoder(&pkcs8_decoder, &ctx, data, datalen); 11462306a36Sopenharmony_ci if (ret < 0) 11562306a36Sopenharmony_ci goto error_decode; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci ret = -ENOMEM; 11862306a36Sopenharmony_ci pub = ctx.pub; 11962306a36Sopenharmony_ci pub->key = kmemdup(ctx.key, ctx.key_size, GFP_KERNEL); 12062306a36Sopenharmony_ci if (!pub->key) 12162306a36Sopenharmony_ci goto error_decode; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci pub->keylen = ctx.key_size; 12462306a36Sopenharmony_ci pub->key_is_private = true; 12562306a36Sopenharmony_ci return pub; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cierror_decode: 12862306a36Sopenharmony_ci kfree(ctx.pub); 12962306a36Sopenharmony_cierror: 13062306a36Sopenharmony_ci return ERR_PTR(ret); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* 13462306a36Sopenharmony_ci * Attempt to parse a data blob for a key as a PKCS#8 private key. 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_cistatic int pkcs8_key_preparse(struct key_preparsed_payload *prep) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci struct public_key *pub; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci pub = pkcs8_parse(prep->data, prep->datalen); 14162306a36Sopenharmony_ci if (IS_ERR(pub)) 14262306a36Sopenharmony_ci return PTR_ERR(pub); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci pr_devel("Cert Key Algo: %s\n", pub->pkey_algo); 14562306a36Sopenharmony_ci pub->id_type = "PKCS8"; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* We're pinning the module by being linked against it */ 14862306a36Sopenharmony_ci __module_get(public_key_subtype.owner); 14962306a36Sopenharmony_ci prep->payload.data[asym_subtype] = &public_key_subtype; 15062306a36Sopenharmony_ci prep->payload.data[asym_key_ids] = NULL; 15162306a36Sopenharmony_ci prep->payload.data[asym_crypto] = pub; 15262306a36Sopenharmony_ci prep->payload.data[asym_auth] = NULL; 15362306a36Sopenharmony_ci prep->quotalen = 100; 15462306a36Sopenharmony_ci return 0; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic struct asymmetric_key_parser pkcs8_key_parser = { 15862306a36Sopenharmony_ci .owner = THIS_MODULE, 15962306a36Sopenharmony_ci .name = "pkcs8", 16062306a36Sopenharmony_ci .parse = pkcs8_key_preparse, 16162306a36Sopenharmony_ci}; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci/* 16462306a36Sopenharmony_ci * Module stuff 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_cistatic int __init pkcs8_key_init(void) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci return register_asymmetric_key_parser(&pkcs8_key_parser); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic void __exit pkcs8_key_exit(void) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci unregister_asymmetric_key_parser(&pkcs8_key_parser); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cimodule_init(pkcs8_key_init); 17762306a36Sopenharmony_cimodule_exit(pkcs8_key_exit); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ciMODULE_DESCRIPTION("PKCS#8 certificate parser"); 18062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 181