Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
E
ezynq
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Elphel
ezynq
Commits
0cbec1fd
Commit
0cbec1fd
authored
Dec 27, 2018
by
Oleg Dzhimiev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
now rsa
parent
22b56617
Changes
6
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
1727 additions
and
0 deletions
+1727
-0
Kconfig
u-boot-tree/lib/rsa/Kconfig
+37
-0
Makefile
u-boot-tree/lib/rsa/Makefile
+9
-0
rsa-checksum.c
u-boot-tree/lib/rsa/rsa-checksum.c
+51
-0
rsa-mod-exp.c
u-boot-tree/lib/rsa/rsa-mod-exp.c
+353
-0
rsa-sign.c
u-boot-tree/lib/rsa/rsa-sign.c
+814
-0
rsa-verify.c
u-boot-tree/lib/rsa/rsa-verify.c
+463
-0
No files found.
u-boot-tree/lib/rsa/Kconfig
0 → 100644
View file @
0cbec1fd
config RSA
bool "Use RSA Library"
select RSA_FREESCALE_EXP if FSL_CAAM && !ARCH_MX7 && !ARCH_MX6 && !ARCH_MX5
select RSA_SOFTWARE_EXP if !RSA_FREESCALE_EXP
help
RSA support. This enables the RSA algorithm used for FIT image
verification in U-Boot.
See doc/uImage.FIT/signature.txt 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"
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/uImage.FIT/signature.txt for more details.
config RSA_FREESCALE_EXP
bool "Enable RSA Modular Exponentiation with FSL crypto accelerator"
depends on DM && FSL_CAAM && !ARCH_MX7 && !ARCH_MX6 && !ARCH_MX5
help
Enables driver for RSA modular exponentiation using Freescale cryptographic
accelerator - CAAM.
endif
u-boot-tree/lib/rsa/Makefile
0 → 100644
View file @
0cbec1fd
# 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_$(SPL_)FIT_SIGNATURE)
+=
rsa-verify.o
rsa-checksum.o
obj-$(CONFIG_RSA_SOFTWARE_EXP)
+=
rsa-mod-exp.o
u-boot-tree/lib/rsa/rsa-checksum.c
0 → 100644
View file @
0cbec1fd
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2013, Andreas Oetken.
*/
#ifndef USE_HOSTCC
#include <common.h>
#include <fdtdec.h>
#include <asm/byteorder.h>
#include <linux/errno.h>
#include <asm/unaligned.h>
#include <hash.h>
#else
#include "fdt_host.h"
#endif
#include <u-boot/rsa.h>
int
hash_calculate
(
const
char
*
name
,
const
struct
image_region
region
[],
int
region_count
,
uint8_t
*
checksum
)
{
struct
hash_algo
*
algo
;
int
ret
=
0
;
void
*
ctx
;
uint32_t
i
;
i
=
0
;
ret
=
hash_progressive_lookup_algo
(
name
,
&
algo
);
if
(
ret
)
return
ret
;
ret
=
algo
->
hash_init
(
algo
,
&
ctx
);
if
(
ret
)
return
ret
;
for
(
i
=
0
;
i
<
region_count
-
1
;
i
++
)
{
ret
=
algo
->
hash_update
(
algo
,
ctx
,
region
[
i
].
data
,
region
[
i
].
size
,
0
);
if
(
ret
)
return
ret
;
}
ret
=
algo
->
hash_update
(
algo
,
ctx
,
region
[
i
].
data
,
region
[
i
].
size
,
1
);
if
(
ret
)
return
ret
;
ret
=
algo
->
hash_finish
(
algo
,
ctx
,
checksum
,
algo
->
digest_size
);
if
(
ret
)
return
ret
;
return
0
;
}
u-boot-tree/lib/rsa/rsa-mod-exp.c
0 → 100644
View file @
0cbec1fd
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2013, Google Inc.
*/
#ifndef USE_HOSTCC
#include <common.h>
#include <fdtdec.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))
/* 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_cpu
(
*
((
uint64_t
*
)(
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
(
u32
*
keyptr
,
u32
*
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
u-boot-tree/lib/rsa/rsa-sign.c
0 → 100644
View file @
0cbec1fd
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2013, Google Inc.
*/
#include "mkimage.h"
#include <stdio.h>
#include <string.h>
#include <image.h>
#include <time.h>
#include <openssl/bn.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>
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
#define HAVE_ERR_REMOVE_THREAD_STATE
#endif
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x02070000fL)
static
void
RSA_get0_key
(
const
RSA
*
r
,
const
BIGNUM
**
n
,
const
BIGNUM
**
e
,
const
BIGNUM
**
d
)
{
if
(
n
!=
NULL
)
*
n
=
r
->
n
;
if
(
e
!=
NULL
)
*
e
=
r
->
e
;
if
(
d
!=
NULL
)
*
d
=
r
->
d
;
}
#endif
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)
* @rsap Returns RSA object, or NULL on failure
* @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
*/
static
int
rsa_pem_get_pub_key
(
const
char
*
keydir
,
const
char
*
name
,
RSA
**
rsap
)
{
char
path
[
1024
];
EVP_PKEY
*
key
;
X509
*
cert
;
RSA
*
rsa
;
FILE
*
f
;
int
ret
;
*
rsap
=
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
;
}
/* Convert to a RSA_style key. */
rsa
=
EVP_PKEY_get1_RSA
(
key
);
if
(
!
rsa
)
{
rsa_err
(
"Couldn't convert to a RSA style key"
);
ret
=
-
EINVAL
;
goto
err_rsa
;
}
fclose
(
f
);
EVP_PKEY_free
(
key
);
X509_free
(
cert
);
*
rsap
=
rsa
;
return
0
;
err_rsa:
EVP_PKEY_free
(
key
);
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
* @rsap Returns RSA object, or NULL on failure
* @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
*/
static
int
rsa_engine_get_pub_key
(
const
char
*
keydir
,
const
char
*
name
,
ENGINE
*
engine
,
RSA
**
rsap
)
{
const
char
*
engine_id
;
char
key_id
[
1024
];
EVP_PKEY
*
key
;
RSA
*
rsa
;
int
ret
;
*
rsap
=
NULL
;
engine_id
=
ENGINE_get_id
(
engine
);
if
(
engine_id
&&
!
strcmp
(
engine_id
,
"pkcs11"
))
{
if
(
keydir
)
snprintf
(
key_id
,
sizeof
(
key_id
),
"pkcs11:%s;object=%s;type=public"
,
keydir
,
name
);
else
snprintf
(
key_id
,
sizeof
(
key_id
),
"pkcs11:object=%s;type=public"
,
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"
);
/* Convert to a RSA_style key. */
rsa
=
EVP_PKEY_get1_RSA
(
key
);
if
(
!
rsa
)
{
rsa_err
(
"Couldn't convert to a RSA style key"
);
ret
=
-
EINVAL
;
goto
err_rsa
;
}
EVP_PKEY_free
(
key
);
*
rsap
=
rsa
;
return
0
;
err_rsa:
EVP_PKEY_free
(
key
);
return
ret
;
}
/**
* 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
* @rsap Returns RSA object, or NULL on failure
* @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
*/
static
int
rsa_get_pub_key
(
const
char
*
keydir
,
const
char
*
name
,
ENGINE
*
engine
,
RSA
**
rsap
)
{
if
(
engine
)
return
rsa_engine_get_pub_key
(
keydir
,
name
,
engine
,
rsap
);
return
rsa_pem_get_pub_key
(
keydir
,
name
,
rsap
);
}
/**
* 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)
* @rsap Returns RSA object, or NULL on failure
* @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
*/
static
int
rsa_pem_get_priv_key
(
const
char
*
keydir
,
const
char
*
name
,
RSA
**
rsap
)
{
char
path
[
1024
];
RSA
*
rsa
;
FILE
*
f
;
*
rsap
=
NULL
;
snprintf
(
path
,
sizeof
(
path
),
"%s/%s.key"
,
keydir
,
name
);
f
=
fopen
(
path
,
"r"
);
if
(
!
f
)
{
fprintf
(
stderr
,
"Couldn't open RSA private key: '%s': %s
\n
"
,
path
,
strerror
(
errno
));
return
-
ENOENT
;
}
rsa
=
PEM_read_RSAPrivateKey
(
f
,
0
,
NULL
,
path
);
if
(
!
rsa
)
{
rsa_err
(
"Failure reading private key"
);
fclose
(
f
);
return
-
EPROTO
;
}
fclose
(
f
);
*
rsap
=
rsa
;
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
* @rsap Returns RSA object, or NULL on failure
* @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
*/
static
int
rsa_engine_get_priv_key
(
const
char
*
keydir
,
const
char
*
name
,
ENGINE
*
engine
,
RSA
**
rsap
)
{
const
char
*
engine_id
;
char
key_id
[
1024
];
EVP_PKEY
*
key
;
RSA
*
rsa
;
int
ret
;
*
rsap
=
NULL
;
engine_id
=
ENGINE_get_id
(
engine
);
if
(
engine_id
&&
!
strcmp
(
engine_id
,
"pkcs11"
))
{
if
(
keydir
)
snprintf
(
key_id
,
sizeof
(
key_id
),
"pkcs11:%s;object=%s;type=private"
,
keydir
,
name
);
else
snprintf
(
key_id
,
sizeof
(
key_id
),
"pkcs11:object=%s;type=private"
,
name
);
}
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"
);
/* Convert to a RSA_style key. */
rsa
=
EVP_PKEY_get1_RSA
(
key
);
if
(
!
rsa
)
{
rsa_err
(
"Couldn't convert to a RSA style key"
);
ret
=
-
EINVAL
;
goto
err_rsa
;
}
EVP_PKEY_free
(
key
);
*
rsap
=
rsa
;
return
0
;
err_rsa:
EVP_PKEY_free
(
key
);
return
ret
;
}
/**
* 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
* @rsap Returns RSA object, or NULL on failure
* @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
*/
static
int
rsa_get_priv_key
(
const
char
*
keydir
,
const
char
*
name
,
ENGINE
*
engine
,
RSA
**
rsap
)
{
if
(
engine
)
return
rsa_engine_get_priv_key
(
keydir
,
name
,
engine
,
rsap
);
return
rsa_pem_get_priv_key
(
keydir
,
name
,
rsap
);
}
static
int
rsa_init
(
void
)
{
int
ret
;
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x02070000fL)
ret
=
SSL_library_init
();
#else
ret
=
OPENSSL_init_ssl
(
0
,
NULL
);
#endif
if
(
!
ret
)
{
fprintf
(
stderr
,
"Failure to init SSL library
\n
"
);
return
-
1
;
}
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x02070000fL)
SSL_load_error_strings
();
OpenSSL_add_all_algorithms
();
OpenSSL_add_all_digests
();
OpenSSL_add_all_ciphers
();
#endif
return
0
;
}
static
int
rsa_engine_init
(
const
char
*
engine_id
,
ENGINE
**
pe
)
{
ENGINE
*
e
;
int
ret
;
ENGINE_load_builtin_engines
();
e
=
ENGINE_by_id
(
engine_id
);
if
(
!
e
)
{
fprintf
(
stderr
,
"Engine isn't available
\n
"
);
ret
=
-
1
;
goto
err_engine_by_id
;
}
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
;
}
*
pe
=
e
;
return
0
;
err_set_rsa:
ENGINE_finish
(
e
);
err_engine_init:
ENGINE_free
(
e
);
err_engine_by_id:
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x02070000fL)
ENGINE_cleanup
();
#endif
return
ret
;
}
static
void
rsa_remove
(
void
)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x02070000fL)
CRYPTO_cleanup_all_ex_data
();
ERR_free_strings
();
#ifdef HAVE_ERR_REMOVE_THREAD_STATE
ERR_remove_thread_state
(
NULL
);
#else
ERR_remove_state
(
0
);
#endif
EVP_cleanup
();
#endif
}
static
void
rsa_engine_remove
(
ENGINE
*
e
)
{
if
(
e
)
{
ENGINE_finish
(
e
);
ENGINE_free
(
e
);
}
}
static
int
rsa_sign_with_key
(
RSA
*
rsa
,
struct
padding_algo
*
padding_algo
,
struct
checksum_algo
*
checksum_algo
,
const
struct
image_region
region
[],
int
region_count
,
uint8_t
**
sigp
,
uint
*
sig_size
)
{
EVP_PKEY
*
key
;
EVP_PKEY_CTX
*
ckey
;
EVP_MD_CTX
*
context
;
int
ret
=
0
;
size_t
size
;
uint8_t
*
sig
;
int
i
;
key
=
EVP_PKEY_new
();
if
(
!
key
)
return
rsa_err
(
"EVP_PKEY object creation failed"
);
if
(
!
EVP_PKEY_set1_RSA
(
key
,
rsa
))
{
ret
=
rsa_err
(
"EVP key setup failed"
);
goto
err_set
;
}
size
=
EVP_PKEY_size
(
key
);
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_create
();
if
(
!
context
)
{
ret
=
rsa_err
(
"EVP context creation failed"
);
goto
err_create
;
}
EVP_MD_CTX_init
(
context
);
ckey
=
EVP_PKEY_CTX_new
(
key
,
NULL
);
if
(
!
ckey
)
{
ret
=
rsa_err
(
"EVP key context creation failed"
);
goto
err_create
;
}
if
(
EVP_DigestSignInit
(
context
,
&
ckey
,
checksum_algo
->
calculate_sign
(),
NULL
,
key
)
<=
0
)
{
ret
=
rsa_err
(
"Signer setup failed"
);
goto
err_sign
;
}
#ifdef CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT
if
(
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
;
}
}
#endif
/* CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT */
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
;
}
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x02070000fL)
EVP_MD_CTX_cleanup
(
context
);
#else
EVP_MD_CTX_reset
(
context
);
#endif
EVP_MD_CTX_destroy
(
context
);
EVP_PKEY_free
(
key
);
debug
(
"Got signature: %d bytes, expected %zu
\n
"
,
*
sig_size
,
size
);
*
sigp
=
sig
;
*
sig_size
=
size
;
return
0
;
err_sign:
EVP_MD_CTX_destroy
(
context
);
err_create:
free
(
sig
);
err_alloc:
err_set:
EVP_PKEY_free
(
key
);
return
ret
;
}
int
rsa_sign
(
struct
image_sign_info
*
info
,
const
struct
image_region
region
[],
int
region_count
,
uint8_t
**
sigp
,
uint
*
sig_len
)
{
RSA
*
rsa
;
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
)
goto
err_engine
;
}
ret
=
rsa_get_priv_key
(
info
->
keydir
,
info
->
keyname
,
e
,
&
rsa
);
if
(
ret
)
goto
err_priv
;
ret
=
rsa_sign_with_key
(
rsa
,
info
->
padding
,
info
->
checksum
,
region
,
region_count
,
sigp
,
sig_len
);
if
(
ret
)
goto
err_sign
;
RSA_free
(
rsa
);
if
(
info
->
engine_id
)
rsa_engine_remove
(
e
);
rsa_remove
();
return
ret
;
err_sign:
RSA_free
(
rsa
);
err_priv:
if
(
info
->
engine_id
)
rsa_engine_remove
(
e
);
err_engine:
rsa_remove
();
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
;
}
static
int
fdt_add_bignum
(
void
*
blob
,
int
noffset
,
const
char
*
prop_name
,
BIGNUM
*
num
,
int
num_bits
)
{
int
nwords
=
num_bits
/
32
;
int
size
;
uint32_t
*
buf
,
*
ptr
;
BIGNUM
*
tmp
,
*
big2
,
*
big32
,
*
big2_32
;
BN_CTX
*
ctx
;
int
ret
;
tmp
=
BN_new
();
big2
=
BN_new
();
big32
=
BN_new
();
big2_32
=
BN_new
();
/*
* Note: This code assumes that all of the above succeed, or all fail.
* In practice memory allocations generally do not fail (unless the
* process is killed), so it does not seem worth handling each of these
* as a separate case. Technicaly this could leak memory on failure,
* but a) it won't happen in practice, and b) it doesn't matter as we
* will immediately exit with a failure code.
*/
if
(
!
tmp
||
!
big2
||
!
big32
||
!
big2_32
)
{
fprintf
(
stderr
,
"Out of memory (bignum)
\n
"
);
return
-
ENOMEM
;
}
ctx
=
BN_CTX_new
();
if
(
!
tmp
)
{
fprintf
(
stderr
,
"Out of memory (bignum context)
\n
"
);
return
-
ENOMEM
;
}
BN_set_word
(
big2
,
2L
);
BN_set_word
(
big32
,
32L
);
BN_exp
(
big2_32
,
big2
,
big32
,
ctx
);
/* B = 2^32 */
size
=
nwords
*
sizeof
(
uint32_t
);
buf
=
malloc
(
size
);
if
(
!
buf
)
{
fprintf
(
stderr
,
"Out of memory (%d bytes)
\n
"
,
size
);
return
-
ENOMEM
;
}
/* Write out modulus as big endian array of integers */
for
(
ptr
=
buf
+
nwords
-
1
;
ptr
>=
buf
;
ptr
--
)
{
BN_mod
(
tmp
,
num
,
big2_32
,
ctx
);
/* n = N mod B */
*
ptr
=
cpu_to_fdt32
(
BN_get_word
(
tmp
));
BN_rshift
(
num
,
num
,
32
);
/* N = N/B */
}
/*
* We try signing with successively increasing size values, so this
* might fail several times
*/
ret
=
fdt_setprop
(
blob
,
noffset
,
prop_name
,
buf
,
size
);
free
(
buf
);
BN_free
(
tmp
);
BN_free
(
big2
);
BN_free
(
big32
);
BN_free
(
big2_32
);
return
ret
?
-
FDT_ERR_NOSPACE
:
0
;
}
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
;
char
name
[
100
];
int
ret
;
int
bits
;
RSA
*
rsa
;
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
,
&
rsa
);
if
(
ret
)
goto
err_get_pub_key
;
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
,
"key-name-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
,
"required"
,
info
->
require_keys
);
}
done:
BN_free
(
modulus
);
BN_free
(
r_squared
);
if
(
ret
)
ret
=
ret
==
-
FDT_ERR_NOSPACE
?
-
ENOSPC
:
-
EIO
;
err_get_params:
RSA_free
(
rsa
);
err_get_pub_key:
if
(
info
->
engine_id
)
rsa_engine_remove
(
e
);
return
ret
;
}
u-boot-tree/lib/rsa/rsa-verify.c
0 → 100644
View file @
0cbec1fd
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2013, Google Inc.
*/
#ifndef USE_HOSTCC
#include <common.h>
#include <fdtdec.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 <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
,
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
;
}
#ifdef CONFIG_FIT_ENABLE_RSASSA_PSS_SUPPORT
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
,
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
,
uint8_t
*
pad
,
int
pad_len
,
uint8_t
*
hash
,
int
hash_len
,
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
;
}
int
padding_pss_verify
(
struct
image_sign_info
*
info
,
uint8_t
*
msg
,
int
msg_len
,
const
uint8_t
*
hash
,
int
hash_len
)
{
uint8_t
*
masked_db
=
NULL
;
int
masked_db_len
=
msg_len
-
hash_len
-
1
;
uint8_t
*
h
=
NULL
,
*
hprime
=
NULL
;
int
h_len
=
hash_len
;
uint8_t
*
db_mask
=
NULL
;
int
db_mask_len
=
masked_db_len
;
uint8_t
*
db
=
NULL
,
*
salt
=
NULL
;
int
db_len
=
masked_db_len
,
salt_len
=
msg_len
-
hash_len
-
2
;
uint8_t
pad_zero
[
8
]
=
{
0
};
int
ret
,
i
,
leftmost_bits
=
1
;
uint8_t
leftmost_mask
;
struct
checksum_algo
*
checksum
=
info
->
checksum
;
/* first, allocate everything */
masked_db
=
malloc
(
masked_db_len
);
h
=
malloc
(
h_len
);
db_mask
=
malloc
(
db_mask_len
);
db
=
malloc
(
db_len
);
salt
=
malloc
(
salt_len
);
hprime
=
malloc
(
hash_len
);
if
(
!
masked_db
||
!
h
||
!
db_mask
||
!
db
||
!
salt
||
!
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 */
memcpy
(
masked_db
,
msg
,
masked_db_len
);
memcpy
(
h
,
msg
+
masked_db_len
,
h_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_mask_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 */
if
(
db
[
0
]
!=
0x01
)
{
printf
(
"%s: invalid pss padding "
,
__func__
);
printf
(
"(leftmost byte of db isn't 0x01)
\n
"
);
ret
=
EINVAL
;
goto
out
;
}
/* step 11 */
memcpy
(
salt
,
&
db
[
1
],
salt_len
);
/* step 12 & 13 */
compute_hash_prime
(
checksum
,
pad_zero
,
8
,
(
uint8_t
*
)
hash
,
hash_len
,
salt
,
salt_len
,
hprime
);
/* step 14 */
ret
=
memcmp
(
h
,
hprime
,
hash_len
);
out:
free
(
hprime
);
free
(
salt
);
free
(
db
);
free
(
db_mask
);
free
(
h
);
free
(
masked_db
);
return
ret
;
}
#endif
/**
* rsa_verify_key() - Verify a signature against some data using RSA Key
*
* Verify a RSA PKCS1.5 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
=
checksum
->
checksum_len
;
if
(
!
prop
||
!
sig
||
!
hash
||
!
checksum
)
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"
,
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
];
#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_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 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
;
if
(
node
<
0
)
{
debug
(
"%s: Skipping invalid node"
,
__func__
);
return
-
EBADF
;
}
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
)
{
debug
(
"%s: Missing RSA key info"
,
__func__
);
return
-
EFAULT
;
}
ret
=
rsa_verify_key
(
info
,
&
prop
,
sig
,
sig_len
,
hash
,
info
->
crypto
->
key_len
);
return
ret
;
}
int
rsa_verify
(
struct
image_sign_info
*
info
,
const
struct
image_region
region
[],
int
region_count
,
uint8_t
*
sig
,
uint
sig_len
)
{
const
void
*
blob
=
info
->
fdt_blob
;
/* Reserve memory for maximum checksum-length */
uint8_t
hash
[
info
->
crypto
->
key_len
];
int
ndepth
,
noffset
;
int
sig_node
,
node
;
char
name
[
100
];
int
ret
;
/*
* Verify that the checksum-length does not exceed the
* rsa-signature-length
*/
if
(
info
->
checksum
->
checksum_len
>
info
->
crypto
->
key_len
)
{
debug
(
"%s: invlaid checksum-algorithm %s for %s
\n
"
,
__func__
,
info
->
checksum
->
name
,
info
->
crypto
->
name
);
return
-
EINVAL
;
}
sig_node
=
fdt_subnode_offset
(
blob
,
0
,
FIT_SIG_NODENAME
);
if
(
sig_node
<
0
)
{
debug
(
"%s: No signature node found
\n
"
,
__func__
);
return
-
ENOENT
;
}
/* 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
;
}
/* 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
)
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
;
/* No luck, so try each of the keys in turn */
for
(
ndepth
=
0
,
noffset
=
fdt_next_node
(
info
->
fit
,
sig_node
,
&
ndepth
);
(
noffset
>=
0
)
&&
(
ndepth
>
0
);
noffset
=
fdt_next_node
(
info
->
fit
,
noffset
,
&
ndepth
))
{
if
(
ndepth
==
1
&&
noffset
!=
node
)
{
ret
=
rsa_verify_with_keynode
(
info
,
hash
,
sig
,
sig_len
,
noffset
);
if
(
!
ret
)
break
;
}
}
return
ret
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment