ref: e18ea66b577b3678c8897e26bc29dcbf027e2fcb
parent: a7d243ef71a1b27166c158ba148da2363402f328
author: Ori Bernstein <ori@eigenstate.org>
date: Wed Mar 4 00:24:06 EST 2026
libsec.diff: update to match current libsec
--- a/libsec.diff
+++ b/libsec.diff
@@ -1,4 +1,4 @@
-diff 051804186780ef7f3b2f4cb548be1dd0685de5fe uncommitted
+diff e1201b57f3e37d06589578280251d5b54e490317 uncommitted
--- a/sys/include/libsec.h
+++ b/sys/include/libsec.h
@@ -1,7 +1,6 @@
@@ -9,7 +9,7 @@
#ifndef _MPINT
typedef struct mpint mpint;
#endif
-@@ -318,6 +317,7 @@
+@@ -325,6 +324,7 @@
typedef struct RSApub RSApub;
typedef struct RSApriv RSApriv;
typedef struct PEMChain PEMChain;
@@ -17,7 +17,7 @@
/* public/encryption key */
struct RSApub
-@@ -347,6 +347,24 @@
+@@ -354,6 +354,24 @@
int pemlen;
};
@@ -42,7 +42,7 @@
RSApriv* rsagen(int nlen, int elen, int rounds);
RSApriv* rsafill(mpint *n, mpint *e, mpint *d, mpint *p, mpint *q);
mpint* rsaencrypt(RSApub *k, mpint *in, mpint *out);
-@@ -356,6 +374,9 @@
+@@ -363,6 +381,9 @@
RSApriv* rsaprivalloc(void);
void rsaprivfree(RSApriv*);
RSApub* rsaprivtopub(RSApriv*);
@@ -52,7 +52,7 @@
RSApub* X509toRSApub(uchar*, int, char*, int);
RSApub* X509reqtoRSApub(uchar*, int, char*, int);
RSApub* asn1toRSApub(uchar*, int);
-@@ -368,7 +389,7 @@
+@@ -375,7 +396,7 @@
char* X509rsaverify(uchar *cert, int ncert, RSApub *pk);
char* X509rsaverifydigest(uchar *sig, int siglen, uchar *edigest, int edigestlen, RSApub *pk);
@@ -61,7 +61,7 @@
mpint* pkcs1padbuf(uchar *buf, int len, mpint *modulus, int blocktype);
int pkcs1unpadbuf(uchar *buf, int len, mpint *modulus, int blocktype);
-@@ -488,7 +509,51 @@
+@@ -495,7 +516,51 @@
char *pskID;
} TLSconn;
@@ -113,6 +113,857 @@
int tlsClient(int fd, TLSconn *c);
int tlsServer(int fd, TLSconn *c);
+--- a/sys/src/libsec/port/curve25519_dh.c
++++ b/sys/src/libsec/port/curve25519_dh.c
+@@ -1,39 +1,816 @@
+ #include "os.h"
+ #include <mp.h>
+ #include <libsec.h>
++// Derived From Monocypher version 4.0.2
++//
++// This file is dual-licensed. Choose whichever licence you want from
++// the two licences listed below.
++//
++// The first licence is a regular 2-clause BSD licence. The second licence
++// is the CC-0 from Creative Commons. It is intended to release Monocypher
++// to the public domain. The BSD licence serves as a fallback option.
++//
++// SPDX-License-Identifier: BSD-2-Clause OR CC0-1.0
++//
++// ------------------------------------------------------------------------
++//
++// Copyright (c) 2017-2020, Loup Vaillant
++// All rights reserved.
++//
++//
++// Redistribution and use in source and binary forms, with or without
++// modification, are permitted provided that the following conditions are
++// met:
++//
++// 1. Redistributions of source code must retain the above copyright
++// notice, this list of conditions and the following disclaimer.
++//
++// 2. Redistributions in binary form must reproduce the above copyright
++// notice, this list of conditions and the following disclaimer in the
++// documentation and/or other materials provided with the
++// distribution.
++//
++// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++//
++// ------------------------------------------------------------------------
++//
++// Written in 2017-2020 by Loup Vaillant
++//
++// To the extent possible under law, the author(s) have dedicated all copyright
++// and related neighboring rights to this software to the public domain
++// worldwide. This software is distributed without any warranty.
++//
++// You should have received a copy of the CC0 Public Domain Dedication along
++// with this software. If not, see
++// <https://creativecommons.org/publicdomain/zero/1.0/>
+
+-static uchar nine[32] = {9};+-static uchar zero[32] = {0};++/////////////////
++/// Utilities ///
++/////////////////
++#define FOR_T(type, i, start, end) for (type i = (start); i < (end); i++)
++#define FOR(i, start, end) FOR_T(usize, i, start, end)
++#define COPY(dst, src, size) FOR(_i_, 0, size) (dst)[_i_] = (src)[_i_]
++#define ZERO(buf, size) FOR(_i_, 0, size) (buf)[_i_] = 0
++#define WIPE_CTX(ctx) crypto_wipe(ctx , sizeof(*(ctx)))
++#define WIPE_BUFFER(buffer) crypto_wipe(buffer, sizeof(buffer))
++#define MIN(a, b) ((a) <= (b) ? (a) : (b))
++#define MAX(a, b) ((a) >= (b) ? (a) : (b))
+
+-int
+-x25519(uchar out[32], uchar s[32], uchar u[32])
++typedef s8int i8;
++typedef u8int u8;
++typedef s16int i16;
++typedef u32int u32;
++typedef s32int i32;
++typedef s64int i64;
++typedef u64int u64;
++#ifdef __U_H
++typedef size_t usize;
++#endif
++
++static const u8 zero[128] = {0};++
++// returns the smallest positive integer y such that
++// (x + y) % pow_2 == 0
++// Basically, y is the "gap" missing to align x.
++// Only works when pow_2 is a power of 2.
++// Note: we use ~x+1 instead of -x to avoid compiler warnings
++static usize gap(usize x, usize pow_2)
+ {+- uchar sf, sl, ul;
++ return (~x + 1) & (pow_2 - 1);
++}
+
+- sf = s[0];
+- sl = s[31];
+- ul = u[31];
++static u32 load24_le(const u8 s[3])
++{++ return
++ ((u32)s[0] << 0) |
++ ((u32)s[1] << 8) |
++ ((u32)s[2] << 16);
++}
+
+- /* clamp */
+- s[0] &= ~7; /* clear bit 0,1,2 */
+- s[31] = 0x40 | (s[31] & 0x7f); /* set bit 254, clear bit 255 */
++static u32 load32_le(const u8 s[4])
++{++ return
++ ((u32)s[0] << 0) |
++ ((u32)s[1] << 8) |
++ ((u32)s[2] << 16) |
++ ((u32)s[3] << 24);
++}
+
+- /*
+- Implementations MUST accept non-canonical values and process them as
+- if they had been reduced modulo the field prime. The non-canonical
+- values are 2^255 - 19 through 2^255 - 1 for X25519
+- */
+- u[31] &= 0x7f;
+-
+- curve25519(out, s, u);
++static u64 load64_le(const u8 s[8])
++{++ return load32_le(s) | ((u64)load32_le(s+4) << 32);
++}
+
+- s[0] = sf;
+- s[31] = sl;
+- u[31] = ul;
++static void store32_le(u8 out[4], u32 in)
++{++ out[0] = in & 0xff;
++ out[1] = (in >> 8) & 0xff;
++ out[2] = (in >> 16) & 0xff;
++ out[3] = (in >> 24) & 0xff;
++}
+
+- return tsmemcmp(out, zero, 32) != 0;
++static void store64_le(u8 out[8], u64 in)
++{++ store32_le(out , (u32)in );
++ store32_le(out + 4, in >> 32);
+ }
+
++static void load32_le_buf (u32 *dst, const u8 *src, usize size) {++ FOR(i, 0, size) { dst[i] = load32_le(src + i*4); }++}
++static void load64_le_buf (u64 *dst, const u8 *src, usize size) {++ FOR(i, 0, size) { dst[i] = load64_le(src + i*8); }++}
++static void store32_le_buf(u8 *dst, const u32 *src, usize size) {++ FOR(i, 0, size) { store32_le(dst + i*4, src[i]); }++}
++static void store64_le_buf(u8 *dst, const u64 *src, usize size) {++ FOR(i, 0, size) { store64_le(dst + i*8, src[i]); }++}
++
++static u64 rotr64(u64 x, u64 n) { return (x >> n) ^ (x << (64 - n)); }++static u32 rotl32(u32 x, u32 n) { return (x << n) ^ (x >> (32 - n)); }++
++static int neq0(u64 diff)
++{++ // constant time comparison to zero
++ // return diff != 0 ? -1 : 0
++ u64 half = (diff >> 32) | ((u32)diff);
++ return (1 & ((half - 1) >> 32)) - 1;
++}
++
++static u64 x16(const u8 a[16], const u8 b[16])
++{++ return (load64_le(a + 0) ^ load64_le(b + 0))
++ | (load64_le(a + 8) ^ load64_le(b + 8));
++}
++static u64 x32(const u8 a[32],const u8 b[32]){return x16(a,b)| x16(a+16, b+16);}++static u64 x64(const u8 a[64],const u8 b[64]){return x32(a,b)| x32(a+32, b+32);}++int crypto_verify16(const u8 a[16], const u8 b[16]){ return neq0(x16(a, b)); }++int crypto_verify32(const u8 a[32], const u8 b[32]){ return neq0(x32(a, b)); }++int crypto_verify64(const u8 a[64], const u8 b[64]){ return neq0(x64(a, b)); }++
++void crypto_wipe(void *secret, usize size)
++{++ volatile u8 *v_secret = (u8*)secret;
++ ZERO(v_secret, size);
++}
++
++////////////////////////////////////
++/// Arithmetic modulo 2^255 - 19 ///
++////////////////////////////////////
++// Originally taken from SUPERCOP's ref10 implementation.
++// A bit bigger than TweetNaCl, over 4 times faster.
++
++// field element
++typedef i32 fe[10];
++
++// field constants
++//
++// fe_one : 1
++// sqrtm1 : sqrt(-1)
++// d : -121665 / 121666
++// D2 : 2 * -121665 / 121666
++// lop_x, lop_y: low order point in Edwards coordinates
++// ufactor : -sqrt(-1) * 2
++// A2 : 486662^2 (A squared)
++static const fe fe_one = {1};++static const fe sqrtm1 = {++ -32595792, -7943725, 9377950, 3500415, 12389472,
++ -272473, -25146209, -2005654, 326686, 11406482,
++};
++static const fe d = {++ -10913610, 13857413, -15372611, 6949391, 114729,
++ -8787816, -6275908, -3247719, -18696448, -12055116,
++};
++static const fe D2 = {++ -21827239, -5839606, -30745221, 13898782, 229458,
++ 15978800, -12551817, -6495438, 29715968, 9444199,
++};
++static const fe lop_x = {++ 21352778, 5345713, 4660180, -8347857, 24143090,
++ 14568123, 30185756, -12247770, -33528939, 8345319,
++};
++static const fe lop_y = {++ -6952922, -1265500, 6862341, -7057498, -4037696,
++ -5447722, 31680899, -15325402, -19365852, 1569102,
++};
++static const fe ufactor = {++ -1917299, 15887451, -18755900, -7000830, -24778944,
++ 544946, -16816446, 4011309, -653372, 10741468,
++};
++static const fe A2 = {++ 12721188, 3529, 0, 0, 0, 0, 0, 0, 0, 0,
++};
++
++static void fe_0(fe h) { ZERO(h , 10); }++static void fe_1(fe h) { h[0] = 1; ZERO(h+1, 9); }++
++static void fe_copy(fe h,const fe f ){FOR(i,0,10) h[i] = f[i]; }++static void fe_neg (fe h,const fe f ){FOR(i,0,10) h[i] = -f[i]; }++static void fe_add (fe h,const fe f,const fe g){FOR(i,0,10) h[i] = f[i] + g[i];}++static void fe_sub (fe h,const fe f,const fe g){FOR(i,0,10) h[i] = f[i] - g[i];}++
++static void fe_cswap(fe f, fe g, int b)
++{++ i32 mask = -b; // -1 = 0xffffffff
++ FOR (i, 0, 10) {++ i32 x = (f[i] ^ g[i]) & mask;
++ f[i] = f[i] ^ x;
++ g[i] = g[i] ^ x;
++ }
++}
++
++static void fe_ccopy(fe f, const fe g, int b)
++{++ i32 mask = -b; // -1 = 0xffffffff
++ FOR (i, 0, 10) {++ i32 x = (f[i] ^ g[i]) & mask;
++ f[i] = f[i] ^ x;
++ }
++}
++
++
++// Signed carry propagation
++// ------------------------
++//
++// Let t be a number. It can be uniquely decomposed thus:
++//
++// t = h*2^26 + l
++// such that -2^25 <= l < 2^25
++//
++// Let c = (t + 2^25) / 2^26 (rounded down)
++// c = (h*2^26 + l + 2^25) / 2^26 (rounded down)
++// c = h + (l + 2^25) / 2^26 (rounded down)
++// c = h (exactly)
++// Because 0 <= l + 2^25 < 2^26
++//
++// Let u = t - c*2^26
++// u = h*2^26 + l - h*2^26
++// u = l
++// Therefore, -2^25 <= u < 2^25
++//
++// Additionally, if |t| < x, then |h| < x/2^26 (rounded down)
++//
++// Notations:
++// - In C, 1<<25 means 2^25.
++// - In C, x>>25 means floor(x / (2^25)).
++// - All of the above applies with 25 & 24 as well as 26 & 25.
++//
++//
++// Note on negative right shifts
++// -----------------------------
++//
++// In C, x >> n, where x is a negative integer, is implementation
++// defined. In practice, all platforms do arithmetic shift, which is
++// equivalent to division by 2^26, rounded down. Some compilers, like
++// GCC, even guarantee it.
++//
++// If we ever stumble upon a platform that does not propagate the sign
++// bit (we won't), visible failures will show at the slightest test, and
++// the signed shifts can be replaced by the following:
++//
++// typedef struct { i64 x:39; } s25;++// typedef struct { i64 x:38; } s26;++// i64 shift25(i64 x) { s25 s; s.x = ((u64)x)>>25; return s.x; }++// i64 shift26(i64 x) { s26 s; s.x = ((u64)x)>>26; return s.x; }++//
++// Current compilers cannot optimise this, causing a 30% drop in
++// performance. Fairly expensive for something that never happens.
++//
++//
++// Precondition
++// ------------
++//
++// |t0| < 2^63
++// |t1|..|t9| < 2^62
++//
++// Algorithm
++// ---------
++// c = t0 + 2^25 / 2^26 -- |c| <= 2^36
++// t0 -= c * 2^26 -- |t0| <= 2^25
++// t1 += c -- |t1| <= 2^63
++//
++// c = t4 + 2^25 / 2^26 -- |c| <= 2^36
++// t4 -= c * 2^26 -- |t4| <= 2^25
++// t5 += c -- |t5| <= 2^63
++//
++// c = t1 + 2^24 / 2^25 -- |c| <= 2^38
++// t1 -= c * 2^25 -- |t1| <= 2^24
++// t2 += c -- |t2| <= 2^63
++//
++// c = t5 + 2^24 / 2^25 -- |c| <= 2^38
++// t5 -= c * 2^25 -- |t5| <= 2^24
++// t6 += c -- |t6| <= 2^63
++//
++// c = t2 + 2^25 / 2^26 -- |c| <= 2^37
++// t2 -= c * 2^26 -- |t2| <= 2^25 < 1.1 * 2^25 (final t2)
++// t3 += c -- |t3| <= 2^63
++//
++// c = t6 + 2^25 / 2^26 -- |c| <= 2^37
++// t6 -= c * 2^26 -- |t6| <= 2^25 < 1.1 * 2^25 (final t6)
++// t7 += c -- |t7| <= 2^63
++//
++// c = t3 + 2^24 / 2^25 -- |c| <= 2^38
++// t3 -= c * 2^25 -- |t3| <= 2^24 < 1.1 * 2^24 (final t3)
++// t4 += c -- |t4| <= 2^25 + 2^38 < 2^39
++//
++// c = t7 + 2^24 / 2^25 -- |c| <= 2^38
++// t7 -= c * 2^25 -- |t7| <= 2^24 < 1.1 * 2^24 (final t7)
++// t8 += c -- |t8| <= 2^63
++//
++// c = t4 + 2^25 / 2^26 -- |c| <= 2^13
++// t4 -= c * 2^26 -- |t4| <= 2^25 < 1.1 * 2^25 (final t4)
++// t5 += c -- |t5| <= 2^24 + 2^13 < 1.1 * 2^24 (final t5)
++//
++// c = t8 + 2^25 / 2^26 -- |c| <= 2^37
++// t8 -= c * 2^26 -- |t8| <= 2^25 < 1.1 * 2^25 (final t8)
++// t9 += c -- |t9| <= 2^63
++//
++// c = t9 + 2^24 / 2^25 -- |c| <= 2^38
++// t9 -= c * 2^25 -- |t9| <= 2^24 < 1.1 * 2^24 (final t9)
++// t0 += c * 19 -- |t0| <= 2^25 + 2^38*19 < 2^44
++//
++// c = t0 + 2^25 / 2^26 -- |c| <= 2^18
++// t0 -= c * 2^26 -- |t0| <= 2^25 < 1.1 * 2^25 (final t0)
++// t1 += c -- |t1| <= 2^24 + 2^18 < 1.1 * 2^24 (final t1)
++//
++// Postcondition
++// -------------
++// |t0|, |t2|, |t4|, |t6|, |t8| < 1.1 * 2^25
++// |t1|, |t3|, |t5|, |t7|, |t9| < 1.1 * 2^24
++#define FE_CARRY \
++ i64 c; \
++ c = (t0 + ((i64)1<<25)) >> 26; t0 -= c * ((i64)1 << 26); t1 += c; \
++ c = (t4 + ((i64)1<<25)) >> 26; t4 -= c * ((i64)1 << 26); t5 += c; \
++ c = (t1 + ((i64)1<<24)) >> 25; t1 -= c * ((i64)1 << 25); t2 += c; \
++ c = (t5 + ((i64)1<<24)) >> 25; t5 -= c * ((i64)1 << 25); t6 += c; \
++ c = (t2 + ((i64)1<<25)) >> 26; t2 -= c * ((i64)1 << 26); t3 += c; \
++ c = (t6 + ((i64)1<<25)) >> 26; t6 -= c * ((i64)1 << 26); t7 += c; \
++ c = (t3 + ((i64)1<<24)) >> 25; t3 -= c * ((i64)1 << 25); t4 += c; \
++ c = (t7 + ((i64)1<<24)) >> 25; t7 -= c * ((i64)1 << 25); t8 += c; \
++ c = (t4 + ((i64)1<<25)) >> 26; t4 -= c * ((i64)1 << 26); t5 += c; \
++ c = (t8 + ((i64)1<<25)) >> 26; t8 -= c * ((i64)1 << 26); t9 += c; \
++ c = (t9 + ((i64)1<<24)) >> 25; t9 -= c * ((i64)1 << 25); t0 += c * 19; \
++ c = (t0 + ((i64)1<<25)) >> 26; t0 -= c * ((i64)1 << 26); t1 += c; \
++ h[0]=(i32)t0; h[1]=(i32)t1; h[2]=(i32)t2; h[3]=(i32)t3; h[4]=(i32)t4; \
++ h[5]=(i32)t5; h[6]=(i32)t6; h[7]=(i32)t7; h[8]=(i32)t8; h[9]=(i32)t9
++
++// Decodes a field element from a byte buffer.
++// mask specifies how many bits we ignore.
++// Traditionally we ignore 1. It's useful for EdDSA,
++// which uses that bit to denote the sign of x.
++// Elligator however uses positive representatives,
++// which means ignoring 2 bits instead.
++static void fe_frombytes_mask(fe h, const u8 s[32], unsigned nb_mask)
++{++ u32 mask = 0xffffff >> nb_mask;
++ i64 t0 = load32_le(s); // t0 < 2^32
++ i64 t1 = load24_le(s + 4) << 6; // t1 < 2^30
++ i64 t2 = load24_le(s + 7) << 5; // t2 < 2^29
++ i64 t3 = load24_le(s + 10) << 3; // t3 < 2^27
++ i64 t4 = load24_le(s + 13) << 2; // t4 < 2^26
++ i64 t5 = load32_le(s + 16); // t5 < 2^32
++ i64 t6 = load24_le(s + 20) << 7; // t6 < 2^31
++ i64 t7 = load24_le(s + 23) << 5; // t7 < 2^29
++ i64 t8 = load24_le(s + 26) << 4; // t8 < 2^28
++ i64 t9 = (load24_le(s + 29) & mask) << 2; // t9 < 2^25
++ FE_CARRY; // Carry precondition OK
++}
++
++static void fe_frombytes(fe h, const u8 s[32])
++{++ fe_frombytes_mask(h, s, 1);
++}
++
++
++// Precondition
++// |h[0]|, |h[2]|, |h[4]|, |h[6]|, |h[8]| < 1.1 * 2^25
++// |h[1]|, |h[3]|, |h[5]|, |h[7]|, |h[9]| < 1.1 * 2^24
++//
++// Therefore, |h| < 2^255-19
++// There are two possibilities:
++//
++// - If h is positive, all we need to do is reduce its individual
++// limbs down to their tight positive range.
++// - If h is negative, we also need to add 2^255-19 to it.
++// Or just remove 19 and chop off any excess bit.
++static void fe_tobytes(u8 s[32], const fe h)
++{++ i32 t[10];
++ COPY(t, h, 10);
++ i32 q = (19 * t[9] + (((i32) 1) << 24)) >> 25;
++ // |t9| < 1.1 * 2^24
++ // -1.1 * 2^24 < t9 < 1.1 * 2^24
++ // -21 * 2^24 < 19 * t9 < 21 * 2^24
++ // -2^29 < 19 * t9 + 2^24 < 2^29
++ // -2^29 / 2^25 < (19 * t9 + 2^24) / 2^25 < 2^29 / 2^25
++ // -16 < (19 * t9 + 2^24) / 2^25 < 16
++ FOR (i, 0, 5) {++ q += t[2*i ]; q >>= 26; // q = 0 or -1
++ q += t[2*i+1]; q >>= 25; // q = 0 or -1
++ }
++ // q = 0 iff h >= 0
++ // q = -1 iff h < 0
++ // Adding q * 19 to h reduces h to its proper range.
++ q *= 19; // Shift carry back to the beginning
++ FOR (i, 0, 5) {++ t[i*2 ] += q; q = t[i*2 ] >> 26; t[i*2 ] -= q * ((i32)1 << 26);
++ t[i*2+1] += q; q = t[i*2+1] >> 25; t[i*2+1] -= q * ((i32)1 << 25);
++ }
++ // h is now fully reduced, and q represents the excess bit.
++
++ store32_le(s + 0, ((u32)t[0] >> 0) | ((u32)t[1] << 26));
++ store32_le(s + 4, ((u32)t[1] >> 6) | ((u32)t[2] << 19));
++ store32_le(s + 8, ((u32)t[2] >> 13) | ((u32)t[3] << 13));
++ store32_le(s + 12, ((u32)t[3] >> 19) | ((u32)t[4] << 6));
++ store32_le(s + 16, ((u32)t[5] >> 0) | ((u32)t[6] << 25));
++ store32_le(s + 20, ((u32)t[6] >> 7) | ((u32)t[7] << 19));
++ store32_le(s + 24, ((u32)t[7] >> 13) | ((u32)t[8] << 12));
++ store32_le(s + 28, ((u32)t[8] >> 20) | ((u32)t[9] << 6));
++
++ WIPE_BUFFER(t);
++}
++
++// Precondition
++// -------------
++// |f0|, |f2|, |f4|, |f6|, |f8| < 1.65 * 2^26
++// |f1|, |f3|, |f5|, |f7|, |f9| < 1.65 * 2^25
++//
++// |g0|, |g2|, |g4|, |g6|, |g8| < 1.65 * 2^26
++// |g1|, |g3|, |g5|, |g7|, |g9| < 1.65 * 2^25
++static void fe_mul_small(fe h, const fe f, i32 g)
++{++ i64 t0 = f[0] * (i64) g; i64 t1 = f[1] * (i64) g;
++ i64 t2 = f[2] * (i64) g; i64 t3 = f[3] * (i64) g;
++ i64 t4 = f[4] * (i64) g; i64 t5 = f[5] * (i64) g;
++ i64 t6 = f[6] * (i64) g; i64 t7 = f[7] * (i64) g;
++ i64 t8 = f[8] * (i64) g; i64 t9 = f[9] * (i64) g;
++ // |t0|, |t2|, |t4|, |t6|, |t8| < 1.65 * 2^26 * 2^31 < 2^58
++ // |t1|, |t3|, |t5|, |t7|, |t9| < 1.65 * 2^25 * 2^31 < 2^57
++
++ FE_CARRY; // Carry precondition OK
++}
++
++// Precondition
++// -------------
++// |f0|, |f2|, |f4|, |f6|, |f8| < 1.65 * 2^26
++// |f1|, |f3|, |f5|, |f7|, |f9| < 1.65 * 2^25
++//
++// |g0|, |g2|, |g4|, |g6|, |g8| < 1.65 * 2^26
++// |g1|, |g3|, |g5|, |g7|, |g9| < 1.65 * 2^25
++static void fe_mul(fe h, const fe f, const fe g)
++{++ // Everything is unrolled and put in temporary variables.
++ // We could roll the loop, but that would make curve25519 twice as slow.
++ i32 f0 = f[0]; i32 f1 = f[1]; i32 f2 = f[2]; i32 f3 = f[3]; i32 f4 = f[4];
++ i32 f5 = f[5]; i32 f6 = f[6]; i32 f7 = f[7]; i32 f8 = f[8]; i32 f9 = f[9];
++ i32 g0 = g[0]; i32 g1 = g[1]; i32 g2 = g[2]; i32 g3 = g[3]; i32 g4 = g[4];
++ i32 g5 = g[5]; i32 g6 = g[6]; i32 g7 = g[7]; i32 g8 = g[8]; i32 g9 = g[9];
++ i32 F1 = f1*2; i32 F3 = f3*2; i32 F5 = f5*2; i32 F7 = f7*2; i32 F9 = f9*2;
++ i32 G1 = g1*19; i32 G2 = g2*19; i32 G3 = g3*19;
++ i32 G4 = g4*19; i32 G5 = g5*19; i32 G6 = g6*19;
++ i32 G7 = g7*19; i32 G8 = g8*19; i32 G9 = g9*19;
++ // |F1|, |F3|, |F5|, |F7|, |F9| < 1.65 * 2^26
++ // |G0|, |G2|, |G4|, |G6|, |G8| < 2^31
++ // |G1|, |G3|, |G5|, |G7|, |G9| < 2^30
++
++ i64 t0 = f0*(i64)g0 + F1*(i64)G9 + f2*(i64)G8 + F3*(i64)G7 + f4*(i64)G6
++ + F5*(i64)G5 + f6*(i64)G4 + F7*(i64)G3 + f8*(i64)G2 + F9*(i64)G1;
++ i64 t1 = f0*(i64)g1 + f1*(i64)g0 + f2*(i64)G9 + f3*(i64)G8 + f4*(i64)G7
++ + f5*(i64)G6 + f6*(i64)G5 + f7*(i64)G4 + f8*(i64)G3 + f9*(i64)G2;
++ i64 t2 = f0*(i64)g2 + F1*(i64)g1 + f2*(i64)g0 + F3*(i64)G9 + f4*(i64)G8
++ + F5*(i64)G7 + f6*(i64)G6 + F7*(i64)G5 + f8*(i64)G4 + F9*(i64)G3;
++ i64 t3 = f0*(i64)g3 + f1*(i64)g2 + f2*(i64)g1 + f3*(i64)g0 + f4*(i64)G9
++ + f5*(i64)G8 + f6*(i64)G7 + f7*(i64)G6 + f8*(i64)G5 + f9*(i64)G4;
++ i64 t4 = f0*(i64)g4 + F1*(i64)g3 + f2*(i64)g2 + F3*(i64)g1 + f4*(i64)g0
++ + F5*(i64)G9 + f6*(i64)G8 + F7*(i64)G7 + f8*(i64)G6 + F9*(i64)G5;
++ i64 t5 = f0*(i64)g5 + f1*(i64)g4 + f2*(i64)g3 + f3*(i64)g2 + f4*(i64)g1
++ + f5*(i64)g0 + f6*(i64)G9 + f7*(i64)G8 + f8*(i64)G7 + f9*(i64)G6;
++ i64 t6 = f0*(i64)g6 + F1*(i64)g5 + f2*(i64)g4 + F3*(i64)g3 + f4*(i64)g2
++ + F5*(i64)g1 + f6*(i64)g0 + F7*(i64)G9 + f8*(i64)G8 + F9*(i64)G7;
++ i64 t7 = f0*(i64)g7 + f1*(i64)g6 + f2*(i64)g5 + f3*(i64)g4 + f4*(i64)g3
++ + f5*(i64)g2 + f6*(i64)g1 + f7*(i64)g0 + f8*(i64)G9 + f9*(i64)G8;
++ i64 t8 = f0*(i64)g8 + F1*(i64)g7 + f2*(i64)g6 + F3*(i64)g5 + f4*(i64)g4
++ + F5*(i64)g3 + f6*(i64)g2 + F7*(i64)g1 + f8*(i64)g0 + F9*(i64)G9;
++ i64 t9 = f0*(i64)g9 + f1*(i64)g8 + f2*(i64)g7 + f3*(i64)g6 + f4*(i64)g5
++ + f5*(i64)g4 + f6*(i64)g3 + f7*(i64)g2 + f8*(i64)g1 + f9*(i64)g0;
++ // t0 < 0.67 * 2^61
++ // t1 < 0.41 * 2^61
++ // t2 < 0.52 * 2^61
++ // t3 < 0.32 * 2^61
++ // t4 < 0.38 * 2^61
++ // t5 < 0.22 * 2^61
++ // t6 < 0.23 * 2^61
++ // t7 < 0.13 * 2^61
++ // t8 < 0.09 * 2^61
++ // t9 < 0.03 * 2^61
++
++ FE_CARRY; // Everything below 2^62, Carry precondition OK
++}
++
++// Precondition
++// -------------
++// |f0|, |f2|, |f4|, |f6|, |f8| < 1.65 * 2^26
++// |f1|, |f3|, |f5|, |f7|, |f9| < 1.65 * 2^25
++//
++// Note: we could use fe_mul() for this, but this is significantly faster
++static void fe_sq(fe h, const fe f)
++{++ i32 f0 = f[0]; i32 f1 = f[1]; i32 f2 = f[2]; i32 f3 = f[3]; i32 f4 = f[4];
++ i32 f5 = f[5]; i32 f6 = f[6]; i32 f7 = f[7]; i32 f8 = f[8]; i32 f9 = f[9];
++ i32 f0_2 = f0*2; i32 f1_2 = f1*2; i32 f2_2 = f2*2; i32 f3_2 = f3*2;
++ i32 f4_2 = f4*2; i32 f5_2 = f5*2; i32 f6_2 = f6*2; i32 f7_2 = f7*2;
++ i32 f5_38 = f5*38; i32 f6_19 = f6*19; i32 f7_38 = f7*38;
++ i32 f8_19 = f8*19; i32 f9_38 = f9*38;
++ // |f0_2| , |f2_2| , |f4_2| , |f6_2| , |f8_2| < 1.65 * 2^27
++ // |f1_2| , |f3_2| , |f5_2| , |f7_2| , |f9_2| < 1.65 * 2^26
++ // |f5_38|, |f6_19|, |f7_38|, |f8_19|, |f9_38| < 2^31
++
++ i64 t0 = f0 *(i64)f0 + f1_2*(i64)f9_38 + f2_2*(i64)f8_19
++ + f3_2*(i64)f7_38 + f4_2*(i64)f6_19 + f5 *(i64)f5_38;
++ i64 t1 = f0_2*(i64)f1 + f2 *(i64)f9_38 + f3_2*(i64)f8_19
++ + f4 *(i64)f7_38 + f5_2*(i64)f6_19;
++ i64 t2 = f0_2*(i64)f2 + f1_2*(i64)f1 + f3_2*(i64)f9_38
++ + f4_2*(i64)f8_19 + f5_2*(i64)f7_38 + f6 *(i64)f6_19;
++ i64 t3 = f0_2*(i64)f3 + f1_2*(i64)f2 + f4 *(i64)f9_38
++ + f5_2*(i64)f8_19 + f6 *(i64)f7_38;
++ i64 t4 = f0_2*(i64)f4 + f1_2*(i64)f3_2 + f2 *(i64)f2
++ + f5_2*(i64)f9_38 + f6_2*(i64)f8_19 + f7 *(i64)f7_38;
++ i64 t5 = f0_2*(i64)f5 + f1_2*(i64)f4 + f2_2*(i64)f3
++ + f6 *(i64)f9_38 + f7_2*(i64)f8_19;
++ i64 t6 = f0_2*(i64)f6 + f1_2*(i64)f5_2 + f2_2*(i64)f4
++ + f3_2*(i64)f3 + f7_2*(i64)f9_38 + f8 *(i64)f8_19;
++ i64 t7 = f0_2*(i64)f7 + f1_2*(i64)f6 + f2_2*(i64)f5
++ + f3_2*(i64)f4 + f8 *(i64)f9_38;
++ i64 t8 = f0_2*(i64)f8 + f1_2*(i64)f7_2 + f2_2*(i64)f6
++ + f3_2*(i64)f5_2 + f4 *(i64)f4 + f9 *(i64)f9_38;
++ i64 t9 = f0_2*(i64)f9 + f1_2*(i64)f8 + f2_2*(i64)f7
++ + f3_2*(i64)f6 + f4 *(i64)f5_2;
++ // t0 < 0.67 * 2^61
++ // t1 < 0.41 * 2^61
++ // t2 < 0.52 * 2^61
++ // t3 < 0.32 * 2^61
++ // t4 < 0.38 * 2^61
++ // t5 < 0.22 * 2^61
++ // t6 < 0.23 * 2^61
++ // t7 < 0.13 * 2^61
++ // t8 < 0.09 * 2^61
++ // t9 < 0.03 * 2^61
++
++ FE_CARRY;
++}
++
++// Parity check. Returns 0 if even, 1 if odd
++static int fe_isodd(const fe f)
++{++ u8 s[32];
++ fe_tobytes(s, f);
++ u8 isodd = s[0] & 1;
++ WIPE_BUFFER(s);
++ return isodd;
++}
++
++// Returns 1 if equal, 0 if not equal
++static int fe_isequal(const fe f, const fe g)
++{++ u8 fs[32];
++ u8 gs[32];
++ fe_tobytes(fs, f);
++ fe_tobytes(gs, g);
++ int isdifferent = crypto_verify32(fs, gs);
++ WIPE_BUFFER(fs);
++ WIPE_BUFFER(gs);
++ return 1 + isdifferent;
++}
++
++// Inverse square root.
++// Returns true if x is a square, false otherwise.
++// After the call:
++// isr = sqrt(1/x) if x is a non-zero square.
++// isr = sqrt(sqrt(-1)/x) if x is not a square.
++// isr = 0 if x is zero.
++// We do not guarantee the sign of the square root.
++//
++// Notes:
++// Let quartic = x^((p-1)/4)
++//
++// x^((p-1)/2) = chi(x)
++// quartic^2 = chi(x)
++// quartic = sqrt(chi(x))
++// quartic = 1 or -1 or sqrt(-1) or -sqrt(-1)
++//
++// Note that x is a square if quartic is 1 or -1
++// There are 4 cases to consider:
++//
++// if quartic = 1 (x is a square)
++// then x^((p-1)/4) = 1
++// x^((p-5)/4) * x = 1
++// x^((p-5)/4) = 1/x
++// x^((p-5)/8) = sqrt(1/x) or -sqrt(1/x)
++//
++// if quartic = -1 (x is a square)
++// then x^((p-1)/4) = -1
++// x^((p-5)/4) * x = -1
++// x^((p-5)/4) = -1/x
++// x^((p-5)/8) = sqrt(-1) / sqrt(x)
++// x^((p-5)/8) * sqrt(-1) = sqrt(-1)^2 / sqrt(x)
++// x^((p-5)/8) * sqrt(-1) = -1/sqrt(x)
++// x^((p-5)/8) * sqrt(-1) = -sqrt(1/x) or sqrt(1/x)
++//
++// if quartic = sqrt(-1) (x is not a square)
++// then x^((p-1)/4) = sqrt(-1)
++// x^((p-5)/4) * x = sqrt(-1)b
++// x^((p-5)/4) = sqrt(-1)/x
++// x^((p-5)/8) = sqrt(sqrt(-1)/x) or -sqrt(sqrt(-1)/x)
++//
++// Note that the product of two non-squares is always a square:
++// For any non-squares a and b, chi(a) = -1 and chi(b) = -1.
++// Since chi(x) = x^((p-1)/2), chi(a)*chi(b) = chi(a*b) = 1.
++// Therefore a*b is a square.
++//
++// Since sqrt(-1) and x are both non-squares, their product is a
++// square, and we can compute their square root.
++//
++// if quartic = -sqrt(-1) (x is not a square)
++// then x^((p-1)/4) = -sqrt(-1)
++// x^((p-5)/4) * x = -sqrt(-1)
++// x^((p-5)/4) = -sqrt(-1)/x
++// x^((p-5)/8) = sqrt(-sqrt(-1)/x)
++// x^((p-5)/8) = sqrt( sqrt(-1)/x) * sqrt(-1)
++// x^((p-5)/8) * sqrt(-1) = sqrt( sqrt(-1)/x) * sqrt(-1)^2
++// x^((p-5)/8) * sqrt(-1) = sqrt( sqrt(-1)/x) * -1
++// x^((p-5)/8) * sqrt(-1) = -sqrt(sqrt(-1)/x) or sqrt(sqrt(-1)/x)
++static int invsqrt(fe isr, const fe x)
++{++ fe t0, t1, t2;
++
++ // t0 = x^((p-5)/8)
++ // Can be achieved with a simple double & add ladder,
++ // but it would be slower.
++ fe_sq(t0, x);
++ fe_sq(t1,t0); fe_sq(t1, t1); fe_mul(t1, x, t1);
++ fe_mul(t0, t0, t1);
++ fe_sq(t0, t0); fe_mul(t0, t1, t0);
++ fe_sq(t1, t0); FOR (i, 1, 5) { fe_sq(t1, t1); } fe_mul(t0, t1, t0);++ fe_sq(t1, t0); FOR (i, 1, 10) { fe_sq(t1, t1); } fe_mul(t1, t1, t0);++ fe_sq(t2, t1); FOR (i, 1, 20) { fe_sq(t2, t2); } fe_mul(t1, t2, t1);++ fe_sq(t1, t1); FOR (i, 1, 10) { fe_sq(t1, t1); } fe_mul(t0, t1, t0);++ fe_sq(t1, t0); FOR (i, 1, 50) { fe_sq(t1, t1); } fe_mul(t1, t1, t0);++ fe_sq(t2, t1); FOR (i, 1, 100) { fe_sq(t2, t2); } fe_mul(t1, t2, t1);++ fe_sq(t1, t1); FOR (i, 1, 50) { fe_sq(t1, t1); } fe_mul(t0, t1, t0);++ fe_sq(t0, t0); FOR (i, 1, 2) { fe_sq(t0, t0); } fe_mul(t0, t0, x);++
++ // quartic = x^((p-1)/4)
++ i32 *quartic = t1;
++ fe_sq (quartic, t0);
++ fe_mul(quartic, quartic, x);
++
++ i32 *check = t2;
++ fe_0 (check); int z0 = fe_isequal(x , check);
++ fe_1 (check); int p1 = fe_isequal(quartic, check);
++ fe_neg(check, check ); int m1 = fe_isequal(quartic, check);
++ fe_neg(check, sqrtm1); int ms = fe_isequal(quartic, check);
++
++ // if quartic == -1 or sqrt(-1)
++ // then isr = x^((p-1)/4) * sqrt(-1)
++ // else isr = x^((p-1)/4)
++ fe_mul(isr, t0, sqrtm1);
++ fe_ccopy(isr, t0, 1 - (m1 | ms));
++
++ WIPE_BUFFER(t0);
++ WIPE_BUFFER(t1);
++ WIPE_BUFFER(t2);
++ return p1 | m1 | z0;
++}
++
++// Inverse in terms of inverse square root.
++// Requires two additional squarings to get rid of the sign.
++//
++// 1/x = x * (+invsqrt(x^2))^2
++// = x * (-invsqrt(x^2))^2
++//
++// A fully optimised exponentiation by p-1 would save 6 field
++// multiplications, but it would require more code.
++static void fe_invert(fe out, const fe x)
++{++ fe tmp;
++ fe_sq(tmp, x);
++ invsqrt(tmp, tmp);
++ fe_sq(tmp, tmp);
++ fe_mul(out, tmp, x);
++ WIPE_BUFFER(tmp);
++}
++
++// trim a scalar for scalar multiplication
++void crypto_eddsa_trim_scalar(u8 out[32], const u8 in[32])
++{++ COPY(out, in, 32);
++ out[ 0] &= 248;
++ out[31] &= 127;
++ out[31] |= 64;
++}
++
++// get bit from scalar at position i
++static int scalar_bit(const u8 s[32], int i)
++{++ if (i < 0) { return 0; } // handle -1 for sliding windows++ return (s[i>>3] >> (i&7)) & 1;
++}
++
++///////////////
++/// X-25519 /// Taken from SUPERCOP's ref10 implementation.
++///////////////
++static void scalarmult(u8 q[32], const u8 scalar[32], const u8 p[32],
++ int nb_bits)
++{++ // computes the scalar product
++ fe x1;
++ fe_frombytes(x1, p);
++
++ // computes the actual scalar product (the result is in x2 and z2)
++ fe x2, z2, x3, z3, t0, t1;
++ // Montgomery ladder
++ // In projective coordinates, to avoid divisions: x = X / Z
++ // We don't care about the y coordinate, it's only 1 bit of information
++ fe_1(x2); fe_0(z2); // "zero" point
++ fe_copy(x3, x1); fe_1(z3); // "one" point
++ int swap = 0;
++ for (int pos = nb_bits-1; pos >= 0; --pos) {++ // constant time conditional swap before ladder step
++ int b = scalar_bit(scalar, pos);
++ swap ^= b; // xor trick avoids swapping at the end of the loop
++ fe_cswap(x2, x3, swap);
++ fe_cswap(z2, z3, swap);
++ swap = b; // anticipates one last swap after the loop
++
++ // Montgomery ladder step: replaces (P2, P3) by (P2*2, P2+P3)
++ // with differential addition
++ fe_sub(t0, x3, z3);
++ fe_sub(t1, x2, z2);
++ fe_add(x2, x2, z2);
++ fe_add(z2, x3, z3);
++ fe_mul(z3, t0, x2);
++ fe_mul(z2, z2, t1);
++ fe_sq (t0, t1 );
++ fe_sq (t1, x2 );
++ fe_add(x3, z3, z2);
++ fe_sub(z2, z3, z2);
++ fe_mul(x2, t1, t0);
++ fe_sub(t1, t1, t0);
++ fe_sq (z2, z2 );
++ fe_mul_small(z3, t1, 121666);
++ fe_sq (x3, x3 );
++ fe_add(t0, t0, z3);
++ fe_mul(z3, x1, z2);
++ fe_mul(z2, t1, t0);
++ }
++ // last swap is necessary to compensate for the xor trick
++ // Note: after this swap, P3 == P2 + P1.
++ fe_cswap(x2, x3, swap);
++ fe_cswap(z2, z3, swap);
++
++ // normalises the coordinates: x == X / Z
++ fe_invert(z2, z2);
++ fe_mul(x2, x2, z2);
++ fe_tobytes(q, x2);
++
++ WIPE_BUFFER(x1);
++ WIPE_BUFFER(x2); WIPE_BUFFER(z2); WIPE_BUFFER(t0);
++ WIPE_BUFFER(x3); WIPE_BUFFER(z3); WIPE_BUFFER(t1);
++}
++
++static void crypto_x25519(u8 raw_shared_secret[32],
++ const u8 your_secret_key [32],
++ const u8 their_public_key [32])
++{++ // restrict the possible scalar values
++ u8 e[32];
++ crypto_eddsa_trim_scalar(e, your_secret_key);
++ scalarmult(raw_shared_secret, e, their_public_key, 255);
++ WIPE_BUFFER(e);
++}
++
++static const uchar xnine[32] = {9};++static const uchar xzero[32] = {0};++
++int
++x25519(uchar out[32], uchar s[32], uchar u[32])
++{++ crypto_x25519(out, s, u);
++ return tsmemcmp(out, xzero, 32) != 0;
++}
++
+ void
+ curve25519_dh_new(uchar x[32], uchar y[32])
+ {+@@ -44,7 +821,7 @@
+ /* don't check for zero: the scalar is never
+ zero because of clamping, and the basepoint is not the identity
+ in the prime-order subgroup(s). */
+- x25519(y, x, nine);
++ crypto_x25519(y, x, xnine);
+
+ /* bit 255 is always 0, so make it random */
+ y[31] |= b & 0x80;
--- a/sys/src/libsec/port/tlshand.c
+++ b/sys/src/libsec/port/tlshand.c
@@ -91,7 +91,8 @@
@@ -522,7 +1373,7 @@
static int decode(uchar* a, int alen, Elem* pelem);
static int encode(Elem e, Bytes** pbytes);
static int oid_lookup(Ints* o, Ints** tab);
-@@ -1277,15 +1277,24 @@
+@@ -1281,15 +1281,24 @@
}
static int
@@ -554,7 +1405,7 @@
}
-@@ -1581,20 +1590,6 @@
+@@ -1585,20 +1594,6 @@
* revocationDate UTCTime}
*/
@@ -575,7 +1426,7 @@
/* Algorithm object-ids */
enum {ALG_rsaEncryption,
-@@ -1730,14 +1725,12 @@
+@@ -1734,14 +1729,12 @@
static void appendaltnames(char *name, int nname, Bytes *ext, int req);
@@ -592,7 +1443,7 @@
free(c->subject);
freebits(c->publickey);
freebits(c->signature);
-@@ -1791,7 +1784,7 @@
+@@ -1795,7 +1788,7 @@
el = el->tl;
}
if(i > 0) {@@ -601,7 +1452,7 @@
*ans = '\0';
while(--i >= 0) {s = parts[i];
-@@ -1833,154 +1826,6 @@
+@@ -1837,152 +1830,6 @@
return oid_lookup(oid, namedcurves_oid_tab);
}
@@ -711,8 +1562,6 @@
-
- /* resume CertificateInfo */
- c->subject = parse_name(esubj);
-- if(c->subject == nil)
-- goto errret;
-
- /* SubjectPublicKeyInfo */
- if(!is_seq(epubkey, &elpubkey))
@@ -756,7 +1605,7 @@
/*
* RSAPublickKey ::= SEQUENCE {* modulus INTEGER,
-@@ -2187,6 +2032,156 @@
+@@ -2189,6 +2036,152 @@
static char Ebadsig[] = "bad signature";
@@ -793,7 +1642,6 @@
+ c->validity_start = -1;
+ c->validity_end = -1;
+ c->subject = nil;
-+ c->altsubject = nil;
+ c->publickey_alg = -1;
+ c->publickey = nil;
+ c->signature_alg = -1;
@@ -859,14 +1707,14 @@
+ e = &elvalidity->hd;
+ if(!parse_time(e, &c->validity_start))
+ goto errret;
++ e->val.u.stringval = nil; /* string ownership transfer */
+ e = &elvalidity->tl->hd;
+ if(!parse_time(e, &c->validity_end))
+ goto errret;
++ e->val.u.stringval = nil; /* string ownership transfer */
+
+ /* resume CertificateInfo */
+ c->subject = parse_name(esubj);
-+ if(c->subject == nil)
-+ goto errret;
+
+ /* SubjectPublicKeyInfo */
+ if(!is_seq(epubkey, &elpubkey))
@@ -896,9 +1744,6 @@
+ goto errret;
+ esig->val.u.bitstringval = nil; /* transfer ownership */
+ c->signature = bits;
-+ c->digestlen = digest_certinfo(buf, len, digestalg[c->signature_alg], c->digest);
-+ if(c->digestlen < 0)
-+ goto errret;
+ ok = 1;
+
+errret:
@@ -913,7 +1758,7 @@
char*
X509rsaverifydigest(uchar *sig, int siglen, uchar *edigest, int edigestlen, RSApub *pk)
{-@@ -2288,8 +2283,9 @@
+@@ -2290,8 +2283,9 @@
{CertX509 *c;
ECpub *pub;
@@ -924,7 +1769,7 @@
if(c == nil)
return nil;
copysubject(name, nname, c->subject);
-@@ -2297,11 +2293,12 @@
+@@ -2299,11 +2293,12 @@
pub = nil;
if(c->publickey_alg == ALG_ecPublicKey){ecdominit(dom, namedcurves[c->curve]);
@@ -939,7 +1784,7 @@
return pub;
}
-@@ -2309,20 +2306,22 @@
+@@ -2311,20 +2306,22 @@
X509ecdsaverify(uchar *cert, int ncert, ECdomain *dom, ECpub *pk)
{char *e;
@@ -966,7 +1811,7 @@
return e;
}
-@@ -2331,40 +2330,71 @@
+@@ -2333,40 +2330,71 @@
{CertX509 *c;
RSApub *pub;
@@ -1046,7 +1891,7 @@
/* ------- Elem constructors ---------- */
static Elem
Null(void)
-@@ -3125,14 +3155,16 @@
+@@ -3125,14 +3153,16 @@
X509digestSPKI(uchar *cert, int ncert, DigestState* (*fun)(uchar*, ulong, uchar*, DigestState*), uchar *digest)
{CertX509 *c;
@@ -1066,7 +1911,7 @@
return 0;
}
-@@ -3227,60 +3259,55 @@
+@@ -3241,60 +3271,55 @@
}
void
@@ -1150,7 +1995,7 @@
ecpubfree(ecpub);
}
ecdomfree(&ecdom);
-@@ -3287,15 +3314,15 @@
+@@ -3301,15 +3326,15 @@
break;
}
--
⑨