dep-mongoose/src/tls_rsa.c
Sergio R. Caprile a9df523f76 assorted patches
2026-06-23 13:38:35 -03:00

953 lines
25 KiB
C

#include "sha256.h"
#include "tls.h"
#include "tls_rsa.h"
#include "util.h"
#if MG_TLS == MG_TLS_BUILTIN
/*
* The RSA bigint backend below is derived from BearSSL's i31 RSA code.
*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#define BR_MAX_RSA_SIZE 4096
#define BR_MAX_RSA_FACTOR ((BR_MAX_RSA_SIZE + 64) >> 1)
#define BR_I31_WORDS(bits) (2 + (((bits) + 30) / 31))
#define BR_RSA_WORDS BR_I31_WORDS(BR_MAX_RSA_SIZE)
#define BR_RSA_FACTOR_WORDS BR_I31_WORDS(BR_MAX_RSA_FACTOR)
#define BR_64 1
#define MUL31(x, y) ((uint64_t) (x) * (uint64_t) (y))
#define MUL31_lo(x, y) (((uint32_t) (x) * (uint32_t) (y)) & 0x7fffffffU)
#define CCOPY br_ccopy
static uint32_t NOT(uint32_t ctl) { return ctl ^ 1; }
static uint32_t MUX(uint32_t ctl, uint32_t x, uint32_t y) {
return y ^ (-ctl & (x ^ y));
}
static uint32_t EQ(uint32_t x, uint32_t y) {
uint32_t q = x ^ y;
return NOT((q | -q) >> 31);
}
static uint32_t NEQ(uint32_t x, uint32_t y) {
uint32_t q = x ^ y;
return (q | -q) >> 31;
}
static uint32_t GT(uint32_t x, uint32_t y) {
uint32_t z = y - x;
return (z ^ ((x ^ y) & (x ^ z))) >> 31;
}
#define GE(x, y) NOT(GT(y, x))
#define LT(x, y) GT(y, x)
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;
}
static void br_enc32be(void *dst, uint32_t x) {
unsigned char *buf = (unsigned char *) dst;
buf[0] = (unsigned char) (x >> 24);
buf[1] = (unsigned char) (x >> 16);
buf[2] = (unsigned char) (x >> 8);
buf[3] = (unsigned char) x;
}
static void br_ccopy(uint32_t ctl, void *dst, const void *src, size_t len) {
unsigned char *d = (unsigned char *) dst;
const unsigned char *s = (const unsigned char *) src;
while (len-- > 0) {
uint32_t x = *s++, y = *d;
*d++ = (unsigned char) MUX(ctl, x, y);
}
}
static uint32_t br_i31_add(uint32_t *, const uint32_t *, uint32_t);
static uint32_t br_i31_sub(uint32_t *, const uint32_t *, uint32_t);
static uint32_t br_i31_bit_length(uint32_t *, size_t);
static void br_i31_decode(uint32_t *, const void *, size_t);
static void br_i31_encode(void *, size_t, const uint32_t *);
static uint32_t br_i31_ninv31(uint32_t);
static uint32_t br_divrem(uint32_t, uint32_t, uint32_t, uint32_t *);
static void br_i31_muladd_small(uint32_t *, uint32_t, const uint32_t *);
static void br_i31_reduce(uint32_t *, const uint32_t *, const uint32_t *);
static void br_i31_rshift(uint32_t *, int);
static void br_i31_decode_reduce(uint32_t *, const void *, size_t, const uint32_t *);
static void br_i31_mulacc(uint32_t *, const uint32_t *, const uint32_t *);
static void br_i31_montymul(uint32_t *, const uint32_t *, const uint32_t *, const uint32_t *, uint32_t);
static void br_i31_to_monty(uint32_t *, const uint32_t *);
static void br_i31_modpow(uint32_t *, const unsigned char *, size_t, const uint32_t *, uint32_t, uint32_t *, uint32_t *);
static void br_i31_zero(uint32_t *x, uint32_t bit_len) {
*x++ = bit_len;
memset(x, 0, ((bit_len + 31) >> 5) * sizeof *x);
}
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;
}
static uint32_t br_div(uint32_t hi, uint32_t lo, uint32_t d) {
uint32_t r;
return br_divrem(hi, lo, d, &r);
}
static uint32_t
br_i31_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;
cc = naw >> 31;
a[u] = MUX(ctl, naw & (uint32_t)0x7FFFFFFF, aw);
}
return cc;
}
static uint32_t
br_i31_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;
cc = naw >> 31;
a[u] = MUX(ctl, naw & 0x7FFFFFFF, aw);
}
return cc;
}
static uint32_t
br_i31_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);
}
static void
br_i31_decode(uint32_t *x, const void *src, size_t len)
{
const unsigned char *buf;
size_t u, v;
uint32_t acc;
int acc_len;
buf = (const unsigned char *) src;
u = len;
v = 1;
acc = 0;
acc_len = 0;
while (u -- > 0) {
uint32_t b;
b = buf[u];
acc |= (b << acc_len);
acc_len += 8;
if (acc_len >= 31) {
x[v ++] = acc & (uint32_t)0x7FFFFFFF;
acc_len -= 31;
acc = b >> (8 - acc_len);
}
}
if (acc_len != 0) {
x[v ++] = acc;
}
x[0] = br_i31_bit_length(x + 1, v - 1);
}
static void
br_i31_encode(void *dst, size_t len, const uint32_t *x)
{
unsigned char *buf;
size_t k, xlen;
uint32_t acc;
int acc_len;
xlen = (x[0] + 31) >> 5;
if (xlen == 0) {
memset(dst, 0, len);
return;
}
buf = (unsigned char *)dst + len;
k = 1;
acc = 0;
acc_len = 0;
while (len != 0) {
uint32_t w;
w = (k <= xlen) ? x[k] : 0;
k ++;
if (acc_len == 0) {
acc = w;
acc_len = 31;
} else {
uint32_t z;
z = acc | (w << acc_len);
acc_len --;
acc = w >> (31 - acc_len);
if (len >= 4) {
buf -= 4;
len -= 4;
br_enc32be(buf, z);
} else {
switch (len) {
case 3:
buf[-3] = (unsigned char)(z >> 16);
/* fall through */
case 2:
buf[-2] = (unsigned char)(z >> 8);
/* fall through */
case 1:
buf[-1] = (unsigned char)z;
break;
}
return;
}
}
}
}
static uint32_t
br_i31_ninv31(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) & 0x7FFFFFFF;
}
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;
}
static void
br_i31_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m)
{
uint32_t m_bitlen;
unsigned mblr;
size_t u, mlen;
uint32_t a0, a1, b0, hi, g, q, tb;
uint32_t under, over;
uint32_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 <= 31) {
uint32_t lo;
hi = x[1] >> 1;
lo = (x[1] << 31) | z;
x[1] = br_rem(hi, lo, m[1]);
return;
}
mlen = (m_bitlen + 31) >> 5;
mblr = (unsigned)m_bitlen & 31;
/*
* Principle: we estimate the quotient (x*2^31+z)/m by
* doing a 64/32 division with the high words.
*
* Let:
* w = 2^31
* 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 < b0)
* Then the following holds:
* 0 <= u <= w
* u-2 <= q <= u
*/
hi = x[mlen];
if (mblr == 0) {
a0 = x[mlen];
memmove(x + 2, x + 1, (mlen - 1) * sizeof *x);
x[1] = z;
a1 = x[mlen];
b0 = m[mlen];
} else {
a0 = ((x[mlen] << (31 - mblr)) | (x[mlen - 1] >> mblr))
& 0x7FFFFFFF;
memmove(x + 2, x + 1, (mlen - 1) * sizeof *x);
x[1] = z;
a1 = ((x[mlen] << (31 - mblr)) | (x[mlen - 1] >> mblr))
& 0x7FFFFFFF;
b0 = ((m[mlen] << (31 - mblr)) | (m[mlen - 1] >> mblr))
& 0x7FFFFFFF;
}
/*
* We estimate a divisor q. If the quotient returned by br_div()
* is g:
* -- If a0 == b0 then g == 0; we want q = 0x7FFFFFFF.
* -- 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.
*
* Take care that a0, a1 and b0 are 31-bit words, not 32-bit. We
* must adjust the parameters to br_div() accordingly.
*/
g = br_div(a0 >> 1, a1 | (a0 << 31), b0);
q = MUX(EQ(a0, b0), 0x7FFFFFFF, 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 = MUL31(mw, q) + cc;
cc = (uint32_t)(zl >> 31);
zw = (uint32_t)zl & (uint32_t)0x7FFFFFFF;
xw = x[u];
nxw = xw - zw;
cc += nxw >> 31;
nxw &= 0x7FFFFFFF;
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.
*/
over = GT(cc, hi);
under = ~over & (tb | LT(cc, hi));
br_i31_add(x, m, over);
br_i31_sub(x, m, under);
}
static void
br_i31_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_i31_muladd_small(x, a[u], m);
}
}
static void
br_i31_rshift(uint32_t *x, int count)
{
size_t u, len;
uint32_t r;
len = (x[0] + 31) >> 5;
if (len == 0) {
return;
}
r = x[1] >> count;
for (u = 2; u <= len; u ++) {
uint32_t w;
w = x[u];
x[u - 1] = ((w << (31 - count)) | r) & 0x7FFFFFFF;
r = w >> count;
}
x[len] = r;
}
static void
br_i31_decode_reduce(uint32_t *x,
const void *src, size_t len, const uint32_t *m)
{
uint32_t m_ebitlen, m_rbitlen;
size_t mblen, k;
const unsigned char *buf;
uint32_t acc;
int acc_len;
/*
* Get the encoded bit length.
*/
m_ebitlen = m[0];
/*
* Special case for an invalid (null) modulus.
*/
if (m_ebitlen == 0) {
x[0] = 0;
return;
}
/*
* Clear the destination.
*/
br_i31_zero(x, m_ebitlen);
/*
* First decode directly as many bytes as possible. This requires
* computing the actual bit length.
*/
m_rbitlen = m_ebitlen >> 5;
m_rbitlen = (m_ebitlen & 31) + (m_rbitlen << 5) - m_rbitlen;
mblen = (m_rbitlen + 7) >> 3;
k = mblen - 1;
if (k >= len) {
br_i31_decode(x, src, len);
x[0] = m_ebitlen;
return;
}
buf = (const unsigned char *) src;
br_i31_decode(x, buf, k);
x[0] = m_ebitlen;
/*
* Input remaining bytes, using 31-bit words.
*/
acc = 0;
acc_len = 0;
while (k < len) {
uint32_t v;
v = buf[k ++];
if (acc_len >= 23) {
acc_len -= 23;
acc <<= (8 - acc_len);
acc |= v >> acc_len;
br_i31_muladd_small(x, acc, m);
acc = v & (0xFF >> (8 - acc_len));
} else {
acc = (acc << 8) | v;
acc_len += 8;
}
}
/*
* We may have some bits accumulated. We then perform a shift to
* be able to inject these bits as a full 31-bit word.
*/
if (acc_len != 0) {
acc = (acc | (x[1] << acc_len)) & 0x7FFFFFFF;
br_i31_rshift(x, 31 - acc_len);
br_i31_muladd_small(x, acc, m);
}
}
static void
br_i31_mulacc(uint32_t *d, const uint32_t *a, const uint32_t *b)
{
size_t alen, blen, u;
uint32_t dl, dh;
alen = (a[0] + 31) >> 5;
blen = (b[0] + 31) >> 5;
/*
* We want to add the two bit lengths, but these are encoded,
* which requires some extra care.
*/
dl = (a[0] & 31) + (b[0] & 31);
dh = (a[0] >> 5) + (b[0] >> 5);
d[0] = (dh << 5) + dl + (~(uint32_t)(dl - 31) >> 31);
for (u = 0; u < blen; u ++) {
uint32_t f;
size_t v;
/*
* Carry always fits on 31 bits; we want to keep it in a
* 32-bit register on 32-bit architectures (on a 64-bit
* architecture, cast down from 64 to 32 bits means
* clearing the high bits, which is not free; on a 32-bit
* architecture, the same operation really means ignoring
* the top register, which has negative or zero cost).
*/
#if BR_64
uint64_t cc;
#else
uint32_t cc;
#endif
f = b[1 + u];
cc = 0;
for (v = 0; v < alen; v ++) {
uint64_t z;
z = (uint64_t)d[1 + u + v] + MUL31(f, a[1 + v]) + cc;
cc = z >> 31;
d[1 + u + v] = (uint32_t)z & 0x7FFFFFFF;
}
d[1 + u + alen] = (uint32_t)cc;
}
}
static void
br_i31_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y,
const uint32_t *m, uint32_t m0i)
{
/*
* Each outer loop iteration computes:
* d <- (d + xu*y + f*m) / 2^31
* We have xu <= 2^31-1 and f <= 2^31-1.
* Thus, if d <= 2*m-1 on input, then:
* 2*m-1 + 2*(2^31-1)*m <= (2^32)*m-1
* and the new d value is less than 2*m.
*
* We represent d over 31-bit words, with an extra word 'dh'
* which can thus be only 0 or 1.
*/
size_t len, len4, u, v;
uint32_t dh;
len = (m[0] + 31) >> 5;
len4 = len & ~(size_t)3;
br_i31_zero(d, m[0]);
dh = 0;
for (u = 0; u < len; u ++) {
/*
* The carry for each operation fits on 32 bits:
* d[v+1] <= 2^31-1
* xu*y[v+1] <= (2^31-1)*(2^31-1)
* f*m[v+1] <= (2^31-1)*(2^31-1)
* r <= 2^32-1
* (2^31-1) + 2*(2^31-1)*(2^31-1) + (2^32-1) = 2^63 - 2^31
* After division by 2^31, the new r is then at most 2^32-1
*
* Using a 32-bit carry has performance benefits on 32-bit
* systems; however, on 64-bit architectures, we prefer to
* keep the carry (r) in a 64-bit register, thus avoiding some
* "clear high bits" operations.
*/
uint32_t f, xu;
#if BR_64
uint64_t r;
#else
uint32_t r;
#endif
xu = x[u + 1];
f = MUL31_lo((d[1] + MUL31_lo(x[u + 1], y[1])), m0i);
r = 0;
for (v = 0; v < len4; v += 4) {
uint64_t z;
z = (uint64_t)d[v + 1] + MUL31(xu, y[v + 1])
+ MUL31(f, m[v + 1]) + r;
r = z >> 31;
d[v + 0] = (uint32_t)z & 0x7FFFFFFF;
z = (uint64_t)d[v + 2] + MUL31(xu, y[v + 2])
+ MUL31(f, m[v + 2]) + r;
r = z >> 31;
d[v + 1] = (uint32_t)z & 0x7FFFFFFF;
z = (uint64_t)d[v + 3] + MUL31(xu, y[v + 3])
+ MUL31(f, m[v + 3]) + r;
r = z >> 31;
d[v + 2] = (uint32_t)z & 0x7FFFFFFF;
z = (uint64_t)d[v + 4] + MUL31(xu, y[v + 4])
+ MUL31(f, m[v + 4]) + r;
r = z >> 31;
d[v + 3] = (uint32_t)z & 0x7FFFFFFF;
}
for (; v < len; v ++) {
uint64_t z;
z = (uint64_t)d[v + 1] + MUL31(xu, y[v + 1])
+ MUL31(f, m[v + 1]) + r;
r = z >> 31;
d[v] = (uint32_t)z & 0x7FFFFFFF;
}
/*
* Since the new dh can only be 0 or 1, the addition of
* the old dh with the carry MUST fit on 32 bits, and
* thus can be done into dh itself.
*/
dh += (uint32_t) r;
d[len] = dh & 0x7FFFFFFF;
dh >>= 31;
}
/*
* We must write back the bit length because it was overwritten in
* the loop (not overwriting it would require a test in the loop,
* which would yield bigger and slower code).
*/
d[0] = m[0];
/*
* d[] may still be greater than m[] at that point; notably, the
* 'dh' word may be non-zero.
*/
br_i31_sub(d, m, NEQ(dh, 0) | NOT(br_i31_sub(d, m, 0)));
}
static void
br_i31_to_monty(uint32_t *x, const uint32_t *m)
{
uint32_t k;
for (k = (m[0] + 31) >> 5; k > 0; k --) {
br_i31_muladd_small(x, 0, m);
}
}
static void
br_i31_modpow(uint32_t *x,
const unsigned char *e, size_t elen,
const uint32_t *m, uint32_t m0i, uint32_t *t1, uint32_t *t2)
{
size_t mlen;
uint32_t k;
/*
* 'mlen' is the length of m[] expressed in bytes (including
* the "bit length" first field).
*/
mlen = ((m[0] + 63) >> 5) * sizeof m[0];
/*
* Throughout the algorithm:
* -- t1[] is in Montgomery representation; it contains x, x^2,
* x^4, x^8...
* -- The result is accumulated, in normal representation, in
* the x[] array.
* -- t2[] is used as destination buffer for each multiplication.
*
* Note that there is no need to call br_i32_from_monty().
*/
memcpy(t1, x, mlen);
br_i31_to_monty(t1, m);
br_i31_zero(x, m[0]);
x[1] = 1;
for (k = 0; k < ((uint32_t)elen << 3); k ++) {
uint32_t ctl;
ctl = (e[elen - 1 - (k >> 3)] >> (k & 7)) & 1;
br_i31_montymul(t2, x, t1, m, m0i);
CCOPY(ctl, x, t2, mlen);
br_i31_montymul(t2, t1, t1, m, m0i);
memcpy(t1, t2, mlen);
}
}
static size_t rsa_trim(const uint8_t **p, size_t n) {
while (n > 0 && **p == 0) (*p)++, n--;
return n;
}
static int rsa_i31_len(size_t nbytes) {
int z = (int) (nbytes * 8U);
int n = 1;
while (z > 0) z -= 31, n++;
return n + (n & 1);
}
static int rsa_fail(uint8_t *out, size_t outsz) {
mg_bzero(out, outsz);
return -1;
}
static int rsa_i31_eq(const uint32_t *a, const uint32_t *b) {
uint32_t r = a[0] ^ b[0];
size_t u, n = (a[0] + 31) >> 5;
for (u = 1; u <= n; u++) r |= a[u] ^ b[u];
return r == 0;
}
int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp,
size_t expsz, const uint8_t *msg, size_t msgsz,
uint8_t *out, size_t outsz) {
uint32_t tmp[4 * BR_RSA_WORDS], *m = tmp, *x, *t1, *t2, m0i;
int fwlen;
if (out == NULL) return -1;
mg_bzero(out, outsz);
if (mod == NULL || exp == NULL || msg == NULL) return -1;
modsz = rsa_trim(&mod, modsz);
expsz = rsa_trim(&exp, expsz);
if (modsz < 256 || modsz > (BR_MAX_RSA_SIZE >> 3) || expsz == 0 ||
expsz > modsz || outsz != modsz || msgsz != modsz) {
return -1;
}
if (memcmp(msg, mod, modsz) >= 0) return -1;
fwlen = rsa_i31_len(modsz);
if (4 * (size_t) fwlen > sizeof(tmp) / sizeof(tmp[0])) return -1;
x = m + fwlen, t1 = x + fwlen, t2 = t1 + fwlen;
br_i31_decode(m, mod, modsz);
m0i = br_i31_ninv31(m[1]);
if ((m0i & 1) == 0) return rsa_fail((uint8_t *) tmp, sizeof(tmp));
br_i31_decode_reduce(x, msg, msgsz, m);
br_i31_modpow(x, exp, expsz, m, m0i, t1, t2);
br_i31_encode(out, outsz, x);
mg_bzero((uint8_t *) tmp, sizeof(tmp));
return 0;
}
int mg_rsa_crt_sign(const uint8_t *em, size_t em_len,
const uint8_t *dP, size_t dP_len,
const uint8_t *dQ, size_t dQ_len,
const uint8_t *p, size_t p_len,
const uint8_t *q, size_t q_len,
const uint8_t *qInv, size_t qInv_len,
uint8_t *signature, size_t sig_len) {
uint32_t tmp[8 * BR_RSA_FACTOR_WORDS], *mq = tmp, *s2, *mp, *s1, *t1, *t2;
uint32_t *c1, *c2;
uint32_t p0i, q0i;
size_t plen, qlen, xlen = sig_len, u;
int fwlen, ok = 0;
uint8_t x[BR_MAX_RSA_SIZE >> 3];
if (signature == NULL) return -1;
mg_bzero(signature, sig_len);
if (em == NULL || dP == NULL || dQ == NULL || p == NULL || q == NULL ||
qInv == NULL) {
return -1;
}
p_len = rsa_trim(&p, p_len);
q_len = rsa_trim(&q, q_len);
dP_len = rsa_trim(&dP, dP_len);
dQ_len = rsa_trim(&dQ, dQ_len);
qInv_len = rsa_trim(&qInv, qInv_len);
if (p_len < 128 || q_len < 128 || p_len > (BR_MAX_RSA_FACTOR >> 3) ||
q_len > (BR_MAX_RSA_FACTOR >> 3) || dP_len == 0 || dQ_len == 0 ||
qInv_len == 0 || dP_len > p_len || dQ_len > q_len ||
qInv_len > p_len || xlen > sizeof(x) || em_len == 0 ||
em_len > xlen) {
return -1;
}
plen = p_len, qlen = q_len;
fwlen = rsa_i31_len(plen > qlen ? plen : qlen);
if (8 * fwlen > (int) (sizeof(tmp) / sizeof(tmp[0]))) return -1;
s2 = mq + fwlen, mp = mq + 2 * fwlen, s1 = mq + 3 * fwlen;
t1 = mq + 4 * fwlen, t2 = mq + 5 * fwlen;
c1 = mq + 6 * fwlen, c2 = mq + 7 * fwlen;
memset(x, 0, xlen - em_len);
memcpy(x + xlen - em_len, em, em_len);
br_i31_decode(mq, q, qlen);
br_i31_decode(mp, p, plen);
q0i = br_i31_ninv31(mq[1]);
p0i = br_i31_ninv31(mp[1]);
if (((p0i & q0i) & 1) == 0) goto done;
memset(t2, 0, 2 * (size_t) fwlen * sizeof(*t2));
t2[0] = mq[0];
br_i31_mulacc(t2, mq, mp);
if (xlen != ((t2[0] + 7) >> 3)) goto done;
br_i31_encode(signature, xlen, t2);
for (u = xlen, ok = 0; u > 0; u--) {
uint32_t wn = signature[u - 1], wx = x[u - 1];
ok = (int) (((wx - (wn + (uint32_t) ok)) >> 8) & 1);
}
if (!ok) goto done;
ok = 0;
br_i31_decode_reduce(s2, x, xlen, mq);
br_i31_modpow(s2, dQ, dQ_len, mq, q0i, t1, t2);
br_i31_decode_reduce(s1, x, xlen, mp);
br_i31_modpow(s1, dP, dP_len, mp, p0i, t1, t2);
memcpy(c1, s1, (size_t) fwlen * sizeof(*s1));
memcpy(c2, s2, (size_t) fwlen * sizeof(*s2));
br_i31_reduce(t2, s2, mp);
br_i31_add(s1, mp, br_i31_sub(s1, t2, 1));
br_i31_to_monty(s1, mp);
br_i31_decode_reduce(t1, qInv, qInv_len, mp);
br_i31_montymul(t2, s1, t1, mp, p0i);
br_i31_mulacc(s2, mq, t2);
br_i31_reduce(t1, s2, mq);
ok = rsa_i31_eq(t1, c2);
br_i31_decode(mp, p, plen);
br_i31_reduce(t1, s2, mp);
ok &= rsa_i31_eq(t1, c1);
if (!ok) goto done;
ok = 0;
br_i31_encode(signature, sig_len, s2);
ok = 1;
done:
mg_bzero((uint8_t *) tmp, sizeof(tmp));
mg_bzero(x, sizeof(x));
if (!ok) return rsa_fail(signature, sig_len);
return 0;
}
// MGF1-SHA256 RFC 8017 B.2.1
static void mgf1_sha256(const uint8_t *seed, size_t seed_len,
uint8_t *mask, size_t mask_len) {
uint8_t cnt[4]; // I2OSP(counter, 4), big-endian
uint8_t tmp[32]; // one SHA-256 output block
uint32_t counter = 0;
size_t off = 0;
mg_sha256_ctx ctx;
while (off < mask_len) {
size_t n = mask_len - off;
if (n > 32) n = 32;
br_enc32be(cnt, counter);
mg_sha256_init(&ctx);
mg_sha256_update(&ctx, seed, seed_len);
mg_sha256_update(&ctx, cnt, 4);
mg_sha256_final(tmp, &ctx);
memcpy(mask + off, tmp, n);
off += n;
++counter;
}
}
// Full RSASSA-PSS-VERIFY for rsa_pss_rsae_sha256 (RFC 8017 9.1.2)
// em - output of RSA public-key primitive (nlen bytes)
// nlen - modulus byte length (66 to 512)
// mhash - SHA-256 of the TLS 1.3 signed content (tls->sighash, 32 bytes)
static bool pss_verify_sha256(const uint8_t *em, size_t nlen, const uint8_t *mhash) {
// TLS 1.3: H_len = salt_len = 32
uint8_t db[479]; // unmasked DB after MGF1 XOR
uint8_t dbmask[479]; // MGF1-SHA256(H, db_len); nlen - hLen - 1 = 479
uint8_t Hprime[32]; // SHA-256(0x00*8 || mhash || salt)
uint8_t Mprime[8 + 32 + 32]; // 0*8 || mhash || salt
const uint8_t *H;
const uint8_t *salt;
size_t db_len;
size_t i;
uint8_t bad;
if (nlen < 32 + 32 + 2 || nlen - 32 - 1 > sizeof(db)) return -1;
if (em[nlen - 1] != 0xbc) return false;
if (em[0] & 0x80) return false;
db_len = nlen - 32 - 1;
H = em + db_len;
mgf1_sha256(H, 32, dbmask, db_len);
for (i = 0; i < db_len; i++) db[i] = em[i] ^ dbmask[i];
db[0] &= 0x7f; // DB = 0x00^(db_len-salt_len-1) || 0x01 || salt(salt_Len)
bad = 0;
for (i = 0; i < db_len - 32 - 1; i++) bad |= db[i];
bad |= db[db_len - 32 - 1] ^ 0x01;
if (bad != 0) return false;
salt = db + db_len - 32;
memset(Mprime, 0, 8);
memcpy(Mprime + 8, mhash, 32);
memcpy(Mprime + 8 + 32, salt, 32);
mg_sha256(Hprime, Mprime, sizeof(Mprime));
bad = 0;
for (i = 0; i < 32; i++) bad |= Hprime[i] ^ H[i];
return (bad == 0);
}
bool mg_rsa_verify(const uint8_t *em, size_t nlen, const uint8_t *mhash) {
return pss_verify_sha256(em, nlen, mhash);
}
#endif /* MG_TLS == MG_TLS_BUILTIN */