xref: /rk3399_rockchip-uboot/lib/rsa/rsa-sign.c (revision bc61c80792725a063477c83e5ee06c435679cd6c)
119c402afSSimon Glass /*
219c402afSSimon Glass  * Copyright (c) 2013, Google Inc.
319c402afSSimon Glass  *
41a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
519c402afSSimon Glass  */
619c402afSSimon Glass 
719c402afSSimon Glass #include "mkimage.h"
819c402afSSimon Glass #include <stdio.h>
919c402afSSimon Glass #include <string.h>
1019c402afSSimon Glass #include <image.h>
1119c402afSSimon Glass #include <time.h>
12781ee9b3SJason Zhu #include <generated/autoconf.h>
13c3b43281SJelle van der Waa #include <openssl/bn.h>
1419c402afSSimon Glass #include <openssl/rsa.h>
1519c402afSSimon Glass #include <openssl/pem.h>
1619c402afSSimon Glass #include <openssl/err.h>
1719c402afSSimon Glass #include <openssl/ssl.h>
1819c402afSSimon Glass #include <openssl/evp.h>
19f1ca1fdeSGeorge McCollister #include <openssl/engine.h>
2019c402afSSimon Glass 
2119c402afSSimon Glass #if OPENSSL_VERSION_NUMBER >= 0x10000000L
2219c402afSSimon Glass #define HAVE_ERR_REMOVE_THREAD_STATE
2319c402afSSimon Glass #endif
2419c402afSSimon Glass 
25c3b43281SJelle van der Waa #if OPENSSL_VERSION_NUMBER < 0x10100000L
RSA_get0_key(const RSA * r,const BIGNUM ** n,const BIGNUM ** e,const BIGNUM ** d)26c3b43281SJelle van der Waa static void RSA_get0_key(const RSA *r,
27c3b43281SJelle van der Waa                  const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
28c3b43281SJelle van der Waa {
29c3b43281SJelle van der Waa    if (n != NULL)
30c3b43281SJelle van der Waa        *n = r->n;
31c3b43281SJelle van der Waa    if (e != NULL)
32c3b43281SJelle van der Waa        *e = r->e;
33c3b43281SJelle van der Waa    if (d != NULL)
34c3b43281SJelle van der Waa        *d = r->d;
35c3b43281SJelle van der Waa }
36c3b43281SJelle van der Waa #endif
37c3b43281SJelle van der Waa 
rsa_err(const char * msg)3819c402afSSimon Glass static int rsa_err(const char *msg)
3919c402afSSimon Glass {
4019c402afSSimon Glass 	unsigned long sslErr = ERR_get_error();
4119c402afSSimon Glass 
4219c402afSSimon Glass 	fprintf(stderr, "%s", msg);
4319c402afSSimon Glass 	fprintf(stderr, ": %s\n",
4419c402afSSimon Glass 		ERR_error_string(sslErr, 0));
4519c402afSSimon Glass 
4619c402afSSimon Glass 	return -1;
4719c402afSSimon Glass }
4819c402afSSimon Glass 
4919c402afSSimon Glass /**
50f1ca1fdeSGeorge McCollister  * rsa_pem_get_pub_key() - read a public key from a .crt file
5119c402afSSimon Glass  *
5219c402afSSimon Glass  * @keydir:	Directory containins the key
5319c402afSSimon Glass  * @name	Name of key file (will have a .crt extension)
5419c402afSSimon Glass  * @rsap	Returns RSA object, or NULL on failure
5519c402afSSimon Glass  * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
5619c402afSSimon Glass  */
rsa_pem_get_pub_key(const char * keydir,const char * name,RSA ** rsap)57f1ca1fdeSGeorge McCollister static int rsa_pem_get_pub_key(const char *keydir, const char *name, RSA **rsap)
5819c402afSSimon Glass {
5919c402afSSimon Glass 	char path[1024];
6019c402afSSimon Glass 	EVP_PKEY *key;
6119c402afSSimon Glass 	X509 *cert;
6219c402afSSimon Glass 	RSA *rsa;
6319c402afSSimon Glass 	FILE *f;
6419c402afSSimon Glass 	int ret;
6519c402afSSimon Glass 
6619c402afSSimon Glass 	*rsap = NULL;
6719c402afSSimon Glass 	snprintf(path, sizeof(path), "%s/%s.crt", keydir, name);
6819c402afSSimon Glass 	f = fopen(path, "r");
6919c402afSSimon Glass 	if (!f) {
7019c402afSSimon Glass 		fprintf(stderr, "Couldn't open RSA certificate: '%s': %s\n",
7119c402afSSimon Glass 			path, strerror(errno));
7219c402afSSimon Glass 		return -EACCES;
7319c402afSSimon Glass 	}
7419c402afSSimon Glass 
7519c402afSSimon Glass 	/* Read the certificate */
7619c402afSSimon Glass 	cert = NULL;
7719c402afSSimon Glass 	if (!PEM_read_X509(f, &cert, NULL, NULL)) {
7819c402afSSimon Glass 		rsa_err("Couldn't read certificate");
7919c402afSSimon Glass 		ret = -EINVAL;
8019c402afSSimon Glass 		goto err_cert;
8119c402afSSimon Glass 	}
8219c402afSSimon Glass 
8319c402afSSimon Glass 	/* Get the public key from the certificate. */
8419c402afSSimon Glass 	key = X509_get_pubkey(cert);
8519c402afSSimon Glass 	if (!key) {
8619c402afSSimon Glass 		rsa_err("Couldn't read public key\n");
8719c402afSSimon Glass 		ret = -EINVAL;
8819c402afSSimon Glass 		goto err_pubkey;
8919c402afSSimon Glass 	}
9019c402afSSimon Glass 
9119c402afSSimon Glass 	/* Convert to a RSA_style key. */
9219c402afSSimon Glass 	rsa = EVP_PKEY_get1_RSA(key);
9319c402afSSimon Glass 	if (!rsa) {
9419c402afSSimon Glass 		rsa_err("Couldn't convert to a RSA style key");
9554267162SSimon Glass 		ret = -EINVAL;
9619c402afSSimon Glass 		goto err_rsa;
9719c402afSSimon Glass 	}
9819c402afSSimon Glass 	fclose(f);
9919c402afSSimon Glass 	EVP_PKEY_free(key);
10019c402afSSimon Glass 	X509_free(cert);
10119c402afSSimon Glass 	*rsap = rsa;
10219c402afSSimon Glass 
10319c402afSSimon Glass 	return 0;
10419c402afSSimon Glass 
10519c402afSSimon Glass err_rsa:
10619c402afSSimon Glass 	EVP_PKEY_free(key);
10719c402afSSimon Glass err_pubkey:
10819c402afSSimon Glass 	X509_free(cert);
10919c402afSSimon Glass err_cert:
11019c402afSSimon Glass 	fclose(f);
11119c402afSSimon Glass 	return ret;
11219c402afSSimon Glass }
11319c402afSSimon Glass 
11419c402afSSimon Glass /**
115f1ca1fdeSGeorge McCollister  * rsa_engine_get_pub_key() - read a public key from given engine
11619c402afSSimon Glass  *
117f1ca1fdeSGeorge McCollister  * @keydir:	Key prefix
118f1ca1fdeSGeorge McCollister  * @name	Name of key
119f1ca1fdeSGeorge McCollister  * @engine	Engine to use
120f1ca1fdeSGeorge McCollister  * @rsap	Returns RSA object, or NULL on failure
121f1ca1fdeSGeorge McCollister  * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
122f1ca1fdeSGeorge McCollister  */
rsa_engine_get_pub_key(const char * keydir,const char * name,ENGINE * engine,RSA ** rsap)123f1ca1fdeSGeorge McCollister static int rsa_engine_get_pub_key(const char *keydir, const char *name,
124f1ca1fdeSGeorge McCollister 				  ENGINE *engine, RSA **rsap)
125f1ca1fdeSGeorge McCollister {
126f1ca1fdeSGeorge McCollister 	const char *engine_id;
127f1ca1fdeSGeorge McCollister 	char key_id[1024];
128f1ca1fdeSGeorge McCollister 	EVP_PKEY *key;
129f1ca1fdeSGeorge McCollister 	RSA *rsa;
130f1ca1fdeSGeorge McCollister 	int ret;
131f1ca1fdeSGeorge McCollister 
132f1ca1fdeSGeorge McCollister 	*rsap = NULL;
133f1ca1fdeSGeorge McCollister 
134f1ca1fdeSGeorge McCollister 	engine_id = ENGINE_get_id(engine);
135f1ca1fdeSGeorge McCollister 
136f1ca1fdeSGeorge McCollister 	if (engine_id && !strcmp(engine_id, "pkcs11")) {
137f1ca1fdeSGeorge McCollister 		if (keydir)
138f1ca1fdeSGeorge McCollister 			snprintf(key_id, sizeof(key_id),
139f1ca1fdeSGeorge McCollister 				 "pkcs11:%s;object=%s;type=public",
140f1ca1fdeSGeorge McCollister 				 keydir, name);
141f1ca1fdeSGeorge McCollister 		else
142f1ca1fdeSGeorge McCollister 			snprintf(key_id, sizeof(key_id),
143f1ca1fdeSGeorge McCollister 				 "pkcs11:object=%s;type=public",
144f1ca1fdeSGeorge McCollister 				 name);
145f1ca1fdeSGeorge McCollister 	} else {
146f1ca1fdeSGeorge McCollister 		fprintf(stderr, "Engine not supported\n");
147f1ca1fdeSGeorge McCollister 		return -ENOTSUP;
148f1ca1fdeSGeorge McCollister 	}
149f1ca1fdeSGeorge McCollister 
150f1ca1fdeSGeorge McCollister 	key = ENGINE_load_public_key(engine, key_id, NULL, NULL);
151f1ca1fdeSGeorge McCollister 	if (!key)
152f1ca1fdeSGeorge McCollister 		return rsa_err("Failure loading public key from engine");
153f1ca1fdeSGeorge McCollister 
154f1ca1fdeSGeorge McCollister 	/* Convert to a RSA_style key. */
155f1ca1fdeSGeorge McCollister 	rsa = EVP_PKEY_get1_RSA(key);
156f1ca1fdeSGeorge McCollister 	if (!rsa) {
157f1ca1fdeSGeorge McCollister 		rsa_err("Couldn't convert to a RSA style key");
158f1ca1fdeSGeorge McCollister 		ret = -EINVAL;
159f1ca1fdeSGeorge McCollister 		goto err_rsa;
160f1ca1fdeSGeorge McCollister 	}
161f1ca1fdeSGeorge McCollister 
162f1ca1fdeSGeorge McCollister 	EVP_PKEY_free(key);
163f1ca1fdeSGeorge McCollister 	*rsap = rsa;
164f1ca1fdeSGeorge McCollister 
165f1ca1fdeSGeorge McCollister 	return 0;
166f1ca1fdeSGeorge McCollister 
167f1ca1fdeSGeorge McCollister err_rsa:
168f1ca1fdeSGeorge McCollister 	EVP_PKEY_free(key);
169f1ca1fdeSGeorge McCollister 	return ret;
170f1ca1fdeSGeorge McCollister }
171f1ca1fdeSGeorge McCollister 
172f1ca1fdeSGeorge McCollister /**
173f1ca1fdeSGeorge McCollister  * rsa_get_pub_key() - read a public key
174f1ca1fdeSGeorge McCollister  *
175f1ca1fdeSGeorge McCollister  * @keydir:	Directory containing the key (PEM file) or key prefix (engine)
176f1ca1fdeSGeorge McCollister  * @name	Name of key file (will have a .crt extension)
177f1ca1fdeSGeorge McCollister  * @engine	Engine to use
178f1ca1fdeSGeorge McCollister  * @rsap	Returns RSA object, or NULL on failure
179f1ca1fdeSGeorge McCollister  * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
180f1ca1fdeSGeorge McCollister  */
rsa_get_pub_key(const char * keydir,const char * name,ENGINE * engine,RSA ** rsap)181f1ca1fdeSGeorge McCollister static int rsa_get_pub_key(const char *keydir, const char *name,
182f1ca1fdeSGeorge McCollister 			   ENGINE *engine, RSA **rsap)
183f1ca1fdeSGeorge McCollister {
184f1ca1fdeSGeorge McCollister 	if (engine)
185f1ca1fdeSGeorge McCollister 		return rsa_engine_get_pub_key(keydir, name, engine, rsap);
186f1ca1fdeSGeorge McCollister 	return rsa_pem_get_pub_key(keydir, name, rsap);
187f1ca1fdeSGeorge McCollister }
188f1ca1fdeSGeorge McCollister 
189f1ca1fdeSGeorge McCollister /**
190f1ca1fdeSGeorge McCollister  * rsa_pem_get_priv_key() - read a private key from a .key file
191f1ca1fdeSGeorge McCollister  *
192f1ca1fdeSGeorge McCollister  * @keydir:	Directory containing the key
19319c402afSSimon Glass  * @name	Name of key file (will have a .key extension)
19419c402afSSimon Glass  * @rsap	Returns RSA object, or NULL on failure
19519c402afSSimon Glass  * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
19619c402afSSimon Glass  */
rsa_pem_get_priv_key(const char * keydir,const char * name,RSA ** rsap)197f1ca1fdeSGeorge McCollister static int rsa_pem_get_priv_key(const char *keydir, const char *name,
198f1ca1fdeSGeorge McCollister 				RSA **rsap)
19919c402afSSimon Glass {
20019c402afSSimon Glass 	char path[1024];
20119c402afSSimon Glass 	RSA *rsa;
20219c402afSSimon Glass 	FILE *f;
20319c402afSSimon Glass 
20419c402afSSimon Glass 	*rsap = NULL;
20519c402afSSimon Glass 	snprintf(path, sizeof(path), "%s/%s.key", keydir, name);
20619c402afSSimon Glass 	f = fopen(path, "r");
20719c402afSSimon Glass 	if (!f) {
20819c402afSSimon Glass 		fprintf(stderr, "Couldn't open RSA private key: '%s': %s\n",
20919c402afSSimon Glass 			path, strerror(errno));
21019c402afSSimon Glass 		return -ENOENT;
21119c402afSSimon Glass 	}
21219c402afSSimon Glass 
21319c402afSSimon Glass 	rsa = PEM_read_RSAPrivateKey(f, 0, NULL, path);
21419c402afSSimon Glass 	if (!rsa) {
21519c402afSSimon Glass 		rsa_err("Failure reading private key");
21619c402afSSimon Glass 		fclose(f);
21719c402afSSimon Glass 		return -EPROTO;
21819c402afSSimon Glass 	}
21919c402afSSimon Glass 	fclose(f);
22019c402afSSimon Glass 	*rsap = rsa;
22119c402afSSimon Glass 
22219c402afSSimon Glass 	return 0;
22319c402afSSimon Glass }
22419c402afSSimon Glass 
225f1ca1fdeSGeorge McCollister /**
226f1ca1fdeSGeorge McCollister  * rsa_engine_get_priv_key() - read a private key from given engine
227f1ca1fdeSGeorge McCollister  *
228f1ca1fdeSGeorge McCollister  * @keydir:	Key prefix
229f1ca1fdeSGeorge McCollister  * @name	Name of key
230f1ca1fdeSGeorge McCollister  * @engine	Engine to use
231f1ca1fdeSGeorge McCollister  * @rsap	Returns RSA object, or NULL on failure
232f1ca1fdeSGeorge McCollister  * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
233f1ca1fdeSGeorge McCollister  */
rsa_engine_get_priv_key(const char * keydir,const char * name,ENGINE * engine,RSA ** rsap)234f1ca1fdeSGeorge McCollister static int rsa_engine_get_priv_key(const char *keydir, const char *name,
235f1ca1fdeSGeorge McCollister 				   ENGINE *engine, RSA **rsap)
236f1ca1fdeSGeorge McCollister {
237f1ca1fdeSGeorge McCollister 	const char *engine_id;
238f1ca1fdeSGeorge McCollister 	char key_id[1024];
239f1ca1fdeSGeorge McCollister 	EVP_PKEY *key;
240f1ca1fdeSGeorge McCollister 	RSA *rsa;
241f1ca1fdeSGeorge McCollister 	int ret;
242f1ca1fdeSGeorge McCollister 
243f1ca1fdeSGeorge McCollister 	*rsap = NULL;
244f1ca1fdeSGeorge McCollister 
245f1ca1fdeSGeorge McCollister 	engine_id = ENGINE_get_id(engine);
246f1ca1fdeSGeorge McCollister 
247f1ca1fdeSGeorge McCollister 	if (engine_id && !strcmp(engine_id, "pkcs11")) {
248f1ca1fdeSGeorge McCollister 		if (keydir)
249f1ca1fdeSGeorge McCollister 			snprintf(key_id, sizeof(key_id),
250f1ca1fdeSGeorge McCollister 				 "pkcs11:%s;object=%s;type=private",
251f1ca1fdeSGeorge McCollister 				 keydir, name);
252f1ca1fdeSGeorge McCollister 		else
253f1ca1fdeSGeorge McCollister 			snprintf(key_id, sizeof(key_id),
254f1ca1fdeSGeorge McCollister 				 "pkcs11:object=%s;type=private",
255f1ca1fdeSGeorge McCollister 				 name);
256f1ca1fdeSGeorge McCollister 	} else {
257f1ca1fdeSGeorge McCollister 		fprintf(stderr, "Engine not supported\n");
258f1ca1fdeSGeorge McCollister 		return -ENOTSUP;
259f1ca1fdeSGeorge McCollister 	}
260f1ca1fdeSGeorge McCollister 
261f1ca1fdeSGeorge McCollister 	key = ENGINE_load_private_key(engine, key_id, NULL, NULL);
262f1ca1fdeSGeorge McCollister 	if (!key)
263f1ca1fdeSGeorge McCollister 		return rsa_err("Failure loading private key from engine");
264f1ca1fdeSGeorge McCollister 
265f1ca1fdeSGeorge McCollister 	/* Convert to a RSA_style key. */
266f1ca1fdeSGeorge McCollister 	rsa = EVP_PKEY_get1_RSA(key);
267f1ca1fdeSGeorge McCollister 	if (!rsa) {
268f1ca1fdeSGeorge McCollister 		rsa_err("Couldn't convert to a RSA style key");
269f1ca1fdeSGeorge McCollister 		ret = -EINVAL;
270f1ca1fdeSGeorge McCollister 		goto err_rsa;
271f1ca1fdeSGeorge McCollister 	}
272f1ca1fdeSGeorge McCollister 
273f1ca1fdeSGeorge McCollister 	EVP_PKEY_free(key);
274f1ca1fdeSGeorge McCollister 	*rsap = rsa;
275f1ca1fdeSGeorge McCollister 
276f1ca1fdeSGeorge McCollister 	return 0;
277f1ca1fdeSGeorge McCollister 
278f1ca1fdeSGeorge McCollister err_rsa:
279f1ca1fdeSGeorge McCollister 	EVP_PKEY_free(key);
280f1ca1fdeSGeorge McCollister 	return ret;
281f1ca1fdeSGeorge McCollister }
282f1ca1fdeSGeorge McCollister 
283f1ca1fdeSGeorge McCollister /**
284f1ca1fdeSGeorge McCollister  * rsa_get_priv_key() - read a private key
285f1ca1fdeSGeorge McCollister  *
286f1ca1fdeSGeorge McCollister  * @keydir:	Directory containing the key (PEM file) or key prefix (engine)
287f1ca1fdeSGeorge McCollister  * @name	Name of key
288f1ca1fdeSGeorge McCollister  * @engine	Engine to use for signing
289f1ca1fdeSGeorge McCollister  * @rsap	Returns RSA object, or NULL on failure
290f1ca1fdeSGeorge McCollister  * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
291f1ca1fdeSGeorge McCollister  */
rsa_get_priv_key(const char * keydir,const char * name,ENGINE * engine,RSA ** rsap)292f1ca1fdeSGeorge McCollister static int rsa_get_priv_key(const char *keydir, const char *name,
293f1ca1fdeSGeorge McCollister 			    ENGINE *engine, RSA **rsap)
294f1ca1fdeSGeorge McCollister {
295f1ca1fdeSGeorge McCollister 	if (engine)
296f1ca1fdeSGeorge McCollister 		return rsa_engine_get_priv_key(keydir, name, engine, rsap);
297f1ca1fdeSGeorge McCollister 	return rsa_pem_get_priv_key(keydir, name, rsap);
298f1ca1fdeSGeorge McCollister }
299f1ca1fdeSGeorge McCollister 
rsa_init(void)30019c402afSSimon Glass static int rsa_init(void)
30119c402afSSimon Glass {
30219c402afSSimon Glass 	int ret;
30319c402afSSimon Glass 
304c3b43281SJelle van der Waa #if OPENSSL_VERSION_NUMBER < 0x10100000L
30519c402afSSimon Glass 	ret = SSL_library_init();
306c3b43281SJelle van der Waa #else
307c3b43281SJelle van der Waa 	ret = OPENSSL_init_ssl(0, NULL);
308c3b43281SJelle van der Waa #endif
30919c402afSSimon Glass 	if (!ret) {
31019c402afSSimon Glass 		fprintf(stderr, "Failure to init SSL library\n");
31119c402afSSimon Glass 		return -1;
31219c402afSSimon Glass 	}
313c3b43281SJelle van der Waa #if OPENSSL_VERSION_NUMBER < 0x10100000L
31419c402afSSimon Glass 	SSL_load_error_strings();
31519c402afSSimon Glass 
31619c402afSSimon Glass 	OpenSSL_add_all_algorithms();
31719c402afSSimon Glass 	OpenSSL_add_all_digests();
31819c402afSSimon Glass 	OpenSSL_add_all_ciphers();
319c3b43281SJelle van der Waa #endif
32019c402afSSimon Glass 
32119c402afSSimon Glass 	return 0;
32219c402afSSimon Glass }
32319c402afSSimon Glass 
rsa_engine_init(const char * engine_id,ENGINE ** pe)324f1ca1fdeSGeorge McCollister static int rsa_engine_init(const char *engine_id, ENGINE **pe)
325f1ca1fdeSGeorge McCollister {
326f1ca1fdeSGeorge McCollister 	ENGINE *e;
327f1ca1fdeSGeorge McCollister 	int ret;
328f1ca1fdeSGeorge McCollister 
329f1ca1fdeSGeorge McCollister 	ENGINE_load_builtin_engines();
330f1ca1fdeSGeorge McCollister 
331f1ca1fdeSGeorge McCollister 	e = ENGINE_by_id(engine_id);
332f1ca1fdeSGeorge McCollister 	if (!e) {
333f1ca1fdeSGeorge McCollister 		fprintf(stderr, "Engine isn't available\n");
334f1ca1fdeSGeorge McCollister 		ret = -1;
335f1ca1fdeSGeorge McCollister 		goto err_engine_by_id;
336f1ca1fdeSGeorge McCollister 	}
337f1ca1fdeSGeorge McCollister 
338f1ca1fdeSGeorge McCollister 	if (!ENGINE_init(e)) {
339f1ca1fdeSGeorge McCollister 		fprintf(stderr, "Couldn't initialize engine\n");
340f1ca1fdeSGeorge McCollister 		ret = -1;
341f1ca1fdeSGeorge McCollister 		goto err_engine_init;
342f1ca1fdeSGeorge McCollister 	}
343f1ca1fdeSGeorge McCollister 
344f1ca1fdeSGeorge McCollister 	if (!ENGINE_set_default_RSA(e)) {
345f1ca1fdeSGeorge McCollister 		fprintf(stderr, "Couldn't set engine as default for RSA\n");
346f1ca1fdeSGeorge McCollister 		ret = -1;
347f1ca1fdeSGeorge McCollister 		goto err_set_rsa;
348f1ca1fdeSGeorge McCollister 	}
349f1ca1fdeSGeorge McCollister 
350f1ca1fdeSGeorge McCollister 	*pe = e;
351f1ca1fdeSGeorge McCollister 
352f1ca1fdeSGeorge McCollister 	return 0;
353f1ca1fdeSGeorge McCollister 
354f1ca1fdeSGeorge McCollister err_set_rsa:
355f1ca1fdeSGeorge McCollister 	ENGINE_finish(e);
356f1ca1fdeSGeorge McCollister err_engine_init:
357f1ca1fdeSGeorge McCollister 	ENGINE_free(e);
358f1ca1fdeSGeorge McCollister err_engine_by_id:
359c3b43281SJelle van der Waa #if OPENSSL_VERSION_NUMBER < 0x10100000L
360f1ca1fdeSGeorge McCollister 	ENGINE_cleanup();
361c3b43281SJelle van der Waa #endif
362f1ca1fdeSGeorge McCollister 	return ret;
363f1ca1fdeSGeorge McCollister }
364f1ca1fdeSGeorge McCollister 
rsa_remove(void)36519c402afSSimon Glass static void rsa_remove(void)
36619c402afSSimon Glass {
367c3b43281SJelle van der Waa #if OPENSSL_VERSION_NUMBER < 0x10100000L
36819c402afSSimon Glass 	CRYPTO_cleanup_all_ex_data();
36919c402afSSimon Glass 	ERR_free_strings();
37019c402afSSimon Glass #ifdef HAVE_ERR_REMOVE_THREAD_STATE
37119c402afSSimon Glass 	ERR_remove_thread_state(NULL);
37219c402afSSimon Glass #else
37319c402afSSimon Glass 	ERR_remove_state(0);
37419c402afSSimon Glass #endif
37519c402afSSimon Glass 	EVP_cleanup();
376c3b43281SJelle van der Waa #endif
37719c402afSSimon Glass }
37819c402afSSimon Glass 
rsa_engine_remove(ENGINE * e)379f1ca1fdeSGeorge McCollister static void rsa_engine_remove(ENGINE *e)
380f1ca1fdeSGeorge McCollister {
381f1ca1fdeSGeorge McCollister 	if (e) {
382f1ca1fdeSGeorge McCollister 		ENGINE_finish(e);
383f1ca1fdeSGeorge McCollister 		ENGINE_free(e);
384f1ca1fdeSGeorge McCollister 	}
385f1ca1fdeSGeorge McCollister }
386f1ca1fdeSGeorge McCollister 
387d46373c1SJoseph Chen /*
388d46373c1SJoseph Chen  * With this data2sign.bin, we can provide it to who real holds the RAS-private
389d46373c1SJoseph Chen  * key to sign current fit image. Then we replace the signature in fit image
390d46373c1SJoseph Chen  * with a valid one.
391d46373c1SJoseph Chen  */
gen_data2sign(const struct image_region region[],int region_count)392242e56faSJoseph Chen static int gen_data2sign(const struct image_region region[], int region_count)
393d46373c1SJoseph Chen {
394d46373c1SJoseph Chen 	char *file = "data2sign.bin";
395d46373c1SJoseph Chen 	FILE *fd;
396d46373c1SJoseph Chen 	int i;
397d46373c1SJoseph Chen 
398d46373c1SJoseph Chen 	fd = fopen(file, "wb");
399d46373c1SJoseph Chen 	if (!fd) {
400d46373c1SJoseph Chen 		fprintf(stderr, "Failed to create %s: %s\n",
401d46373c1SJoseph Chen 			file, strerror(errno));
402d46373c1SJoseph Chen 		return -ENOENT;
403d46373c1SJoseph Chen 	}
404d46373c1SJoseph Chen 
405d46373c1SJoseph Chen 	for (i = 0; i < region_count; i++)
406d46373c1SJoseph Chen 		fwrite(region[i].data, region[i].size, 1, fd);
407d46373c1SJoseph Chen 
408d46373c1SJoseph Chen 	fclose(fd);
409242e56faSJoseph Chen 
410242e56faSJoseph Chen 	return 0;
411d46373c1SJoseph Chen }
412d46373c1SJoseph Chen 
rsa_sign_with_key(RSA * rsa,struct padding_algo * padding_algo,struct checksum_algo * checksum_algo,const struct image_region region[],int region_count,uint8_t ** sigp,uint * sig_size)413219050bfSPhilippe Reynes static int rsa_sign_with_key(RSA *rsa, struct padding_algo *padding_algo,
414219050bfSPhilippe Reynes 			     struct checksum_algo *checksum_algo,
415646257d1SHeiko Schocher 		const struct image_region region[], int region_count,
416646257d1SHeiko Schocher 		uint8_t **sigp, uint *sig_size)
41719c402afSSimon Glass {
41819c402afSSimon Glass 	EVP_PKEY *key;
419219050bfSPhilippe Reynes 	EVP_PKEY_CTX *ckey;
42019c402afSSimon Glass 	EVP_MD_CTX *context;
421624f7c07SPhilippe Reynes 	int ret = 0;
422624f7c07SPhilippe Reynes 	size_t size;
42319c402afSSimon Glass 	uint8_t *sig;
42419c402afSSimon Glass 	int i;
42519c402afSSimon Glass 
42619c402afSSimon Glass 	key = EVP_PKEY_new();
42719c402afSSimon Glass 	if (!key)
42819c402afSSimon Glass 		return rsa_err("EVP_PKEY object creation failed");
42919c402afSSimon Glass 
43019c402afSSimon Glass 	if (!EVP_PKEY_set1_RSA(key, rsa)) {
43119c402afSSimon Glass 		ret = rsa_err("EVP key setup failed");
43219c402afSSimon Glass 		goto err_set;
43319c402afSSimon Glass 	}
43419c402afSSimon Glass 
43519c402afSSimon Glass 	size = EVP_PKEY_size(key);
43619c402afSSimon Glass 	sig = malloc(size);
43719c402afSSimon Glass 	if (!sig) {
438624f7c07SPhilippe Reynes 		fprintf(stderr, "Out of memory for signature (%zu bytes)\n",
43919c402afSSimon Glass 			size);
44019c402afSSimon Glass 		ret = -ENOMEM;
44119c402afSSimon Glass 		goto err_alloc;
44219c402afSSimon Glass 	}
44319c402afSSimon Glass 
44419c402afSSimon Glass 	context = EVP_MD_CTX_create();
44519c402afSSimon Glass 	if (!context) {
44619c402afSSimon Glass 		ret = rsa_err("EVP context creation failed");
44719c402afSSimon Glass 		goto err_create;
44819c402afSSimon Glass 	}
44919c402afSSimon Glass 	EVP_MD_CTX_init(context);
450219050bfSPhilippe Reynes 
451219050bfSPhilippe Reynes 	ckey = EVP_PKEY_CTX_new(key, NULL);
452219050bfSPhilippe Reynes 	if (!ckey) {
453219050bfSPhilippe Reynes 		ret = rsa_err("EVP key context creation failed");
454219050bfSPhilippe Reynes 		goto err_create;
455219050bfSPhilippe Reynes 	}
456219050bfSPhilippe Reynes 
457219050bfSPhilippe Reynes 	if (EVP_DigestSignInit(context, &ckey,
458624f7c07SPhilippe Reynes 			       checksum_algo->calculate_sign(),
459624f7c07SPhilippe Reynes 			       NULL, key) <= 0) {
46019c402afSSimon Glass 		ret = rsa_err("Signer setup failed");
46119c402afSSimon Glass 		goto err_sign;
46219c402afSSimon Glass 	}
46319c402afSSimon Glass 
46485289e9dSPhilippe Reynes #ifdef CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT
46585289e9dSPhilippe Reynes 	if (padding_algo && !strcmp(padding_algo->name, "pss")) {
46685289e9dSPhilippe Reynes 		if (EVP_PKEY_CTX_set_rsa_padding(ckey,
46785289e9dSPhilippe Reynes 						 RSA_PKCS1_PSS_PADDING) <= 0) {
46885289e9dSPhilippe Reynes 			ret = rsa_err("Signer padding setup failed");
46985289e9dSPhilippe Reynes 			goto err_sign;
47085289e9dSPhilippe Reynes 		}
47185289e9dSPhilippe Reynes 	}
47285289e9dSPhilippe Reynes #endif /* CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT */
47385289e9dSPhilippe Reynes 
47419c402afSSimon Glass 	for (i = 0; i < region_count; i++) {
475624f7c07SPhilippe Reynes 		if (!EVP_DigestSignUpdate(context, region[i].data,
476624f7c07SPhilippe Reynes 					  region[i].size)) {
47719c402afSSimon Glass 			ret = rsa_err("Signing data failed");
47819c402afSSimon Glass 			goto err_sign;
47919c402afSSimon Glass 		}
48019c402afSSimon Glass 	}
48119c402afSSimon Glass 
482624f7c07SPhilippe Reynes 	if (!EVP_DigestSignFinal(context, sig, &size)) {
48319c402afSSimon Glass 		ret = rsa_err("Could not obtain signature");
48419c402afSSimon Glass 		goto err_sign;
48519c402afSSimon Glass 	}
486624f7c07SPhilippe Reynes 
487624f7c07SPhilippe Reynes 	#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
488624f7c07SPhilippe Reynes 		(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x02070000fL)
48919c402afSSimon Glass 		EVP_MD_CTX_cleanup(context);
490c3b43281SJelle van der Waa 	#else
491c3b43281SJelle van der Waa 		EVP_MD_CTX_reset(context);
492c3b43281SJelle van der Waa 	#endif
49319c402afSSimon Glass 	EVP_MD_CTX_destroy(context);
49419c402afSSimon Glass 	EVP_PKEY_free(key);
49519c402afSSimon Glass 
496624f7c07SPhilippe Reynes 	debug("Got signature: %d bytes, expected %zu\n", *sig_size, size);
49719c402afSSimon Glass 	*sigp = sig;
49819c402afSSimon Glass 	*sig_size = size;
49919c402afSSimon Glass 
500d46373c1SJoseph Chen 	gen_data2sign(region, region_count);
501d46373c1SJoseph Chen 
50219c402afSSimon Glass 	return 0;
50319c402afSSimon Glass 
50419c402afSSimon Glass err_sign:
50519c402afSSimon Glass 	EVP_MD_CTX_destroy(context);
50619c402afSSimon Glass err_create:
50719c402afSSimon Glass 	free(sig);
50819c402afSSimon Glass err_alloc:
50919c402afSSimon Glass err_set:
51019c402afSSimon Glass 	EVP_PKEY_free(key);
51119c402afSSimon Glass 	return ret;
51219c402afSSimon Glass }
51319c402afSSimon Glass 
rsa_sign(struct image_sign_info * info,const struct image_region region[],int region_count,uint8_t ** sigp,uint * sig_len)51419c402afSSimon Glass int rsa_sign(struct image_sign_info *info,
51519c402afSSimon Glass 	     const struct image_region region[], int region_count,
51619c402afSSimon Glass 	     uint8_t **sigp, uint *sig_len)
51719c402afSSimon Glass {
51819c402afSSimon Glass 	RSA *rsa;
519f1ca1fdeSGeorge McCollister 	ENGINE *e = NULL;
52019c402afSSimon Glass 	int ret;
52119c402afSSimon Glass 
52219c402afSSimon Glass 	ret = rsa_init();
52319c402afSSimon Glass 	if (ret)
52419c402afSSimon Glass 		return ret;
52519c402afSSimon Glass 
526f1ca1fdeSGeorge McCollister 	if (info->engine_id) {
527f1ca1fdeSGeorge McCollister 		ret = rsa_engine_init(info->engine_id, &e);
528f1ca1fdeSGeorge McCollister 		if (ret)
529f1ca1fdeSGeorge McCollister 			goto err_engine;
530f1ca1fdeSGeorge McCollister 	}
531f1ca1fdeSGeorge McCollister 
532f1ca1fdeSGeorge McCollister 	ret = rsa_get_priv_key(info->keydir, info->keyname, e, &rsa);
53319c402afSSimon Glass 	if (ret)
53419c402afSSimon Glass 		goto err_priv;
535219050bfSPhilippe Reynes 	ret = rsa_sign_with_key(rsa, info->padding, info->checksum, region,
536646257d1SHeiko Schocher 				region_count, sigp, sig_len);
53719c402afSSimon Glass 	if (ret)
53819c402afSSimon Glass 		goto err_sign;
53919c402afSSimon Glass 
54019c402afSSimon Glass 	RSA_free(rsa);
541f1ca1fdeSGeorge McCollister 	if (info->engine_id)
542f1ca1fdeSGeorge McCollister 		rsa_engine_remove(e);
54319c402afSSimon Glass 	rsa_remove();
54419c402afSSimon Glass 
54519c402afSSimon Glass 	return ret;
54619c402afSSimon Glass 
54719c402afSSimon Glass err_sign:
54819c402afSSimon Glass 	RSA_free(rsa);
54919c402afSSimon Glass err_priv:
550f1ca1fdeSGeorge McCollister 	if (info->engine_id)
551f1ca1fdeSGeorge McCollister 		rsa_engine_remove(e);
552f1ca1fdeSGeorge McCollister err_engine:
55319c402afSSimon Glass 	rsa_remove();
55419c402afSSimon Glass 	return ret;
55519c402afSSimon Glass }
55619c402afSSimon Glass 
55719c402afSSimon Glass /*
558e0f2f155SMichael van der Westhuizen  * rsa_get_exponent(): - Get the public exponent from an RSA key
559e0f2f155SMichael van der Westhuizen  */
rsa_get_exponent(RSA * key,uint64_t * e)560e0f2f155SMichael van der Westhuizen static int rsa_get_exponent(RSA *key, uint64_t *e)
561e0f2f155SMichael van der Westhuizen {
562e0f2f155SMichael van der Westhuizen 	int ret;
563e0f2f155SMichael van der Westhuizen 	BIGNUM *bn_te;
564c3b43281SJelle van der Waa 	const BIGNUM *key_e;
565e0f2f155SMichael van der Westhuizen 	uint64_t te;
566e0f2f155SMichael van der Westhuizen 
567e0f2f155SMichael van der Westhuizen 	ret = -EINVAL;
568e0f2f155SMichael van der Westhuizen 	bn_te = NULL;
569e0f2f155SMichael van der Westhuizen 
570e0f2f155SMichael van der Westhuizen 	if (!e)
571e0f2f155SMichael van der Westhuizen 		goto cleanup;
572e0f2f155SMichael van der Westhuizen 
573c3b43281SJelle van der Waa 	RSA_get0_key(key, NULL, &key_e, NULL);
574c3b43281SJelle van der Waa 	if (BN_num_bits(key_e) > 64)
575e0f2f155SMichael van der Westhuizen 		goto cleanup;
576e0f2f155SMichael van der Westhuizen 
577c3b43281SJelle van der Waa 	*e = BN_get_word(key_e);
578e0f2f155SMichael van der Westhuizen 
579c3b43281SJelle van der Waa 	if (BN_num_bits(key_e) < 33) {
580e0f2f155SMichael van der Westhuizen 		ret = 0;
581e0f2f155SMichael van der Westhuizen 		goto cleanup;
582e0f2f155SMichael van der Westhuizen 	}
583e0f2f155SMichael van der Westhuizen 
584c3b43281SJelle van der Waa 	bn_te = BN_dup(key_e);
585e0f2f155SMichael van der Westhuizen 	if (!bn_te)
586e0f2f155SMichael van der Westhuizen 		goto cleanup;
587e0f2f155SMichael van der Westhuizen 
588e0f2f155SMichael van der Westhuizen 	if (!BN_rshift(bn_te, bn_te, 32))
589e0f2f155SMichael van der Westhuizen 		goto cleanup;
590e0f2f155SMichael van der Westhuizen 
591e0f2f155SMichael van der Westhuizen 	if (!BN_mask_bits(bn_te, 32))
592e0f2f155SMichael van der Westhuizen 		goto cleanup;
593e0f2f155SMichael van der Westhuizen 
594e0f2f155SMichael van der Westhuizen 	te = BN_get_word(bn_te);
595e0f2f155SMichael van der Westhuizen 	te <<= 32;
596e0f2f155SMichael van der Westhuizen 	*e |= te;
597e0f2f155SMichael van der Westhuizen 	ret = 0;
598e0f2f155SMichael van der Westhuizen 
599e0f2f155SMichael van der Westhuizen cleanup:
600e0f2f155SMichael van der Westhuizen 	if (bn_te)
601e0f2f155SMichael van der Westhuizen 		BN_free(bn_te);
602e0f2f155SMichael van der Westhuizen 
603e0f2f155SMichael van der Westhuizen 	return ret;
604e0f2f155SMichael van der Westhuizen }
605e0f2f155SMichael van der Westhuizen 
606e0f2f155SMichael van der Westhuizen /*
60719c402afSSimon Glass  * rsa_get_params(): - Get the important parameters of an RSA public key
60819c402afSSimon Glass  */
rsa_get_params(RSA * key,uint64_t * exponent,uint32_t * n0_invp,BIGNUM ** modulusp,BIGNUM ** exponent_BN,BIGNUM ** r_squaredp,BIGNUM ** c_factorp,BIGNUM ** np_factorp)609e0f2f155SMichael van der Westhuizen int rsa_get_params(RSA *key, uint64_t *exponent, uint32_t *n0_invp,
610008ec9b4SJoseph Chen 		   BIGNUM **modulusp, BIGNUM **exponent_BN, BIGNUM **r_squaredp,
611008ec9b4SJoseph Chen 		   BIGNUM **c_factorp, BIGNUM **np_factorp)
61219c402afSSimon Glass {
613*bc61c807SYi Liu 	BIGNUM *big1, *big2, *big32, *big2_32, *big4100, *big2180, *big4228;
614008ec9b4SJoseph Chen 	BIGNUM *n, *e, *r, *r_squared, *tmp, *c_factor, *np_factor;
615008ec9b4SJoseph Chen 	const BIGNUM *key_n, *key_e;
61619c402afSSimon Glass 	BN_CTX *bn_ctx = BN_CTX_new();
61719c402afSSimon Glass 	int ret = 0;
61819c402afSSimon Glass 
61919c402afSSimon Glass 	/* Initialize BIGNUMs */
62019c402afSSimon Glass 	big1 = BN_new();
62119c402afSSimon Glass 	big2 = BN_new();
62219c402afSSimon Glass 	big32 = BN_new();
623008ec9b4SJoseph Chen 	big4100 = BN_new();
624008ec9b4SJoseph Chen 	big2180 = BN_new();
625*bc61c807SYi Liu 	big4228 = BN_new();
626008ec9b4SJoseph Chen 
62719c402afSSimon Glass 	r = BN_new();
62819c402afSSimon Glass 	r_squared = BN_new();
629008ec9b4SJoseph Chen 	c_factor = BN_new();
630008ec9b4SJoseph Chen 	np_factor = BN_new();
63119c402afSSimon Glass 	tmp = BN_new();
63219c402afSSimon Glass 	big2_32 = BN_new();
63319c402afSSimon Glass 	n = BN_new();
634008ec9b4SJoseph Chen 	e = BN_new();
635*bc61c807SYi Liu 	if (!big1 || !big2 || !big32 || !big4100 || !big2180 || !big4228 || !r ||
636008ec9b4SJoseph Chen 	    !r_squared || !tmp || !big2_32 || !n || !e ||
637008ec9b4SJoseph Chen 	    !c_factor || !np_factor) {
63819c402afSSimon Glass 		fprintf(stderr, "Out of memory (bignum)\n");
63919c402afSSimon Glass 		return -ENOMEM;
64019c402afSSimon Glass 	}
64119c402afSSimon Glass 
642e0f2f155SMichael van der Westhuizen 	if (0 != rsa_get_exponent(key, exponent))
643e0f2f155SMichael van der Westhuizen 		ret = -1;
644e0f2f155SMichael van der Westhuizen 
645008ec9b4SJoseph Chen 	RSA_get0_key(key, &key_n, &key_e, NULL);
646008ec9b4SJoseph Chen 	if (!BN_copy(n, key_n) || !BN_copy(e, key_e) ||
647008ec9b4SJoseph Chen 	    !BN_set_word(big1, 1L) ||
648008ec9b4SJoseph Chen 	    !BN_set_word(big2, 2L) || !BN_set_word(big32, 32L) ||
649*bc61c807SYi Liu 	    !BN_set_word(big4100, 4100L) || !BN_set_word(big2180, 2180L) ||
650*bc61c807SYi Liu 	    !BN_set_word(big4228, 4228L))
65119c402afSSimon Glass 		ret = -1;
65219c402afSSimon Glass 
65319c402afSSimon Glass 	/* big2_32 = 2^32 */
65419c402afSSimon Glass 	if (!BN_exp(big2_32, big2, big32, bn_ctx))
65519c402afSSimon Glass 		ret = -1;
65619c402afSSimon Glass 
65719c402afSSimon Glass 	/* Calculate n0_inv = -1 / n[0] mod 2^32 */
65819c402afSSimon Glass 	if (!BN_mod_inverse(tmp, n, big2_32, bn_ctx) ||
65919c402afSSimon Glass 	    !BN_sub(tmp, big2_32, tmp))
66019c402afSSimon Glass 		ret = -1;
66119c402afSSimon Glass 	*n0_invp = BN_get_word(tmp);
66219c402afSSimon Glass 
66319c402afSSimon Glass 	/* Calculate R = 2^(# of key bits) */
66419c402afSSimon Glass 	if (!BN_set_word(tmp, BN_num_bits(n)) ||
66519c402afSSimon Glass 	    !BN_exp(r, big2, tmp, bn_ctx))
66619c402afSSimon Glass 		ret = -1;
66719c402afSSimon Glass 
66819c402afSSimon Glass 	/* Calculate r_squared = R^2 mod n */
66919c402afSSimon Glass 	if (!BN_copy(r_squared, r) ||
67019c402afSSimon Glass 	    !BN_mul(tmp, r_squared, r, bn_ctx) ||
67119c402afSSimon Glass 	    !BN_mod(r_squared, tmp, n, bn_ctx))
67219c402afSSimon Glass 		ret = -1;
67319c402afSSimon Glass 
674008ec9b4SJoseph Chen 	/* Calculate c_factor = 2^4100 mod n */
675008ec9b4SJoseph Chen 	if (!BN_exp(tmp, big2, big4100, bn_ctx) ||
676008ec9b4SJoseph Chen 	    !BN_mod(c_factor, tmp, n, bn_ctx))
677008ec9b4SJoseph Chen 		ret = -1;
678008ec9b4SJoseph Chen 
679008ec9b4SJoseph Chen 	/* Calculate np_factor = 2^2180 div n */
680*bc61c807SYi Liu 	if (BN_num_bits(n) == 2048) {
681008ec9b4SJoseph Chen 		if (!BN_exp(tmp, big2, big2180, bn_ctx) ||
682008ec9b4SJoseph Chen 		    !BN_div(np_factor, NULL, tmp, n, bn_ctx))
683008ec9b4SJoseph Chen 			ret = -1;
684*bc61c807SYi Liu 	} else {/* Calculate 4096 np_factor = 2^4228 div n */
685*bc61c807SYi Liu 		if (!BN_exp(tmp, big2, big4228, bn_ctx) ||
686*bc61c807SYi Liu 		    !BN_div(np_factor, NULL, tmp, n, bn_ctx))
687*bc61c807SYi Liu 			ret = -1;
688*bc61c807SYi Liu 	}
689008ec9b4SJoseph Chen 
69019c402afSSimon Glass 	*modulusp = n;
691008ec9b4SJoseph Chen 	*exponent_BN = e;
69219c402afSSimon Glass 	*r_squaredp = r_squared;
693008ec9b4SJoseph Chen 	*c_factorp = c_factor;
694008ec9b4SJoseph Chen 	*np_factorp = np_factor;
69519c402afSSimon Glass 
69619c402afSSimon Glass 	BN_free(big1);
69719c402afSSimon Glass 	BN_free(big2);
69819c402afSSimon Glass 	BN_free(big32);
699008ec9b4SJoseph Chen 	BN_free(big4100);
700008ec9b4SJoseph Chen 	BN_free(big2180);
701*bc61c807SYi Liu 	BN_free(big4228);
70219c402afSSimon Glass 	BN_free(r);
70319c402afSSimon Glass 	BN_free(tmp);
70419c402afSSimon Glass 	BN_free(big2_32);
70519c402afSSimon Glass 	if (ret) {
70619c402afSSimon Glass 		fprintf(stderr, "Bignum operations failed\n");
70719c402afSSimon Glass 		return -ENOMEM;
70819c402afSSimon Glass 	}
70919c402afSSimon Glass 
71019c402afSSimon Glass 	return ret;
71119c402afSSimon Glass }
71219c402afSSimon Glass 
rsa_convert_big_endian(uint32_t * dst,const uint32_t * src,int total_len,int convert_len)713781ee9b3SJason Zhu static void rsa_convert_big_endian(uint32_t *dst, const uint32_t *src,
714781ee9b3SJason Zhu 				   int total_len, int convert_len)
715b6ea0cb4SJoseph Chen {
716781ee9b3SJason Zhu 	int total_wd, convert_wd, i;
717b6ea0cb4SJoseph Chen 
718781ee9b3SJason Zhu 	if (total_len < convert_len)
719781ee9b3SJason Zhu 		convert_len = total_len;
720781ee9b3SJason Zhu 
721781ee9b3SJason Zhu 	total_wd = total_len / sizeof(uint32_t);
722781ee9b3SJason Zhu 	convert_wd = convert_len / sizeof(uint32_t);
723781ee9b3SJason Zhu 	for (i = 0; i < convert_wd; i++)
724781ee9b3SJason Zhu 		dst[i] = fdt32_to_cpu(src[total_wd - 1 - i]);
725b6ea0cb4SJoseph Chen }
726b6ea0cb4SJoseph Chen 
rsa_set_key_hash(void * keydest,int key_node,int key_len,const char * csum_algo)727b6ea0cb4SJoseph Chen static int rsa_set_key_hash(void *keydest, int key_node,
728b6ea0cb4SJoseph Chen 			    int key_len, const char *csum_algo)
729b6ea0cb4SJoseph Chen {
730b6ea0cb4SJoseph Chen 	const void *rsa_n, *rsa_e, *rsa_c, *rsa_np;
731b6ea0cb4SJoseph Chen 	void *n, *e, *c, *np;
732b6ea0cb4SJoseph Chen 	uint8_t value[FIT_MAX_HASH_LEN];
733b6ea0cb4SJoseph Chen 	char hash_c[] = "hash@c";
734b6ea0cb4SJoseph Chen 	char hash_np[] = "hash@np";
735b6ea0cb4SJoseph Chen 	char *rsa_key;
736b6ea0cb4SJoseph Chen 	int hash_node;
737b6ea0cb4SJoseph Chen 	int value_len;
738b6ea0cb4SJoseph Chen 	int ret = -ENOSPC;
739b6ea0cb4SJoseph Chen 
740781ee9b3SJason Zhu 	rsa_key = calloc(key_len * 3, sizeof(char));
741b6ea0cb4SJoseph Chen 	if (!rsa_key)
742b6ea0cb4SJoseph Chen 		return -ENOSPC;
743b6ea0cb4SJoseph Chen 
744b6ea0cb4SJoseph Chen 	rsa_n = fdt_getprop(keydest, key_node, "rsa,modulus", NULL);
745b6ea0cb4SJoseph Chen 	rsa_e = fdt_getprop(keydest, key_node, "rsa,exponent-BN", NULL);
746b6ea0cb4SJoseph Chen 	rsa_c = fdt_getprop(keydest, key_node, "rsa,c", NULL);
747b6ea0cb4SJoseph Chen 	rsa_np = fdt_getprop(keydest, key_node, "rsa,np", NULL);
748b6ea0cb4SJoseph Chen 	if (!rsa_c || !rsa_np || !rsa_n || !rsa_e)
749b6ea0cb4SJoseph Chen 		goto err_nospc;
750b6ea0cb4SJoseph Chen 
751b6ea0cb4SJoseph Chen 	n = rsa_key;
752781ee9b3SJason Zhu 	e = rsa_key + CONFIG_RSA_N_SIZE;
753781ee9b3SJason Zhu 	rsa_convert_big_endian(n, rsa_n, key_len, CONFIG_RSA_N_SIZE);
754781ee9b3SJason Zhu 	rsa_convert_big_endian(e, rsa_e, key_len, CONFIG_RSA_E_SIZE);
755b6ea0cb4SJoseph Chen 
756b6ea0cb4SJoseph Chen 	/* hash@c node: n, e, c */
757781ee9b3SJason Zhu 	c = rsa_key + CONFIG_RSA_N_SIZE + CONFIG_RSA_E_SIZE;
758781ee9b3SJason Zhu 	rsa_convert_big_endian(c, rsa_c, key_len, CONFIG_RSA_C_SIZE);
759b6ea0cb4SJoseph Chen 	hash_node = fdt_add_subnode(keydest, key_node, hash_c);
760b6ea0cb4SJoseph Chen 	if (hash_node < 0)
761b6ea0cb4SJoseph Chen 		goto err_nospc;
762b6ea0cb4SJoseph Chen 	ret = calculate_hash(rsa_key, key_len * 3, csum_algo, value, &value_len);
763b6ea0cb4SJoseph Chen 	if (ret)
764b6ea0cb4SJoseph Chen 		goto err_nospc;
765b6ea0cb4SJoseph Chen 	ret = fdt_setprop(keydest, hash_node, FIT_VALUE_PROP, value, value_len);
766b6ea0cb4SJoseph Chen 	if (ret)
767b6ea0cb4SJoseph Chen 		goto err_nospc;
768b6ea0cb4SJoseph Chen 	ret = fdt_setprop_string(keydest, hash_node, FIT_ALGO_PROP, csum_algo);
769b6ea0cb4SJoseph Chen 	if (ret < 0)
770b6ea0cb4SJoseph Chen 		goto err_nospc;
771b6ea0cb4SJoseph Chen 
772b6ea0cb4SJoseph Chen 	/* hash@np node: n, e, np */
773781ee9b3SJason Zhu 	np = rsa_key + CONFIG_RSA_N_SIZE + CONFIG_RSA_E_SIZE;
774781ee9b3SJason Zhu 	rsa_convert_big_endian(np, rsa_np, key_len, CONFIG_RSA_C_SIZE);
775b6ea0cb4SJoseph Chen 	hash_node = fdt_add_subnode(keydest, key_node, hash_np);
776b6ea0cb4SJoseph Chen 	if (hash_node < 0)
777b6ea0cb4SJoseph Chen 		goto err_nospc;
778b6ea0cb4SJoseph Chen 
779781ee9b3SJason Zhu 	ret = calculate_hash(rsa_key, CONFIG_RSA_N_SIZE + CONFIG_RSA_E_SIZE + CONFIG_RSA_C_SIZE,
780781ee9b3SJason Zhu 			     csum_algo, value, &value_len);
781b6ea0cb4SJoseph Chen 	if (ret)
782b6ea0cb4SJoseph Chen 		goto err_nospc;
783b6ea0cb4SJoseph Chen 	ret = fdt_setprop(keydest, hash_node, FIT_VALUE_PROP, value, value_len);
784b6ea0cb4SJoseph Chen 	if (ret < 0)
785b6ea0cb4SJoseph Chen 		goto err_nospc;
786b6ea0cb4SJoseph Chen 	ret = fdt_setprop_string(keydest, hash_node, FIT_ALGO_PROP, csum_algo);
787b6ea0cb4SJoseph Chen 
788b6ea0cb4SJoseph Chen err_nospc:
789b6ea0cb4SJoseph Chen 	if (rsa_key)
790b6ea0cb4SJoseph Chen 		free(rsa_key);
791b6ea0cb4SJoseph Chen 
792b6ea0cb4SJoseph Chen 	return ret ? -ENOSPC : 0;
793b6ea0cb4SJoseph Chen }
794b6ea0cb4SJoseph Chen 
fdt_add_bignum(void * blob,int noffset,const char * prop_name,BIGNUM * num,int num_bits)79519c402afSSimon Glass static int fdt_add_bignum(void *blob, int noffset, const char *prop_name,
79619c402afSSimon Glass 			  BIGNUM *num, int num_bits)
79719c402afSSimon Glass {
79819c402afSSimon Glass 	int nwords = num_bits / 32;
79919c402afSSimon Glass 	int size;
80019c402afSSimon Glass 	uint32_t *buf, *ptr;
80119c402afSSimon Glass 	BIGNUM *tmp, *big2, *big32, *big2_32;
80219c402afSSimon Glass 	BN_CTX *ctx;
80319c402afSSimon Glass 	int ret;
80419c402afSSimon Glass 
80519c402afSSimon Glass 	tmp = BN_new();
80619c402afSSimon Glass 	big2 = BN_new();
80719c402afSSimon Glass 	big32 = BN_new();
80819c402afSSimon Glass 	big2_32 = BN_new();
80919c402afSSimon Glass 	if (!tmp || !big2 || !big32 || !big2_32) {
81019c402afSSimon Glass 		fprintf(stderr, "Out of memory (bignum)\n");
81119c402afSSimon Glass 		return -ENOMEM;
81219c402afSSimon Glass 	}
81319c402afSSimon Glass 	ctx = BN_CTX_new();
81419c402afSSimon Glass 	if (!tmp) {
81519c402afSSimon Glass 		fprintf(stderr, "Out of memory (bignum context)\n");
81619c402afSSimon Glass 		return -ENOMEM;
81719c402afSSimon Glass 	}
81819c402afSSimon Glass 	BN_set_word(big2, 2L);
81919c402afSSimon Glass 	BN_set_word(big32, 32L);
82019c402afSSimon Glass 	BN_exp(big2_32, big2, big32, ctx); /* B = 2^32 */
82119c402afSSimon Glass 
82219c402afSSimon Glass 	size = nwords * sizeof(uint32_t);
82319c402afSSimon Glass 	buf = malloc(size);
82419c402afSSimon Glass 	if (!buf) {
82519c402afSSimon Glass 		fprintf(stderr, "Out of memory (%d bytes)\n", size);
82619c402afSSimon Glass 		return -ENOMEM;
82719c402afSSimon Glass 	}
82819c402afSSimon Glass 
82919c402afSSimon Glass 	/* Write out modulus as big endian array of integers */
83019c402afSSimon Glass 	for (ptr = buf + nwords - 1; ptr >= buf; ptr--) {
83119c402afSSimon Glass 		BN_mod(tmp, num, big2_32, ctx); /* n = N mod B */
83219c402afSSimon Glass 		*ptr = cpu_to_fdt32(BN_get_word(tmp));
83319c402afSSimon Glass 		BN_rshift(num, num, 32); /*  N = N/B */
83419c402afSSimon Glass 	}
83519c402afSSimon Glass 
836713fb2dcSmario.six@gdsys.cc 	/*
837713fb2dcSmario.six@gdsys.cc 	 * We try signing with successively increasing size values, so this
838713fb2dcSmario.six@gdsys.cc 	 * might fail several times
839713fb2dcSmario.six@gdsys.cc 	 */
84019c402afSSimon Glass 	ret = fdt_setprop(blob, noffset, prop_name, buf, size);
8412b9ec762Smario.six@gdsys.cc 	if (ret)
8422b9ec762Smario.six@gdsys.cc 		return -FDT_ERR_NOSPACE;
84319c402afSSimon Glass 	free(buf);
84419c402afSSimon Glass 	BN_free(tmp);
84519c402afSSimon Glass 	BN_free(big2);
84619c402afSSimon Glass 	BN_free(big32);
84719c402afSSimon Glass 	BN_free(big2_32);
84819c402afSSimon Glass 
84919c402afSSimon Glass 	return ret;
85019c402afSSimon Glass }
85119c402afSSimon Glass 
rsa_add_verify_data(struct image_sign_info * info,void * keydest)85219c402afSSimon Glass int rsa_add_verify_data(struct image_sign_info *info, void *keydest)
85319c402afSSimon Glass {
854008ec9b4SJoseph Chen 	BIGNUM *modulus, *exponent_BN, *r_squared, *c_factor, *np_factor;
855e0f2f155SMichael van der Westhuizen 	uint64_t exponent;
85619c402afSSimon Glass 	uint32_t n0_inv;
85719c402afSSimon Glass 	int parent, node;
85819c402afSSimon Glass 	char name[100];
85919c402afSSimon Glass 	int ret;
86019c402afSSimon Glass 	int bits;
86119c402afSSimon Glass 	RSA *rsa;
862f1ca1fdeSGeorge McCollister 	ENGINE *e = NULL;
86319c402afSSimon Glass 
86419c402afSSimon Glass 	debug("%s: Getting verification data\n", __func__);
865f1ca1fdeSGeorge McCollister 	if (info->engine_id) {
866f1ca1fdeSGeorge McCollister 		ret = rsa_engine_init(info->engine_id, &e);
86719c402afSSimon Glass 		if (ret)
86819c402afSSimon Glass 			return ret;
869f1ca1fdeSGeorge McCollister 	}
870f1ca1fdeSGeorge McCollister 	ret = rsa_get_pub_key(info->keydir, info->keyname, e, &rsa);
871f1ca1fdeSGeorge McCollister 	if (ret)
872f1ca1fdeSGeorge McCollister 		goto err_get_pub_key;
873008ec9b4SJoseph Chen 	ret = rsa_get_params(rsa, &exponent, &n0_inv, &modulus,
874008ec9b4SJoseph Chen 			     &exponent_BN, &r_squared, &c_factor, &np_factor);
87519c402afSSimon Glass 	if (ret)
876f1ca1fdeSGeorge McCollister 		goto err_get_params;
87719c402afSSimon Glass 	bits = BN_num_bits(modulus);
87819c402afSSimon Glass 	parent = fdt_subnode_offset(keydest, 0, FIT_SIG_NODENAME);
87919c402afSSimon Glass 	if (parent == -FDT_ERR_NOTFOUND) {
88019c402afSSimon Glass 		parent = fdt_add_subnode(keydest, 0, FIT_SIG_NODENAME);
88119c402afSSimon Glass 		if (parent < 0) {
882597a8b2cSSimon Glass 			ret = parent;
883597a8b2cSSimon Glass 			if (ret != -FDT_ERR_NOSPACE) {
88419c402afSSimon Glass 				fprintf(stderr, "Couldn't create signature node: %s\n",
88519c402afSSimon Glass 					fdt_strerror(parent));
88619c402afSSimon Glass 			}
88719c402afSSimon Glass 		}
888597a8b2cSSimon Glass 	}
889597a8b2cSSimon Glass 	if (ret)
890597a8b2cSSimon Glass 		goto done;
89119c402afSSimon Glass 
89219c402afSSimon Glass 	/* Either create or overwrite the named key node */
89319c402afSSimon Glass 	snprintf(name, sizeof(name), "key-%s", info->keyname);
89419c402afSSimon Glass 	node = fdt_subnode_offset(keydest, parent, name);
89519c402afSSimon Glass 	if (node == -FDT_ERR_NOTFOUND) {
89619c402afSSimon Glass 		node = fdt_add_subnode(keydest, parent, name);
89719c402afSSimon Glass 		if (node < 0) {
898597a8b2cSSimon Glass 			ret = node;
899597a8b2cSSimon Glass 			if (ret != -FDT_ERR_NOSPACE) {
90019c402afSSimon Glass 				fprintf(stderr, "Could not create key subnode: %s\n",
90119c402afSSimon Glass 					fdt_strerror(node));
902597a8b2cSSimon Glass 			}
90319c402afSSimon Glass 		}
90419c402afSSimon Glass 	} else if (node < 0) {
90519c402afSSimon Glass 		fprintf(stderr, "Cannot select keys parent: %s\n",
90619c402afSSimon Glass 			fdt_strerror(node));
907597a8b2cSSimon Glass 		ret = node;
90819c402afSSimon Glass 	}
90919c402afSSimon Glass 
910597a8b2cSSimon Glass 	if (!ret) {
91119c402afSSimon Glass 		ret = fdt_setprop_string(keydest, node, "key-name-hint",
91219c402afSSimon Glass 				 info->keyname);
913597a8b2cSSimon Glass 	}
9144f427a42SSimon Glass 	if (!ret)
9154f427a42SSimon Glass 		ret = fdt_setprop_u32(keydest, node, "rsa,num-bits", bits);
9164f427a42SSimon Glass 	if (!ret)
9174f427a42SSimon Glass 		ret = fdt_setprop_u32(keydest, node, "rsa,n0-inverse", n0_inv);
9184f427a42SSimon Glass 	if (!ret) {
919e0f2f155SMichael van der Westhuizen 		ret = fdt_setprop_u64(keydest, node, "rsa,exponent", exponent);
920e0f2f155SMichael van der Westhuizen 	}
921e0f2f155SMichael van der Westhuizen 	if (!ret) {
922008ec9b4SJoseph Chen 		ret = fdt_add_bignum(keydest, node, "rsa,exponent-BN",
923008ec9b4SJoseph Chen 				     exponent_BN, bits);
924008ec9b4SJoseph Chen 	}
925008ec9b4SJoseph Chen 	if (!ret) {
9264f427a42SSimon Glass 		ret = fdt_add_bignum(keydest, node, "rsa,modulus", modulus,
9274f427a42SSimon Glass 				     bits);
9284f427a42SSimon Glass 	}
9294f427a42SSimon Glass 	if (!ret) {
9304f427a42SSimon Glass 		ret = fdt_add_bignum(keydest, node, "rsa,r-squared", r_squared,
9314f427a42SSimon Glass 				     bits);
9324f427a42SSimon Glass 	}
9334f427a42SSimon Glass 	if (!ret) {
934008ec9b4SJoseph Chen 		ret = fdt_add_bignum(keydest, node, "rsa,c", c_factor,
935008ec9b4SJoseph Chen 				     bits);
936008ec9b4SJoseph Chen 	}
937008ec9b4SJoseph Chen 	if (!ret) {
938008ec9b4SJoseph Chen 		ret = fdt_add_bignum(keydest, node, "rsa,np", np_factor,
939008ec9b4SJoseph Chen 				     bits);
940008ec9b4SJoseph Chen 	}
941008ec9b4SJoseph Chen 	if (!ret) {
9424f427a42SSimon Glass 		ret = fdt_setprop_string(keydest, node, FIT_ALGO_PROP,
94383dd98e0SAndrew Duda 					 info->name);
9444f427a42SSimon Glass 	}
9452b9ec762Smario.six@gdsys.cc 	if (!ret && info->require_keys) {
9464f427a42SSimon Glass 		ret = fdt_setprop_string(keydest, node, "required",
94719c402afSSimon Glass 					 info->require_keys);
94819c402afSSimon Glass 	}
949b6ea0cb4SJoseph Chen 	if (!ret) {
950b6ea0cb4SJoseph Chen 		ret = rsa_set_key_hash(keydest, node, info->crypto->key_len,
951b6ea0cb4SJoseph Chen 				       info->checksum->name);
952b6ea0cb4SJoseph Chen 	}
953597a8b2cSSimon Glass done:
95419c402afSSimon Glass 	BN_free(modulus);
95519c402afSSimon Glass 	BN_free(r_squared);
95619c402afSSimon Glass 	if (ret)
957f1ca1fdeSGeorge McCollister 		ret = ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;
958f1ca1fdeSGeorge McCollister err_get_params:
959f1ca1fdeSGeorge McCollister 	RSA_free(rsa);
960f1ca1fdeSGeorge McCollister err_get_pub_key:
961f1ca1fdeSGeorge McCollister 	if (info->engine_id)
962f1ca1fdeSGeorge McCollister 		rsa_engine_remove(e);
96319c402afSSimon Glass 
964f1ca1fdeSGeorge McCollister 	return ret;
96519c402afSSimon Glass }
966