Import U-Boot v2026.07 (unmodified upstream source, base for rtwo patches)

This commit is contained in:
2026-09-16 23:15:56 -03:00
commit 391981275c
38022 changed files with 8370285 additions and 0 deletions
+107
View File
@@ -0,0 +1,107 @@
config RSA
bool "Use RSA Library"
select RSA_FREESCALE_EXP if FSL_CAAM && !ARCH_MX7 && !ARCH_MX7ULP && !ARCH_MX6 && !ARCH_MX5
select RSA_ASPEED_EXP if ASPEED_ACRY
select RSA_SOFTWARE_EXP if !RSA_FREESCALE_EXP && !RSA_ASPEED_EXP
help
RSA support. This enables the RSA algorithm used for FIT image
verification in U-Boot.
See doc/usage/fit/signature.rst for more details.
The Modular Exponentiation algorithm in RSA is implemented using
driver model. So CONFIG_DM needs to be enabled by default for this
library to function.
The signing part is build into mkimage regardless of this
option. The software based modular exponentiation is built into
mkimage irrespective of this option.
if RSA
config SPL_RSA
bool "Use RSA Library within SPL"
depends on SPL
config SPL_RSA_VERIFY
bool
depends on SPL_RSA
help
Add RSA signature verification support in SPL.
config RSA_VERIFY
bool
help
Add RSA signature verification support.
config RSA_VERIFY_WITH_PKEY
bool "Execute RSA verification without key parameters from FDT"
select RSA_VERIFY
select ASYMMETRIC_KEY_TYPE
select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
select RSA_PUBLIC_KEY_PARSER
help
The standard RSA-signature verification code (FIT_SIGNATURE) uses
pre-calculated key properties, that are stored in fdt blob, in
decrypting a signature.
This does not suit the use case where there is no way defined to
provide such additional key properties in standardized form,
particularly UEFI secure boot.
This option enables RSA signature verification with a public key
directly specified in image_sign_info, where all the necessary
key properties will be calculated on the fly in verification code.
config SPL_RSA_VERIFY_WITH_PKEY
bool "Execute RSA verification without key parameters from FDT within SPL"
depends on SPL
select SPL_RSA_VERIFY
select SPL_ASYMMETRIC_KEY_TYPE
select SPL_ASYMMETRIC_PUBLIC_KEY_SUBTYPE
select SPL_RSA_PUBLIC_KEY_PARSER
help
The standard RSA-signature verification code (FIT_SIGNATURE) uses
pre-calculated key properties, that are stored in fdt blob, in
decrypting a signature.
This does not suit the use case where there is no way defined to
provide such additional key properties in standardized form,
particularly UEFI secure boot.
This option enables RSA signature verification with a public key
directly specified in image_sign_info, where all the necessary
key properties will be calculated on the fly in verification code
in the SPL.
config RSASSA_PSS
bool "Support rsassa-pss signature scheme"
depends on RSA_VERIFY
help
Enable this to support the pss padding algorithm as described
in the rfc8017 (https://tools.ietf.org/html/rfc8017).
config SPL_RSASSA_PSS
bool "Support rsassa-pss signature scheme within SPL"
depends on SPL_RSA_VERIFY
help
Enable this to support the pss padding algorithm as described
in the rfc8017 (https://tools.ietf.org/html/rfc8017) within SPL.
config RSA_SOFTWARE_EXP
bool "Enable driver for RSA Modular Exponentiation in software"
depends on DM
help
Enables driver for modular exponentiation in software. This is a RSA
algorithm used in FIT image verification. It required RSA Key as
input.
See doc/usage/fit/signature.rst for more details.
config RSA_FREESCALE_EXP
bool "Enable RSA Modular Exponentiation with FSL crypto accelerator"
depends on DM && FSL_CAAM && !ARCH_MX7 && !ARCH_MX7ULP && !ARCH_MX6 && !ARCH_MX5
help
Enables driver for RSA modular exponentiation using Freescale cryptographic
accelerator - CAAM.
config RSA_ASPEED_EXP
bool "Enable RSA Modular Exponentiation with ASPEED crypto accelerator"
depends on DM && ASPEED_ACRY
help
Enables driver for RSA modular exponentiation using ASPEED cryptographic
accelerator - ACRY
endif
+10
View File
@@ -0,0 +1,10 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (c) 2013, Google Inc.
#
# (C) Copyright 2000-2007
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
obj-$(CONFIG_$(PHASE_)RSA_VERIFY) += rsa-verify.o
obj-$(CONFIG_$(PHASE_)RSA_VERIFY_WITH_PKEY) += rsa-keyprop.o
obj-$(CONFIG_RSA_SOFTWARE_EXP) += rsa-mod-exp.o
+727
View File
@@ -0,0 +1,727 @@
// SPDX-License-Identifier: GPL-2.0+ and MIT
/*
* RSA library - generate parameters for a public key
*
* Copyright (c) 2019 Linaro Limited
* Author: AKASHI Takahiro
*
* Big number routines in this file come from BearSSL:
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*/
#include <image.h>
#include <malloc.h>
#include <crypto/internal/rsa.h>
#include <u-boot/rsa-mod-exp.h>
#include <asm/unaligned.h>
/**
* br_dec16be() - Convert 16-bit big-endian integer to native
* @src: Pointer to data
* Return: Native-endian integer
*/
static unsigned br_dec16be(const void *src)
{
return get_unaligned_be16(src);
}
/**
* br_dec32be() - Convert 32-bit big-endian integer to native
* @src: Pointer to data
* Return: Native-endian integer
*/
static uint32_t br_dec32be(const void *src)
{
return get_unaligned_be32(src);
}
/**
* br_enc32be() - Convert native 32-bit integer to big-endian
* @dst: Pointer to buffer to store big-endian integer in
* @x: Native 32-bit integer
*/
static void br_enc32be(void *dst, uint32_t x)
{
__be32 tmp;
tmp = cpu_to_be32(x);
memcpy(dst, &tmp, sizeof(tmp));
}
/* from BearSSL's src/inner.h */
/*
* Negate a boolean.
*/
static uint32_t NOT(uint32_t ctl)
{
return ctl ^ 1;
}
/*
* Multiplexer: returns x if ctl == 1, y if ctl == 0.
*/
static uint32_t MUX(uint32_t ctl, uint32_t x, uint32_t y)
{
return y ^ (-ctl & (x ^ y));
}
/*
* Equality check: returns 1 if x == y, 0 otherwise.
*/
static uint32_t EQ(uint32_t x, uint32_t y)
{
uint32_t q;
q = x ^ y;
return NOT((q | -q) >> 31);
}
/*
* Inequality check: returns 1 if x != y, 0 otherwise.
*/
static uint32_t NEQ(uint32_t x, uint32_t y)
{
uint32_t q;
q = x ^ y;
return (q | -q) >> 31;
}
/*
* Comparison: returns 1 if x > y, 0 otherwise.
*/
static uint32_t GT(uint32_t x, uint32_t y)
{
/*
* If both x < 2^31 and y < 2^31, then y-x will have its high
* bit set if x > y, cleared otherwise.
*
* If either x >= 2^31 or y >= 2^31 (but not both), then the
* result is the high bit of x.
*
* If both x >= 2^31 and y >= 2^31, then we can virtually
* subtract 2^31 from both, and we are back to the first case.
* Since (y-2^31)-(x-2^31) = y-x, the subtraction is already
* fine.
*/
uint32_t z;
z = y - x;
return (z ^ ((x ^ y) & (x ^ z))) >> 31;
}
/*
* Compute the bit length of a 32-bit integer. Returned value is between 0
* and 32 (inclusive).
*/
static uint32_t BIT_LENGTH(uint32_t x)
{
uint32_t k, c;
k = NEQ(x, 0);
c = GT(x, 0xFFFF); x = MUX(c, x >> 16, x); k += c << 4;
c = GT(x, 0x00FF); x = MUX(c, x >> 8, x); k += c << 3;
c = GT(x, 0x000F); x = MUX(c, x >> 4, x); k += c << 2;
c = GT(x, 0x0003); x = MUX(c, x >> 2, x); k += c << 1;
k += GT(x, 0x0001);
return k;
}
#define GE(x, y) NOT(GT(y, x))
#define LT(x, y) GT(y, x)
#define MUL(x, y) ((uint64_t)(x) * (uint64_t)(y))
/*
* Integers 'i32'
* --------------
*
* The 'i32' functions implement computations on big integers using
* an internal representation as an array of 32-bit integers. For
* an array x[]:
* -- x[0] contains the "announced bit length" of the integer
* -- x[1], x[2]... contain the value in little-endian order (x[1]
* contains the least significant 32 bits)
*
* Multiplications rely on the elementary 32x32->64 multiplication.
*
* The announced bit length specifies the number of bits that are
* significant in the subsequent 32-bit words. Unused bits in the
* last (most significant) word are set to 0; subsequent words are
* uninitialized and need not exist at all.
*
* The execution time and memory access patterns of all computations
* depend on the announced bit length, but not on the actual word
* values. For modular integers, the announced bit length of any integer
* modulo n is equal to the actual bit length of n; thus, computations
* on modular integers are "constant-time" (only the modulus length may
* leak).
*/
/*
* Extract one word from an integer. The offset is counted in bits.
* The word MUST entirely fit within the word elements corresponding
* to the announced bit length of a[].
*/
static uint32_t br_i32_word(const uint32_t *a, uint32_t off)
{
size_t u;
unsigned j;
u = (size_t)(off >> 5) + 1;
j = (unsigned)off & 31;
if (j == 0) {
return a[u];
} else {
return (a[u] >> j) | (a[u + 1] << (32 - j));
}
}
/* from BearSSL's src/int/i32_bitlen.c */
/*
* Compute the actual bit length of an integer. The argument x should
* point to the first (least significant) value word of the integer.
* The len 'xlen' contains the number of 32-bit words to access.
*
* CT: value or length of x does not leak.
*/
static uint32_t br_i32_bit_length(uint32_t *x, size_t xlen)
{
uint32_t tw, twk;
tw = 0;
twk = 0;
while (xlen -- > 0) {
uint32_t w, c;
c = EQ(tw, 0);
w = x[xlen];
tw = MUX(c, w, tw);
twk = MUX(c, (uint32_t)xlen, twk);
}
return (twk << 5) + BIT_LENGTH(tw);
}
/* from BearSSL's src/int/i32_decode.c */
/*
* Decode an integer from its big-endian unsigned representation. The
* "true" bit length of the integer is computed, but all words of x[]
* corresponding to the full 'len' bytes of the source are set.
*
* CT: value or length of x does not leak.
*/
static void br_i32_decode(uint32_t *x, const void *src, size_t len)
{
const unsigned char *buf;
size_t u, v;
buf = src;
u = len;
v = 1;
for (;;) {
if (u < 4) {
uint32_t w;
if (u < 2) {
if (u == 0) {
break;
} else {
w = buf[0];
}
} else {
if (u == 2) {
w = br_dec16be(buf);
} else {
w = ((uint32_t)buf[0] << 16)
| br_dec16be(buf + 1);
}
}
x[v ++] = w;
break;
} else {
u -= 4;
x[v ++] = br_dec32be(buf + u);
}
}
x[0] = br_i32_bit_length(x + 1, v - 1);
}
/* from BearSSL's src/int/i32_encode.c */
/*
* Encode an integer into its big-endian unsigned representation. The
* output length in bytes is provided (parameter 'len'); if the length
* is too short then the integer is appropriately truncated; if it is
* too long then the extra bytes are set to 0.
*/
static void br_i32_encode(void *dst, size_t len, const uint32_t *x)
{
unsigned char *buf;
size_t k;
buf = dst;
/*
* Compute the announced size of x in bytes; extra bytes are
* filled with zeros.
*/
k = (x[0] + 7) >> 3;
while (len > k) {
*buf ++ = 0;
len --;
}
/*
* Now we use k as index within x[]. That index starts at 1;
* we initialize it to the topmost complete word, and process
* any remaining incomplete word.
*/
k = (len + 3) >> 2;
switch (len & 3) {
case 3:
*buf ++ = x[k] >> 16;
/* fall through */
case 2:
*buf ++ = x[k] >> 8;
/* fall through */
case 1:
*buf ++ = x[k];
k --;
}
/*
* Encode all complete words.
*/
while (k > 0) {
br_enc32be(buf, x[k]);
k --;
buf += 4;
}
}
/* from BearSSL's src/int/i32_ninv32.c */
/*
* Compute -(1/x) mod 2^32. If x is even, then this function returns 0.
*/
static uint32_t br_i32_ninv32(uint32_t x)
{
uint32_t y;
y = 2 - x;
y *= 2 - y * x;
y *= 2 - y * x;
y *= 2 - y * x;
y *= 2 - y * x;
return MUX(x & 1, -y, 0);
}
/* from BearSSL's src/int/i32_add.c */
/*
* Add b[] to a[] and return the carry (0 or 1). If ctl is 0, then a[]
* is unmodified, but the carry is still computed and returned. The
* arrays a[] and b[] MUST have the same announced bit length.
*
* a[] and b[] MAY be the same array, but partial overlap is not allowed.
*/
static uint32_t br_i32_add(uint32_t *a, const uint32_t *b, uint32_t ctl)
{
uint32_t cc;
size_t u, m;
cc = 0;
m = (a[0] + 63) >> 5;
for (u = 1; u < m; u ++) {
uint32_t aw, bw, naw;
aw = a[u];
bw = b[u];
naw = aw + bw + cc;
/*
* Carry is 1 if naw < aw. Carry is also 1 if naw == aw
* AND the carry was already 1.
*/
cc = (cc & EQ(naw, aw)) | LT(naw, aw);
a[u] = MUX(ctl, naw, aw);
}
return cc;
}
/* from BearSSL's src/int/i32_sub.c */
/*
* Subtract b[] from a[] and return the carry (0 or 1). If ctl is 0,
* then a[] is unmodified, but the carry is still computed and returned.
* The arrays a[] and b[] MUST have the same announced bit length.
*
* a[] and b[] MAY be the same array, but partial overlap is not allowed.
*/
static uint32_t br_i32_sub(uint32_t *a, const uint32_t *b, uint32_t ctl)
{
uint32_t cc;
size_t u, m;
cc = 0;
m = (a[0] + 63) >> 5;
for (u = 1; u < m; u ++) {
uint32_t aw, bw, naw;
aw = a[u];
bw = b[u];
naw = aw - bw - cc;
/*
* Carry is 1 if naw > aw. Carry is 1 also if naw == aw
* AND the carry was already 1.
*/
cc = (cc & EQ(naw, aw)) | GT(naw, aw);
a[u] = MUX(ctl, naw, aw);
}
return cc;
}
/* from BearSSL's src/int/i32_div32.c */
/*
* Constant-time division. The dividend hi:lo is divided by the
* divisor d; the quotient is returned and the remainder is written
* in *r. If hi == d, then the quotient does not fit on 32 bits;
* returned value is thus truncated. If hi > d, returned values are
* indeterminate.
*/
static uint32_t br_divrem(uint32_t hi, uint32_t lo, uint32_t d, uint32_t *r)
{
/* TODO: optimize this */
uint32_t q;
uint32_t ch, cf;
int k;
q = 0;
ch = EQ(hi, d);
hi = MUX(ch, 0, hi);
for (k = 31; k > 0; k --) {
int j;
uint32_t w, ctl, hi2, lo2;
j = 32 - k;
w = (hi << j) | (lo >> k);
ctl = GE(w, d) | (hi >> k);
hi2 = (w - d) >> j;
lo2 = lo - (d << k);
hi = MUX(ctl, hi2, hi);
lo = MUX(ctl, lo2, lo);
q |= ctl << k;
}
cf = GE(lo, d) | hi;
q |= cf;
*r = MUX(cf, lo - d, lo);
return q;
}
/*
* Wrapper for br_divrem(); the remainder is returned, and the quotient
* is discarded.
*/
static uint32_t br_rem(uint32_t hi, uint32_t lo, uint32_t d)
{
uint32_t r;
br_divrem(hi, lo, d, &r);
return r;
}
/*
* Wrapper for br_divrem(); the quotient is returned, and the remainder
* is discarded.
*/
static uint32_t br_div(uint32_t hi, uint32_t lo, uint32_t d)
{
uint32_t r;
return br_divrem(hi, lo, d, &r);
}
/* from BearSSL's src/int/i32_muladd.c */
/*
* Multiply x[] by 2^32 and then add integer z, modulo m[]. This
* function assumes that x[] and m[] have the same announced bit
* length, and the announced bit length of m[] matches its true
* bit length.
*
* x[] and m[] MUST be distinct arrays.
*
* CT: only the common announced bit length of x and m leaks, not
* the values of x, z or m.
*/
static void br_i32_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m)
{
uint32_t m_bitlen;
size_t u, mlen;
uint32_t a0, a1, b0, hi, g, q, tb;
uint32_t chf, clow, under, over;
uint64_t cc;
/*
* We can test on the modulus bit length since we accept to
* leak that length.
*/
m_bitlen = m[0];
if (m_bitlen == 0) {
return;
}
if (m_bitlen <= 32) {
x[1] = br_rem(x[1], z, m[1]);
return;
}
mlen = (m_bitlen + 31) >> 5;
/*
* Principle: we estimate the quotient (x*2^32+z)/m by
* doing a 64/32 division with the high words.
*
* Let:
* w = 2^32
* a = (w*a0 + a1) * w^N + a2
* b = b0 * w^N + b2
* such that:
* 0 <= a0 < w
* 0 <= a1 < w
* 0 <= a2 < w^N
* w/2 <= b0 < w
* 0 <= b2 < w^N
* a < w*b
* I.e. the two top words of a are a0:a1, the top word of b is
* b0, we ensured that b0 is "full" (high bit set), and a is
* such that the quotient q = a/b fits on one word (0 <= q < w).
*
* If a = b*q + r (with 0 <= r < q), we can estimate q by
* doing an Euclidean division on the top words:
* a0*w+a1 = b0*u + v (with 0 <= v < w)
* Then the following holds:
* 0 <= u <= w
* u-2 <= q <= u
*/
a0 = br_i32_word(x, m_bitlen - 32);
hi = x[mlen];
memmove(x + 2, x + 1, (mlen - 1) * sizeof *x);
x[1] = z;
a1 = br_i32_word(x, m_bitlen - 32);
b0 = br_i32_word(m, m_bitlen - 32);
/*
* We estimate a divisor q. If the quotient returned by br_div()
* is g:
* -- If a0 == b0 then g == 0; we want q = 0xFFFFFFFF.
* -- Otherwise:
* -- if g == 0 then we set q = 0;
* -- otherwise, we set q = g - 1.
* The properties described above then ensure that the true
* quotient is q-1, q or q+1.
*/
g = br_div(a0, a1, b0);
q = MUX(EQ(a0, b0), 0xFFFFFFFF, MUX(EQ(g, 0), 0, g - 1));
/*
* We subtract q*m from x (with the extra high word of value 'hi').
* Since q may be off by 1 (in either direction), we may have to
* add or subtract m afterwards.
*
* The 'tb' flag will be true (1) at the end of the loop if the
* result is greater than or equal to the modulus (not counting
* 'hi' or the carry).
*/
cc = 0;
tb = 1;
for (u = 1; u <= mlen; u ++) {
uint32_t mw, zw, xw, nxw;
uint64_t zl;
mw = m[u];
zl = MUL(mw, q) + cc;
cc = (uint32_t)(zl >> 32);
zw = (uint32_t)zl;
xw = x[u];
nxw = xw - zw;
cc += (uint64_t)GT(nxw, xw);
x[u] = nxw;
tb = MUX(EQ(nxw, mw), tb, GT(nxw, mw));
}
/*
* If we underestimated q, then either cc < hi (one extra bit
* beyond the top array word), or cc == hi and tb is true (no
* extra bit, but the result is not lower than the modulus). In
* these cases we must subtract m once.
*
* Otherwise, we may have overestimated, which will show as
* cc > hi (thus a negative result). Correction is adding m once.
*/
chf = (uint32_t)(cc >> 32);
clow = (uint32_t)cc;
over = chf | GT(clow, hi);
under = ~over & (tb | (~chf & LT(clow, hi)));
br_i32_add(x, m, over);
br_i32_sub(x, m, under);
}
/* from BearSSL's src/int/i32_reduce.c */
/*
* Reduce an integer (a[]) modulo another (m[]). The result is written
* in x[] and its announced bit length is set to be equal to that of m[].
*
* x[] MUST be distinct from a[] and m[].
*
* CT: only announced bit lengths leak, not values of x, a or m.
*/
static void br_i32_reduce(uint32_t *x, const uint32_t *a, const uint32_t *m)
{
uint32_t m_bitlen, a_bitlen;
size_t mlen, alen, u;
m_bitlen = m[0];
mlen = (m_bitlen + 31) >> 5;
x[0] = m_bitlen;
if (m_bitlen == 0) {
return;
}
/*
* If the source is shorter, then simply copy all words from a[]
* and zero out the upper words.
*/
a_bitlen = a[0];
alen = (a_bitlen + 31) >> 5;
if (a_bitlen < m_bitlen) {
memcpy(x + 1, a + 1, alen * sizeof *a);
for (u = alen; u < mlen; u ++) {
x[u + 1] = 0;
}
return;
}
/*
* The source length is at least equal to that of the modulus.
* We must thus copy N-1 words, and input the remaining words
* one by one.
*/
memcpy(x + 1, a + 2 + (alen - mlen), (mlen - 1) * sizeof *a);
x[mlen] = 0;
for (u = 1 + alen - mlen; u > 0; u --) {
br_i32_muladd_small(x, a[u], m);
}
}
/**
* rsa_free_key_prop() - Free key properties
* @prop: Pointer to struct key_prop
*
* This function frees all the memories allocated by rsa_gen_key_prop().
*/
void rsa_free_key_prop(struct key_prop *prop)
{
if (!prop)
return;
free((void *)prop->modulus);
free((void *)prop->public_exponent);
free((void *)prop->rr);
free(prop);
}
/**
* rsa_gen_key_prop() - Generate key properties of RSA public key
* @key: Specifies key data in DER format
* @keylen: Length of @key
* @prop: Generated key property
*
* This function takes a blob of encoded RSA public key data in DER
* format, parse it and generate all the relevant properties
* in key_prop structure.
* Return a pointer to struct key_prop in @prop on success.
*
* Return: 0 on success, negative on error
*/
int rsa_gen_key_prop(const void *key, uint32_t keylen, struct key_prop **prop)
{
struct rsa_key rsa_key;
uint32_t *n = NULL, *rr = NULL, *rrtmp = NULL;
int rlen, i, ret = 0;
*prop = calloc(sizeof(**prop), 1);
if (!(*prop)) {
ret = -ENOMEM;
goto out;
}
ret = rsa_parse_pub_key(&rsa_key, key, keylen);
if (ret)
goto out;
/* modulus */
/* removing leading 0's */
for (i = 0; i < rsa_key.n_sz && !rsa_key.n[i]; i++)
;
(*prop)->num_bits = (rsa_key.n_sz - i) * 8;
(*prop)->modulus = malloc(rsa_key.n_sz - i);
if (!(*prop)->modulus) {
ret = -ENOMEM;
goto out;
}
memcpy((void *)(*prop)->modulus, &rsa_key.n[i], rsa_key.n_sz - i);
n = calloc(sizeof(uint32_t), 1 + ((*prop)->num_bits >> 5));
rr = calloc(sizeof(uint32_t), 1 + (((*prop)->num_bits * 2) >> 5));
rrtmp = calloc(sizeof(uint32_t), 2 + (((*prop)->num_bits * 2) >> 5));
if (!n || !rr || !rrtmp) {
ret = -ENOMEM;
goto out;
}
/* exponent */
(*prop)->public_exponent = calloc(1, sizeof(uint64_t));
if (!(*prop)->public_exponent) {
ret = -ENOMEM;
goto out;
}
memcpy((void *)(*prop)->public_exponent + sizeof(uint64_t)
- rsa_key.e_sz,
rsa_key.e, rsa_key.e_sz);
(*prop)->exp_len = sizeof(uint64_t);
/* n0 inverse */
br_i32_decode(n, &rsa_key.n[i], rsa_key.n_sz - i);
(*prop)->n0inv = br_i32_ninv32(n[1]);
/* R^2 mod n; R = 2^(num_bits) */
rlen = (*prop)->num_bits * 2; /* #bits of R^2 = (2^num_bits)^2 */
rr[0] = 0;
*(uint8_t *)&rr[0] = (1 << (rlen % 8));
for (i = 1; i < (((rlen + 31) >> 5) + 1); i++)
rr[i] = 0;
br_i32_decode(rrtmp, rr, ((rlen + 7) >> 3) + 1);
br_i32_reduce(rr, rrtmp, n);
rlen = ((*prop)->num_bits + 7) >> 3; /* #bytes of R^2 mod n */
(*prop)->rr = malloc(rlen);
if (!(*prop)->rr) {
ret = -ENOMEM;
goto out;
}
br_i32_encode((void *)(*prop)->rr, rlen, rr);
out:
free(n);
free(rr);
free(rrtmp);
if (ret < 0)
rsa_free_key_prop(*prop);
return ret;
}
+360
View File
@@ -0,0 +1,360 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2013, Google Inc.
*/
#ifndef USE_HOSTCC
#include <fdtdec.h>
#include <log.h>
#include <asm/types.h>
#include <asm/byteorder.h>
#include <linux/errno.h>
#include <asm/types.h>
#include <asm/unaligned.h>
#else
#include "fdt_host.h"
#include "mkimage.h"
#include <fdt_support.h>
#endif
#include <u-boot/rsa.h>
#include <u-boot/rsa-mod-exp.h>
#define UINT64_MULT32(v, multby) (((uint64_t)(v)) * ((uint32_t)(multby)))
#define get_unaligned_be32(a) fdt32_to_cpu(*(uint32_t *)a)
#define put_unaligned_be32(a, b) (*(uint32_t *)(b) = cpu_to_fdt32(a))
static inline uint64_t fdt64_to_cpup(const void *p)
{
fdt64_t w;
memcpy(&w, p, sizeof(w));
return fdt64_to_cpu(w);
}
/* Default public exponent for backward compatibility */
#define RSA_DEFAULT_PUBEXP 65537
/**
* subtract_modulus() - subtract modulus from the given value
*
* @key: Key containing modulus to subtract
* @num: Number to subtract modulus from, as little endian word array
*/
static void subtract_modulus(const struct rsa_public_key *key, uint32_t num[])
{
int64_t acc = 0;
uint i;
for (i = 0; i < key->len; i++) {
acc += (uint64_t)num[i] - key->modulus[i];
num[i] = (uint32_t)acc;
acc >>= 32;
}
}
/**
* greater_equal_modulus() - check if a value is >= modulus
*
* @key: Key containing modulus to check
* @num: Number to check against modulus, as little endian word array
* Return: 0 if num < modulus, 1 if num >= modulus
*/
static int greater_equal_modulus(const struct rsa_public_key *key,
uint32_t num[])
{
int i;
for (i = (int)key->len - 1; i >= 0; i--) {
if (num[i] < key->modulus[i])
return 0;
if (num[i] > key->modulus[i])
return 1;
}
return 1; /* equal */
}
/**
* montgomery_mul_add_step() - Perform montgomery multiply-add step
*
* Operation: montgomery result[] += a * b[] / n0inv % modulus
*
* @key: RSA key
* @result: Place to put result, as little endian word array
* @a: Multiplier
* @b: Multiplicand, as little endian word array
*/
static void montgomery_mul_add_step(const struct rsa_public_key *key,
uint32_t result[], const uint32_t a, const uint32_t b[])
{
uint64_t acc_a, acc_b;
uint32_t d0;
uint i;
acc_a = (uint64_t)a * b[0] + result[0];
d0 = (uint32_t)acc_a * key->n0inv;
acc_b = (uint64_t)d0 * key->modulus[0] + (uint32_t)acc_a;
for (i = 1; i < key->len; i++) {
acc_a = (acc_a >> 32) + (uint64_t)a * b[i] + result[i];
acc_b = (acc_b >> 32) + (uint64_t)d0 * key->modulus[i] +
(uint32_t)acc_a;
result[i - 1] = (uint32_t)acc_b;
}
acc_a = (acc_a >> 32) + (acc_b >> 32);
result[i - 1] = (uint32_t)acc_a;
if (acc_a >> 32)
subtract_modulus(key, result);
}
/**
* montgomery_mul() - Perform montgomery mutitply
*
* Operation: montgomery result[] = a[] * b[] / n0inv % modulus
*
* @key: RSA key
* @result: Place to put result, as little endian word array
* @a: Multiplier, as little endian word array
* @b: Multiplicand, as little endian word array
*/
static void montgomery_mul(const struct rsa_public_key *key,
uint32_t result[], uint32_t a[], const uint32_t b[])
{
uint i;
for (i = 0; i < key->len; ++i)
result[i] = 0;
for (i = 0; i < key->len; ++i)
montgomery_mul_add_step(key, result, a[i], b);
}
/**
* num_pub_exponent_bits() - Number of bits in the public exponent
*
* @key: RSA key
* @num_bits: Storage for the number of public exponent bits
*/
static int num_public_exponent_bits(const struct rsa_public_key *key,
int *num_bits)
{
uint64_t exponent;
int exponent_bits;
const uint max_bits = (sizeof(exponent) * 8);
exponent = key->exponent;
exponent_bits = 0;
if (!exponent) {
*num_bits = exponent_bits;
return 0;
}
for (exponent_bits = 1; exponent_bits < max_bits + 1; ++exponent_bits)
if (!(exponent >>= 1)) {
*num_bits = exponent_bits;
return 0;
}
return -EINVAL;
}
/**
* is_public_exponent_bit_set() - Check if a bit in the public exponent is set
*
* @key: RSA key
* @pos: The bit position to check
*/
static int is_public_exponent_bit_set(const struct rsa_public_key *key,
int pos)
{
return key->exponent & (1ULL << pos);
}
/**
* pow_mod() - in-place public exponentiation
*
* @key: RSA key
* @inout: Big-endian word array containing value and result
*/
static int pow_mod(const struct rsa_public_key *key, uint32_t *inout)
{
uint32_t *result, *ptr;
uint i;
int j, k;
/* Sanity check for stack size - key->len is in 32-bit words */
if (key->len > RSA_MAX_KEY_BITS / 32) {
debug("RSA key words %u exceeds maximum %d\n", key->len,
RSA_MAX_KEY_BITS / 32);
return -EINVAL;
}
uint32_t val[key->len], acc[key->len], tmp[key->len];
uint32_t a_scaled[key->len];
result = tmp; /* Re-use location. */
/* Convert from big endian byte array to little endian word array. */
for (i = 0, ptr = inout + key->len - 1; i < key->len; i++, ptr--)
val[i] = get_unaligned_be32(ptr);
if (0 != num_public_exponent_bits(key, &k))
return -EINVAL;
if (k < 2) {
debug("Public exponent is too short (%d bits, minimum 2)\n",
k);
return -EINVAL;
}
if (!is_public_exponent_bit_set(key, 0)) {
debug("LSB of RSA public exponent must be set.\n");
return -EINVAL;
}
/* the bit at e[k-1] is 1 by definition, so start with: C := M */
montgomery_mul(key, acc, val, key->rr); /* acc = a * RR / R mod n */
/* retain scaled version for intermediate use */
memcpy(a_scaled, acc, key->len * sizeof(a_scaled[0]));
for (j = k - 2; j > 0; --j) {
montgomery_mul(key, tmp, acc, acc); /* tmp = acc^2 / R mod n */
if (is_public_exponent_bit_set(key, j)) {
/* acc = tmp * val / R mod n */
montgomery_mul(key, acc, tmp, a_scaled);
} else {
/* e[j] == 0, copy tmp back to acc for next operation */
memcpy(acc, tmp, key->len * sizeof(acc[0]));
}
}
/* the bit at e[0] is always 1 */
montgomery_mul(key, tmp, acc, acc); /* tmp = acc^2 / R mod n */
montgomery_mul(key, acc, tmp, val); /* acc = tmp * a / R mod M */
memcpy(result, acc, key->len * sizeof(result[0]));
/* Make sure result < mod; result is at most 1x mod too large. */
if (greater_equal_modulus(key, result))
subtract_modulus(key, result);
/* Convert to bigendian byte array */
for (i = key->len - 1, ptr = inout; (int)i >= 0; i--, ptr++)
put_unaligned_be32(result[i], ptr);
return 0;
}
static void rsa_convert_big_endian(uint32_t *dst, const uint32_t *src, int len)
{
int i;
for (i = 0; i < len; i++)
dst[i] = fdt32_to_cpu(src[len - 1 - i]);
}
int rsa_mod_exp_sw(const uint8_t *sig, uint32_t sig_len,
struct key_prop *prop, uint8_t *out)
{
struct rsa_public_key key;
int ret;
if (!prop) {
debug("%s: Skipping invalid prop", __func__);
return -EBADF;
}
key.n0inv = prop->n0inv;
key.len = prop->num_bits;
if (!prop->public_exponent)
key.exponent = RSA_DEFAULT_PUBEXP;
else
key.exponent = fdt64_to_cpup(prop->public_exponent);
if (!key.len || !prop->modulus || !prop->rr) {
debug("%s: Missing RSA key info", __func__);
return -EFAULT;
}
/* Sanity check for stack size */
if (key.len > RSA_MAX_KEY_BITS || key.len < RSA_MIN_KEY_BITS) {
debug("RSA key bits %u outside allowed range %d..%d\n",
key.len, RSA_MIN_KEY_BITS, RSA_MAX_KEY_BITS);
return -EFAULT;
}
key.len /= sizeof(uint32_t) * 8;
uint32_t key1[key.len], key2[key.len];
key.modulus = key1;
key.rr = key2;
rsa_convert_big_endian(key.modulus, (uint32_t *)prop->modulus, key.len);
rsa_convert_big_endian(key.rr, (uint32_t *)prop->rr, key.len);
if (!key.modulus || !key.rr) {
debug("%s: Out of memory", __func__);
return -ENOMEM;
}
uint32_t buf[sig_len / sizeof(uint32_t)];
memcpy(buf, sig, sig_len);
ret = pow_mod(&key, buf);
if (ret)
return ret;
memcpy(out, buf, sig_len);
return 0;
}
#if defined(CONFIG_CMD_ZYNQ_RSA)
/**
* zynq_pow_mod - in-place public exponentiation
*
* @keyptr: RSA key
* @inout: Big-endian word array containing value and result
* Return: 0 on successful calculation, otherwise failure error code
*
* FIXME: Use pow_mod() instead of zynq_pow_mod()
* pow_mod calculation required for zynq is bit different from
* pw_mod above here, hence defined zynq specific routine.
*/
int zynq_pow_mod(uint32_t *keyptr, uint32_t *inout)
{
u32 *result, *ptr;
uint i;
struct rsa_public_key *key;
u32 val[RSA2048_BYTES], acc[RSA2048_BYTES], tmp[RSA2048_BYTES];
key = (struct rsa_public_key *)keyptr;
/* Sanity check for stack size - key->len is in 32-bit words */
if (key->len > RSA_MAX_KEY_BITS / 32) {
debug("RSA key words %u exceeds maximum %d\n", key->len,
RSA_MAX_KEY_BITS / 32);
return -EINVAL;
}
result = tmp; /* Re-use location. */
for (i = 0, ptr = inout; i < key->len; i++, ptr++)
val[i] = *(ptr);
montgomery_mul(key, acc, val, key->rr); /* axx = a * RR / R mod M */
for (i = 0; i < 16; i += 2) {
montgomery_mul(key, tmp, acc, acc); /* tmp = acc^2 / R mod M */
montgomery_mul(key, acc, tmp, tmp); /* acc = tmp^2 / R mod M */
}
montgomery_mul(key, result, acc, val); /* result = XX * a / R mod M */
/* Make sure result < mod; result is at most 1x mod too large. */
if (greater_equal_modulus(key, result))
subtract_modulus(key, result);
for (i = 0, ptr = inout; i < key->len; i++, ptr++)
*ptr = result[i];
return 0;
}
#endif
+736
View File
@@ -0,0 +1,736 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2013, Google Inc.
*/
#define OPENSSL_API_COMPAT 0x10101000L
#include "mkimage.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <image.h>
#include <time.h>
#include <u-boot/fdt-libcrypto.h>
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/evp.h>
#include <openssl/engine.h>
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;
}
/**
* rsa_pem_get_pub_key() - read a public key from a .crt file
*
* @keydir: Directory containins the key
* @name Name of key file (will have a .crt extension)
* @evpp Returns EVP_PKEY object, or NULL on failure
* Return: 0 if ok, -ve on error (in which case *evpp will be set to NULL)
*/
static int rsa_pem_get_pub_key(const char *keydir, const char *name, EVP_PKEY **evpp)
{
char path[1024];
EVP_PKEY *key = NULL;
X509 *cert;
FILE *f;
int ret;
if (!evpp)
return -EINVAL;
*evpp = NULL;
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);
*evpp = key;
X509_free(cert);
return 0;
err_pubkey:
X509_free(cert);
err_cert:
fclose(f);
return ret;
}
/**
* rsa_engine_get_pub_key() - read a public key from given engine
*
* @keydir: Key prefix
* @name Name of key
* @engine Engine to use
* @evpp Returns EVP_PKEY object, or NULL on failure
* Return: 0 if ok, -ve on error (in which case *evpp will be set to NULL)
*/
static int rsa_engine_get_pub_key(const char *keydir, const char *name,
ENGINE *engine, EVP_PKEY **evpp)
{
const char *engine_id;
char key_id[1024];
EVP_PKEY *key = NULL;
const char *const pkcs11_schema = "pkcs11:";
const char *pkcs11_uri_prepend = "";
if (!evpp)
return -EINVAL;
*evpp = NULL;
engine_id = ENGINE_get_id(engine);
if (engine_id && !strcmp(engine_id, "pkcs11")) {
if (keydir) {
// Check for legacy keydir spec and prepend
if (strncmp(pkcs11_schema, keydir, strlen(pkcs11_schema))) {
pkcs11_uri_prepend = pkcs11_schema;
fprintf(stderr, "WARNING: Legacy URI specified. Please add '%s'.\n", pkcs11_schema);
}
if (strstr(keydir, "object=") || strstr(keydir, "id="))
snprintf(key_id, sizeof(key_id),
"%s%s;type=public",
pkcs11_uri_prepend, keydir);
else
snprintf(key_id, sizeof(key_id),
"%s%s;object=%s;type=public",
pkcs11_uri_prepend, keydir, name);
} else {
snprintf(key_id, sizeof(key_id),
"pkcs11:object=%s;type=public",
name);
}
} 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);
} 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");
*evpp = key;
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
* @evpp Returns EVP_PKEY object, or NULL on failure
* Return: 0 if ok, -ve on error (in which case *evpp will be set to NULL)
*/
static int rsa_get_pub_key(const char *keydir, const char *name,
ENGINE *engine, EVP_PKEY **evpp)
{
if (engine)
return rsa_engine_get_pub_key(keydir, name, engine, evpp);
return rsa_pem_get_pub_key(keydir, name, evpp);
}
/**
* rsa_pem_get_priv_key() - read a private key from a .key file
*
* @keydir: Directory containing the key
* @name Name of key file (will have a .key extension)
* @evpp Returns EVP_PKEY object, or NULL on failure
* Return: 0 if ok, -ve on error (in which case *evpp will be set to NULL)
*/
static int rsa_pem_get_priv_key(const char *keydir, const char *name,
const char *keyfile, EVP_PKEY **evpp)
{
char path[1024] = {0};
FILE *f = NULL;
if (!evpp)
return -EINVAL;
*evpp = NULL;
if (keydir && name)
snprintf(path, sizeof(path), "%s/%s.key", keydir, name);
else if (keyfile)
snprintf(path, sizeof(path), "%s", keyfile);
else
return -EINVAL;
f = fopen(path, "r");
if (!f) {
fprintf(stderr, "Couldn't open RSA private key: '%s': %s\n",
path, strerror(errno));
return -ENOENT;
}
if (!PEM_read_PrivateKey(f, evpp, NULL, path)) {
rsa_err("Failure reading private key");
fclose(f);
return -EPROTO;
}
fclose(f);
return 0;
}
/**
* rsa_engine_get_priv_key() - read a private key from given engine
*
* @keydir: Key prefix
* @name Name of key
* @engine Engine to use
* @evpp Returns EVP_PKEY object, or NULL on failure
* Return: 0 if ok, -ve on error (in which case *evpp will be set to NULL)
*/
static int rsa_engine_get_priv_key(const char *keydir, const char *name,
const char *keyfile,
ENGINE *engine, EVP_PKEY **evpp)
{
const char *engine_id;
char key_id[1024];
EVP_PKEY *key = NULL;
const char *const pkcs11_schema = "pkcs11:";
const char *pkcs11_uri_prepend = "";
if (!evpp)
return -EINVAL;
engine_id = ENGINE_get_id(engine);
if (engine_id && !strcmp(engine_id, "pkcs11")) {
if (!keydir && !name) {
fprintf(stderr, "Please use 'keydir' with PKCS11\n");
return -EINVAL;
}
if (keydir) {
// Check for legacy keydir spec and prepend
if (strncmp(pkcs11_schema, keydir, strlen(pkcs11_schema))) {
pkcs11_uri_prepend = pkcs11_schema;
fprintf(stderr, "WARNING: Legacy URI specified. Please add '%s'.\n", pkcs11_schema);
}
if (strstr(keydir, "object=") || strstr(keydir, "id="))
snprintf(key_id, sizeof(key_id),
"%s%s;type=private",
pkcs11_uri_prepend, keydir);
else
snprintf(key_id, sizeof(key_id),
"%s%s;object=%s;type=private",
pkcs11_uri_prepend, keydir, name);
} else {
snprintf(key_id, sizeof(key_id),
"pkcs11:object=%s;type=private",
name);
}
} else if (engine_id) {
if (keydir && name)
snprintf(key_id, sizeof(key_id),
"%s%s",
keydir, name);
else if (name)
snprintf(key_id, sizeof(key_id),
"%s",
name ? name : "");
else if (keyfile)
snprintf(key_id, sizeof(key_id), "%s", keyfile);
else
return -EINVAL;
} 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");
*evpp = key;
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
* @evpp Returns EVP_PKEY object, or NULL on failure
* Return: 0 if ok, -ve on error (in which case *evpp will be set to NULL)
*/
static int rsa_get_priv_key(const char *keydir, const char *name,
const char *keyfile, ENGINE *engine, EVP_PKEY **evpp)
{
if (engine)
return rsa_engine_get_priv_key(keydir, name, keyfile, engine,
evpp);
return rsa_pem_get_priv_key(keydir, name, keyfile, evpp);
}
static int rsa_init(void)
{
int ret;
ret = OPENSSL_init_ssl(0, NULL);
if (!ret) {
fprintf(stderr, "Failure to init SSL library\n");
return -1;
}
return 0;
}
static int rsa_engine_init(const char *engine_id, ENGINE **pe)
{
const char *key_pass;
ENGINE *e;
int ret;
ENGINE_load_builtin_engines();
e = ENGINE_by_id(engine_id);
if (!e) {
fprintf(stderr, "Engine '%s' isn't available\n", engine_id);
ERR_print_errors_fp(stderr);
return -1;
}
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;
}
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;
}
}
*pe = e;
return 0;
err_set_pin:
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);
}
}
static int rsa_sign_with_key(EVP_PKEY *pkey, struct padding_algo *padding_algo,
struct checksum_algo *checksum_algo,
const struct image_region region[], int region_count,
uint8_t **sigp, uint *sig_size)
{
EVP_PKEY_CTX *ckey;
EVP_MD_CTX *context;
int ret = 0;
size_t size;
uint8_t *sig;
int i;
size = EVP_PKEY_size(pkey);
sig = malloc(size);
if (!sig) {
fprintf(stderr, "Out of memory for signature (%zu bytes)\n",
size);
ret = -ENOMEM;
goto err_alloc;
}
context = EVP_MD_CTX_new();
if (!context) {
ret = rsa_err("EVP context creation failed");
goto err_create;
}
ckey = EVP_PKEY_CTX_new(pkey, NULL);
if (!ckey) {
ret = rsa_err("EVP key context creation failed");
goto err_create;
}
if (EVP_DigestSignInit(context, &ckey,
checksum_algo->calculate_sign(),
NULL, pkey) <= 0) {
ret = rsa_err("Signer setup failed");
goto err_sign;
}
if (CONFIG_IS_ENABLED(RSASSA_PSS) && padding_algo &&
!strcmp(padding_algo->name, "pss")) {
if (EVP_PKEY_CTX_set_rsa_padding(ckey,
RSA_PKCS1_PSS_PADDING) <= 0) {
ret = rsa_err("Signer padding setup failed");
goto err_sign;
}
/* Per RFC 3447 (and convention) the Typical salt length is the
* length of the output of the digest algorithm.
*/
if (EVP_PKEY_CTX_set_rsa_pss_saltlen(ckey,
checksum_algo->checksum_len) <= 0) {
ret = rsa_err("Signer salt length setup failed");
goto err_sign;
}
}
for (i = 0; i < region_count; i++) {
if (!EVP_DigestSignUpdate(context, region[i].data,
region[i].size)) {
ret = rsa_err("Signing data failed");
goto err_sign;
}
}
if (!EVP_DigestSignFinal(context, sig, &size)) {
ret = rsa_err("Could not obtain signature");
goto err_sign;
}
EVP_MD_CTX_free(context);
debug("Got signature: %zu bytes, expected %d\n", size, EVP_PKEY_size(pkey));
*sigp = sig;
*sig_size = size;
return 0;
err_sign:
EVP_MD_CTX_free(context);
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)
{
EVP_PKEY *pkey = NULL;
ENGINE *e = NULL;
int ret;
ret = rsa_init();
if (ret)
return ret;
if (info->engine_id) {
ret = rsa_engine_init(info->engine_id, &e);
if (ret)
return ret;
}
ret = rsa_get_priv_key(info->keydir, info->keyname, info->keyfile,
e, &pkey);
if (ret)
goto err_priv;
ret = rsa_sign_with_key(pkey, info->padding, info->checksum, region,
region_count, sigp, sig_len);
if (ret)
goto err_sign;
EVP_PKEY_free(pkey);
if (info->engine_id)
rsa_engine_remove(e);
return ret;
err_sign:
EVP_PKEY_free(pkey);
err_priv:
if (info->engine_id)
rsa_engine_remove(e);
return ret;
}
/*
* 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;
const BIGNUM *key_e;
uint64_t te;
ret = -EINVAL;
bn_te = NULL;
if (!e)
goto cleanup;
RSA_get0_key(key, NULL, &key_e, NULL);
if (BN_num_bits(key_e) > 64)
goto cleanup;
*e = BN_get_word(key_e);
if (BN_num_bits(key_e) < 33) {
ret = 0;
goto cleanup;
}
bn_te = BN_dup(key_e);
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;
}
/*
* rsa_get_params(): - Get the important parameters of an RSA public key
*/
int rsa_get_params(RSA *key, uint64_t *exponent, uint32_t *n0_invp,
BIGNUM **modulusp, BIGNUM **r_squaredp)
{
BIGNUM *big1, *big2, *big32, *big2_32;
BIGNUM *n, *r, *r_squared, *tmp;
const BIGNUM *key_n;
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;
}
if (0 != rsa_get_exponent(key, exponent))
ret = -1;
RSA_get0_key(key, &key_n, NULL, NULL);
if (!BN_copy(n, key_n) || !BN_set_word(big1, 1L) ||
!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;
uint64_t exponent;
uint32_t n0_inv;
int parent, node = -FDT_ERR_NOTFOUND;
char name[100];
int ret;
int bits;
RSA *rsa;
EVP_PKEY *pkey = NULL;
ENGINE *e = NULL;
debug("%s: Getting verification data\n", __func__);
if (info->engine_id) {
ret = rsa_engine_init(info->engine_id, &e);
if (ret)
return ret;
}
ret = rsa_get_pub_key(info->keydir, info->keyname, e, &pkey);
if (ret)
goto err_get_pub_key;
rsa = (RSA *)EVP_PKEY_get0_RSA(pkey);
ret = rsa_get_params(rsa, &exponent, &n0_inv, &modulus, &r_squared);
if (ret)
goto err_get_params;
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) {
ret = parent;
if (ret != -FDT_ERR_NOSPACE) {
fprintf(stderr, "Couldn't create signature node: %s\n",
fdt_strerror(parent));
}
}
}
if (ret)
goto done;
/* 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) {
ret = node;
if (ret != -FDT_ERR_NOSPACE) {
fprintf(stderr, "Could not create key subnode: %s\n",
fdt_strerror(node));
}
}
} else if (node < 0) {
fprintf(stderr, "Cannot select keys parent: %s\n",
fdt_strerror(node));
ret = node;
}
if (!ret) {
ret = fdt_setprop_string(keydest, node, FIT_KEY_HINT,
info->keyname);
}
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);
if (!ret) {
ret = fdt_setprop_u64(keydest, node, "rsa,exponent", exponent);
}
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,
info->name);
}
if (!ret && info->require_keys) {
ret = fdt_setprop_string(keydest, node, FIT_KEY_REQUIRED,
info->require_keys);
}
done:
BN_free(modulus);
BN_free(r_squared);
if (ret)
ret = ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;
err_get_params:
EVP_PKEY_free(pkey);
err_get_pub_key:
if (info->engine_id)
rsa_engine_remove(e);
if (ret)
return ret;
return node;
}
+620
View File
@@ -0,0 +1,620 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2013, Google Inc.
*/
#ifndef USE_HOSTCC
#include <fdtdec.h>
#include <log.h>
#include <malloc.h>
#include <asm/types.h>
#include <asm/byteorder.h>
#include <linux/errno.h>
#include <asm/types.h>
#include <asm/unaligned.h>
#include <dm.h>
#else
#include "fdt_host.h"
#include "mkimage.h"
#include <linux/kconfig.h>
#include <fdt_support.h>
#endif
#include <u-boot/rsa-mod-exp.h>
#include <u-boot/rsa.h>
/* Default public exponent for backward compatibility */
#define RSA_DEFAULT_PUBEXP 65537
/**
* rsa_verify_padding() - Verify RSA message padding is valid
*
* Verify a RSA message's padding is consistent with PKCS1.5
* padding as described in the RSA PKCS#1 v2.1 standard.
*
* @msg: Padded message
* @pad_len: Number of expected padding bytes
* @algo: Checksum algo structure having information on DER encoding etc.
* Return: 0 on success, != 0 on failure
*/
static int rsa_verify_padding(const uint8_t *msg, const int pad_len,
struct checksum_algo *algo)
{
int ff_len;
int ret;
/* first byte must be 0x00 */
ret = *msg++;
/* second byte must be 0x01 */
ret |= *msg++ ^ 0x01;
/* next ff_len bytes must be 0xff */
ff_len = pad_len - algo->der_len - 3;
ret |= *msg ^ 0xff;
ret |= memcmp(msg, msg+1, ff_len-1);
msg += ff_len;
/* next byte must be 0x00 */
ret |= *msg++;
/* next der_len bytes must match der_prefix */
ret |= memcmp(msg, algo->der_prefix, algo->der_len);
return ret;
}
int padding_pkcs_15_verify(struct image_sign_info *info,
const uint8_t *msg, int msg_len,
const uint8_t *hash, int hash_len)
{
struct checksum_algo *checksum = info->checksum;
int ret, pad_len = msg_len - checksum->checksum_len;
/* Check pkcs1.5 padding bytes */
ret = rsa_verify_padding(msg, pad_len, checksum);
if (ret) {
debug("In RSAVerify(): Padding check failed!\n");
return -EINVAL;
}
/* Check hash */
if (memcmp((uint8_t *)msg + pad_len, hash, msg_len - pad_len)) {
debug("In RSAVerify(): Hash check failed!\n");
return -EACCES;
}
return 0;
}
#ifndef USE_HOSTCC
U_BOOT_PADDING_ALGO(pkcs_15) = {
.name = "pkcs-1.5",
.verify = padding_pkcs_15_verify,
};
#endif
#if CONFIG_IS_ENABLED(RSASSA_PSS)
static void u32_i2osp(uint32_t val, uint8_t *buf)
{
buf[0] = (uint8_t)((val >> 24) & 0xff);
buf[1] = (uint8_t)((val >> 16) & 0xff);
buf[2] = (uint8_t)((val >> 8) & 0xff);
buf[3] = (uint8_t)((val >> 0) & 0xff);
}
/**
* mask_generation_function1() - generate an octet string
*
* Generate an octet string used to check rsa signature.
* It use an input octet string and a hash function.
*
* @checksum: A Hash function
* @seed: Specifies an input variable octet string
* @seed_len: Size of the input octet string
* @output: Specifies the output octet string
* @output_len: Size of the output octet string
* Return: 0 if the octet string was correctly generated, others on error
*/
static int mask_generation_function1(struct checksum_algo *checksum,
const uint8_t *seed, int seed_len,
uint8_t *output, int output_len)
{
struct image_region region[2];
int ret = 0, i, i_output = 0, region_count = 2;
uint32_t counter = 0;
uint8_t buf_counter[4], *tmp;
int hash_len = checksum->checksum_len;
memset(output, 0, output_len);
region[0].data = seed;
region[0].size = seed_len;
region[1].data = &buf_counter[0];
region[1].size = 4;
tmp = malloc(hash_len);
if (!tmp) {
debug("%s: can't allocate array tmp\n", __func__);
ret = -ENOMEM;
goto out;
}
while (i_output < output_len) {
u32_i2osp(counter, &buf_counter[0]);
ret = checksum->calculate(checksum->name,
region, region_count,
tmp);
if (ret < 0) {
debug("%s: Error in checksum calculation\n", __func__);
goto out;
}
i = 0;
while ((i_output < output_len) && (i < hash_len)) {
output[i_output] = tmp[i];
i_output++;
i++;
}
counter++;
}
out:
free(tmp);
return ret;
}
static int compute_hash_prime(struct checksum_algo *checksum,
const uint8_t *pad, int pad_len,
const uint8_t *hash, int hash_len,
const uint8_t *salt, int salt_len,
uint8_t *hprime)
{
struct image_region region[3];
int ret, region_count = 3;
region[0].data = pad;
region[0].size = pad_len;
region[1].data = hash;
region[1].size = hash_len;
region[2].data = salt;
region[2].size = salt_len;
ret = checksum->calculate(checksum->name, region, region_count, hprime);
if (ret < 0) {
debug("%s: Error in checksum calculation\n", __func__);
goto out;
}
out:
return ret;
}
/*
* padding_pss_verify() - verify the pss padding of a signature
*
* Works with any salt length
*
* msg is a concatenation of : masked_db + h + 0xbc
* Once unmasked, db is a concatenation of : [0x00]* + 0x01 + salt
* Length of 0-padding at begin of db depends on salt length.
*
* @info: Specifies key and FIT information
* @msg: byte array of message, len equal to msg_len
* @msg_len: Message length
* @hash: Pointer to the expected hash
* @hash_len: Length of the hash
*
* Return: 0 if padding is correct, non-zero otherwise
*/
int padding_pss_verify(struct image_sign_info *info,
const uint8_t *msg, int msg_len,
const uint8_t *hash, int hash_len)
{
const uint8_t *masked_db = NULL;
uint8_t *db_mask = NULL;
uint8_t *db = NULL;
int db_len = msg_len - hash_len - 1;
const uint8_t *h = NULL;
uint8_t *hprime = NULL;
int h_len = hash_len;
uint8_t *db_nopad = NULL, *salt = NULL;
int db_padlen, salt_len;
uint8_t pad_zero[8] = { 0 };
int ret, i, leftmost_bits = 1;
uint8_t leftmost_mask;
struct checksum_algo *checksum = info->checksum;
if (db_len <= 0)
return -EINVAL;
/* first, allocate everything */
db_mask = malloc(db_len);
db = malloc(db_len);
hprime = malloc(hash_len);
if (!db_mask || !db || !hprime) {
printf("%s: can't allocate some buffer\n", __func__);
ret = -ENOMEM;
goto out;
}
/* step 4: check if the last byte is 0xbc */
if (msg[msg_len - 1] != 0xbc) {
printf("%s: invalid pss padding (0xbc is missing)\n", __func__);
ret = -EINVAL;
goto out;
}
/* step 5 */
masked_db = &msg[0];
h = &msg[db_len];
/* step 6 */
leftmost_mask = (0xff >> (8 - leftmost_bits)) << (8 - leftmost_bits);
if (masked_db[0] & leftmost_mask) {
printf("%s: invalid pss padding ", __func__);
printf("(leftmost bit of maskedDB not zero)\n");
ret = -EINVAL;
goto out;
}
/* step 7 */
mask_generation_function1(checksum, h, h_len, db_mask, db_len);
/* step 8 */
for (i = 0; i < db_len; i++)
db[i] = masked_db[i] ^ db_mask[i];
/* step 9 */
db[0] &= 0xff >> leftmost_bits;
/* step 10 */
db_padlen = 0;
while (db[db_padlen] == 0x00 && db_padlen < (db_len - 1))
db_padlen++;
db_nopad = &db[db_padlen];
if (db_nopad[0] != 0x01) {
printf("%s: invalid pss padding ", __func__);
printf("(leftmost byte of db after 0-padding isn't 0x01)\n");
ret = EINVAL;
goto out;
}
/* step 11 */
salt_len = db_len - db_padlen - 1;
salt = &db_nopad[1];
/* step 12 & 13 */
compute_hash_prime(checksum, pad_zero, 8,
hash, hash_len,
salt, salt_len, hprime);
/* step 14 */
ret = memcmp(h, hprime, hash_len);
out:
free(hprime);
free(db);
free(db_mask);
return ret;
}
#ifndef USE_HOSTCC
U_BOOT_PADDING_ALGO(pss) = {
.name = "pss",
.verify = padding_pss_verify,
};
#endif
#endif
/**
* rsa_verify_key() - Verify a signature against some data using RSA Key
*
* Verify a RSA PKCS1.5/PSS signature against an expected hash using
* the RSA Key properties in prop structure.
*
* @info: Specifies key and FIT information
* @prop: Specifies key
* @sig: Signature
* @sig_len: Number of bytes in signature
* @hash: Pointer to the expected hash
* @key_len: Number of bytes in rsa key
* Return: 0 if verified, -ve on error
*/
static int rsa_verify_key(struct image_sign_info *info,
struct key_prop *prop, const uint8_t *sig,
const uint32_t sig_len, const uint8_t *hash,
const uint32_t key_len)
{
int ret;
#if !defined(USE_HOSTCC)
struct udevice *mod_exp_dev;
#endif
struct checksum_algo *checksum = info->checksum;
struct padding_algo *padding = info->padding;
int hash_len;
if (!prop || !sig || !hash || !checksum || !padding)
return -EIO;
if (sig_len != (prop->num_bits / 8)) {
debug("Signature is of incorrect length %d\n", sig_len);
return -EINVAL;
}
debug("Checksum algorithm: %s\n", checksum->name);
/* Sanity check for stack size */
if (sig_len > RSA_MAX_SIG_BITS / 8) {
debug("Signature length %u exceeds maximum %d\n", sig_len,
RSA_MAX_SIG_BITS / 8);
return -EINVAL;
}
uint8_t buf[sig_len];
hash_len = checksum->checksum_len;
#if !defined(USE_HOSTCC)
ret = uclass_get_device(UCLASS_MOD_EXP, 0, &mod_exp_dev);
if (ret) {
printf("RSA: Can't find Modular Exp implementation\n");
return -EINVAL;
}
ret = rsa_mod_exp(mod_exp_dev, sig, sig_len, prop, buf);
#else
ret = rsa_mod_exp_sw(sig, sig_len, prop, buf);
#endif
if (ret) {
debug("Error in Modular exponentation\n");
return ret;
}
ret = padding->verify(info, buf, key_len, hash, hash_len);
if (ret) {
debug("In RSAVerify(): padding check failed!\n");
return ret;
}
return 0;
}
/**
* rsa_verify_with_pkey() - Verify a signature against some data using
* only modulus and exponent as RSA key properties.
* @info: Specifies key information
* @hash: Pointer to the expected hash
* @sig: Signature
* @sig_len: Number of bytes in signature
*
* Parse a RSA public key blob in DER format pointed to in @info and fill
* a key_prop structure with properties of the key. Then verify a RSA PKCS1.5/PSS
* signature against an expected hash using the calculated properties.
*
* Return 0 if verified, -ve on error
*/
int rsa_verify_with_pkey(struct image_sign_info *info,
const void *hash, uint8_t *sig, uint sig_len)
{
struct key_prop *prop;
int ret;
if (!CONFIG_IS_ENABLED(RSA_VERIFY_WITH_PKEY))
return -EACCES;
/* Public key is self-described to fill key_prop */
ret = rsa_gen_key_prop(info->key, info->keylen, &prop);
if (ret) {
debug("Generating necessary parameter for decoding failed\n");
return ret;
}
ret = rsa_verify_key(info, prop, sig, sig_len, hash,
info->crypto->key_len);
rsa_free_key_prop(prop);
return ret;
}
#if CONFIG_IS_ENABLED(FIT_SIGNATURE)
/**
* rsa_verify_with_keynode() - Verify a signature against some data using
* information in node with prperties of RSA Key like modulus, exponent etc.
*
* Parse sign-node and fill a key_prop structure with properties of the
* key. Verify a RSA PKCS1.5/PSS signature against an expected hash using
* the properties parsed
*
* @info: Specifies key and FIT information
* @hash: Pointer to the expected hash
* @sig: Signature
* @sig_len: Number of bytes in signature
* @node: Node having the RSA Key properties
* Return: 0 if verified, -ve on error
*/
static int rsa_verify_with_keynode(struct image_sign_info *info,
const void *hash, uint8_t *sig,
uint sig_len, int node)
{
const void *blob = info->fdt_blob;
struct key_prop prop;
int length;
int ret = 0;
const char *algo;
if (node < 0) {
debug("%s: Skipping invalid node\n", __func__);
return -EBADF;
}
algo = fdt_getprop(blob, node, FIT_ALGO_PROP, NULL);
if (!algo) {
debug("%s: Missing 'algo' property\n", __func__);
return -EFAULT;
}
if (strcmp(info->name, algo)) {
debug("%s: Wrong algo: have %s, expected %s\n", __func__,
info->name, algo);
return -EFAULT;
}
prop.num_bits = fdtdec_get_int(blob, node, "rsa,num-bits", 0);
prop.n0inv = fdtdec_get_int(blob, node, "rsa,n0-inverse", 0);
prop.public_exponent = fdt_getprop(blob, node, "rsa,exponent", &length);
if (!prop.public_exponent || length < sizeof(uint64_t))
prop.public_exponent = NULL;
prop.exp_len = sizeof(uint64_t);
prop.modulus = fdt_getprop(blob, node, "rsa,modulus", NULL);
prop.rr = fdt_getprop(blob, node, "rsa,r-squared", NULL);
if (!prop.num_bits || !prop.modulus || !prop.rr) {
debug("%s: Missing RSA key info\n", __func__);
return -EFAULT;
}
ret = rsa_verify_key(info, &prop, sig, sig_len, hash,
info->crypto->key_len);
return ret;
}
#else
static int rsa_verify_with_keynode(struct image_sign_info *info,
const void *hash, uint8_t *sig,
uint sig_len, int node)
{
return -EACCES;
}
#endif
int rsa_verify_hash(struct image_sign_info *info,
const uint8_t *hash, uint8_t *sig, uint sig_len)
{
int ret = -EACCES;
/*
* Since host tools, like mkimage, make use of openssl library for
* RSA encryption, rsa_verify_with_pkey()/rsa_gen_key_prop() are
* of no use and should not be compiled in.
*/
if (!tools_build() && CONFIG_IS_ENABLED(RSA_VERIFY_WITH_PKEY) &&
!info->fdt_blob) {
/* don't rely on fdt properties */
ret = rsa_verify_with_pkey(info, hash, sig, sig_len);
if (ret)
debug("%s: rsa_verify_with_pkey() failed\n", __func__);
return ret;
}
if (CONFIG_IS_ENABLED(FIT_SIGNATURE)) {
const void *blob = info->fdt_blob;
int ndepth, noffset;
int sig_node, node;
char name[100];
sig_node = fdt_subnode_offset(blob, 0, FIT_SIG_NODENAME);
if (sig_node < 0) {
debug("%s: No signature node found\n", __func__);
return -ENOENT;
}
/* See if we must use a particular key */
if (info->required_keynode != -1) {
ret = rsa_verify_with_keynode(info, hash, sig, sig_len,
info->required_keynode);
if (ret)
debug("%s: Failed to verify required_keynode\n",
__func__);
return ret;
}
/* Look for a key that matches our hint */
snprintf(name, sizeof(name), "key-%s", info->keyname);
node = fdt_subnode_offset(blob, sig_node, name);
ret = rsa_verify_with_keynode(info, hash, sig, sig_len, node);
if (!ret)
return ret;
debug("%s: Could not verify key '%s', trying all\n", __func__,
name);
/* No luck, so try each of the keys in turn */
for (ndepth = 0, noffset = fdt_next_node(blob, sig_node,
&ndepth);
(noffset >= 0) && (ndepth > 0);
noffset = fdt_next_node(blob, noffset, &ndepth)) {
if (ndepth == 1 && noffset != node) {
ret = rsa_verify_with_keynode(info, hash,
sig, sig_len,
noffset);
if (!ret)
break;
}
}
}
debug("%s: Failed to verify by any means\n", __func__);
return ret;
}
int rsa_verify(struct image_sign_info *info,
const struct image_region region[], int region_count,
uint8_t *sig, uint sig_len)
{
/* Reserve memory for maximum checksum-length */
uint8_t hash[info->crypto->key_len];
int ret;
#if defined(USE_HOSTCC) && CONFIG_IS_ENABLED(LIBCRYPTO)
if (!info->fdt_blob)
return rsa_verify_openssl(info, region, region_count, sig, sig_len);
#endif
/*
* Verify that the checksum-length does not exceed the
* rsa-signature-length
*/
if (info->checksum->checksum_len >
info->crypto->key_len) {
debug("%s: invalid checksum-algorithm %s for %s\n",
__func__, info->checksum->name, info->crypto->name);
return -EINVAL;
}
/* Calculate checksum with checksum-algorithm */
ret = info->checksum->calculate(info->checksum->name,
region, region_count, hash);
if (ret < 0) {
debug("%s: Error in checksum calculation\n", __func__);
return -EINVAL;
}
return rsa_verify_hash(info, hash, sig, sig_len);
}
#ifndef USE_HOSTCC
U_BOOT_CRYPTO_ALGO(rsa2048) = {
.name = "rsa2048",
.key_len = RSA2048_BYTES,
.verify = rsa_verify,
};
U_BOOT_CRYPTO_ALGO(rsa3072) = {
.name = "rsa3072",
.key_len = RSA3072_BYTES,
.verify = rsa_verify,
};
U_BOOT_CRYPTO_ALGO(rsa4096) = {
.name = "rsa4096",
.key_len = RSA4096_BYTES,
.verify = rsa_verify,
};
#endif