2018-05-06 21:58:06 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
2013-06-13 22:10:02 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2013, Google Inc.
|
|
|
|
*/
|
|
|
|
|
2021-12-18 10:25:12 +00:00
|
|
|
#define OPENSSL_API_COMPAT 0x10101000L
|
|
|
|
|
2013-06-13 22:10:02 +00:00
|
|
|
#include "mkimage.h"
|
2020-05-15 12:20:34 +00:00
|
|
|
#include <stdlib.h>
|
2013-06-13 22:10:02 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <image.h>
|
|
|
|
#include <time.h>
|
2021-02-19 18:45:11 +00:00
|
|
|
#include <u-boot/fdt-libcrypto.h>
|
2017-05-08 19:31:19 +00:00
|
|
|
#include <openssl/bn.h>
|
2021-04-01 22:42:36 +00:00
|
|
|
#include <openssl/ec.h>
|
2013-06-13 22:10:02 +00:00
|
|
|
#include <openssl/rsa.h>
|
|
|
|
#include <openssl/pem.h>
|
|
|
|
#include <openssl/err.h>
|
|
|
|
#include <openssl/ssl.h>
|
|
|
|
#include <openssl/evp.h>
|
2017-01-06 19:14:17 +00:00
|
|
|
#include <openssl/engine.h>
|
2013-06-13 22:10:02 +00:00
|
|
|
|
|
|
|
static int rsa_err(const char *msg)
|
|
|
|
{
|
|
|
|
unsigned long sslErr = ERR_get_error();
|
|
|
|
|
|
|
|
fprintf(stderr, "%s", msg);
|
|
|
|
fprintf(stderr, ": %s\n",
|
|
|
|
ERR_error_string(sslErr, 0));
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-01-06 19:14:17 +00:00
|
|
|
* rsa_pem_get_pub_key() - read a public key from a .crt file
|
2013-06-13 22:10:02 +00:00
|
|
|
*
|
|
|
|
* @keydir: Directory containins the key
|
|
|
|
* @name Name of key file (will have a .crt extension)
|
2021-04-01 22:42:36 +00:00
|
|
|
* @evpp Returns EVP_PKEY object, or NULL on failure
|
2022-01-19 17:05:50 +00:00
|
|
|
* Return: 0 if ok, -ve on error (in which case *evpp will be set to NULL)
|
2013-06-13 22:10:02 +00:00
|
|
|
*/
|
2021-04-01 22:42:36 +00:00
|
|
|
static int rsa_pem_get_pub_key(const char *keydir, const char *name, EVP_PKEY **evpp)
|
2013-06-13 22:10:02 +00:00
|
|
|
{
|
|
|
|
char path[1024];
|
2021-04-01 22:42:36 +00:00
|
|
|
EVP_PKEY *key = NULL;
|
2013-06-13 22:10:02 +00:00
|
|
|
X509 *cert;
|
|
|
|
FILE *f;
|
|
|
|
int ret;
|
|
|
|
|
2021-04-01 22:42:36 +00:00
|
|
|
if (!evpp)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
*evpp = NULL;
|
2013-06-13 22:10:02 +00:00
|
|
|
snprintf(path, sizeof(path), "%s/%s.crt", keydir, name);
|
|
|
|
f = fopen(path, "r");
|
|
|
|
if (!f) {
|
|
|
|
fprintf(stderr, "Couldn't open RSA certificate: '%s': %s\n",
|
|
|
|
path, strerror(errno));
|
|
|
|
return -EACCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read the certificate */
|
|
|
|
cert = NULL;
|
|
|
|
if (!PEM_read_X509(f, &cert, NULL, NULL)) {
|
|
|
|
rsa_err("Couldn't read certificate");
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_cert;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the public key from the certificate. */
|
|
|
|
key = X509_get_pubkey(cert);
|
|
|
|
if (!key) {
|
|
|
|
rsa_err("Couldn't read public key\n");
|
|
|
|
ret = -EINVAL;
|
|
|
|
goto err_pubkey;
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(f);
|
2021-04-01 22:42:36 +00:00
|
|
|
*evpp = key;
|
2013-06-13 22:10:02 +00:00
|
|
|
X509_free(cert);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_pubkey:
|
|
|
|
X509_free(cert);
|
|
|
|
err_cert:
|
|
|
|
fclose(f);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-01-06 19:14:17 +00:00
|
|
|
* rsa_engine_get_pub_key() - read a public key from given engine
|
2013-06-13 22:10:02 +00:00
|
|
|
*
|
2017-01-06 19:14:17 +00:00
|
|
|
* @keydir: Key prefix
|
|
|
|
* @name Name of key
|
|
|
|
* @engine Engine to use
|
2021-04-01 22:42:36 +00:00
|
|
|
* @evpp Returns EVP_PKEY object, or NULL on failure
|
2022-01-19 17:05:50 +00:00
|
|
|
* Return: 0 if ok, -ve on error (in which case *evpp will be set to NULL)
|
2017-01-06 19:14:17 +00:00
|
|
|
*/
|
|
|
|
static int rsa_engine_get_pub_key(const char *keydir, const char *name,
|
2021-04-01 22:42:36 +00:00
|
|
|
ENGINE *engine, EVP_PKEY **evpp)
|
2017-01-06 19:14:17 +00:00
|
|
|
{
|
|
|
|
const char *engine_id;
|
|
|
|
char key_id[1024];
|
2021-04-01 22:42:36 +00:00
|
|
|
EVP_PKEY *key = NULL;
|
|
|
|
|
|
|
|
if (!evpp)
|
|
|
|
return -EINVAL;
|
2017-01-06 19:14:17 +00:00
|
|
|
|
2021-04-01 22:42:36 +00:00
|
|
|
*evpp = NULL;
|
2017-01-06 19:14:17 +00:00
|
|
|
|
|
|
|
engine_id = ENGINE_get_id(engine);
|
|
|
|
|
|
|
|
if (engine_id && !strcmp(engine_id, "pkcs11")) {
|
|
|
|
if (keydir)
|
2020-05-13 10:26:24 +00:00
|
|
|
if (strstr(keydir, "object="))
|
|
|
|
snprintf(key_id, sizeof(key_id),
|
|
|
|
"pkcs11:%s;type=public",
|
|
|
|
keydir);
|
|
|
|
else
|
|
|
|
snprintf(key_id, sizeof(key_id),
|
|
|
|
"pkcs11:%s;object=%s;type=public",
|
|
|
|
keydir, name);
|
2017-01-06 19:14:17 +00:00
|
|
|
else
|
|
|
|
snprintf(key_id, sizeof(key_id),
|
|
|
|
"pkcs11:object=%s;type=public",
|
|
|
|
name);
|
2019-06-16 17:53:38 +00:00
|
|
|
} else if (engine_id) {
|
|
|
|
if (keydir)
|
|
|
|
snprintf(key_id, sizeof(key_id),
|
|
|
|
"%s%s",
|
|
|
|
keydir, name);
|
|
|
|
else
|
|
|
|
snprintf(key_id, sizeof(key_id),
|
|
|
|
"%s",
|
|
|
|
name);
|
2017-01-06 19:14:17 +00:00
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Engine not supported\n");
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
key = ENGINE_load_public_key(engine, key_id, NULL, NULL);
|
|
|
|
if (!key)
|
|
|
|
return rsa_err("Failure loading public key from engine");
|
|
|
|
|
2021-04-01 22:42:36 +00:00
|
|
|
*evpp = key;
|
2017-01-06 19:14:17 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* rsa_get_pub_key() - read a public key
|
|
|
|
*
|
|
|
|
* @keydir: Directory containing the key (PEM file) or key prefix (engine)
|
|
|
|
* @name Name of key file (will have a .crt extension)
|
|
|
|
* @engine Engine to use
|
2021-04-01 22:42:36 +00:00
|
|
|
* @evpp Returns EVP_PKEY object, or NULL on failure
|
2022-01-19 17:05:50 +00:00
|
|
|
* Return: 0 if ok, -ve on error (in which case *evpp will be set to NULL)
|
2017-01-06 19:14:17 +00:00
|
|
|
*/
|
|
|
|
static int rsa_get_pub_key(const char *keydir, const char *name,
|
2021-04-01 22:42:36 +00:00
|
|
|
ENGINE *engine, EVP_PKEY **evpp)
|
2017-01-06 19:14:17 +00:00
|
|
|
{
|
|
|
|
if (engine)
|
2021-04-01 22:42:36 +00:00
|
|
|
return rsa_engine_get_pub_key(keydir, name, engine, evpp);
|
|
|
|
return rsa_pem_get_pub_key(keydir, name, evpp);
|
2017-01-06 19:14:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* rsa_pem_get_priv_key() - read a private key from a .key file
|
|
|
|
*
|
|
|
|
* @keydir: Directory containing the key
|
2013-06-13 22:10:02 +00:00
|
|
|
* @name Name of key file (will have a .key extension)
|
2021-04-01 22:42:36 +00:00
|
|
|
* @evpp Returns EVP_PKEY object, or NULL on failure
|
2022-01-19 17:05:50 +00:00
|
|
|
* Return: 0 if ok, -ve on error (in which case *evpp will be set to NULL)
|
2013-06-13 22:10:02 +00:00
|
|
|
*/
|
2017-01-06 19:14:17 +00:00
|
|
|
static int rsa_pem_get_priv_key(const char *keydir, const char *name,
|
2021-04-01 22:42:36 +00:00
|
|
|
const char *keyfile, EVP_PKEY **evpp)
|
2013-06-13 22:10:02 +00:00
|
|
|
{
|
2021-04-01 22:42:36 +00:00
|
|
|
char path[1024] = {0};
|
|
|
|
FILE *f = NULL;
|
|
|
|
|
|
|
|
if (!evpp)
|
|
|
|
return -EINVAL;
|
2013-06-13 22:10:02 +00:00
|
|
|
|
2021-04-01 22:42:36 +00:00
|
|
|
*evpp = NULL;
|
2021-02-19 18:45:18 +00:00
|
|
|
if (keydir && name)
|
|
|
|
snprintf(path, sizeof(path), "%s/%s.key", keydir, name);
|
|
|
|
else if (keyfile)
|
|
|
|
snprintf(path, sizeof(path), "%s", keyfile);
|
|
|
|
else
|
|
|
|
return -EINVAL;
|
|
|
|
|
2013-06-13 22:10:02 +00:00
|
|
|
f = fopen(path, "r");
|
|
|
|
if (!f) {
|
|
|
|
fprintf(stderr, "Couldn't open RSA private key: '%s': %s\n",
|
|
|
|
path, strerror(errno));
|
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
2021-04-01 22:42:36 +00:00
|
|
|
if (!PEM_read_PrivateKey(f, evpp, NULL, path)) {
|
2013-06-13 22:10:02 +00:00
|
|
|
rsa_err("Failure reading private key");
|
|
|
|
fclose(f);
|
|
|
|
return -EPROTO;
|
|
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-01-06 19:14:17 +00:00
|
|
|
/**
|
|
|
|
* rsa_engine_get_priv_key() - read a private key from given engine
|
|
|
|
*
|
|
|
|
* @keydir: Key prefix
|
|
|
|
* @name Name of key
|
|
|
|
* @engine Engine to use
|
2021-04-01 22:42:36 +00:00
|
|
|
* @evpp Returns EVP_PKEY object, or NULL on failure
|
2022-01-19 17:05:50 +00:00
|
|
|
* Return: 0 if ok, -ve on error (in which case *evpp will be set to NULL)
|
2017-01-06 19:14:17 +00:00
|
|
|
*/
|
|
|
|
static int rsa_engine_get_priv_key(const char *keydir, const char *name,
|
2021-02-19 18:45:18 +00:00
|
|
|
const char *keyfile,
|
2021-04-01 22:42:36 +00:00
|
|
|
ENGINE *engine, EVP_PKEY **evpp)
|
2017-01-06 19:14:17 +00:00
|
|
|
{
|
|
|
|
const char *engine_id;
|
|
|
|
char key_id[1024];
|
2021-04-01 22:42:36 +00:00
|
|
|
EVP_PKEY *key = NULL;
|
2017-01-06 19:14:17 +00:00
|
|
|
|
2021-04-01 22:42:36 +00:00
|
|
|
if (!evpp)
|
|
|
|
return -EINVAL;
|
2017-01-06 19:14:17 +00:00
|
|
|
|
|
|
|
engine_id = ENGINE_get_id(engine);
|
|
|
|
|
|
|
|
if (engine_id && !strcmp(engine_id, "pkcs11")) {
|
2021-02-19 18:45:18 +00:00
|
|
|
if (!keydir && !name) {
|
|
|
|
fprintf(stderr, "Please use 'keydir' with PKCS11\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2017-01-06 19:14:17 +00:00
|
|
|
if (keydir)
|
2020-05-13 10:26:24 +00:00
|
|
|
if (strstr(keydir, "object="))
|
|
|
|
snprintf(key_id, sizeof(key_id),
|
|
|
|
"pkcs11:%s;type=private",
|
|
|
|
keydir);
|
|
|
|
else
|
|
|
|
snprintf(key_id, sizeof(key_id),
|
|
|
|
"pkcs11:%s;object=%s;type=private",
|
|
|
|
keydir, name);
|
2017-01-06 19:14:17 +00:00
|
|
|
else
|
|
|
|
snprintf(key_id, sizeof(key_id),
|
|
|
|
"pkcs11:object=%s;type=private",
|
|
|
|
name);
|
2019-06-16 17:53:38 +00:00
|
|
|
} else if (engine_id) {
|
2021-02-19 18:45:18 +00:00
|
|
|
if (keydir && name)
|
2019-06-16 17:53:38 +00:00
|
|
|
snprintf(key_id, sizeof(key_id),
|
|
|
|
"%s%s",
|
|
|
|
keydir, name);
|
2021-08-28 10:13:05 +00:00
|
|
|
else if (name)
|
2019-06-16 17:53:38 +00:00
|
|
|
snprintf(key_id, sizeof(key_id),
|
|
|
|
"%s",
|
2021-07-30 15:05:07 +00:00
|
|
|
name ? name : "");
|
2021-02-19 18:45:18 +00:00
|
|
|
else if (keyfile)
|
|
|
|
snprintf(key_id, sizeof(key_id), "%s", keyfile);
|
|
|
|
else
|
|
|
|
return -EINVAL;
|
|
|
|
|
2017-01-06 19:14:17 +00:00
|
|
|
} else {
|
|
|
|
fprintf(stderr, "Engine not supported\n");
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
key = ENGINE_load_private_key(engine, key_id, NULL, NULL);
|
|
|
|
if (!key)
|
|
|
|
return rsa_err("Failure loading private key from engine");
|
|
|
|
|
2021-04-01 22:42:36 +00:00
|
|
|
*evpp = key;
|
2017-01-06 19:14:17 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* rsa_get_priv_key() - read a private key
|
|
|
|
*
|
|
|
|
* @keydir: Directory containing the key (PEM file) or key prefix (engine)
|
|
|
|
* @name Name of key
|
|
|
|
* @engine Engine to use for signing
|
2021-04-01 22:42:36 +00:00
|
|
|
* @evpp Returns EVP_PKEY object, or NULL on failure
|
2022-01-19 17:05:50 +00:00
|
|
|
* Return: 0 if ok, -ve on error (in which case *evpp will be set to NULL)
|
2017-01-06 19:14:17 +00:00
|
|
|
*/
|
|
|
|
static int rsa_get_priv_key(const char *keydir, const char *name,
|
2021-04-01 22:42:36 +00:00
|
|
|
const char *keyfile, ENGINE *engine, EVP_PKEY **evpp)
|
2017-01-06 19:14:17 +00:00
|
|
|
{
|
|
|
|
if (engine)
|
2021-02-19 18:45:18 +00:00
|
|
|
return rsa_engine_get_priv_key(keydir, name, keyfile, engine,
|
2021-04-01 22:42:36 +00:00
|
|
|
evpp);
|
|
|
|
return rsa_pem_get_priv_key(keydir, name, keyfile, evpp);
|
2017-01-06 19:14:17 +00:00
|
|
|
}
|
|
|
|
|
2013-06-13 22:10:02 +00:00
|
|
|
static int rsa_init(void)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2017-05-08 19:31:19 +00:00
|
|
|
ret = OPENSSL_init_ssl(0, NULL);
|
2013-06-13 22:10:02 +00:00
|
|
|
if (!ret) {
|
|
|
|
fprintf(stderr, "Failure to init SSL library\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-01-06 19:14:17 +00:00
|
|
|
static int rsa_engine_init(const char *engine_id, ENGINE **pe)
|
|
|
|
{
|
2021-07-23 20:17:50 +00:00
|
|
|
const char *key_pass;
|
2017-01-06 19:14:17 +00:00
|
|
|
ENGINE *e;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ENGINE_load_builtin_engines();
|
|
|
|
|
|
|
|
e = ENGINE_by_id(engine_id);
|
|
|
|
if (!e) {
|
|
|
|
fprintf(stderr, "Engine isn't available\n");
|
2021-07-29 18:31:21 +00:00
|
|
|
return -1;
|
2017-01-06 19:14:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!ENGINE_init(e)) {
|
|
|
|
fprintf(stderr, "Couldn't initialize engine\n");
|
|
|
|
ret = -1;
|
|
|
|
goto err_engine_init;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ENGINE_set_default_RSA(e)) {
|
|
|
|
fprintf(stderr, "Couldn't set engine as default for RSA\n");
|
|
|
|
ret = -1;
|
|
|
|
goto err_set_rsa;
|
|
|
|
}
|
|
|
|
|
2021-07-23 20:17:50 +00:00
|
|
|
key_pass = getenv("MKIMAGE_SIGN_PIN");
|
|
|
|
if (key_pass) {
|
|
|
|
if (!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0)) {
|
|
|
|
fprintf(stderr, "Couldn't set PIN\n");
|
|
|
|
ret = -1;
|
|
|
|
goto err_set_pin;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-06 19:14:17 +00:00
|
|
|
*pe = e;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2021-07-23 20:17:50 +00:00
|
|
|
err_set_pin:
|
2017-01-06 19:14:17 +00:00
|
|
|
err_set_rsa:
|
|
|
|
ENGINE_finish(e);
|
|
|
|
err_engine_init:
|
|
|
|
ENGINE_free(e);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void rsa_engine_remove(ENGINE *e)
|
|
|
|
{
|
|
|
|
if (e) {
|
|
|
|
ENGINE_finish(e);
|
|
|
|
ENGINE_free(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-01 22:42:36 +00:00
|
|
|
static int rsa_sign_with_key(EVP_PKEY *pkey, struct padding_algo *padding_algo,
|
2018-11-14 12:51:00 +00:00
|
|
|
struct checksum_algo *checksum_algo,
|
2014-03-03 11:19:26 +00:00
|
|
|
const struct image_region region[], int region_count,
|
|
|
|
uint8_t **sigp, uint *sig_size)
|
2013-06-13 22:10:02 +00:00
|
|
|
{
|
2018-11-14 12:51:00 +00:00
|
|
|
EVP_PKEY_CTX *ckey;
|
2013-06-13 22:10:02 +00:00
|
|
|
EVP_MD_CTX *context;
|
2018-11-14 12:50:59 +00:00
|
|
|
int ret = 0;
|
|
|
|
size_t size;
|
2013-06-13 22:10:02 +00:00
|
|
|
uint8_t *sig;
|
|
|
|
int i;
|
|
|
|
|
2021-04-01 22:42:36 +00:00
|
|
|
size = EVP_PKEY_size(pkey);
|
2013-06-13 22:10:02 +00:00
|
|
|
sig = malloc(size);
|
|
|
|
if (!sig) {
|
2018-11-14 12:50:59 +00:00
|
|
|
fprintf(stderr, "Out of memory for signature (%zu bytes)\n",
|
2013-06-13 22:10:02 +00:00
|
|
|
size);
|
|
|
|
ret = -ENOMEM;
|
|
|
|
goto err_alloc;
|
|
|
|
}
|
|
|
|
|
2022-03-01 15:12:34 +00:00
|
|
|
context = EVP_MD_CTX_new();
|
2013-06-13 22:10:02 +00:00
|
|
|
if (!context) {
|
|
|
|
ret = rsa_err("EVP context creation failed");
|
|
|
|
goto err_create;
|
|
|
|
}
|
2018-11-14 12:51:00 +00:00
|
|
|
|
2021-04-01 22:42:36 +00:00
|
|
|
ckey = EVP_PKEY_CTX_new(pkey, NULL);
|
2018-11-14 12:51:00 +00:00
|
|
|
if (!ckey) {
|
|
|
|
ret = rsa_err("EVP key context creation failed");
|
|
|
|
goto err_create;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (EVP_DigestSignInit(context, &ckey,
|
2018-11-14 12:50:59 +00:00
|
|
|
checksum_algo->calculate_sign(),
|
2021-04-01 22:42:36 +00:00
|
|
|
NULL, pkey) <= 0) {
|
2013-06-13 22:10:02 +00:00
|
|
|
ret = rsa_err("Signer setup failed");
|
|
|
|
goto err_sign;
|
|
|
|
}
|
|
|
|
|
2021-09-26 01:43:23 +00:00
|
|
|
if (CONFIG_IS_ENABLED(FIT_RSASSA_PSS) && padding_algo &&
|
|
|
|
!strcmp(padding_algo->name, "pss")) {
|
2018-11-14 12:51:01 +00:00
|
|
|
if (EVP_PKEY_CTX_set_rsa_padding(ckey,
|
|
|
|
RSA_PKCS1_PSS_PADDING) <= 0) {
|
|
|
|
ret = rsa_err("Signer padding setup failed");
|
|
|
|
goto err_sign;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-13 22:10:02 +00:00
|
|
|
for (i = 0; i < region_count; i++) {
|
2018-11-14 12:50:59 +00:00
|
|
|
if (!EVP_DigestSignUpdate(context, region[i].data,
|
|
|
|
region[i].size)) {
|
2013-06-13 22:10:02 +00:00
|
|
|
ret = rsa_err("Signing data failed");
|
|
|
|
goto err_sign;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-14 12:50:59 +00:00
|
|
|
if (!EVP_DigestSignFinal(context, sig, &size)) {
|
2013-06-13 22:10:02 +00:00
|
|
|
ret = rsa_err("Could not obtain signature");
|
|
|
|
goto err_sign;
|
|
|
|
}
|
2018-11-14 12:50:59 +00:00
|
|
|
|
2022-03-01 15:12:34 +00:00
|
|
|
EVP_MD_CTX_free(context);
|
2013-06-13 22:10:02 +00:00
|
|
|
|
2021-07-19 16:18:54 +00:00
|
|
|
debug("Got signature: %zu bytes, expected %d\n", size, EVP_PKEY_size(pkey));
|
2013-06-13 22:10:02 +00:00
|
|
|
*sigp = sig;
|
|
|
|
*sig_size = size;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
err_sign:
|
2022-03-01 15:12:34 +00:00
|
|
|
EVP_MD_CTX_free(context);
|
2013-06-13 22:10:02 +00:00
|
|
|
err_create:
|
|
|
|
free(sig);
|
|
|
|
err_alloc:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rsa_sign(struct image_sign_info *info,
|
|
|
|
const struct image_region region[], int region_count,
|
|
|
|
uint8_t **sigp, uint *sig_len)
|
|
|
|
{
|
2021-04-01 22:42:36 +00:00
|
|
|
EVP_PKEY *pkey = NULL;
|
2017-01-06 19:14:17 +00:00
|
|
|
ENGINE *e = NULL;
|
2013-06-13 22:10:02 +00:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = rsa_init();
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2017-01-06 19:14:17 +00:00
|
|
|
if (info->engine_id) {
|
|
|
|
ret = rsa_engine_init(info->engine_id, &e);
|
|
|
|
if (ret)
|
2021-07-29 18:31:21 +00:00
|
|
|
return ret;
|
2017-01-06 19:14:17 +00:00
|
|
|
}
|
|
|
|
|
2021-02-19 18:45:18 +00:00
|
|
|
ret = rsa_get_priv_key(info->keydir, info->keyname, info->keyfile,
|
2021-04-01 22:42:36 +00:00
|
|
|
e, &pkey);
|
2013-06-13 22:10:02 +00:00
|
|
|
if (ret)
|
|
|
|
goto err_priv;
|
2021-04-01 22:42:36 +00:00
|
|
|
ret = rsa_sign_with_key(pkey, info->padding, info->checksum, region,
|
2014-03-03 11:19:26 +00:00
|
|
|
region_count, sigp, sig_len);
|
2013-06-13 22:10:02 +00:00
|
|
|
if (ret)
|
|
|
|
goto err_sign;
|
|
|
|
|
2021-04-01 22:42:36 +00:00
|
|
|
EVP_PKEY_free(pkey);
|
2017-01-06 19:14:17 +00:00
|
|
|
if (info->engine_id)
|
|
|
|
rsa_engine_remove(e);
|
2013-06-13 22:10:02 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
err_sign:
|
2021-04-01 22:42:36 +00:00
|
|
|
EVP_PKEY_free(pkey);
|
2013-06-13 22:10:02 +00:00
|
|
|
err_priv:
|
2017-01-06 19:14:17 +00:00
|
|
|
if (info->engine_id)
|
|
|
|
rsa_engine_remove(e);
|
2013-06-13 22:10:02 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-07-02 08:17:26 +00:00
|
|
|
/*
|
|
|
|
* rsa_get_exponent(): - Get the public exponent from an RSA key
|
|
|
|
*/
|
|
|
|
static int rsa_get_exponent(RSA *key, uint64_t *e)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
BIGNUM *bn_te;
|
2017-05-08 19:31:19 +00:00
|
|
|
const BIGNUM *key_e;
|
2014-07-02 08:17:26 +00:00
|
|
|
uint64_t te;
|
|
|
|
|
|
|
|
ret = -EINVAL;
|
|
|
|
bn_te = NULL;
|
|
|
|
|
|
|
|
if (!e)
|
|
|
|
goto cleanup;
|
|
|
|
|
2017-05-08 19:31:19 +00:00
|
|
|
RSA_get0_key(key, NULL, &key_e, NULL);
|
|
|
|
if (BN_num_bits(key_e) > 64)
|
2014-07-02 08:17:26 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
2017-05-08 19:31:19 +00:00
|
|
|
*e = BN_get_word(key_e);
|
2014-07-02 08:17:26 +00:00
|
|
|
|
2017-05-08 19:31:19 +00:00
|
|
|
if (BN_num_bits(key_e) < 33) {
|
2014-07-02 08:17:26 +00:00
|
|
|
ret = 0;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2017-05-08 19:31:19 +00:00
|
|
|
bn_te = BN_dup(key_e);
|
2014-07-02 08:17:26 +00:00
|
|
|
if (!bn_te)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!BN_rshift(bn_te, bn_te, 32))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (!BN_mask_bits(bn_te, 32))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
te = BN_get_word(bn_te);
|
|
|
|
te <<= 32;
|
|
|
|
*e |= te;
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (bn_te)
|
|
|
|
BN_free(bn_te);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-06-13 22:10:02 +00:00
|
|
|
/*
|
|
|
|
* rsa_get_params(): - Get the important parameters of an RSA public key
|
|
|
|
*/
|
2014-07-02 08:17:26 +00:00
|
|
|
int rsa_get_params(RSA *key, uint64_t *exponent, uint32_t *n0_invp,
|
|
|
|
BIGNUM **modulusp, BIGNUM **r_squaredp)
|
2013-06-13 22:10:02 +00:00
|
|
|
{
|
|
|
|
BIGNUM *big1, *big2, *big32, *big2_32;
|
|
|
|
BIGNUM *n, *r, *r_squared, *tmp;
|
2017-05-08 19:31:19 +00:00
|
|
|
const BIGNUM *key_n;
|
2013-06-13 22:10:02 +00:00
|
|
|
BN_CTX *bn_ctx = BN_CTX_new();
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
/* Initialize BIGNUMs */
|
|
|
|
big1 = BN_new();
|
|
|
|
big2 = BN_new();
|
|
|
|
big32 = BN_new();
|
|
|
|
r = BN_new();
|
|
|
|
r_squared = BN_new();
|
|
|
|
tmp = BN_new();
|
|
|
|
big2_32 = BN_new();
|
|
|
|
n = BN_new();
|
|
|
|
if (!big1 || !big2 || !big32 || !r || !r_squared || !tmp || !big2_32 ||
|
|
|
|
!n) {
|
|
|
|
fprintf(stderr, "Out of memory (bignum)\n");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
2014-07-02 08:17:26 +00:00
|
|
|
if (0 != rsa_get_exponent(key, exponent))
|
|
|
|
ret = -1;
|
|
|
|
|
2017-05-08 19:31:19 +00:00
|
|
|
RSA_get0_key(key, &key_n, NULL, NULL);
|
|
|
|
if (!BN_copy(n, key_n) || !BN_set_word(big1, 1L) ||
|
2013-06-13 22:10:02 +00:00
|
|
|
!BN_set_word(big2, 2L) || !BN_set_word(big32, 32L))
|
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
/* big2_32 = 2^32 */
|
|
|
|
if (!BN_exp(big2_32, big2, big32, bn_ctx))
|
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
/* Calculate n0_inv = -1 / n[0] mod 2^32 */
|
|
|
|
if (!BN_mod_inverse(tmp, n, big2_32, bn_ctx) ||
|
|
|
|
!BN_sub(tmp, big2_32, tmp))
|
|
|
|
ret = -1;
|
|
|
|
*n0_invp = BN_get_word(tmp);
|
|
|
|
|
|
|
|
/* Calculate R = 2^(# of key bits) */
|
|
|
|
if (!BN_set_word(tmp, BN_num_bits(n)) ||
|
|
|
|
!BN_exp(r, big2, tmp, bn_ctx))
|
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
/* Calculate r_squared = R^2 mod n */
|
|
|
|
if (!BN_copy(r_squared, r) ||
|
|
|
|
!BN_mul(tmp, r_squared, r, bn_ctx) ||
|
|
|
|
!BN_mod(r_squared, tmp, n, bn_ctx))
|
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
*modulusp = n;
|
|
|
|
*r_squaredp = r_squared;
|
|
|
|
|
|
|
|
BN_free(big1);
|
|
|
|
BN_free(big2);
|
|
|
|
BN_free(big32);
|
|
|
|
BN_free(r);
|
|
|
|
BN_free(tmp);
|
|
|
|
BN_free(big2_32);
|
|
|
|
if (ret) {
|
|
|
|
fprintf(stderr, "Bignum operations failed\n");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rsa_add_verify_data(struct image_sign_info *info, void *keydest)
|
|
|
|
{
|
|
|
|
BIGNUM *modulus, *r_squared;
|
2014-07-02 08:17:26 +00:00
|
|
|
uint64_t exponent;
|
2013-06-13 22:10:02 +00:00
|
|
|
uint32_t n0_inv;
|
|
|
|
int parent, node;
|
|
|
|
char name[100];
|
|
|
|
int ret;
|
|
|
|
int bits;
|
|
|
|
RSA *rsa;
|
2021-04-01 22:42:36 +00:00
|
|
|
EVP_PKEY *pkey = NULL;
|
2017-01-06 19:14:17 +00:00
|
|
|
ENGINE *e = NULL;
|
2013-06-13 22:10:02 +00:00
|
|
|
|
|
|
|
debug("%s: Getting verification data\n", __func__);
|
2017-01-06 19:14:17 +00:00
|
|
|
if (info->engine_id) {
|
|
|
|
ret = rsa_engine_init(info->engine_id, &e);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
}
|
2021-04-01 22:42:36 +00:00
|
|
|
ret = rsa_get_pub_key(info->keydir, info->keyname, e, &pkey);
|
2013-06-13 22:10:02 +00:00
|
|
|
if (ret)
|
2017-01-06 19:14:17 +00:00
|
|
|
goto err_get_pub_key;
|
2021-07-29 18:31:21 +00:00
|
|
|
|
2022-01-09 14:39:40 +00:00
|
|
|
rsa = (RSA *)EVP_PKEY_get0_RSA(pkey);
|
2014-07-02 08:17:26 +00:00
|
|
|
ret = rsa_get_params(rsa, &exponent, &n0_inv, &modulus, &r_squared);
|
2013-06-13 22:10:02 +00:00
|
|
|
if (ret)
|
2017-01-06 19:14:17 +00:00
|
|
|
goto err_get_params;
|
2013-06-13 22:10:02 +00:00
|
|
|
bits = BN_num_bits(modulus);
|
|
|
|
parent = fdt_subnode_offset(keydest, 0, FIT_SIG_NODENAME);
|
|
|
|
if (parent == -FDT_ERR_NOTFOUND) {
|
|
|
|
parent = fdt_add_subnode(keydest, 0, FIT_SIG_NODENAME);
|
|
|
|
if (parent < 0) {
|
2014-06-12 13:24:42 +00:00
|
|
|
ret = parent;
|
|
|
|
if (ret != -FDT_ERR_NOSPACE) {
|
|
|
|
fprintf(stderr, "Couldn't create signature node: %s\n",
|
|
|
|
fdt_strerror(parent));
|
|
|
|
}
|
2013-06-13 22:10:02 +00:00
|
|
|
}
|
|
|
|
}
|
2014-06-12 13:24:42 +00:00
|
|
|
if (ret)
|
|
|
|
goto done;
|
2013-06-13 22:10:02 +00:00
|
|
|
|
|
|
|
/* Either create or overwrite the named key node */
|
|
|
|
snprintf(name, sizeof(name), "key-%s", info->keyname);
|
|
|
|
node = fdt_subnode_offset(keydest, parent, name);
|
|
|
|
if (node == -FDT_ERR_NOTFOUND) {
|
|
|
|
node = fdt_add_subnode(keydest, parent, name);
|
|
|
|
if (node < 0) {
|
2014-06-12 13:24:42 +00:00
|
|
|
ret = node;
|
|
|
|
if (ret != -FDT_ERR_NOSPACE) {
|
|
|
|
fprintf(stderr, "Could not create key subnode: %s\n",
|
|
|
|
fdt_strerror(node));
|
|
|
|
}
|
2013-06-13 22:10:02 +00:00
|
|
|
}
|
|
|
|
} else if (node < 0) {
|
|
|
|
fprintf(stderr, "Cannot select keys parent: %s\n",
|
|
|
|
fdt_strerror(node));
|
2014-06-12 13:24:42 +00:00
|
|
|
ret = node;
|
2013-06-13 22:10:02 +00:00
|
|
|
}
|
|
|
|
|
2014-06-12 13:24:42 +00:00
|
|
|
if (!ret) {
|
2020-03-18 17:44:06 +00:00
|
|
|
ret = fdt_setprop_string(keydest, node, FIT_KEY_HINT,
|
|
|
|
info->keyname);
|
2014-06-12 13:24:42 +00:00
|
|
|
}
|
2014-06-03 04:04:51 +00:00
|
|
|
if (!ret)
|
|
|
|
ret = fdt_setprop_u32(keydest, node, "rsa,num-bits", bits);
|
|
|
|
if (!ret)
|
|
|
|
ret = fdt_setprop_u32(keydest, node, "rsa,n0-inverse", n0_inv);
|
2014-07-02 08:17:26 +00:00
|
|
|
if (!ret) {
|
|
|
|
ret = fdt_setprop_u64(keydest, node, "rsa,exponent", exponent);
|
|
|
|
}
|
2014-06-03 04:04:51 +00:00
|
|
|
if (!ret) {
|
|
|
|
ret = fdt_add_bignum(keydest, node, "rsa,modulus", modulus,
|
|
|
|
bits);
|
|
|
|
}
|
|
|
|
if (!ret) {
|
|
|
|
ret = fdt_add_bignum(keydest, node, "rsa,r-squared", r_squared,
|
|
|
|
bits);
|
|
|
|
}
|
|
|
|
if (!ret) {
|
|
|
|
ret = fdt_setprop_string(keydest, node, FIT_ALGO_PROP,
|
2016-11-08 18:53:41 +00:00
|
|
|
info->name);
|
2014-06-03 04:04:51 +00:00
|
|
|
}
|
rsa: Fix return value and masked error
When signing images, we repeatedly call fit_add_file_data() with
successively increasing size values to include the keys in the DTB.
Unfortunately, if large keys are used (such as 4096 bit RSA keys), this
process fails sometimes, and mkimage needs to be called repeatedly to
integrate the keys into the DTB.
This is because fit_add_file_data actually returns the wrong error
code, and the loop terminates prematurely, instead of trying again with
a larger size value.
This patch corrects the return value by fixing the return value of
fdt_add_bignum, fixes a case where an error is masked by a unconditional
setting of a return value variable, and also removes a error message,
which is misleading, since we actually allow the function to fail. A
(hopefully helpful) comment is also added to explain the lack of error
message.
This is probably related to 1152a05 ("tools: Correct error handling in
fit_image_process_hash()") and the corresponding error reported here:
https://www.mail-archive.com/u-boot@lists.denx.de/msg217417.html
Signed-off-by: Mario Six <mario.six@gdsys.cc>
2016-07-19 09:07:07 +00:00
|
|
|
if (!ret && info->require_keys) {
|
2020-03-18 17:44:06 +00:00
|
|
|
ret = fdt_setprop_string(keydest, node, FIT_KEY_REQUIRED,
|
2014-06-03 04:04:51 +00:00
|
|
|
info->require_keys);
|
2013-06-13 22:10:02 +00:00
|
|
|
}
|
2014-06-12 13:24:42 +00:00
|
|
|
done:
|
2013-06-13 22:10:02 +00:00
|
|
|
BN_free(modulus);
|
|
|
|
BN_free(r_squared);
|
|
|
|
if (ret)
|
2017-01-06 19:14:17 +00:00
|
|
|
ret = ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;
|
|
|
|
err_get_params:
|
2021-04-01 22:42:36 +00:00
|
|
|
EVP_PKEY_free(pkey);
|
2017-01-06 19:14:17 +00:00
|
|
|
err_get_pub_key:
|
|
|
|
if (info->engine_id)
|
|
|
|
rsa_engine_remove(e);
|
2013-06-13 22:10:02 +00:00
|
|
|
|
2021-11-12 19:28:11 +00:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
return node;
|
2013-06-13 22:10:02 +00:00
|
|
|
}
|