summaryrefslogtreecommitdiff
path: root/lib/mbedtls/rsa_helper.c
blob: 3d94eee9954137a82b8d5176cd90f109467f6a6b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// SPDX-License-Identifier: GPL-2.0+
/*
 * RSA helper functions using MbedTLS
 *
 * Copyright (c) 2024 Linaro Limited
 * Author: Raymond Mao <raymond.mao@linaro.org>
 */

#include <linux/err.h>
#include <crypto/internal/rsa.h>
#include <library/common.h>
#include <mbedtls/pk.h>
#include <mbedtls/rsa.h>
#include <mbedtls/asn1.h>

/**
 * rsa_parse_pub_key() - decodes the BER encoded buffer and stores in the
 *                       provided struct rsa_key, pointers to the raw key as is,
 *                       so that the caller can copy it or MPI parse it, etc.
 *
 * @rsa_key:	struct rsa_key key representation
 * @key:	key in BER format
 * @key_len:	length of key
 *
 * Return:	0 on success or error code in case of error
 */
int rsa_parse_pub_key(struct rsa_key *rsa_key, const void *key,
		      unsigned int key_len)
{
	int ret = 0;
	mbedtls_pk_context pk;
	mbedtls_rsa_context *rsa;

	mbedtls_pk_init(&pk);

	ret = mbedtls_pk_parse_public_key(&pk, (const unsigned char *)key,
					  key_len);
	if (ret) {
		pr_err("Failed to parse public key, ret:-0x%04x\n", -ret);
		ret = -EINVAL;
		goto clean_pubkey;
	}

	/* Ensure that it is a RSA key */
	if (mbedtls_pk_get_type(&pk) != MBEDTLS_PK_RSA) {
		pr_err("Non-RSA keys are not supported\n");
		ret = -EKEYREJECTED;
		goto clean_pubkey;
	}

	/* Get RSA key context */
	rsa = mbedtls_pk_rsa(pk);
	if (!rsa) {
		pr_err("Failed to get RSA key context, ret:-0x%04x\n", -ret);
		ret = -EINVAL;
		goto clean_pubkey;
	}

	/* Parse modulus (n) */
	rsa_key->n_sz = mbedtls_mpi_size(&rsa->N);
	rsa_key->n = kzalloc(rsa_key->n_sz, GFP_KERNEL);
	if (!rsa_key->n) {
		ret = -ENOMEM;
		goto clean_pubkey;
	}
	ret = mbedtls_mpi_write_binary(&rsa->N, (unsigned char *)rsa_key->n,
				       rsa_key->n_sz);
	if (ret) {
		pr_err("Failed to parse modulus (n), ret:-0x%04x\n", -ret);
		ret = -EINVAL;
		goto clean_modulus;
	}

	/* Parse public exponent (e) */
	rsa_key->e_sz = mbedtls_mpi_size(&rsa->E);
	rsa_key->e = kzalloc(rsa_key->e_sz, GFP_KERNEL);
	if (!rsa_key->e) {
		ret = -ENOMEM;
		goto clean_modulus;
	}
	ret = mbedtls_mpi_write_binary(&rsa->E, (unsigned char *)rsa_key->e,
				       rsa_key->e_sz);
	if (!ret)
		return 0;

	pr_err("Failed to parse public exponent (e), ret:-0x%04x\n", -ret);
	ret = -EINVAL;

	kfree(rsa_key->e);
clean_modulus:
	kfree(rsa_key->n);
clean_pubkey:
	mbedtls_pk_free(&pk);
	return ret;
}