1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Public key helper functions using MbedTLS X509 library
4  *
5  * Copyright (c) 2024 Linaro Limited
6  * Author: Raymond Mao <raymond.mao@linaro.org>
7  */
8 
9 #include <linux/compat.h>
10 #include <crypto/public_key.h>
11 
public_key_verify_signature(const struct public_key * pkey,const struct public_key_signature * sig)12 int public_key_verify_signature(const struct public_key *pkey,
13 				const struct public_key_signature *sig)
14 {
15 	mbedtls_md_type_t mb_hash_algo;
16 	mbedtls_pk_context pk_ctx;
17 	int ret;
18 
19 	if (!pkey || !sig || pkey->key_is_private)
20 		return -EINVAL;
21 
22 	/*
23 	 * ECRDSA (Elliptic Curve Russian Digital Signature Algorithm) is not
24 	 * supported by MbedTLS.
25 	 */
26 	if (strcmp(pkey->pkey_algo, "rsa")) {
27 		pr_err("Encryption is not RSA: %s\n", sig->pkey_algo);
28 		return -EINVAL;
29 	}
30 
31 	/*
32 	 * Can be pkcs1 or raw, but pkcs1 is expected.
33 	 * This is just for argument checking, not necessarily passed to MbedTLS,
34 	 * For RSA signatures, MbedTLS typically supports the PKCS#1 v1.5
35 	 * (aka. pkcs1) encoding by default.
36 	 * The library internally handles the details of decoding and verifying
37 	 * the signature according to the expected encoding for the specified algorithm.
38 	 */
39 	if (strcmp(sig->encoding, "pkcs1")) {
40 		pr_err("Encoding %s is not supported, only supports pkcs1\n",
41 		       sig->encoding);
42 		return -EINVAL;
43 	}
44 
45 	if (!strcmp(sig->hash_algo, "sha1"))
46 		mb_hash_algo = MBEDTLS_MD_SHA1;
47 	else if (!strcmp(sig->hash_algo, "sha224"))
48 		mb_hash_algo = MBEDTLS_MD_SHA224;
49 	else if (!strcmp(sig->hash_algo, "sha256"))
50 		mb_hash_algo = MBEDTLS_MD_SHA256;
51 	else if (!strcmp(sig->hash_algo, "sha384"))
52 		mb_hash_algo = MBEDTLS_MD_SHA384;
53 	else if (!strcmp(sig->hash_algo, "sha512"))
54 		mb_hash_algo = MBEDTLS_MD_SHA512;
55 	else	/* Unknown or unsupported hash algorithm */
56 		return -EINVAL;
57 	/* Initialize the mbedtls_pk_context with RSA key type */
58 	mbedtls_pk_init(&pk_ctx);
59 
60 	/* Parse the DER-encoded public key */
61 	ret = mbedtls_pk_parse_public_key(&pk_ctx, pkey->key, pkey->keylen);
62 	if (ret) {
63 		pr_err("Failed to parse public key, ret:-0x%04x\n", -ret);
64 		ret = -EINVAL;
65 		goto err_key;
66 	}
67 
68 	/* Ensure that it is a RSA key */
69 	if (mbedtls_pk_get_type(&pk_ctx) != MBEDTLS_PK_RSA) {
70 		pr_err("Only RSA keys are supported\n");
71 		ret = -EKEYREJECTED;
72 		goto err_key;
73 	}
74 
75 	/* Verify the hash */
76 	ret = mbedtls_pk_verify(&pk_ctx, mb_hash_algo, sig->digest,
77 				sig->digest_size, sig->s, sig->s_size);
78 
79 err_key:
80 	mbedtls_pk_free(&pk_ctx);
81 	return ret;
82 }
83