18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/* X.509 certificate parser
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com)
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "X.509: "fmt
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/export.h>
118c2ecf20Sopenharmony_ci#include <linux/slab.h>
128c2ecf20Sopenharmony_ci#include <linux/err.h>
138c2ecf20Sopenharmony_ci#include <linux/oid_registry.h>
148c2ecf20Sopenharmony_ci#include <crypto/public_key.h>
158c2ecf20Sopenharmony_ci#include "x509_parser.h"
168c2ecf20Sopenharmony_ci#include "x509.asn1.h"
178c2ecf20Sopenharmony_ci#include "x509_akid.asn1.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistruct x509_parse_context {
208c2ecf20Sopenharmony_ci	struct x509_certificate	*cert;		/* Certificate being constructed */
218c2ecf20Sopenharmony_ci	unsigned long	data;			/* Start of data */
228c2ecf20Sopenharmony_ci	const void	*cert_start;		/* Start of cert content */
238c2ecf20Sopenharmony_ci	const void	*key;			/* Key data */
248c2ecf20Sopenharmony_ci	size_t		key_size;		/* Size of key data */
258c2ecf20Sopenharmony_ci	const void	*params;		/* Key parameters */
268c2ecf20Sopenharmony_ci	size_t		params_size;		/* Size of key parameters */
278c2ecf20Sopenharmony_ci	enum OID	key_algo;		/* Public key algorithm */
288c2ecf20Sopenharmony_ci	enum OID	last_oid;		/* Last OID encountered */
298c2ecf20Sopenharmony_ci	enum OID	algo_oid;		/* Algorithm OID */
308c2ecf20Sopenharmony_ci	unsigned char	nr_mpi;			/* Number of MPIs stored */
318c2ecf20Sopenharmony_ci	u8		o_size;			/* Size of organizationName (O) */
328c2ecf20Sopenharmony_ci	u8		cn_size;		/* Size of commonName (CN) */
338c2ecf20Sopenharmony_ci	u8		email_size;		/* Size of emailAddress */
348c2ecf20Sopenharmony_ci	u16		o_offset;		/* Offset of organizationName (O) */
358c2ecf20Sopenharmony_ci	u16		cn_offset;		/* Offset of commonName (CN) */
368c2ecf20Sopenharmony_ci	u16		email_offset;		/* Offset of emailAddress */
378c2ecf20Sopenharmony_ci	unsigned	raw_akid_size;
388c2ecf20Sopenharmony_ci	const void	*raw_akid;		/* Raw authorityKeyId in ASN.1 */
398c2ecf20Sopenharmony_ci	const void	*akid_raw_issuer;	/* Raw directoryName in authorityKeyId */
408c2ecf20Sopenharmony_ci	unsigned	akid_raw_issuer_size;
418c2ecf20Sopenharmony_ci};
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/*
448c2ecf20Sopenharmony_ci * Free an X.509 certificate
458c2ecf20Sopenharmony_ci */
468c2ecf20Sopenharmony_civoid x509_free_certificate(struct x509_certificate *cert)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	if (cert) {
498c2ecf20Sopenharmony_ci		public_key_free(cert->pub);
508c2ecf20Sopenharmony_ci		public_key_signature_free(cert->sig);
518c2ecf20Sopenharmony_ci		kfree(cert->issuer);
528c2ecf20Sopenharmony_ci		kfree(cert->subject);
538c2ecf20Sopenharmony_ci		kfree(cert->id);
548c2ecf20Sopenharmony_ci		kfree(cert->skid);
558c2ecf20Sopenharmony_ci		kfree(cert);
568c2ecf20Sopenharmony_ci	}
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(x509_free_certificate);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci/*
618c2ecf20Sopenharmony_ci * Parse an X.509 certificate
628c2ecf20Sopenharmony_ci */
638c2ecf20Sopenharmony_cistruct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	struct x509_certificate *cert;
668c2ecf20Sopenharmony_ci	struct x509_parse_context *ctx;
678c2ecf20Sopenharmony_ci	struct asymmetric_key_id *kid;
688c2ecf20Sopenharmony_ci	long ret;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	ret = -ENOMEM;
718c2ecf20Sopenharmony_ci	cert = kzalloc(sizeof(struct x509_certificate), GFP_KERNEL);
728c2ecf20Sopenharmony_ci	if (!cert)
738c2ecf20Sopenharmony_ci		goto error_no_cert;
748c2ecf20Sopenharmony_ci	cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL);
758c2ecf20Sopenharmony_ci	if (!cert->pub)
768c2ecf20Sopenharmony_ci		goto error_no_ctx;
778c2ecf20Sopenharmony_ci	cert->sig = kzalloc(sizeof(struct public_key_signature), GFP_KERNEL);
788c2ecf20Sopenharmony_ci	if (!cert->sig)
798c2ecf20Sopenharmony_ci		goto error_no_ctx;
808c2ecf20Sopenharmony_ci	ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL);
818c2ecf20Sopenharmony_ci	if (!ctx)
828c2ecf20Sopenharmony_ci		goto error_no_ctx;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	ctx->cert = cert;
858c2ecf20Sopenharmony_ci	ctx->data = (unsigned long)data;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	/* Attempt to decode the certificate */
888c2ecf20Sopenharmony_ci	ret = asn1_ber_decoder(&x509_decoder, ctx, data, datalen);
898c2ecf20Sopenharmony_ci	if (ret < 0)
908c2ecf20Sopenharmony_ci		goto error_decode;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	/* Decode the AuthorityKeyIdentifier */
938c2ecf20Sopenharmony_ci	if (ctx->raw_akid) {
948c2ecf20Sopenharmony_ci		pr_devel("AKID: %u %*phN\n",
958c2ecf20Sopenharmony_ci			 ctx->raw_akid_size, ctx->raw_akid_size, ctx->raw_akid);
968c2ecf20Sopenharmony_ci		ret = asn1_ber_decoder(&x509_akid_decoder, ctx,
978c2ecf20Sopenharmony_ci				       ctx->raw_akid, ctx->raw_akid_size);
988c2ecf20Sopenharmony_ci		if (ret < 0) {
998c2ecf20Sopenharmony_ci			pr_warn("Couldn't decode AuthKeyIdentifier\n");
1008c2ecf20Sopenharmony_ci			goto error_decode;
1018c2ecf20Sopenharmony_ci		}
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	ret = -ENOMEM;
1058c2ecf20Sopenharmony_ci	cert->pub->key = kmemdup(ctx->key, ctx->key_size, GFP_KERNEL);
1068c2ecf20Sopenharmony_ci	if (!cert->pub->key)
1078c2ecf20Sopenharmony_ci		goto error_decode;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	cert->pub->keylen = ctx->key_size;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	cert->pub->params = kmemdup(ctx->params, ctx->params_size, GFP_KERNEL);
1128c2ecf20Sopenharmony_ci	if (!cert->pub->params)
1138c2ecf20Sopenharmony_ci		goto error_decode;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	cert->pub->paramlen = ctx->params_size;
1168c2ecf20Sopenharmony_ci	cert->pub->algo = ctx->key_algo;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	/* Grab the signature bits */
1198c2ecf20Sopenharmony_ci	ret = x509_get_sig_params(cert);
1208c2ecf20Sopenharmony_ci	if (ret < 0)
1218c2ecf20Sopenharmony_ci		goto error_decode;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	/* Generate cert issuer + serial number key ID */
1248c2ecf20Sopenharmony_ci	kid = asymmetric_key_generate_id(cert->raw_serial,
1258c2ecf20Sopenharmony_ci					 cert->raw_serial_size,
1268c2ecf20Sopenharmony_ci					 cert->raw_issuer,
1278c2ecf20Sopenharmony_ci					 cert->raw_issuer_size);
1288c2ecf20Sopenharmony_ci	if (IS_ERR(kid)) {
1298c2ecf20Sopenharmony_ci		ret = PTR_ERR(kid);
1308c2ecf20Sopenharmony_ci		goto error_decode;
1318c2ecf20Sopenharmony_ci	}
1328c2ecf20Sopenharmony_ci	cert->id = kid;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	/* Detect self-signed certificates */
1358c2ecf20Sopenharmony_ci	ret = x509_check_for_self_signed(cert);
1368c2ecf20Sopenharmony_ci	if (ret < 0)
1378c2ecf20Sopenharmony_ci		goto error_decode;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	kfree(ctx);
1408c2ecf20Sopenharmony_ci	return cert;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cierror_decode:
1438c2ecf20Sopenharmony_ci	kfree(ctx);
1448c2ecf20Sopenharmony_cierror_no_ctx:
1458c2ecf20Sopenharmony_ci	x509_free_certificate(cert);
1468c2ecf20Sopenharmony_cierror_no_cert:
1478c2ecf20Sopenharmony_ci	return ERR_PTR(ret);
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(x509_cert_parse);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci/*
1528c2ecf20Sopenharmony_ci * Note an OID when we find one for later processing when we know how
1538c2ecf20Sopenharmony_ci * to interpret it.
1548c2ecf20Sopenharmony_ci */
1558c2ecf20Sopenharmony_ciint x509_note_OID(void *context, size_t hdrlen,
1568c2ecf20Sopenharmony_ci	     unsigned char tag,
1578c2ecf20Sopenharmony_ci	     const void *value, size_t vlen)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	struct x509_parse_context *ctx = context;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	ctx->last_oid = look_up_OID(value, vlen);
1628c2ecf20Sopenharmony_ci	if (ctx->last_oid == OID__NR) {
1638c2ecf20Sopenharmony_ci		char buffer[50];
1648c2ecf20Sopenharmony_ci		sprint_oid(value, vlen, buffer, sizeof(buffer));
1658c2ecf20Sopenharmony_ci		pr_debug("Unknown OID: [%lu] %s\n",
1668c2ecf20Sopenharmony_ci			 (unsigned long)value - ctx->data, buffer);
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci	return 0;
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci/*
1728c2ecf20Sopenharmony_ci * Save the position of the TBS data so that we can check the signature over it
1738c2ecf20Sopenharmony_ci * later.
1748c2ecf20Sopenharmony_ci */
1758c2ecf20Sopenharmony_ciint x509_note_tbs_certificate(void *context, size_t hdrlen,
1768c2ecf20Sopenharmony_ci			      unsigned char tag,
1778c2ecf20Sopenharmony_ci			      const void *value, size_t vlen)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	struct x509_parse_context *ctx = context;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	pr_debug("x509_note_tbs_certificate(,%zu,%02x,%ld,%zu)!\n",
1828c2ecf20Sopenharmony_ci		 hdrlen, tag, (unsigned long)value - ctx->data, vlen);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	ctx->cert->tbs = value - hdrlen;
1858c2ecf20Sopenharmony_ci	ctx->cert->tbs_size = vlen + hdrlen;
1868c2ecf20Sopenharmony_ci	return 0;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci/*
1908c2ecf20Sopenharmony_ci * Record the public key algorithm
1918c2ecf20Sopenharmony_ci */
1928c2ecf20Sopenharmony_ciint x509_note_pkey_algo(void *context, size_t hdrlen,
1938c2ecf20Sopenharmony_ci			unsigned char tag,
1948c2ecf20Sopenharmony_ci			const void *value, size_t vlen)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	struct x509_parse_context *ctx = context;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	pr_debug("PubKey Algo: %u\n", ctx->last_oid);
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	switch (ctx->last_oid) {
2018c2ecf20Sopenharmony_ci	case OID_md2WithRSAEncryption:
2028c2ecf20Sopenharmony_ci	case OID_md3WithRSAEncryption:
2038c2ecf20Sopenharmony_ci	default:
2048c2ecf20Sopenharmony_ci		return -ENOPKG; /* Unsupported combination */
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	case OID_md4WithRSAEncryption:
2078c2ecf20Sopenharmony_ci		ctx->cert->sig->hash_algo = "md4";
2088c2ecf20Sopenharmony_ci		goto rsa_pkcs1;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	case OID_sha1WithRSAEncryption:
2118c2ecf20Sopenharmony_ci		ctx->cert->sig->hash_algo = "sha1";
2128c2ecf20Sopenharmony_ci		goto rsa_pkcs1;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	case OID_sha256WithRSAEncryption:
2158c2ecf20Sopenharmony_ci		ctx->cert->sig->hash_algo = "sha256";
2168c2ecf20Sopenharmony_ci		goto rsa_pkcs1;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	case OID_sha384WithRSAEncryption:
2198c2ecf20Sopenharmony_ci		ctx->cert->sig->hash_algo = "sha384";
2208c2ecf20Sopenharmony_ci		goto rsa_pkcs1;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	case OID_sha512WithRSAEncryption:
2238c2ecf20Sopenharmony_ci		ctx->cert->sig->hash_algo = "sha512";
2248c2ecf20Sopenharmony_ci		goto rsa_pkcs1;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	case OID_sha224WithRSAEncryption:
2278c2ecf20Sopenharmony_ci		ctx->cert->sig->hash_algo = "sha224";
2288c2ecf20Sopenharmony_ci		goto rsa_pkcs1;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	case OID_id_ecdsa_with_sha1:
2318c2ecf20Sopenharmony_ci		ctx->cert->sig->hash_algo = "sha1";
2328c2ecf20Sopenharmony_ci		goto ecdsa;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	case OID_id_ecdsa_with_sha224:
2358c2ecf20Sopenharmony_ci		ctx->cert->sig->hash_algo = "sha224";
2368c2ecf20Sopenharmony_ci		goto ecdsa;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	case OID_id_ecdsa_with_sha256:
2398c2ecf20Sopenharmony_ci		ctx->cert->sig->hash_algo = "sha256";
2408c2ecf20Sopenharmony_ci		goto ecdsa;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	case OID_id_ecdsa_with_sha384:
2438c2ecf20Sopenharmony_ci		ctx->cert->sig->hash_algo = "sha384";
2448c2ecf20Sopenharmony_ci		goto ecdsa;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	case OID_id_ecdsa_with_sha512:
2478c2ecf20Sopenharmony_ci		ctx->cert->sig->hash_algo = "sha512";
2488c2ecf20Sopenharmony_ci		goto ecdsa;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	case OID_gost2012Signature256:
2518c2ecf20Sopenharmony_ci		ctx->cert->sig->hash_algo = "streebog256";
2528c2ecf20Sopenharmony_ci		goto ecrdsa;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	case OID_gost2012Signature512:
2558c2ecf20Sopenharmony_ci		ctx->cert->sig->hash_algo = "streebog512";
2568c2ecf20Sopenharmony_ci		goto ecrdsa;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	case OID_SM2_with_SM3:
2598c2ecf20Sopenharmony_ci		ctx->cert->sig->hash_algo = "sm3";
2608c2ecf20Sopenharmony_ci		goto sm2;
2618c2ecf20Sopenharmony_ci	}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cirsa_pkcs1:
2648c2ecf20Sopenharmony_ci	ctx->cert->sig->pkey_algo = "rsa";
2658c2ecf20Sopenharmony_ci	ctx->cert->sig->encoding = "pkcs1";
2668c2ecf20Sopenharmony_ci	ctx->algo_oid = ctx->last_oid;
2678c2ecf20Sopenharmony_ci	return 0;
2688c2ecf20Sopenharmony_ciecrdsa:
2698c2ecf20Sopenharmony_ci	ctx->cert->sig->pkey_algo = "ecrdsa";
2708c2ecf20Sopenharmony_ci	ctx->cert->sig->encoding = "raw";
2718c2ecf20Sopenharmony_ci	ctx->algo_oid = ctx->last_oid;
2728c2ecf20Sopenharmony_ci	return 0;
2738c2ecf20Sopenharmony_cism2:
2748c2ecf20Sopenharmony_ci	ctx->cert->sig->pkey_algo = "sm2";
2758c2ecf20Sopenharmony_ci	ctx->cert->sig->encoding = "raw";
2768c2ecf20Sopenharmony_ci	ctx->algo_oid = ctx->last_oid;
2778c2ecf20Sopenharmony_ci	return 0;
2788c2ecf20Sopenharmony_ciecdsa:
2798c2ecf20Sopenharmony_ci	ctx->cert->sig->pkey_algo = "ecdsa";
2808c2ecf20Sopenharmony_ci	ctx->cert->sig->encoding = "x962";
2818c2ecf20Sopenharmony_ci	ctx->algo_oid = ctx->last_oid;
2828c2ecf20Sopenharmony_ci	return 0;
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci/*
2868c2ecf20Sopenharmony_ci * Note the whereabouts and type of the signature.
2878c2ecf20Sopenharmony_ci */
2888c2ecf20Sopenharmony_ciint x509_note_signature(void *context, size_t hdrlen,
2898c2ecf20Sopenharmony_ci			unsigned char tag,
2908c2ecf20Sopenharmony_ci			const void *value, size_t vlen)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	struct x509_parse_context *ctx = context;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	pr_debug("Signature type: %u size %zu\n", ctx->last_oid, vlen);
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (ctx->last_oid != ctx->algo_oid) {
2978c2ecf20Sopenharmony_ci		pr_warn("Got cert with pkey (%u) and sig (%u) algorithm OIDs\n",
2988c2ecf20Sopenharmony_ci			ctx->algo_oid, ctx->last_oid);
2998c2ecf20Sopenharmony_ci		return -EINVAL;
3008c2ecf20Sopenharmony_ci	}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	if (strcmp(ctx->cert->sig->pkey_algo, "rsa") == 0 ||
3038c2ecf20Sopenharmony_ci	    strcmp(ctx->cert->sig->pkey_algo, "ecrdsa") == 0 ||
3048c2ecf20Sopenharmony_ci	    strcmp(ctx->cert->sig->pkey_algo, "sm2") == 0 ||
3058c2ecf20Sopenharmony_ci	    strcmp(ctx->cert->sig->pkey_algo, "ecdsa") == 0) {
3068c2ecf20Sopenharmony_ci		/* Discard the BIT STRING metadata */
3078c2ecf20Sopenharmony_ci		if (vlen < 1 || *(const u8 *)value != 0)
3088c2ecf20Sopenharmony_ci			return -EBADMSG;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci		value++;
3118c2ecf20Sopenharmony_ci		vlen--;
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	ctx->cert->raw_sig = value;
3158c2ecf20Sopenharmony_ci	ctx->cert->raw_sig_size = vlen;
3168c2ecf20Sopenharmony_ci	return 0;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci/*
3208c2ecf20Sopenharmony_ci * Note the certificate serial number
3218c2ecf20Sopenharmony_ci */
3228c2ecf20Sopenharmony_ciint x509_note_serial(void *context, size_t hdrlen,
3238c2ecf20Sopenharmony_ci		     unsigned char tag,
3248c2ecf20Sopenharmony_ci		     const void *value, size_t vlen)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	struct x509_parse_context *ctx = context;
3278c2ecf20Sopenharmony_ci	ctx->cert->raw_serial = value;
3288c2ecf20Sopenharmony_ci	ctx->cert->raw_serial_size = vlen;
3298c2ecf20Sopenharmony_ci	return 0;
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci/*
3338c2ecf20Sopenharmony_ci * Note some of the name segments from which we'll fabricate a name.
3348c2ecf20Sopenharmony_ci */
3358c2ecf20Sopenharmony_ciint x509_extract_name_segment(void *context, size_t hdrlen,
3368c2ecf20Sopenharmony_ci			      unsigned char tag,
3378c2ecf20Sopenharmony_ci			      const void *value, size_t vlen)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	struct x509_parse_context *ctx = context;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	switch (ctx->last_oid) {
3428c2ecf20Sopenharmony_ci	case OID_commonName:
3438c2ecf20Sopenharmony_ci		ctx->cn_size = vlen;
3448c2ecf20Sopenharmony_ci		ctx->cn_offset = (unsigned long)value - ctx->data;
3458c2ecf20Sopenharmony_ci		break;
3468c2ecf20Sopenharmony_ci	case OID_organizationName:
3478c2ecf20Sopenharmony_ci		ctx->o_size = vlen;
3488c2ecf20Sopenharmony_ci		ctx->o_offset = (unsigned long)value - ctx->data;
3498c2ecf20Sopenharmony_ci		break;
3508c2ecf20Sopenharmony_ci	case OID_email_address:
3518c2ecf20Sopenharmony_ci		ctx->email_size = vlen;
3528c2ecf20Sopenharmony_ci		ctx->email_offset = (unsigned long)value - ctx->data;
3538c2ecf20Sopenharmony_ci		break;
3548c2ecf20Sopenharmony_ci	default:
3558c2ecf20Sopenharmony_ci		break;
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	return 0;
3598c2ecf20Sopenharmony_ci}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci/*
3628c2ecf20Sopenharmony_ci * Fabricate and save the issuer and subject names
3638c2ecf20Sopenharmony_ci */
3648c2ecf20Sopenharmony_cistatic int x509_fabricate_name(struct x509_parse_context *ctx, size_t hdrlen,
3658c2ecf20Sopenharmony_ci			       unsigned char tag,
3668c2ecf20Sopenharmony_ci			       char **_name, size_t vlen)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	const void *name, *data = (const void *)ctx->data;
3698c2ecf20Sopenharmony_ci	size_t namesize;
3708c2ecf20Sopenharmony_ci	char *buffer;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	if (*_name)
3738c2ecf20Sopenharmony_ci		return -EINVAL;
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	/* Empty name string if no material */
3768c2ecf20Sopenharmony_ci	if (!ctx->cn_size && !ctx->o_size && !ctx->email_size) {
3778c2ecf20Sopenharmony_ci		buffer = kmalloc(1, GFP_KERNEL);
3788c2ecf20Sopenharmony_ci		if (!buffer)
3798c2ecf20Sopenharmony_ci			return -ENOMEM;
3808c2ecf20Sopenharmony_ci		buffer[0] = 0;
3818c2ecf20Sopenharmony_ci		goto done;
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	if (ctx->cn_size && ctx->o_size) {
3858c2ecf20Sopenharmony_ci		/* Consider combining O and CN, but use only the CN if it is
3868c2ecf20Sopenharmony_ci		 * prefixed by the O, or a significant portion thereof.
3878c2ecf20Sopenharmony_ci		 */
3888c2ecf20Sopenharmony_ci		namesize = ctx->cn_size;
3898c2ecf20Sopenharmony_ci		name = data + ctx->cn_offset;
3908c2ecf20Sopenharmony_ci		if (ctx->cn_size >= ctx->o_size &&
3918c2ecf20Sopenharmony_ci		    memcmp(data + ctx->cn_offset, data + ctx->o_offset,
3928c2ecf20Sopenharmony_ci			   ctx->o_size) == 0)
3938c2ecf20Sopenharmony_ci			goto single_component;
3948c2ecf20Sopenharmony_ci		if (ctx->cn_size >= 7 &&
3958c2ecf20Sopenharmony_ci		    ctx->o_size >= 7 &&
3968c2ecf20Sopenharmony_ci		    memcmp(data + ctx->cn_offset, data + ctx->o_offset, 7) == 0)
3978c2ecf20Sopenharmony_ci			goto single_component;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci		buffer = kmalloc(ctx->o_size + 2 + ctx->cn_size + 1,
4008c2ecf20Sopenharmony_ci				 GFP_KERNEL);
4018c2ecf20Sopenharmony_ci		if (!buffer)
4028c2ecf20Sopenharmony_ci			return -ENOMEM;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci		memcpy(buffer,
4058c2ecf20Sopenharmony_ci		       data + ctx->o_offset, ctx->o_size);
4068c2ecf20Sopenharmony_ci		buffer[ctx->o_size + 0] = ':';
4078c2ecf20Sopenharmony_ci		buffer[ctx->o_size + 1] = ' ';
4088c2ecf20Sopenharmony_ci		memcpy(buffer + ctx->o_size + 2,
4098c2ecf20Sopenharmony_ci		       data + ctx->cn_offset, ctx->cn_size);
4108c2ecf20Sopenharmony_ci		buffer[ctx->o_size + 2 + ctx->cn_size] = 0;
4118c2ecf20Sopenharmony_ci		goto done;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	} else if (ctx->cn_size) {
4148c2ecf20Sopenharmony_ci		namesize = ctx->cn_size;
4158c2ecf20Sopenharmony_ci		name = data + ctx->cn_offset;
4168c2ecf20Sopenharmony_ci	} else if (ctx->o_size) {
4178c2ecf20Sopenharmony_ci		namesize = ctx->o_size;
4188c2ecf20Sopenharmony_ci		name = data + ctx->o_offset;
4198c2ecf20Sopenharmony_ci	} else {
4208c2ecf20Sopenharmony_ci		namesize = ctx->email_size;
4218c2ecf20Sopenharmony_ci		name = data + ctx->email_offset;
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_cisingle_component:
4258c2ecf20Sopenharmony_ci	buffer = kmalloc(namesize + 1, GFP_KERNEL);
4268c2ecf20Sopenharmony_ci	if (!buffer)
4278c2ecf20Sopenharmony_ci		return -ENOMEM;
4288c2ecf20Sopenharmony_ci	memcpy(buffer, name, namesize);
4298c2ecf20Sopenharmony_ci	buffer[namesize] = 0;
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_cidone:
4328c2ecf20Sopenharmony_ci	*_name = buffer;
4338c2ecf20Sopenharmony_ci	ctx->cn_size = 0;
4348c2ecf20Sopenharmony_ci	ctx->o_size = 0;
4358c2ecf20Sopenharmony_ci	ctx->email_size = 0;
4368c2ecf20Sopenharmony_ci	return 0;
4378c2ecf20Sopenharmony_ci}
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ciint x509_note_issuer(void *context, size_t hdrlen,
4408c2ecf20Sopenharmony_ci		     unsigned char tag,
4418c2ecf20Sopenharmony_ci		     const void *value, size_t vlen)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	struct x509_parse_context *ctx = context;
4448c2ecf20Sopenharmony_ci	ctx->cert->raw_issuer = value;
4458c2ecf20Sopenharmony_ci	ctx->cert->raw_issuer_size = vlen;
4468c2ecf20Sopenharmony_ci	return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen);
4478c2ecf20Sopenharmony_ci}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ciint x509_note_subject(void *context, size_t hdrlen,
4508c2ecf20Sopenharmony_ci		      unsigned char tag,
4518c2ecf20Sopenharmony_ci		      const void *value, size_t vlen)
4528c2ecf20Sopenharmony_ci{
4538c2ecf20Sopenharmony_ci	struct x509_parse_context *ctx = context;
4548c2ecf20Sopenharmony_ci	ctx->cert->raw_subject = value;
4558c2ecf20Sopenharmony_ci	ctx->cert->raw_subject_size = vlen;
4568c2ecf20Sopenharmony_ci	return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen);
4578c2ecf20Sopenharmony_ci}
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci/*
4608c2ecf20Sopenharmony_ci * Extract the parameters for the public key
4618c2ecf20Sopenharmony_ci */
4628c2ecf20Sopenharmony_ciint x509_note_params(void *context, size_t hdrlen,
4638c2ecf20Sopenharmony_ci		     unsigned char tag,
4648c2ecf20Sopenharmony_ci		     const void *value, size_t vlen)
4658c2ecf20Sopenharmony_ci{
4668c2ecf20Sopenharmony_ci	struct x509_parse_context *ctx = context;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	/*
4698c2ecf20Sopenharmony_ci	 * AlgorithmIdentifier is used three times in the x509, we should skip
4708c2ecf20Sopenharmony_ci	 * first and ignore third, using second one which is after subject and
4718c2ecf20Sopenharmony_ci	 * before subjectPublicKey.
4728c2ecf20Sopenharmony_ci	 */
4738c2ecf20Sopenharmony_ci	if (!ctx->cert->raw_subject || ctx->key)
4748c2ecf20Sopenharmony_ci		return 0;
4758c2ecf20Sopenharmony_ci	ctx->params = value - hdrlen;
4768c2ecf20Sopenharmony_ci	ctx->params_size = vlen + hdrlen;
4778c2ecf20Sopenharmony_ci	return 0;
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci/*
4818c2ecf20Sopenharmony_ci * Extract the data for the public key algorithm
4828c2ecf20Sopenharmony_ci */
4838c2ecf20Sopenharmony_ciint x509_extract_key_data(void *context, size_t hdrlen,
4848c2ecf20Sopenharmony_ci			  unsigned char tag,
4858c2ecf20Sopenharmony_ci			  const void *value, size_t vlen)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	struct x509_parse_context *ctx = context;
4888c2ecf20Sopenharmony_ci	enum OID oid;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	ctx->key_algo = ctx->last_oid;
4918c2ecf20Sopenharmony_ci	switch (ctx->last_oid) {
4928c2ecf20Sopenharmony_ci	case OID_rsaEncryption:
4938c2ecf20Sopenharmony_ci		ctx->cert->pub->pkey_algo = "rsa";
4948c2ecf20Sopenharmony_ci		break;
4958c2ecf20Sopenharmony_ci	case OID_gost2012PKey256:
4968c2ecf20Sopenharmony_ci	case OID_gost2012PKey512:
4978c2ecf20Sopenharmony_ci		ctx->cert->pub->pkey_algo = "ecrdsa";
4988c2ecf20Sopenharmony_ci		break;
4998c2ecf20Sopenharmony_ci	case OID_id_ecPublicKey:
5008c2ecf20Sopenharmony_ci		if (parse_OID(ctx->params, ctx->params_size, &oid) != 0)
5018c2ecf20Sopenharmony_ci			return -EBADMSG;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci		switch (oid) {
5048c2ecf20Sopenharmony_ci		case OID_sm2:
5058c2ecf20Sopenharmony_ci			ctx->cert->pub->pkey_algo = "sm2";
5068c2ecf20Sopenharmony_ci			break;
5078c2ecf20Sopenharmony_ci		case OID_id_prime192v1:
5088c2ecf20Sopenharmony_ci			ctx->cert->pub->pkey_algo = "ecdsa-nist-p192";
5098c2ecf20Sopenharmony_ci			break;
5108c2ecf20Sopenharmony_ci		case OID_id_prime256v1:
5118c2ecf20Sopenharmony_ci			ctx->cert->pub->pkey_algo = "ecdsa-nist-p256";
5128c2ecf20Sopenharmony_ci			break;
5138c2ecf20Sopenharmony_ci		case OID_id_ansip384r1:
5148c2ecf20Sopenharmony_ci			ctx->cert->pub->pkey_algo = "ecdsa-nist-p384";
5158c2ecf20Sopenharmony_ci			break;
5168c2ecf20Sopenharmony_ci		default:
5178c2ecf20Sopenharmony_ci			return -ENOPKG;
5188c2ecf20Sopenharmony_ci		}
5198c2ecf20Sopenharmony_ci		break;
5208c2ecf20Sopenharmony_ci	default:
5218c2ecf20Sopenharmony_ci		return -ENOPKG;
5228c2ecf20Sopenharmony_ci	}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	/* Discard the BIT STRING metadata */
5258c2ecf20Sopenharmony_ci	if (vlen < 1 || *(const u8 *)value != 0)
5268c2ecf20Sopenharmony_ci		return -EBADMSG;
5278c2ecf20Sopenharmony_ci	ctx->key = value + 1;
5288c2ecf20Sopenharmony_ci	ctx->key_size = vlen - 1;
5298c2ecf20Sopenharmony_ci	return 0;
5308c2ecf20Sopenharmony_ci}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci/* The keyIdentifier in AuthorityKeyIdentifier SEQUENCE is tag(CONT,PRIM,0) */
5338c2ecf20Sopenharmony_ci#define SEQ_TAG_KEYID (ASN1_CONT << 6)
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci/*
5368c2ecf20Sopenharmony_ci * Process certificate extensions that are used to qualify the certificate.
5378c2ecf20Sopenharmony_ci */
5388c2ecf20Sopenharmony_ciint x509_process_extension(void *context, size_t hdrlen,
5398c2ecf20Sopenharmony_ci			   unsigned char tag,
5408c2ecf20Sopenharmony_ci			   const void *value, size_t vlen)
5418c2ecf20Sopenharmony_ci{
5428c2ecf20Sopenharmony_ci	struct x509_parse_context *ctx = context;
5438c2ecf20Sopenharmony_ci	struct asymmetric_key_id *kid;
5448c2ecf20Sopenharmony_ci	const unsigned char *v = value;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	pr_debug("Extension: %u\n", ctx->last_oid);
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	if (ctx->last_oid == OID_subjectKeyIdentifier) {
5498c2ecf20Sopenharmony_ci		/* Get hold of the key fingerprint */
5508c2ecf20Sopenharmony_ci		if (ctx->cert->skid || vlen < 3)
5518c2ecf20Sopenharmony_ci			return -EBADMSG;
5528c2ecf20Sopenharmony_ci		if (v[0] != ASN1_OTS || v[1] != vlen - 2)
5538c2ecf20Sopenharmony_ci			return -EBADMSG;
5548c2ecf20Sopenharmony_ci		v += 2;
5558c2ecf20Sopenharmony_ci		vlen -= 2;
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci		ctx->cert->raw_skid_size = vlen;
5588c2ecf20Sopenharmony_ci		ctx->cert->raw_skid = v;
5598c2ecf20Sopenharmony_ci		kid = asymmetric_key_generate_id(v, vlen, "", 0);
5608c2ecf20Sopenharmony_ci		if (IS_ERR(kid))
5618c2ecf20Sopenharmony_ci			return PTR_ERR(kid);
5628c2ecf20Sopenharmony_ci		ctx->cert->skid = kid;
5638c2ecf20Sopenharmony_ci		pr_debug("subjkeyid %*phN\n", kid->len, kid->data);
5648c2ecf20Sopenharmony_ci		return 0;
5658c2ecf20Sopenharmony_ci	}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	if (ctx->last_oid == OID_authorityKeyIdentifier) {
5688c2ecf20Sopenharmony_ci		/* Get hold of the CA key fingerprint */
5698c2ecf20Sopenharmony_ci		ctx->raw_akid = v;
5708c2ecf20Sopenharmony_ci		ctx->raw_akid_size = vlen;
5718c2ecf20Sopenharmony_ci		return 0;
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	return 0;
5758c2ecf20Sopenharmony_ci}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci/**
5788c2ecf20Sopenharmony_ci * x509_decode_time - Decode an X.509 time ASN.1 object
5798c2ecf20Sopenharmony_ci * @_t: The time to fill in
5808c2ecf20Sopenharmony_ci * @hdrlen: The length of the object header
5818c2ecf20Sopenharmony_ci * @tag: The object tag
5828c2ecf20Sopenharmony_ci * @value: The object value
5838c2ecf20Sopenharmony_ci * @vlen: The size of the object value
5848c2ecf20Sopenharmony_ci *
5858c2ecf20Sopenharmony_ci * Decode an ASN.1 universal time or generalised time field into a struct the
5868c2ecf20Sopenharmony_ci * kernel can handle and check it for validity.  The time is decoded thus:
5878c2ecf20Sopenharmony_ci *
5888c2ecf20Sopenharmony_ci *	[RFC5280 §4.1.2.5]
5898c2ecf20Sopenharmony_ci *	CAs conforming to this profile MUST always encode certificate validity
5908c2ecf20Sopenharmony_ci *	dates through the year 2049 as UTCTime; certificate validity dates in
5918c2ecf20Sopenharmony_ci *	2050 or later MUST be encoded as GeneralizedTime.  Conforming
5928c2ecf20Sopenharmony_ci *	applications MUST be able to process validity dates that are encoded in
5938c2ecf20Sopenharmony_ci *	either UTCTime or GeneralizedTime.
5948c2ecf20Sopenharmony_ci */
5958c2ecf20Sopenharmony_ciint x509_decode_time(time64_t *_t,  size_t hdrlen,
5968c2ecf20Sopenharmony_ci		     unsigned char tag,
5978c2ecf20Sopenharmony_ci		     const unsigned char *value, size_t vlen)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	static const unsigned char month_lengths[] = { 31, 28, 31, 30, 31, 30,
6008c2ecf20Sopenharmony_ci						       31, 31, 30, 31, 30, 31 };
6018c2ecf20Sopenharmony_ci	const unsigned char *p = value;
6028c2ecf20Sopenharmony_ci	unsigned year, mon, day, hour, min, sec, mon_len;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci#define dec2bin(X) ({ unsigned char x = (X) - '0'; if (x > 9) goto invalid_time; x; })
6058c2ecf20Sopenharmony_ci#define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; })
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	if (tag == ASN1_UNITIM) {
6088c2ecf20Sopenharmony_ci		/* UTCTime: YYMMDDHHMMSSZ */
6098c2ecf20Sopenharmony_ci		if (vlen != 13)
6108c2ecf20Sopenharmony_ci			goto unsupported_time;
6118c2ecf20Sopenharmony_ci		year = DD2bin(p);
6128c2ecf20Sopenharmony_ci		if (year >= 50)
6138c2ecf20Sopenharmony_ci			year += 1900;
6148c2ecf20Sopenharmony_ci		else
6158c2ecf20Sopenharmony_ci			year += 2000;
6168c2ecf20Sopenharmony_ci	} else if (tag == ASN1_GENTIM) {
6178c2ecf20Sopenharmony_ci		/* GenTime: YYYYMMDDHHMMSSZ */
6188c2ecf20Sopenharmony_ci		if (vlen != 15)
6198c2ecf20Sopenharmony_ci			goto unsupported_time;
6208c2ecf20Sopenharmony_ci		year = DD2bin(p) * 100 + DD2bin(p);
6218c2ecf20Sopenharmony_ci		if (year >= 1950 && year <= 2049)
6228c2ecf20Sopenharmony_ci			goto invalid_time;
6238c2ecf20Sopenharmony_ci	} else {
6248c2ecf20Sopenharmony_ci		goto unsupported_time;
6258c2ecf20Sopenharmony_ci	}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	mon  = DD2bin(p);
6288c2ecf20Sopenharmony_ci	day = DD2bin(p);
6298c2ecf20Sopenharmony_ci	hour = DD2bin(p);
6308c2ecf20Sopenharmony_ci	min  = DD2bin(p);
6318c2ecf20Sopenharmony_ci	sec  = DD2bin(p);
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	if (*p != 'Z')
6348c2ecf20Sopenharmony_ci		goto unsupported_time;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	if (year < 1970 ||
6378c2ecf20Sopenharmony_ci	    mon < 1 || mon > 12)
6388c2ecf20Sopenharmony_ci		goto invalid_time;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	mon_len = month_lengths[mon - 1];
6418c2ecf20Sopenharmony_ci	if (mon == 2) {
6428c2ecf20Sopenharmony_ci		if (year % 4 == 0) {
6438c2ecf20Sopenharmony_ci			mon_len = 29;
6448c2ecf20Sopenharmony_ci			if (year % 100 == 0) {
6458c2ecf20Sopenharmony_ci				mon_len = 28;
6468c2ecf20Sopenharmony_ci				if (year % 400 == 0)
6478c2ecf20Sopenharmony_ci					mon_len = 29;
6488c2ecf20Sopenharmony_ci			}
6498c2ecf20Sopenharmony_ci		}
6508c2ecf20Sopenharmony_ci	}
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	if (day < 1 || day > mon_len ||
6538c2ecf20Sopenharmony_ci	    hour > 24 || /* ISO 8601 permits 24:00:00 as midnight tomorrow */
6548c2ecf20Sopenharmony_ci	    min > 59 ||
6558c2ecf20Sopenharmony_ci	    sec > 60) /* ISO 8601 permits leap seconds [X.680 46.3] */
6568c2ecf20Sopenharmony_ci		goto invalid_time;
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	*_t = mktime64(year, mon, day, hour, min, sec);
6598c2ecf20Sopenharmony_ci	return 0;
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ciunsupported_time:
6628c2ecf20Sopenharmony_ci	pr_debug("Got unsupported time [tag %02x]: '%*phN'\n",
6638c2ecf20Sopenharmony_ci		 tag, (int)vlen, value);
6648c2ecf20Sopenharmony_ci	return -EBADMSG;
6658c2ecf20Sopenharmony_ciinvalid_time:
6668c2ecf20Sopenharmony_ci	pr_debug("Got invalid time [tag %02x]: '%*phN'\n",
6678c2ecf20Sopenharmony_ci		 tag, (int)vlen, value);
6688c2ecf20Sopenharmony_ci	return -EBADMSG;
6698c2ecf20Sopenharmony_ci}
6708c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(x509_decode_time);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ciint x509_note_not_before(void *context, size_t hdrlen,
6738c2ecf20Sopenharmony_ci			 unsigned char tag,
6748c2ecf20Sopenharmony_ci			 const void *value, size_t vlen)
6758c2ecf20Sopenharmony_ci{
6768c2ecf20Sopenharmony_ci	struct x509_parse_context *ctx = context;
6778c2ecf20Sopenharmony_ci	return x509_decode_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen);
6788c2ecf20Sopenharmony_ci}
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ciint x509_note_not_after(void *context, size_t hdrlen,
6818c2ecf20Sopenharmony_ci			unsigned char tag,
6828c2ecf20Sopenharmony_ci			const void *value, size_t vlen)
6838c2ecf20Sopenharmony_ci{
6848c2ecf20Sopenharmony_ci	struct x509_parse_context *ctx = context;
6858c2ecf20Sopenharmony_ci	return x509_decode_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen);
6868c2ecf20Sopenharmony_ci}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci/*
6898c2ecf20Sopenharmony_ci * Note a key identifier-based AuthorityKeyIdentifier
6908c2ecf20Sopenharmony_ci */
6918c2ecf20Sopenharmony_ciint x509_akid_note_kid(void *context, size_t hdrlen,
6928c2ecf20Sopenharmony_ci		       unsigned char tag,
6938c2ecf20Sopenharmony_ci		       const void *value, size_t vlen)
6948c2ecf20Sopenharmony_ci{
6958c2ecf20Sopenharmony_ci	struct x509_parse_context *ctx = context;
6968c2ecf20Sopenharmony_ci	struct asymmetric_key_id *kid;
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	pr_debug("AKID: keyid: %*phN\n", (int)vlen, value);
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	if (ctx->cert->sig->auth_ids[1])
7018c2ecf20Sopenharmony_ci		return 0;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	kid = asymmetric_key_generate_id(value, vlen, "", 0);
7048c2ecf20Sopenharmony_ci	if (IS_ERR(kid))
7058c2ecf20Sopenharmony_ci		return PTR_ERR(kid);
7068c2ecf20Sopenharmony_ci	pr_debug("authkeyid %*phN\n", kid->len, kid->data);
7078c2ecf20Sopenharmony_ci	ctx->cert->sig->auth_ids[1] = kid;
7088c2ecf20Sopenharmony_ci	return 0;
7098c2ecf20Sopenharmony_ci}
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci/*
7128c2ecf20Sopenharmony_ci * Note a directoryName in an AuthorityKeyIdentifier
7138c2ecf20Sopenharmony_ci */
7148c2ecf20Sopenharmony_ciint x509_akid_note_name(void *context, size_t hdrlen,
7158c2ecf20Sopenharmony_ci			unsigned char tag,
7168c2ecf20Sopenharmony_ci			const void *value, size_t vlen)
7178c2ecf20Sopenharmony_ci{
7188c2ecf20Sopenharmony_ci	struct x509_parse_context *ctx = context;
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	pr_debug("AKID: name: %*phN\n", (int)vlen, value);
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	ctx->akid_raw_issuer = value;
7238c2ecf20Sopenharmony_ci	ctx->akid_raw_issuer_size = vlen;
7248c2ecf20Sopenharmony_ci	return 0;
7258c2ecf20Sopenharmony_ci}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci/*
7288c2ecf20Sopenharmony_ci * Note a serial number in an AuthorityKeyIdentifier
7298c2ecf20Sopenharmony_ci */
7308c2ecf20Sopenharmony_ciint x509_akid_note_serial(void *context, size_t hdrlen,
7318c2ecf20Sopenharmony_ci			  unsigned char tag,
7328c2ecf20Sopenharmony_ci			  const void *value, size_t vlen)
7338c2ecf20Sopenharmony_ci{
7348c2ecf20Sopenharmony_ci	struct x509_parse_context *ctx = context;
7358c2ecf20Sopenharmony_ci	struct asymmetric_key_id *kid;
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	pr_debug("AKID: serial: %*phN\n", (int)vlen, value);
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	if (!ctx->akid_raw_issuer || ctx->cert->sig->auth_ids[0])
7408c2ecf20Sopenharmony_ci		return 0;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	kid = asymmetric_key_generate_id(value,
7438c2ecf20Sopenharmony_ci					 vlen,
7448c2ecf20Sopenharmony_ci					 ctx->akid_raw_issuer,
7458c2ecf20Sopenharmony_ci					 ctx->akid_raw_issuer_size);
7468c2ecf20Sopenharmony_ci	if (IS_ERR(kid))
7478c2ecf20Sopenharmony_ci		return PTR_ERR(kid);
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	pr_debug("authkeyid %*phN\n", kid->len, kid->data);
7508c2ecf20Sopenharmony_ci	ctx->cert->sig->auth_ids[0] = kid;
7518c2ecf20Sopenharmony_ci	return 0;
7528c2ecf20Sopenharmony_ci}
753