xref: /rk3399_rockchip-uboot/lib/rsa/rsa-sign.c (revision 008ec9b4bc06f98dd7efdc7d2f44eb066be036e6)
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>
12c3b43281SJelle van der Waa #include <openssl/bn.h>
1319c402afSSimon Glass #include <openssl/rsa.h>
1419c402afSSimon Glass #include <openssl/pem.h>
1519c402afSSimon Glass #include <openssl/err.h>
1619c402afSSimon Glass #include <openssl/ssl.h>
1719c402afSSimon Glass #include <openssl/evp.h>
18f1ca1fdeSGeorge McCollister #include <openssl/engine.h>
1919c402afSSimon Glass 
2019c402afSSimon Glass #if OPENSSL_VERSION_NUMBER >= 0x10000000L
2119c402afSSimon Glass #define HAVE_ERR_REMOVE_THREAD_STATE
2219c402afSSimon Glass #endif
2319c402afSSimon Glass 
24c3b43281SJelle van der Waa #if OPENSSL_VERSION_NUMBER < 0x10100000L
25c3b43281SJelle van der Waa static void RSA_get0_key(const RSA *r,
26c3b43281SJelle van der Waa                  const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
27c3b43281SJelle van der Waa {
28c3b43281SJelle van der Waa    if (n != NULL)
29c3b43281SJelle van der Waa        *n = r->n;
30c3b43281SJelle van der Waa    if (e != NULL)
31c3b43281SJelle van der Waa        *e = r->e;
32c3b43281SJelle van der Waa    if (d != NULL)
33c3b43281SJelle van der Waa        *d = r->d;
34c3b43281SJelle van der Waa }
35c3b43281SJelle van der Waa #endif
36c3b43281SJelle van der Waa 
3719c402afSSimon Glass static int rsa_err(const char *msg)
3819c402afSSimon Glass {
3919c402afSSimon Glass 	unsigned long sslErr = ERR_get_error();
4019c402afSSimon Glass 
4119c402afSSimon Glass 	fprintf(stderr, "%s", msg);
4219c402afSSimon Glass 	fprintf(stderr, ": %s\n",
4319c402afSSimon Glass 		ERR_error_string(sslErr, 0));
4419c402afSSimon Glass 
4519c402afSSimon Glass 	return -1;
4619c402afSSimon Glass }
4719c402afSSimon Glass 
4819c402afSSimon Glass /**
49f1ca1fdeSGeorge McCollister  * rsa_pem_get_pub_key() - read a public key from a .crt file
5019c402afSSimon Glass  *
5119c402afSSimon Glass  * @keydir:	Directory containins the key
5219c402afSSimon Glass  * @name	Name of key file (will have a .crt extension)
5319c402afSSimon Glass  * @rsap	Returns RSA object, or NULL on failure
5419c402afSSimon Glass  * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
5519c402afSSimon Glass  */
56f1ca1fdeSGeorge McCollister static int rsa_pem_get_pub_key(const char *keydir, const char *name, RSA **rsap)
5719c402afSSimon Glass {
5819c402afSSimon Glass 	char path[1024];
5919c402afSSimon Glass 	EVP_PKEY *key;
6019c402afSSimon Glass 	X509 *cert;
6119c402afSSimon Glass 	RSA *rsa;
6219c402afSSimon Glass 	FILE *f;
6319c402afSSimon Glass 	int ret;
6419c402afSSimon Glass 
6519c402afSSimon Glass 	*rsap = NULL;
6619c402afSSimon Glass 	snprintf(path, sizeof(path), "%s/%s.crt", keydir, name);
6719c402afSSimon Glass 	f = fopen(path, "r");
6819c402afSSimon Glass 	if (!f) {
6919c402afSSimon Glass 		fprintf(stderr, "Couldn't open RSA certificate: '%s': %s\n",
7019c402afSSimon Glass 			path, strerror(errno));
7119c402afSSimon Glass 		return -EACCES;
7219c402afSSimon Glass 	}
7319c402afSSimon Glass 
7419c402afSSimon Glass 	/* Read the certificate */
7519c402afSSimon Glass 	cert = NULL;
7619c402afSSimon Glass 	if (!PEM_read_X509(f, &cert, NULL, NULL)) {
7719c402afSSimon Glass 		rsa_err("Couldn't read certificate");
7819c402afSSimon Glass 		ret = -EINVAL;
7919c402afSSimon Glass 		goto err_cert;
8019c402afSSimon Glass 	}
8119c402afSSimon Glass 
8219c402afSSimon Glass 	/* Get the public key from the certificate. */
8319c402afSSimon Glass 	key = X509_get_pubkey(cert);
8419c402afSSimon Glass 	if (!key) {
8519c402afSSimon Glass 		rsa_err("Couldn't read public key\n");
8619c402afSSimon Glass 		ret = -EINVAL;
8719c402afSSimon Glass 		goto err_pubkey;
8819c402afSSimon Glass 	}
8919c402afSSimon Glass 
9019c402afSSimon Glass 	/* Convert to a RSA_style key. */
9119c402afSSimon Glass 	rsa = EVP_PKEY_get1_RSA(key);
9219c402afSSimon Glass 	if (!rsa) {
9319c402afSSimon Glass 		rsa_err("Couldn't convert to a RSA style key");
9454267162SSimon Glass 		ret = -EINVAL;
9519c402afSSimon Glass 		goto err_rsa;
9619c402afSSimon Glass 	}
9719c402afSSimon Glass 	fclose(f);
9819c402afSSimon Glass 	EVP_PKEY_free(key);
9919c402afSSimon Glass 	X509_free(cert);
10019c402afSSimon Glass 	*rsap = rsa;
10119c402afSSimon Glass 
10219c402afSSimon Glass 	return 0;
10319c402afSSimon Glass 
10419c402afSSimon Glass err_rsa:
10519c402afSSimon Glass 	EVP_PKEY_free(key);
10619c402afSSimon Glass err_pubkey:
10719c402afSSimon Glass 	X509_free(cert);
10819c402afSSimon Glass err_cert:
10919c402afSSimon Glass 	fclose(f);
11019c402afSSimon Glass 	return ret;
11119c402afSSimon Glass }
11219c402afSSimon Glass 
11319c402afSSimon Glass /**
114f1ca1fdeSGeorge McCollister  * rsa_engine_get_pub_key() - read a public key from given engine
11519c402afSSimon Glass  *
116f1ca1fdeSGeorge McCollister  * @keydir:	Key prefix
117f1ca1fdeSGeorge McCollister  * @name	Name of key
118f1ca1fdeSGeorge McCollister  * @engine	Engine to use
119f1ca1fdeSGeorge McCollister  * @rsap	Returns RSA object, or NULL on failure
120f1ca1fdeSGeorge McCollister  * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
121f1ca1fdeSGeorge McCollister  */
122f1ca1fdeSGeorge McCollister static int rsa_engine_get_pub_key(const char *keydir, const char *name,
123f1ca1fdeSGeorge McCollister 				  ENGINE *engine, RSA **rsap)
124f1ca1fdeSGeorge McCollister {
125f1ca1fdeSGeorge McCollister 	const char *engine_id;
126f1ca1fdeSGeorge McCollister 	char key_id[1024];
127f1ca1fdeSGeorge McCollister 	EVP_PKEY *key;
128f1ca1fdeSGeorge McCollister 	RSA *rsa;
129f1ca1fdeSGeorge McCollister 	int ret;
130f1ca1fdeSGeorge McCollister 
131f1ca1fdeSGeorge McCollister 	*rsap = NULL;
132f1ca1fdeSGeorge McCollister 
133f1ca1fdeSGeorge McCollister 	engine_id = ENGINE_get_id(engine);
134f1ca1fdeSGeorge McCollister 
135f1ca1fdeSGeorge McCollister 	if (engine_id && !strcmp(engine_id, "pkcs11")) {
136f1ca1fdeSGeorge McCollister 		if (keydir)
137f1ca1fdeSGeorge McCollister 			snprintf(key_id, sizeof(key_id),
138f1ca1fdeSGeorge McCollister 				 "pkcs11:%s;object=%s;type=public",
139f1ca1fdeSGeorge McCollister 				 keydir, name);
140f1ca1fdeSGeorge McCollister 		else
141f1ca1fdeSGeorge McCollister 			snprintf(key_id, sizeof(key_id),
142f1ca1fdeSGeorge McCollister 				 "pkcs11:object=%s;type=public",
143f1ca1fdeSGeorge McCollister 				 name);
144f1ca1fdeSGeorge McCollister 	} else {
145f1ca1fdeSGeorge McCollister 		fprintf(stderr, "Engine not supported\n");
146f1ca1fdeSGeorge McCollister 		return -ENOTSUP;
147f1ca1fdeSGeorge McCollister 	}
148f1ca1fdeSGeorge McCollister 
149f1ca1fdeSGeorge McCollister 	key = ENGINE_load_public_key(engine, key_id, NULL, NULL);
150f1ca1fdeSGeorge McCollister 	if (!key)
151f1ca1fdeSGeorge McCollister 		return rsa_err("Failure loading public key from engine");
152f1ca1fdeSGeorge McCollister 
153f1ca1fdeSGeorge McCollister 	/* Convert to a RSA_style key. */
154f1ca1fdeSGeorge McCollister 	rsa = EVP_PKEY_get1_RSA(key);
155f1ca1fdeSGeorge McCollister 	if (!rsa) {
156f1ca1fdeSGeorge McCollister 		rsa_err("Couldn't convert to a RSA style key");
157f1ca1fdeSGeorge McCollister 		ret = -EINVAL;
158f1ca1fdeSGeorge McCollister 		goto err_rsa;
159f1ca1fdeSGeorge McCollister 	}
160f1ca1fdeSGeorge McCollister 
161f1ca1fdeSGeorge McCollister 	EVP_PKEY_free(key);
162f1ca1fdeSGeorge McCollister 	*rsap = rsa;
163f1ca1fdeSGeorge McCollister 
164f1ca1fdeSGeorge McCollister 	return 0;
165f1ca1fdeSGeorge McCollister 
166f1ca1fdeSGeorge McCollister err_rsa:
167f1ca1fdeSGeorge McCollister 	EVP_PKEY_free(key);
168f1ca1fdeSGeorge McCollister 	return ret;
169f1ca1fdeSGeorge McCollister }
170f1ca1fdeSGeorge McCollister 
171f1ca1fdeSGeorge McCollister /**
172f1ca1fdeSGeorge McCollister  * rsa_get_pub_key() - read a public key
173f1ca1fdeSGeorge McCollister  *
174f1ca1fdeSGeorge McCollister  * @keydir:	Directory containing the key (PEM file) or key prefix (engine)
175f1ca1fdeSGeorge McCollister  * @name	Name of key file (will have a .crt extension)
176f1ca1fdeSGeorge McCollister  * @engine	Engine to use
177f1ca1fdeSGeorge McCollister  * @rsap	Returns RSA object, or NULL on failure
178f1ca1fdeSGeorge McCollister  * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
179f1ca1fdeSGeorge McCollister  */
180f1ca1fdeSGeorge McCollister static int rsa_get_pub_key(const char *keydir, const char *name,
181f1ca1fdeSGeorge McCollister 			   ENGINE *engine, RSA **rsap)
182f1ca1fdeSGeorge McCollister {
183f1ca1fdeSGeorge McCollister 	if (engine)
184f1ca1fdeSGeorge McCollister 		return rsa_engine_get_pub_key(keydir, name, engine, rsap);
185f1ca1fdeSGeorge McCollister 	return rsa_pem_get_pub_key(keydir, name, rsap);
186f1ca1fdeSGeorge McCollister }
187f1ca1fdeSGeorge McCollister 
188f1ca1fdeSGeorge McCollister /**
189f1ca1fdeSGeorge McCollister  * rsa_pem_get_priv_key() - read a private key from a .key file
190f1ca1fdeSGeorge McCollister  *
191f1ca1fdeSGeorge McCollister  * @keydir:	Directory containing the key
19219c402afSSimon Glass  * @name	Name of key file (will have a .key extension)
19319c402afSSimon Glass  * @rsap	Returns RSA object, or NULL on failure
19419c402afSSimon Glass  * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
19519c402afSSimon Glass  */
196f1ca1fdeSGeorge McCollister static int rsa_pem_get_priv_key(const char *keydir, const char *name,
197f1ca1fdeSGeorge McCollister 				RSA **rsap)
19819c402afSSimon Glass {
19919c402afSSimon Glass 	char path[1024];
20019c402afSSimon Glass 	RSA *rsa;
20119c402afSSimon Glass 	FILE *f;
20219c402afSSimon Glass 
20319c402afSSimon Glass 	*rsap = NULL;
20419c402afSSimon Glass 	snprintf(path, sizeof(path), "%s/%s.key", keydir, name);
20519c402afSSimon Glass 	f = fopen(path, "r");
20619c402afSSimon Glass 	if (!f) {
20719c402afSSimon Glass 		fprintf(stderr, "Couldn't open RSA private key: '%s': %s\n",
20819c402afSSimon Glass 			path, strerror(errno));
20919c402afSSimon Glass 		return -ENOENT;
21019c402afSSimon Glass 	}
21119c402afSSimon Glass 
21219c402afSSimon Glass 	rsa = PEM_read_RSAPrivateKey(f, 0, NULL, path);
21319c402afSSimon Glass 	if (!rsa) {
21419c402afSSimon Glass 		rsa_err("Failure reading private key");
21519c402afSSimon Glass 		fclose(f);
21619c402afSSimon Glass 		return -EPROTO;
21719c402afSSimon Glass 	}
21819c402afSSimon Glass 	fclose(f);
21919c402afSSimon Glass 	*rsap = rsa;
22019c402afSSimon Glass 
22119c402afSSimon Glass 	return 0;
22219c402afSSimon Glass }
22319c402afSSimon Glass 
224f1ca1fdeSGeorge McCollister /**
225f1ca1fdeSGeorge McCollister  * rsa_engine_get_priv_key() - read a private key from given engine
226f1ca1fdeSGeorge McCollister  *
227f1ca1fdeSGeorge McCollister  * @keydir:	Key prefix
228f1ca1fdeSGeorge McCollister  * @name	Name of key
229f1ca1fdeSGeorge McCollister  * @engine	Engine to use
230f1ca1fdeSGeorge McCollister  * @rsap	Returns RSA object, or NULL on failure
231f1ca1fdeSGeorge McCollister  * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
232f1ca1fdeSGeorge McCollister  */
233f1ca1fdeSGeorge McCollister static int rsa_engine_get_priv_key(const char *keydir, const char *name,
234f1ca1fdeSGeorge McCollister 				   ENGINE *engine, RSA **rsap)
235f1ca1fdeSGeorge McCollister {
236f1ca1fdeSGeorge McCollister 	const char *engine_id;
237f1ca1fdeSGeorge McCollister 	char key_id[1024];
238f1ca1fdeSGeorge McCollister 	EVP_PKEY *key;
239f1ca1fdeSGeorge McCollister 	RSA *rsa;
240f1ca1fdeSGeorge McCollister 	int ret;
241f1ca1fdeSGeorge McCollister 
242f1ca1fdeSGeorge McCollister 	*rsap = NULL;
243f1ca1fdeSGeorge McCollister 
244f1ca1fdeSGeorge McCollister 	engine_id = ENGINE_get_id(engine);
245f1ca1fdeSGeorge McCollister 
246f1ca1fdeSGeorge McCollister 	if (engine_id && !strcmp(engine_id, "pkcs11")) {
247f1ca1fdeSGeorge McCollister 		if (keydir)
248f1ca1fdeSGeorge McCollister 			snprintf(key_id, sizeof(key_id),
249f1ca1fdeSGeorge McCollister 				 "pkcs11:%s;object=%s;type=private",
250f1ca1fdeSGeorge McCollister 				 keydir, name);
251f1ca1fdeSGeorge McCollister 		else
252f1ca1fdeSGeorge McCollister 			snprintf(key_id, sizeof(key_id),
253f1ca1fdeSGeorge McCollister 				 "pkcs11:object=%s;type=private",
254f1ca1fdeSGeorge McCollister 				 name);
255f1ca1fdeSGeorge McCollister 	} else {
256f1ca1fdeSGeorge McCollister 		fprintf(stderr, "Engine not supported\n");
257f1ca1fdeSGeorge McCollister 		return -ENOTSUP;
258f1ca1fdeSGeorge McCollister 	}
259f1ca1fdeSGeorge McCollister 
260f1ca1fdeSGeorge McCollister 	key = ENGINE_load_private_key(engine, key_id, NULL, NULL);
261f1ca1fdeSGeorge McCollister 	if (!key)
262f1ca1fdeSGeorge McCollister 		return rsa_err("Failure loading private key from engine");
263f1ca1fdeSGeorge McCollister 
264f1ca1fdeSGeorge McCollister 	/* Convert to a RSA_style key. */
265f1ca1fdeSGeorge McCollister 	rsa = EVP_PKEY_get1_RSA(key);
266f1ca1fdeSGeorge McCollister 	if (!rsa) {
267f1ca1fdeSGeorge McCollister 		rsa_err("Couldn't convert to a RSA style key");
268f1ca1fdeSGeorge McCollister 		ret = -EINVAL;
269f1ca1fdeSGeorge McCollister 		goto err_rsa;
270f1ca1fdeSGeorge McCollister 	}
271f1ca1fdeSGeorge McCollister 
272f1ca1fdeSGeorge McCollister 	EVP_PKEY_free(key);
273f1ca1fdeSGeorge McCollister 	*rsap = rsa;
274f1ca1fdeSGeorge McCollister 
275f1ca1fdeSGeorge McCollister 	return 0;
276f1ca1fdeSGeorge McCollister 
277f1ca1fdeSGeorge McCollister err_rsa:
278f1ca1fdeSGeorge McCollister 	EVP_PKEY_free(key);
279f1ca1fdeSGeorge McCollister 	return ret;
280f1ca1fdeSGeorge McCollister }
281f1ca1fdeSGeorge McCollister 
282f1ca1fdeSGeorge McCollister /**
283f1ca1fdeSGeorge McCollister  * rsa_get_priv_key() - read a private key
284f1ca1fdeSGeorge McCollister  *
285f1ca1fdeSGeorge McCollister  * @keydir:	Directory containing the key (PEM file) or key prefix (engine)
286f1ca1fdeSGeorge McCollister  * @name	Name of key
287f1ca1fdeSGeorge McCollister  * @engine	Engine to use for signing
288f1ca1fdeSGeorge McCollister  * @rsap	Returns RSA object, or NULL on failure
289f1ca1fdeSGeorge McCollister  * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
290f1ca1fdeSGeorge McCollister  */
291f1ca1fdeSGeorge McCollister static int rsa_get_priv_key(const char *keydir, const char *name,
292f1ca1fdeSGeorge McCollister 			    ENGINE *engine, RSA **rsap)
293f1ca1fdeSGeorge McCollister {
294f1ca1fdeSGeorge McCollister 	if (engine)
295f1ca1fdeSGeorge McCollister 		return rsa_engine_get_priv_key(keydir, name, engine, rsap);
296f1ca1fdeSGeorge McCollister 	return rsa_pem_get_priv_key(keydir, name, rsap);
297f1ca1fdeSGeorge McCollister }
298f1ca1fdeSGeorge McCollister 
29919c402afSSimon Glass static int rsa_init(void)
30019c402afSSimon Glass {
30119c402afSSimon Glass 	int ret;
30219c402afSSimon Glass 
303c3b43281SJelle van der Waa #if OPENSSL_VERSION_NUMBER < 0x10100000L
30419c402afSSimon Glass 	ret = SSL_library_init();
305c3b43281SJelle van der Waa #else
306c3b43281SJelle van der Waa 	ret = OPENSSL_init_ssl(0, NULL);
307c3b43281SJelle van der Waa #endif
30819c402afSSimon Glass 	if (!ret) {
30919c402afSSimon Glass 		fprintf(stderr, "Failure to init SSL library\n");
31019c402afSSimon Glass 		return -1;
31119c402afSSimon Glass 	}
312c3b43281SJelle van der Waa #if OPENSSL_VERSION_NUMBER < 0x10100000L
31319c402afSSimon Glass 	SSL_load_error_strings();
31419c402afSSimon Glass 
31519c402afSSimon Glass 	OpenSSL_add_all_algorithms();
31619c402afSSimon Glass 	OpenSSL_add_all_digests();
31719c402afSSimon Glass 	OpenSSL_add_all_ciphers();
318c3b43281SJelle van der Waa #endif
31919c402afSSimon Glass 
32019c402afSSimon Glass 	return 0;
32119c402afSSimon Glass }
32219c402afSSimon Glass 
323f1ca1fdeSGeorge McCollister static int rsa_engine_init(const char *engine_id, ENGINE **pe)
324f1ca1fdeSGeorge McCollister {
325f1ca1fdeSGeorge McCollister 	ENGINE *e;
326f1ca1fdeSGeorge McCollister 	int ret;
327f1ca1fdeSGeorge McCollister 
328f1ca1fdeSGeorge McCollister 	ENGINE_load_builtin_engines();
329f1ca1fdeSGeorge McCollister 
330f1ca1fdeSGeorge McCollister 	e = ENGINE_by_id(engine_id);
331f1ca1fdeSGeorge McCollister 	if (!e) {
332f1ca1fdeSGeorge McCollister 		fprintf(stderr, "Engine isn't available\n");
333f1ca1fdeSGeorge McCollister 		ret = -1;
334f1ca1fdeSGeorge McCollister 		goto err_engine_by_id;
335f1ca1fdeSGeorge McCollister 	}
336f1ca1fdeSGeorge McCollister 
337f1ca1fdeSGeorge McCollister 	if (!ENGINE_init(e)) {
338f1ca1fdeSGeorge McCollister 		fprintf(stderr, "Couldn't initialize engine\n");
339f1ca1fdeSGeorge McCollister 		ret = -1;
340f1ca1fdeSGeorge McCollister 		goto err_engine_init;
341f1ca1fdeSGeorge McCollister 	}
342f1ca1fdeSGeorge McCollister 
343f1ca1fdeSGeorge McCollister 	if (!ENGINE_set_default_RSA(e)) {
344f1ca1fdeSGeorge McCollister 		fprintf(stderr, "Couldn't set engine as default for RSA\n");
345f1ca1fdeSGeorge McCollister 		ret = -1;
346f1ca1fdeSGeorge McCollister 		goto err_set_rsa;
347f1ca1fdeSGeorge McCollister 	}
348f1ca1fdeSGeorge McCollister 
349f1ca1fdeSGeorge McCollister 	*pe = e;
350f1ca1fdeSGeorge McCollister 
351f1ca1fdeSGeorge McCollister 	return 0;
352f1ca1fdeSGeorge McCollister 
353f1ca1fdeSGeorge McCollister err_set_rsa:
354f1ca1fdeSGeorge McCollister 	ENGINE_finish(e);
355f1ca1fdeSGeorge McCollister err_engine_init:
356f1ca1fdeSGeorge McCollister 	ENGINE_free(e);
357f1ca1fdeSGeorge McCollister err_engine_by_id:
358c3b43281SJelle van der Waa #if OPENSSL_VERSION_NUMBER < 0x10100000L
359f1ca1fdeSGeorge McCollister 	ENGINE_cleanup();
360c3b43281SJelle van der Waa #endif
361f1ca1fdeSGeorge McCollister 	return ret;
362f1ca1fdeSGeorge McCollister }
363f1ca1fdeSGeorge McCollister 
36419c402afSSimon Glass static void rsa_remove(void)
36519c402afSSimon Glass {
366c3b43281SJelle van der Waa #if OPENSSL_VERSION_NUMBER < 0x10100000L
36719c402afSSimon Glass 	CRYPTO_cleanup_all_ex_data();
36819c402afSSimon Glass 	ERR_free_strings();
36919c402afSSimon Glass #ifdef HAVE_ERR_REMOVE_THREAD_STATE
37019c402afSSimon Glass 	ERR_remove_thread_state(NULL);
37119c402afSSimon Glass #else
37219c402afSSimon Glass 	ERR_remove_state(0);
37319c402afSSimon Glass #endif
37419c402afSSimon Glass 	EVP_cleanup();
375c3b43281SJelle van der Waa #endif
37619c402afSSimon Glass }
37719c402afSSimon Glass 
378f1ca1fdeSGeorge McCollister static void rsa_engine_remove(ENGINE *e)
379f1ca1fdeSGeorge McCollister {
380f1ca1fdeSGeorge McCollister 	if (e) {
381f1ca1fdeSGeorge McCollister 		ENGINE_finish(e);
382f1ca1fdeSGeorge McCollister 		ENGINE_free(e);
383f1ca1fdeSGeorge McCollister 	}
384f1ca1fdeSGeorge McCollister }
385f1ca1fdeSGeorge McCollister 
386646257d1SHeiko Schocher static int rsa_sign_with_key(RSA *rsa, struct checksum_algo *checksum_algo,
387646257d1SHeiko Schocher 		const struct image_region region[], int region_count,
388646257d1SHeiko Schocher 		uint8_t **sigp, uint *sig_size)
38919c402afSSimon Glass {
39019c402afSSimon Glass 	EVP_PKEY *key;
39119c402afSSimon Glass 	EVP_MD_CTX *context;
39219c402afSSimon Glass 	int size, ret = 0;
39319c402afSSimon Glass 	uint8_t *sig;
39419c402afSSimon Glass 	int i;
39519c402afSSimon Glass 
39619c402afSSimon Glass 	key = EVP_PKEY_new();
39719c402afSSimon Glass 	if (!key)
39819c402afSSimon Glass 		return rsa_err("EVP_PKEY object creation failed");
39919c402afSSimon Glass 
40019c402afSSimon Glass 	if (!EVP_PKEY_set1_RSA(key, rsa)) {
40119c402afSSimon Glass 		ret = rsa_err("EVP key setup failed");
40219c402afSSimon Glass 		goto err_set;
40319c402afSSimon Glass 	}
40419c402afSSimon Glass 
40519c402afSSimon Glass 	size = EVP_PKEY_size(key);
40619c402afSSimon Glass 	sig = malloc(size);
40719c402afSSimon Glass 	if (!sig) {
40819c402afSSimon Glass 		fprintf(stderr, "Out of memory for signature (%d bytes)\n",
40919c402afSSimon Glass 			size);
41019c402afSSimon Glass 		ret = -ENOMEM;
41119c402afSSimon Glass 		goto err_alloc;
41219c402afSSimon Glass 	}
41319c402afSSimon Glass 
41419c402afSSimon Glass 	context = EVP_MD_CTX_create();
41519c402afSSimon Glass 	if (!context) {
41619c402afSSimon Glass 		ret = rsa_err("EVP context creation failed");
41719c402afSSimon Glass 		goto err_create;
41819c402afSSimon Glass 	}
41919c402afSSimon Glass 	EVP_MD_CTX_init(context);
42029a23f9dSHeiko Schocher 	if (!EVP_SignInit(context, checksum_algo->calculate_sign())) {
42119c402afSSimon Glass 		ret = rsa_err("Signer setup failed");
42219c402afSSimon Glass 		goto err_sign;
42319c402afSSimon Glass 	}
42419c402afSSimon Glass 
42519c402afSSimon Glass 	for (i = 0; i < region_count; i++) {
42619c402afSSimon Glass 		if (!EVP_SignUpdate(context, region[i].data, region[i].size)) {
42719c402afSSimon Glass 			ret = rsa_err("Signing data failed");
42819c402afSSimon Glass 			goto err_sign;
42919c402afSSimon Glass 		}
43019c402afSSimon Glass 	}
43119c402afSSimon Glass 
43219c402afSSimon Glass 	if (!EVP_SignFinal(context, sig, sig_size, key)) {
43319c402afSSimon Glass 		ret = rsa_err("Could not obtain signature");
43419c402afSSimon Glass 		goto err_sign;
43519c402afSSimon Glass 	}
436c3b43281SJelle van der Waa 	#if OPENSSL_VERSION_NUMBER < 0x10100000L
43719c402afSSimon Glass 		EVP_MD_CTX_cleanup(context);
438c3b43281SJelle van der Waa 	#else
439c3b43281SJelle van der Waa 		EVP_MD_CTX_reset(context);
440c3b43281SJelle van der Waa 	#endif
44119c402afSSimon Glass 	EVP_MD_CTX_destroy(context);
44219c402afSSimon Glass 	EVP_PKEY_free(key);
44319c402afSSimon Glass 
44419c402afSSimon Glass 	debug("Got signature: %d bytes, expected %d\n", *sig_size, size);
44519c402afSSimon Glass 	*sigp = sig;
44619c402afSSimon Glass 	*sig_size = size;
44719c402afSSimon Glass 
44819c402afSSimon Glass 	return 0;
44919c402afSSimon Glass 
45019c402afSSimon Glass err_sign:
45119c402afSSimon Glass 	EVP_MD_CTX_destroy(context);
45219c402afSSimon Glass err_create:
45319c402afSSimon Glass 	free(sig);
45419c402afSSimon Glass err_alloc:
45519c402afSSimon Glass err_set:
45619c402afSSimon Glass 	EVP_PKEY_free(key);
45719c402afSSimon Glass 	return ret;
45819c402afSSimon Glass }
45919c402afSSimon Glass 
46019c402afSSimon Glass int rsa_sign(struct image_sign_info *info,
46119c402afSSimon Glass 	     const struct image_region region[], int region_count,
46219c402afSSimon Glass 	     uint8_t **sigp, uint *sig_len)
46319c402afSSimon Glass {
46419c402afSSimon Glass 	RSA *rsa;
465f1ca1fdeSGeorge McCollister 	ENGINE *e = NULL;
46619c402afSSimon Glass 	int ret;
46719c402afSSimon Glass 
46819c402afSSimon Glass 	ret = rsa_init();
46919c402afSSimon Glass 	if (ret)
47019c402afSSimon Glass 		return ret;
47119c402afSSimon Glass 
472f1ca1fdeSGeorge McCollister 	if (info->engine_id) {
473f1ca1fdeSGeorge McCollister 		ret = rsa_engine_init(info->engine_id, &e);
474f1ca1fdeSGeorge McCollister 		if (ret)
475f1ca1fdeSGeorge McCollister 			goto err_engine;
476f1ca1fdeSGeorge McCollister 	}
477f1ca1fdeSGeorge McCollister 
478f1ca1fdeSGeorge McCollister 	ret = rsa_get_priv_key(info->keydir, info->keyname, e, &rsa);
47919c402afSSimon Glass 	if (ret)
48019c402afSSimon Glass 		goto err_priv;
48183dd98e0SAndrew Duda 	ret = rsa_sign_with_key(rsa, info->checksum, region,
482646257d1SHeiko Schocher 				region_count, sigp, sig_len);
48319c402afSSimon Glass 	if (ret)
48419c402afSSimon Glass 		goto err_sign;
48519c402afSSimon Glass 
48619c402afSSimon Glass 	RSA_free(rsa);
487f1ca1fdeSGeorge McCollister 	if (info->engine_id)
488f1ca1fdeSGeorge McCollister 		rsa_engine_remove(e);
48919c402afSSimon Glass 	rsa_remove();
49019c402afSSimon Glass 
49119c402afSSimon Glass 	return ret;
49219c402afSSimon Glass 
49319c402afSSimon Glass err_sign:
49419c402afSSimon Glass 	RSA_free(rsa);
49519c402afSSimon Glass err_priv:
496f1ca1fdeSGeorge McCollister 	if (info->engine_id)
497f1ca1fdeSGeorge McCollister 		rsa_engine_remove(e);
498f1ca1fdeSGeorge McCollister err_engine:
49919c402afSSimon Glass 	rsa_remove();
50019c402afSSimon Glass 	return ret;
50119c402afSSimon Glass }
50219c402afSSimon Glass 
50319c402afSSimon Glass /*
504e0f2f155SMichael van der Westhuizen  * rsa_get_exponent(): - Get the public exponent from an RSA key
505e0f2f155SMichael van der Westhuizen  */
506e0f2f155SMichael van der Westhuizen static int rsa_get_exponent(RSA *key, uint64_t *e)
507e0f2f155SMichael van der Westhuizen {
508e0f2f155SMichael van der Westhuizen 	int ret;
509e0f2f155SMichael van der Westhuizen 	BIGNUM *bn_te;
510c3b43281SJelle van der Waa 	const BIGNUM *key_e;
511e0f2f155SMichael van der Westhuizen 	uint64_t te;
512e0f2f155SMichael van der Westhuizen 
513e0f2f155SMichael van der Westhuizen 	ret = -EINVAL;
514e0f2f155SMichael van der Westhuizen 	bn_te = NULL;
515e0f2f155SMichael van der Westhuizen 
516e0f2f155SMichael van der Westhuizen 	if (!e)
517e0f2f155SMichael van der Westhuizen 		goto cleanup;
518e0f2f155SMichael van der Westhuizen 
519c3b43281SJelle van der Waa 	RSA_get0_key(key, NULL, &key_e, NULL);
520c3b43281SJelle van der Waa 	if (BN_num_bits(key_e) > 64)
521e0f2f155SMichael van der Westhuizen 		goto cleanup;
522e0f2f155SMichael van der Westhuizen 
523c3b43281SJelle van der Waa 	*e = BN_get_word(key_e);
524e0f2f155SMichael van der Westhuizen 
525c3b43281SJelle van der Waa 	if (BN_num_bits(key_e) < 33) {
526e0f2f155SMichael van der Westhuizen 		ret = 0;
527e0f2f155SMichael van der Westhuizen 		goto cleanup;
528e0f2f155SMichael van der Westhuizen 	}
529e0f2f155SMichael van der Westhuizen 
530c3b43281SJelle van der Waa 	bn_te = BN_dup(key_e);
531e0f2f155SMichael van der Westhuizen 	if (!bn_te)
532e0f2f155SMichael van der Westhuizen 		goto cleanup;
533e0f2f155SMichael van der Westhuizen 
534e0f2f155SMichael van der Westhuizen 	if (!BN_rshift(bn_te, bn_te, 32))
535e0f2f155SMichael van der Westhuizen 		goto cleanup;
536e0f2f155SMichael van der Westhuizen 
537e0f2f155SMichael van der Westhuizen 	if (!BN_mask_bits(bn_te, 32))
538e0f2f155SMichael van der Westhuizen 		goto cleanup;
539e0f2f155SMichael van der Westhuizen 
540e0f2f155SMichael van der Westhuizen 	te = BN_get_word(bn_te);
541e0f2f155SMichael van der Westhuizen 	te <<= 32;
542e0f2f155SMichael van der Westhuizen 	*e |= te;
543e0f2f155SMichael van der Westhuizen 	ret = 0;
544e0f2f155SMichael van der Westhuizen 
545e0f2f155SMichael van der Westhuizen cleanup:
546e0f2f155SMichael van der Westhuizen 	if (bn_te)
547e0f2f155SMichael van der Westhuizen 		BN_free(bn_te);
548e0f2f155SMichael van der Westhuizen 
549e0f2f155SMichael van der Westhuizen 	return ret;
550e0f2f155SMichael van der Westhuizen }
551e0f2f155SMichael van der Westhuizen 
552e0f2f155SMichael van der Westhuizen /*
55319c402afSSimon Glass  * rsa_get_params(): - Get the important parameters of an RSA public key
55419c402afSSimon Glass  */
555e0f2f155SMichael van der Westhuizen int rsa_get_params(RSA *key, uint64_t *exponent, uint32_t *n0_invp,
556*008ec9b4SJoseph Chen 		   BIGNUM **modulusp, BIGNUM **exponent_BN, BIGNUM **r_squaredp,
557*008ec9b4SJoseph Chen 		   BIGNUM **c_factorp, BIGNUM **np_factorp)
55819c402afSSimon Glass {
559*008ec9b4SJoseph Chen 	BIGNUM *big1, *big2, *big32, *big2_32, *big4100, *big2180;
560*008ec9b4SJoseph Chen 	BIGNUM *n, *e, *r, *r_squared, *tmp, *c_factor, *np_factor;
561*008ec9b4SJoseph Chen 	const BIGNUM *key_n, *key_e;
56219c402afSSimon Glass 	BN_CTX *bn_ctx = BN_CTX_new();
56319c402afSSimon Glass 	int ret = 0;
56419c402afSSimon Glass 
56519c402afSSimon Glass 	/* Initialize BIGNUMs */
56619c402afSSimon Glass 	big1 = BN_new();
56719c402afSSimon Glass 	big2 = BN_new();
56819c402afSSimon Glass 	big32 = BN_new();
569*008ec9b4SJoseph Chen 	big4100 = BN_new();
570*008ec9b4SJoseph Chen 	big2180 = BN_new();
571*008ec9b4SJoseph Chen 
57219c402afSSimon Glass 	r = BN_new();
57319c402afSSimon Glass 	r_squared = BN_new();
574*008ec9b4SJoseph Chen 	c_factor = BN_new();
575*008ec9b4SJoseph Chen 	np_factor = BN_new();
57619c402afSSimon Glass 	tmp = BN_new();
57719c402afSSimon Glass 	big2_32 = BN_new();
57819c402afSSimon Glass 	n = BN_new();
579*008ec9b4SJoseph Chen 	e = BN_new();
580*008ec9b4SJoseph Chen 	if (!big1 || !big2 || !big32 || !big4100 || !big2180 || !r ||
581*008ec9b4SJoseph Chen 	    !r_squared || !tmp || !big2_32 || !n || !e ||
582*008ec9b4SJoseph Chen 	    !c_factor || !np_factor) {
58319c402afSSimon Glass 		fprintf(stderr, "Out of memory (bignum)\n");
58419c402afSSimon Glass 		return -ENOMEM;
58519c402afSSimon Glass 	}
58619c402afSSimon Glass 
587e0f2f155SMichael van der Westhuizen 	if (0 != rsa_get_exponent(key, exponent))
588e0f2f155SMichael van der Westhuizen 		ret = -1;
589e0f2f155SMichael van der Westhuizen 
590*008ec9b4SJoseph Chen 	RSA_get0_key(key, &key_n, &key_e, NULL);
591*008ec9b4SJoseph Chen 	if (!BN_copy(n, key_n) || !BN_copy(e, key_e) ||
592*008ec9b4SJoseph Chen 	    !BN_set_word(big1, 1L) ||
593*008ec9b4SJoseph Chen 	    !BN_set_word(big2, 2L) || !BN_set_word(big32, 32L) ||
594*008ec9b4SJoseph Chen 	    !BN_set_word(big4100, 4100L) || !BN_set_word(big2180, 2180L))
59519c402afSSimon Glass 		ret = -1;
59619c402afSSimon Glass 
59719c402afSSimon Glass 	/* big2_32 = 2^32 */
59819c402afSSimon Glass 	if (!BN_exp(big2_32, big2, big32, bn_ctx))
59919c402afSSimon Glass 		ret = -1;
60019c402afSSimon Glass 
60119c402afSSimon Glass 	/* Calculate n0_inv = -1 / n[0] mod 2^32 */
60219c402afSSimon Glass 	if (!BN_mod_inverse(tmp, n, big2_32, bn_ctx) ||
60319c402afSSimon Glass 	    !BN_sub(tmp, big2_32, tmp))
60419c402afSSimon Glass 		ret = -1;
60519c402afSSimon Glass 	*n0_invp = BN_get_word(tmp);
60619c402afSSimon Glass 
60719c402afSSimon Glass 	/* Calculate R = 2^(# of key bits) */
60819c402afSSimon Glass 	if (!BN_set_word(tmp, BN_num_bits(n)) ||
60919c402afSSimon Glass 	    !BN_exp(r, big2, tmp, bn_ctx))
61019c402afSSimon Glass 		ret = -1;
61119c402afSSimon Glass 
61219c402afSSimon Glass 	/* Calculate r_squared = R^2 mod n */
61319c402afSSimon Glass 	if (!BN_copy(r_squared, r) ||
61419c402afSSimon Glass 	    !BN_mul(tmp, r_squared, r, bn_ctx) ||
61519c402afSSimon Glass 	    !BN_mod(r_squared, tmp, n, bn_ctx))
61619c402afSSimon Glass 		ret = -1;
61719c402afSSimon Glass 
618*008ec9b4SJoseph Chen 	/* Calculate c_factor = 2^4100 mod n */
619*008ec9b4SJoseph Chen 	if (!BN_exp(tmp, big2, big4100, bn_ctx) ||
620*008ec9b4SJoseph Chen 	    !BN_mod(c_factor, tmp, n, bn_ctx))
621*008ec9b4SJoseph Chen 		ret = -1;
622*008ec9b4SJoseph Chen 
623*008ec9b4SJoseph Chen 	/* Calculate np_factor = 2^2180 div n */
624*008ec9b4SJoseph Chen 	if (!BN_exp(tmp, big2, big2180, bn_ctx) ||
625*008ec9b4SJoseph Chen 	    !BN_div(np_factor, NULL, tmp, n, bn_ctx))
626*008ec9b4SJoseph Chen 		ret = -1;
627*008ec9b4SJoseph Chen 
62819c402afSSimon Glass 	*modulusp = n;
629*008ec9b4SJoseph Chen 	*exponent_BN = e;
63019c402afSSimon Glass 	*r_squaredp = r_squared;
631*008ec9b4SJoseph Chen 	*c_factorp = c_factor;
632*008ec9b4SJoseph Chen 	*np_factorp = np_factor;
63319c402afSSimon Glass 
63419c402afSSimon Glass 	BN_free(big1);
63519c402afSSimon Glass 	BN_free(big2);
63619c402afSSimon Glass 	BN_free(big32);
637*008ec9b4SJoseph Chen 	BN_free(big4100);
638*008ec9b4SJoseph Chen 	BN_free(big2180);
63919c402afSSimon Glass 	BN_free(r);
64019c402afSSimon Glass 	BN_free(tmp);
64119c402afSSimon Glass 	BN_free(big2_32);
64219c402afSSimon Glass 	if (ret) {
64319c402afSSimon Glass 		fprintf(stderr, "Bignum operations failed\n");
64419c402afSSimon Glass 		return -ENOMEM;
64519c402afSSimon Glass 	}
64619c402afSSimon Glass 
64719c402afSSimon Glass 	return ret;
64819c402afSSimon Glass }
64919c402afSSimon Glass 
65019c402afSSimon Glass static int fdt_add_bignum(void *blob, int noffset, const char *prop_name,
65119c402afSSimon Glass 			  BIGNUM *num, int num_bits)
65219c402afSSimon Glass {
65319c402afSSimon Glass 	int nwords = num_bits / 32;
65419c402afSSimon Glass 	int size;
65519c402afSSimon Glass 	uint32_t *buf, *ptr;
65619c402afSSimon Glass 	BIGNUM *tmp, *big2, *big32, *big2_32;
65719c402afSSimon Glass 	BN_CTX *ctx;
65819c402afSSimon Glass 	int ret;
65919c402afSSimon Glass 
66019c402afSSimon Glass 	tmp = BN_new();
66119c402afSSimon Glass 	big2 = BN_new();
66219c402afSSimon Glass 	big32 = BN_new();
66319c402afSSimon Glass 	big2_32 = BN_new();
66419c402afSSimon Glass 	if (!tmp || !big2 || !big32 || !big2_32) {
66519c402afSSimon Glass 		fprintf(stderr, "Out of memory (bignum)\n");
66619c402afSSimon Glass 		return -ENOMEM;
66719c402afSSimon Glass 	}
66819c402afSSimon Glass 	ctx = BN_CTX_new();
66919c402afSSimon Glass 	if (!tmp) {
67019c402afSSimon Glass 		fprintf(stderr, "Out of memory (bignum context)\n");
67119c402afSSimon Glass 		return -ENOMEM;
67219c402afSSimon Glass 	}
67319c402afSSimon Glass 	BN_set_word(big2, 2L);
67419c402afSSimon Glass 	BN_set_word(big32, 32L);
67519c402afSSimon Glass 	BN_exp(big2_32, big2, big32, ctx); /* B = 2^32 */
67619c402afSSimon Glass 
67719c402afSSimon Glass 	size = nwords * sizeof(uint32_t);
67819c402afSSimon Glass 	buf = malloc(size);
67919c402afSSimon Glass 	if (!buf) {
68019c402afSSimon Glass 		fprintf(stderr, "Out of memory (%d bytes)\n", size);
68119c402afSSimon Glass 		return -ENOMEM;
68219c402afSSimon Glass 	}
68319c402afSSimon Glass 
68419c402afSSimon Glass 	/* Write out modulus as big endian array of integers */
68519c402afSSimon Glass 	for (ptr = buf + nwords - 1; ptr >= buf; ptr--) {
68619c402afSSimon Glass 		BN_mod(tmp, num, big2_32, ctx); /* n = N mod B */
68719c402afSSimon Glass 		*ptr = cpu_to_fdt32(BN_get_word(tmp));
68819c402afSSimon Glass 		BN_rshift(num, num, 32); /*  N = N/B */
68919c402afSSimon Glass 	}
69019c402afSSimon Glass 
691713fb2dcSmario.six@gdsys.cc 	/*
692713fb2dcSmario.six@gdsys.cc 	 * We try signing with successively increasing size values, so this
693713fb2dcSmario.six@gdsys.cc 	 * might fail several times
694713fb2dcSmario.six@gdsys.cc 	 */
69519c402afSSimon Glass 	ret = fdt_setprop(blob, noffset, prop_name, buf, size);
6962b9ec762Smario.six@gdsys.cc 	if (ret)
6972b9ec762Smario.six@gdsys.cc 		return -FDT_ERR_NOSPACE;
69819c402afSSimon Glass 	free(buf);
69919c402afSSimon Glass 	BN_free(tmp);
70019c402afSSimon Glass 	BN_free(big2);
70119c402afSSimon Glass 	BN_free(big32);
70219c402afSSimon Glass 	BN_free(big2_32);
70319c402afSSimon Glass 
70419c402afSSimon Glass 	return ret;
70519c402afSSimon Glass }
70619c402afSSimon Glass 
70719c402afSSimon Glass int rsa_add_verify_data(struct image_sign_info *info, void *keydest)
70819c402afSSimon Glass {
709*008ec9b4SJoseph Chen 	BIGNUM *modulus, *exponent_BN, *r_squared, *c_factor, *np_factor;
710e0f2f155SMichael van der Westhuizen 	uint64_t exponent;
71119c402afSSimon Glass 	uint32_t n0_inv;
71219c402afSSimon Glass 	int parent, node;
71319c402afSSimon Glass 	char name[100];
71419c402afSSimon Glass 	int ret;
71519c402afSSimon Glass 	int bits;
71619c402afSSimon Glass 	RSA *rsa;
717f1ca1fdeSGeorge McCollister 	ENGINE *e = NULL;
71819c402afSSimon Glass 
71919c402afSSimon Glass 	debug("%s: Getting verification data\n", __func__);
720f1ca1fdeSGeorge McCollister 	if (info->engine_id) {
721f1ca1fdeSGeorge McCollister 		ret = rsa_engine_init(info->engine_id, &e);
72219c402afSSimon Glass 		if (ret)
72319c402afSSimon Glass 			return ret;
724f1ca1fdeSGeorge McCollister 	}
725f1ca1fdeSGeorge McCollister 	ret = rsa_get_pub_key(info->keydir, info->keyname, e, &rsa);
726f1ca1fdeSGeorge McCollister 	if (ret)
727f1ca1fdeSGeorge McCollister 		goto err_get_pub_key;
728*008ec9b4SJoseph Chen 	ret = rsa_get_params(rsa, &exponent, &n0_inv, &modulus,
729*008ec9b4SJoseph Chen 			     &exponent_BN, &r_squared, &c_factor, &np_factor);
73019c402afSSimon Glass 	if (ret)
731f1ca1fdeSGeorge McCollister 		goto err_get_params;
73219c402afSSimon Glass 	bits = BN_num_bits(modulus);
73319c402afSSimon Glass 	parent = fdt_subnode_offset(keydest, 0, FIT_SIG_NODENAME);
73419c402afSSimon Glass 	if (parent == -FDT_ERR_NOTFOUND) {
73519c402afSSimon Glass 		parent = fdt_add_subnode(keydest, 0, FIT_SIG_NODENAME);
73619c402afSSimon Glass 		if (parent < 0) {
737597a8b2cSSimon Glass 			ret = parent;
738597a8b2cSSimon Glass 			if (ret != -FDT_ERR_NOSPACE) {
73919c402afSSimon Glass 				fprintf(stderr, "Couldn't create signature node: %s\n",
74019c402afSSimon Glass 					fdt_strerror(parent));
74119c402afSSimon Glass 			}
74219c402afSSimon Glass 		}
743597a8b2cSSimon Glass 	}
744597a8b2cSSimon Glass 	if (ret)
745597a8b2cSSimon Glass 		goto done;
74619c402afSSimon Glass 
74719c402afSSimon Glass 	/* Either create or overwrite the named key node */
74819c402afSSimon Glass 	snprintf(name, sizeof(name), "key-%s", info->keyname);
74919c402afSSimon Glass 	node = fdt_subnode_offset(keydest, parent, name);
75019c402afSSimon Glass 	if (node == -FDT_ERR_NOTFOUND) {
75119c402afSSimon Glass 		node = fdt_add_subnode(keydest, parent, name);
75219c402afSSimon Glass 		if (node < 0) {
753597a8b2cSSimon Glass 			ret = node;
754597a8b2cSSimon Glass 			if (ret != -FDT_ERR_NOSPACE) {
75519c402afSSimon Glass 				fprintf(stderr, "Could not create key subnode: %s\n",
75619c402afSSimon Glass 					fdt_strerror(node));
757597a8b2cSSimon Glass 			}
75819c402afSSimon Glass 		}
75919c402afSSimon Glass 	} else if (node < 0) {
76019c402afSSimon Glass 		fprintf(stderr, "Cannot select keys parent: %s\n",
76119c402afSSimon Glass 			fdt_strerror(node));
762597a8b2cSSimon Glass 		ret = node;
76319c402afSSimon Glass 	}
76419c402afSSimon Glass 
765597a8b2cSSimon Glass 	if (!ret) {
76619c402afSSimon Glass 		ret = fdt_setprop_string(keydest, node, "key-name-hint",
76719c402afSSimon Glass 				 info->keyname);
768597a8b2cSSimon Glass 	}
7694f427a42SSimon Glass 	if (!ret)
7704f427a42SSimon Glass 		ret = fdt_setprop_u32(keydest, node, "rsa,num-bits", bits);
7714f427a42SSimon Glass 	if (!ret)
7724f427a42SSimon Glass 		ret = fdt_setprop_u32(keydest, node, "rsa,n0-inverse", n0_inv);
7734f427a42SSimon Glass 	if (!ret) {
774e0f2f155SMichael van der Westhuizen 		ret = fdt_setprop_u64(keydest, node, "rsa,exponent", exponent);
775e0f2f155SMichael van der Westhuizen 	}
776e0f2f155SMichael van der Westhuizen 	if (!ret) {
777*008ec9b4SJoseph Chen 		ret = fdt_add_bignum(keydest, node, "rsa,exponent-BN",
778*008ec9b4SJoseph Chen 				     exponent_BN, bits);
779*008ec9b4SJoseph Chen 	}
780*008ec9b4SJoseph Chen 	if (!ret) {
7814f427a42SSimon Glass 		ret = fdt_add_bignum(keydest, node, "rsa,modulus", modulus,
7824f427a42SSimon Glass 				     bits);
7834f427a42SSimon Glass 	}
7844f427a42SSimon Glass 	if (!ret) {
7854f427a42SSimon Glass 		ret = fdt_add_bignum(keydest, node, "rsa,r-squared", r_squared,
7864f427a42SSimon Glass 				     bits);
7874f427a42SSimon Glass 	}
7884f427a42SSimon Glass 	if (!ret) {
789*008ec9b4SJoseph Chen 		ret = fdt_add_bignum(keydest, node, "rsa,c", c_factor,
790*008ec9b4SJoseph Chen 				     bits);
791*008ec9b4SJoseph Chen 	}
792*008ec9b4SJoseph Chen 	if (!ret) {
793*008ec9b4SJoseph Chen 		ret = fdt_add_bignum(keydest, node, "rsa,np", np_factor,
794*008ec9b4SJoseph Chen 				     bits);
795*008ec9b4SJoseph Chen 	}
796*008ec9b4SJoseph Chen 	if (!ret) {
7974f427a42SSimon Glass 		ret = fdt_setprop_string(keydest, node, FIT_ALGO_PROP,
79883dd98e0SAndrew Duda 					 info->name);
7994f427a42SSimon Glass 	}
8002b9ec762Smario.six@gdsys.cc 	if (!ret && info->require_keys) {
8014f427a42SSimon Glass 		ret = fdt_setprop_string(keydest, node, "required",
80219c402afSSimon Glass 					 info->require_keys);
80319c402afSSimon Glass 	}
804597a8b2cSSimon Glass done:
80519c402afSSimon Glass 	BN_free(modulus);
80619c402afSSimon Glass 	BN_free(r_squared);
80719c402afSSimon Glass 	if (ret)
808f1ca1fdeSGeorge McCollister 		ret = ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;
809f1ca1fdeSGeorge McCollister err_get_params:
810f1ca1fdeSGeorge McCollister 	RSA_free(rsa);
811f1ca1fdeSGeorge McCollister err_get_pub_key:
812f1ca1fdeSGeorge McCollister 	if (info->engine_id)
813f1ca1fdeSGeorge McCollister 		rsa_engine_remove(e);
81419c402afSSimon Glass 
815f1ca1fdeSGeorge McCollister 	return ret;
81619c402afSSimon Glass }
817