Files
darling-lol/patches/corecrypto.patch
T

495 lines
18 KiB
Diff

diff --git a/src/ccder.c b/src/ccder.c
index 5543c42..e843f46 100644
--- a/src/ccder.c
+++ b/src/ccder.c
@@ -308,8 +308,15 @@ ccder_encode_body(size_t size, const uint8_t* body,
return body_start;
}
+// As in Apple's implementation, the decoders accept a NULL `der` (the failed
+// result of a previous decode step) and return NULL for input that is
+// truncated or does not carry the expected tag.
const uint8_t *ccder_decode_tag(ccder_tag *tagp, const uint8_t *der, const uint8_t *der_end) {
size_t tag_len = 1;
+
+ if (der == NULL || der >= der_end)
+ return NULL;
+
*tagp = ((ccder_tag)(der[0] >> 5)) << CCDER_TAG_MASK_SHIFT_BACK;
if ((der[0] & 0x1f) == 0x1f) {
@@ -317,11 +324,13 @@ const uint8_t *ccder_decode_tag(ccder_tag *tagp, const uint8_t *der, const uint8
// 0x80 == 0b10000000
size_t i = 0;
do {
+ if (der + i + 1 >= der_end)
+ return NULL;
// 0x7f == 0b01111111
*tagp |= (((ccder_tag)der[i + 1] & 0x7fU) << (i * 7));
++i;
++tag_len;
- } while (der[i + 1] & 0x80);
+ } while (der[i] & 0x80);
*tagp <<= 5;
*tagp |= 0x1f;
} else {
@@ -333,26 +342,40 @@ const uint8_t *ccder_decode_tag(ccder_tag *tagp, const uint8_t *der, const uint8
}
const uint8_t* ccder_decode_len(size_t* lenp, const uint8_t* der, const uint8_t* der_end) {
- size_t len_len = 1;
+ size_t len = 0;
+
+ if (der == NULL || der >= der_end)
+ return NULL;
if (der[0] & 0x80) {
// long form
- len_len = der[0] & 0x7f;
+ size_t len_len = der[0] & 0x7f;
++der;
+ if (len_len == 0 || len_len > sizeof(size_t) || (size_t)(der_end - der) < len_len)
+ return NULL;
for (size_t i = len_len; i > 0; --i)
- *lenp |= (size_t)der[len_len - i] << ((i - 1) * 8);
+ len |= (size_t)der[len_len - i] << ((i - 1) * 8);
+ der += len_len;
} else {
// short form
- *lenp = der[0] & 0x7f;
+ len = der[0] & 0x7f;
+ ++der;
}
- return der + len_len;
+ if ((size_t)(der_end - der) < len)
+ return NULL;
+
+ *lenp = len;
+ return der;
}
const uint8_t *ccder_decode_tl(ccder_tag expected_tag, size_t *lenp,
const uint8_t *der, const uint8_t *der_end) {
ccder_tag tag_found = 0;
- return ccder_decode_len(lenp, ccder_decode_tag(&tag_found, der, der_end), der_end);
+ der = ccder_decode_tag(&tag_found, der, der_end);
+ if (der == NULL || tag_found != expected_tag)
+ return NULL;
+ return ccder_decode_len(lenp, der, der_end);
}
const uint8_t *
@@ -360,6 +383,10 @@ ccder_decode_constructed_tl(ccder_tag expected_tag, const uint8_t **body_end,
const uint8_t *der, const uint8_t *der_end) {
size_t body_len = 0;
const uint8_t* body_start = ccder_decode_tl(expected_tag, &body_len, der, der_end);
+ if (body_start == NULL) {
+ *body_end = der;
+ return NULL;
+ }
*body_end = body_start + body_len;
return body_start;
}
@@ -367,21 +394,16 @@ ccder_decode_constructed_tl(ccder_tag expected_tag, const uint8_t **body_end,
const uint8_t *
ccder_decode_sequence_tl(const uint8_t **body_end,
const uint8_t *der, const uint8_t *der_end) {
- // NOTE(@facekapow):
- // we don't just call `ccder_decode_constructed_tl` because in the future,
- // that method will check that the decoded tag is a CONSTRUCTED tag
-
- size_t body_len = 0;
- const uint8_t* body_start = ccder_decode_tl(CCDER_SEQUENCE, &body_len, der, der_end);
- *body_end = body_start + body_len;
- return body_start;
+ return ccder_decode_constructed_tl(CCDER_CONSTRUCTED_SEQUENCE, body_end, der, der_end);
}
const uint8_t *ccder_decode_uint_n(cc_size *n,
const uint8_t *der, const uint8_t *der_end) {
size_t num_len = 0;
const uint8_t* num_start = ccder_decode_tl(CCDER_INTEGER, &num_len, der, der_end);
- while (num_start[0] == 0) {
+ if (num_start == NULL)
+ return NULL;
+ while (num_len > 0 && num_start[0] == 0) {
--num_len;
++num_start;
}
@@ -393,7 +415,9 @@ const uint8_t *ccder_decode_uint(cc_size n, cc_unit *r,
const uint8_t *der, const uint8_t *der_end) {
size_t num_len = 0;
const uint8_t* num_start = ccder_decode_tl(CCDER_INTEGER, &num_len, der, der_end);
- while (num_start[0] == 0) {
+ if (num_start == NULL)
+ return NULL;
+ while (num_len > 0 && num_start[0] == 0) {
--num_len;
++num_start;
}
@@ -405,7 +429,9 @@ const uint8_t *ccder_decode_uint64(uint64_t* r,
const uint8_t *der, const uint8_t *der_end) {
size_t num_len = 0;
const uint8_t* num_start = ccder_decode_tl(CCDER_INTEGER, &num_len, der, der_end);
- while (num_start[0] == 0) {
+ if (num_start == NULL)
+ return NULL;
+ while (num_len > 0 && num_start[0] == 0) {
--num_len;
++num_start;
}
@@ -422,13 +448,15 @@ const uint8_t *ccder_decode_uint64(uint64_t* r,
const uint8_t *ccder_decode_seqii(cc_size n, cc_unit *r, cc_unit *s,
const uint8_t *der, const uint8_t *der_end) {
size_t seq_len = 0;
- return ccder_decode_uint(n, s, ccder_decode_uint(n, r, ccder_decode_tl(CCDER_SEQUENCE, &seq_len, der, der_end), der_end), der_end);
+ return ccder_decode_uint(n, s, ccder_decode_uint(n, r, ccder_decode_tl(CCDER_CONSTRUCTED_SEQUENCE, &seq_len, der, der_end), der_end), der_end);
}
const uint8_t *ccder_decode_oid(ccoid_t *oidp,
const uint8_t *der, const uint8_t *der_end) {
size_t oid_len = 0;
const uint8_t* oid_start = ccder_decode_tl(CCDER_OBJECT_IDENTIFIER, &oid_len, der, der_end);
+ if (oid_start == NULL)
+ return NULL;
size_t total_len = (size_t)(oid_start - der) + oid_len;
CCOID(*oidp) = der;
@@ -441,6 +469,8 @@ const uint8_t *ccder_decode_bitstring(const uint8_t **bit_string,
const uint8_t *der, const uint8_t *der_end) {
size_t byte_len = 0;
const uint8_t* bit_start = ccder_decode_tl(CCDER_BIT_STRING, &byte_len, der, der_end);
+ if (bit_start == NULL)
+ return NULL;
// NOTE(@facekapow):
// i'm not sure if Apple's API meant to include the *entire* bitstring including the leading
diff --git a/src/ccec.c b/src/ccec.c
index 8efd8fb..8c8dfcc 100644
--- a/src/ccec.c
+++ b/src/ccec.c
@@ -458,18 +458,17 @@ static const struct {
CC_UNIT_FORMAT_2(01, ff),
// }
// reciprocal of modulus p {
- // full hex = 20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
- CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 01),
+ // full hex = 80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000
CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
+ CC_UNIT_FORMAT_8(00, 00, 40, 00, 00, 00, 00, 00),
CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
- CC_UNIT_FORMAT_2(02, 00),
- // necessary because the reciprocal *must* be `n + 1` units in length
- CC_UNIT_FORMAT_1(00),
+ CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
+ CC_UNIT_FORMAT_8(00, 80, 00, 00, 00, 00, 00, 00),
// }
// coefficient a {
// full hex = 01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc
@@ -532,18 +531,17 @@ static const struct {
CC_UNIT_FORMAT_2(01, ff),
// }
// reciprocal of order n {
- // full hex = 2000000000000000000000000000000000000000000000000000000000000000005ae79787c40d069948033feb708f65a2fc44a36477663b851449048e16ec79bf7
- CC_UNIT_FORMAT_8(44, 90, 48, e1, 6e, c7, 9b, f7),
- CC_UNIT_FORMAT_8(c4, 4a, 36, 47, 76, 63, b8, 51),
- CC_UNIT_FORMAT_8(80, 33, fe, b7, 08, f6, 5a, 2f),
- CC_UNIT_FORMAT_8(ae, 79, 78, 7c, 40, d0, 69, 94),
- CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 05),
+ // full hex = 8000000000000000000000000000000000000000000000000000000000000000016b9e5e1f10341a65200cffadc23d968bf1128d91dd98ee14512412385bb1e6fdc408f501c8d1cd2dad1d7f46221c
+ CC_UNIT_FORMAT_8(cd, 2d, ad, 1d, 7f, 46, 22, 1c),
+ CC_UNIT_FORMAT_8(e6, fd, c4, 08, f5, 01, c8, d1),
+ CC_UNIT_FORMAT_8(ee, 14, 51, 24, 12, 38, 5b, b1),
+ CC_UNIT_FORMAT_8(96, 8b, f1, 12, 8d, 91, dd, 98),
+ CC_UNIT_FORMAT_8(1a, 65, 20, 0c, ff, ad, c2, 3d),
+ CC_UNIT_FORMAT_8(00, 01, 6b, 9e, 5e, 1f, 10, 34),
CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
CC_UNIT_FORMAT_8(00, 00, 00, 00, 00, 00, 00, 00),
- CC_UNIT_FORMAT_2(02, 00),
- // necessary because the reciprocal *must* be `n + 1` units in length
- CC_UNIT_FORMAT_1(00),
+ CC_UNIT_FORMAT_8(00, 80, 00, 00, 00, 00, 00, 00),
// }
// cofactor h {
// full hex = 01
@@ -624,7 +622,9 @@ int ccec_import_pub(ccec_const_cp_t cp, size_t in_len, const uint8_t* in, ccec_p
}
const cc_size n = cczp_n(cp.zp);
- const cc_size size = ccn_sizeof_n(n);
+ // X9.63 coordinates are as wide as the prime, not as the limbs holding it
+ // (P-521 is 66 bytes in 9 limbs, i.e. 72 bytes)
+ const size_t size = ccec_cp_prime_size(cp);
if (in_len != (2 * size) + 1) {
#if DEBUG
@@ -675,7 +675,24 @@ int ccec_verify(ccec_pub_ctx_t key, size_t digest_len, const uint8_t* digest, si
cc_unit e[n];
memset(e, 0, sizeof e);
- ccn_read_uint(n, e, (log_2_n >= 8 * digest_len) ? (log_2_n + 7) / 8 : digest_len, digest);
+ {
+ // ANSI X9.62: e is the leftmost bitlen(order) bits of the digest
+ size_t use_len = digest_len;
+ if (8 * use_len > log_2_n)
+ use_len = (log_2_n + 7) / 8;
+
+ ccn_read_uint(n, e, use_len, digest);
+
+ const size_t excess_bits = 8 * use_len - log_2_n;
+ if (8 * use_len > log_2_n && excess_bits > 0) {
+ // excess_bits is below 8, so a single pass over the units suffices
+ for (cc_size i = 0; i < n; ++i) {
+ e[i] >>= excess_bits;
+ if (i + 1 < n)
+ e[i] |= e[i + 1] << (CCN_UNIT_BITS - excess_bits);
+ }
+ }
+ }
cc_unit r[n];
cc_unit s[n];
diff --git a/src/ccn.c b/src/ccn.c
index 3bfc8d1..e5c26b0 100644
--- a/src/ccn.c
+++ b/src/ccn.c
@@ -216,185 +216,37 @@ void ccn_lcm(cc_size n, cc_unit *r2n, const cc_unit *s, const cc_unit *t) {
#define CC_COMBINE(lo, hi) ((hi << (CCN_UNIT_BITS >> 1)) | lo)
void ccn_mul(cc_size n, cc_unit *r_2n, const cc_unit *s, const cc_unit *t) {
- // we're using the karatsuba algorithm in base 2^64
- // in the following pseudocode, B is the base of the numbers
- /*
- procedure karatsuba(num1, num2)
- if (num1 < B) and (num2 < B)
- return num1 * num2
-
- // Calculates the size of the numbers.
- m = max(size_base(num1, B), size_base(num2, B))
- m2 = floor(m / 2)
-
- // Split the digit sequences in the middle.
- high1, low1 = split_at(num1, m2)
- high2, low2 = split_at(num2, m2)
-
- // 3 calls made to numbers approximately half the size.
- z0 = karatsuba(low1, low2)
- z1 = karatsuba(high1, high2)
- z2 = karatsuba((low1 + high1), (low2 + high2))
-
- t0 = (z2 - z0 - z1) * (B ** m2)
- t1 = z1 * (B ** (m2 * 2))
- // this is equivalent to:
- // t0 = (z2 - z0 - z1) << m2
- // t1 = z1 << (m2 * 2)
-
- return t0 + t1 + z0
- */
- cc_size s_n = ccn_n(n, s);
- cc_size t_n = ccn_n(n, t);
-
+ // schoolbook multiplication; the operands here are at most a few dozen
+ // units, where it is faster than any divide and conquer scheme.
+ // the result must not overlap the operands.
memset(r_2n, 0, ccn_sizeof_n(n * 2));
- if (s_n < 2 && t_n < 2) {
- // multiplication algorithm that prevents overflow
- // based on https://stackoverflow.com/a/1815371
- const cc_unit s_hi = CC_HI_BITS(s[0]);
- const cc_unit s_lo = CC_LO_BITS(s[0]);
- const cc_unit t_hi = CC_HI_BITS(t[0]);
- const cc_unit t_lo = CC_LO_BITS(t[0]);
-
- cc_unit x = s_lo * t_lo;
- const cc_unit prod_0 = CC_LO_BITS(x);
-
- x = s_hi * t_lo + CC_HI_BITS(x);
- cc_unit prod_1 = CC_LO_BITS(x);
- cc_unit prod_2 = CC_HI_BITS(x);
-
- x = prod_1 + s_lo * t_hi;
- prod_1 = CC_LO_BITS(x);
-
- x = prod_2 + s_hi * t_hi + CC_HI_BITS(x);
+#if CCN_UNIT_SIZE == 8
+ for (cc_size i = 0; i < n; ++i) {
+ unsigned __int128 carry = 0;
+ const cc_unit s_i = s[i];
- r_2n[0] = CC_COMBINE(prod_0, prod_1);
- r_2n[1] = x;
+ for (cc_size j = 0; j < n; ++j) {
+ const unsigned __int128 accumulator = (unsigned __int128)s_i * t[j] + r_2n[i + j] + carry;
+ r_2n[i + j] = (cc_unit)accumulator;
+ carry = accumulator >> 64;
+ }
- return;
+ r_2n[i + n] = (cc_unit)carry;
}
+#else
+ for (cc_size i = 0; i < n; ++i) {
+ uint64_t carry = 0;
- cc_size max_n = s_n > t_n ? s_n : t_n;
- cc_size half_n = (max_n + 1) / 2;
- cc_size result_n = max_n * 2;
- cc_size intermediate_mul_n = (half_n * 2) + 2;
-
- cc_size max_size = ccn_sizeof_n(max_n);
- cc_size half_size = ccn_sizeof_n(half_n);
- cc_size half_size_for_addition = ccn_sizeof_n(half_n + 1);
- cc_size result_size = ccn_sizeof_n(result_n);
- cc_size intermediate_mul_size = ccn_sizeof_n(intermediate_mul_n);
- cc_size hi_half_size = max_size - half_size;
-
- // half_size_for_addition is used to allocate enough for addition
- // later when we do `hi + lo -> lo`
-
- cc_unit* s_hi = __builtin_alloca(half_size);
- cc_unit* s_lo = __builtin_alloca(half_size_for_addition);
-
- cc_unit* t_hi = __builtin_alloca(half_size);
- cc_unit* t_lo = __builtin_alloca(half_size_for_addition);
-
- memset(s_hi, 0, half_size);
- memset(s_lo, 0, half_size_for_addition);
- memset(t_hi, 0, half_size);
- memset(t_lo, 0, half_size_for_addition);
-
- // copy `half_size` bytes from `s` into `s_lo`
- memcpy(s_lo, s, half_size);
- // copy the rest into `s_hi`
- memcpy(s_hi, (uint8_t*)s + half_size, hi_half_size);
-
- // copy `half_size` bytes from `t` into `t_lo`
- memcpy(t_lo, t, half_size);
- // copy the rest into `t_hi`
- memcpy(t_hi, (uint8_t*)t + half_size, hi_half_size);
-
- cc_unit* z0 = __builtin_alloca(intermediate_mul_size);
- cc_unit* z1 = __builtin_alloca(intermediate_mul_size);
- cc_unit* z2 = __builtin_alloca(intermediate_mul_size);
-
- memset(z0, 0, intermediate_mul_size);
- memset(z1, 0, intermediate_mul_size);
- memset(z2, 0, intermediate_mul_size);
-
- // z0 = s_lo * t_lo
- ccn_mul(half_n, z0, s_lo, t_lo);
- // z1 = s_hi * t_hi
- ccn_mul(half_n, z1, s_hi, t_hi);
-
- // we add the `hi`s directly into the `lo`s to avoid additional allocations
-
- // s_lo = s_lo + s_hi
- cc_unit s_carry = ccn_add(half_n, s_lo, s_lo, s_hi);
- // t_lo = t_lo + s_hi
- cc_unit t_carry = ccn_add(half_n, t_lo, t_lo, t_hi);
-
- // this is safe; remember we already allocated an extra unit in the `lo`s
- s_lo[half_n] = s_carry;
- t_lo[half_n] = t_carry;
-
- // z2 = (s_lo + s_hi) * (t_lo + t_hi)
- ccn_mul(half_n + 1, z2, s_lo, t_lo);
-
- cc_unit* t0 = __builtin_alloca(result_size);
- cc_unit* t1 = __builtin_alloca(result_size);
-
- memset(t0, 0, result_size);
- memset(t1, 0, result_size);
-
- // since we don't use z2 anymore, we can just subtract z1 and z0
- // directly into it to avoid additional allocations
-
- // z2 = z2 - z1
- ccn_sub(intermediate_mul_n, z2, z2, z1);
- // z2 = z2 - z0
- ccn_sub(intermediate_mul_n, z2, z2, z0);
-
- // t0 = z2 - z1 - z0
- // technically, this is `t0 = z2` because we already subtracted them into z2
- ccn_set(intermediate_mul_n, t0, z2);
- // t0 = z1
- ccn_set(intermediate_mul_n, t1, z1);
-
- const cc_unit* t0_end = t0 + result_n;
- const cc_unit* t1_end = t1 + result_n;
-
- // t0 = t0 << half_n
- //
- // shift t0 to the left by `half_n` units
- // (which in little endian is actually shifting the bytes right)
- //
- // why don't we use `ccn_shift_left`? remember that we're in base 2^64
- // `ccn_shift_left` shifts base-2 bits, not base-2^64 bits (i.e. units)
- for (cc_size i = intermediate_mul_n; i > 0; --i) {
- cc_unit* tgt = t0 + half_n + (i - 1);
- // make sure that the target isn't past our boundary
- if (tgt < t0_end)
- *tgt = t0[i - 1];
- }
- // zero the previously occupied bytes
- for (cc_size i = 0; i < half_n; ++i)
- t0[i] = 0;
+ for (cc_size j = 0; j < n; ++j) {
+ const uint64_t accumulator = (uint64_t)s[i] * t[j] + r_2n[i + j] + carry;
+ r_2n[i + j] = (cc_unit)accumulator;
+ carry = accumulator >> CCN_UNIT_BITS;
+ }
- // t1 = t1 << (half_n * 2)
- //
- // shift t1 to the left by `half_n * 2` units
- for (cc_size i = intermediate_mul_n; i > 0; --i) {
- cc_unit* tgt = t1 + (half_n * 2) + (i - 1);
- // make sure that the target isn't past our boundary
- if (tgt < t1_end)
- *tgt = t1[i - 1];
+ r_2n[i + n] = (cc_unit)carry;
}
- // zero the previously occupied bytes
- for (cc_size i = 0; i < half_n * 2; ++i)
- t1[i] = 0;
-
- // r_2n = z0 + t0 + t1
- ccn_set(intermediate_mul_n, r_2n, z0);
- ccn_add(result_n, r_2n, r_2n, t0);
- ccn_add(result_n, r_2n, r_2n, t1);
+#endif
}
void ccn_mul_ws(cc_size count, cc_unit *r, const cc_unit *s, const cc_unit *t, cc_ws_t ws) {
diff --git a/src/cczp.c b/src/cczp.c
index 7a7d0a6..b4d3081 100644
--- a/src/cczp.c
+++ b/src/cczp.c
@@ -114,13 +114,11 @@ void cczp_mod(cczp_const_t zp, cc_unit* result, const cc_unit* operand, cc_ws_t
memset(r_extra, 0, normal_size);
bool underflow = ccn_sub(n + 1, r_extra, r_1, r_2);
- // `if r < 0`
- if (underflow) {
- for (cc_size i = 0; i < n + 1; ++i)
- r_extra[i] = ~r_extra[i];
-
- ccn_add1(n + 1, r_extra, r_extra, 1);
- }
+ // `if r < 0, r = r + b^(k + 1)`
+ // the subtraction above wrapped modulo b^(k + 1), which is exactly that
+ // addition. (Negating the wrapped value instead yields something close to
+ // b^(k + 1), and the loop below would then run for ~2^64 iterations.)
+ (void)underflow;
// `while r >= m`
while (ccn_cmp(n + 1, r_extra, m_copy) >= 0) {