ref: e18ea66b577b3678c8897e26bc29dcbf027e2fcb
dir: /libsec.diff/
diff e1201b57f3e37d06589578280251d5b54e490317 uncommitted
--- a/sys/include/libsec.h
+++ b/sys/include/libsec.h
@@ -1,7 +1,6 @@
#pragma lib "libsec.a"
#pragma src "/sys/src/libsec"
-
#ifndef _MPINT
typedef struct mpint mpint;
#endif
@@ -325,6 +324,7 @@
typedef struct RSApub RSApub;
typedef struct RSApriv RSApriv;
typedef struct PEMChain PEMChain;
+typedef struct CertX509 CertX509;
/* public/encryption key */
struct RSApub
@@ -354,6 +354,24 @@
int pemlen;
};
+struct CertX509 {
+ int serial;
+ char* issuer;
+ vlong validity_start;
+ vlong validity_end;
+ char* subject;
+ char** altsubject;
+ int naltsubject;
+ int publickey_alg;
+ void* publickey;
+ int signature_alg;
+ void* signature;
+ int curve;
+ void* ext;
+ uchar digest[SHA2_512dlen];
+ int digestlen;
+};
+
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);
@@ -363,6 +381,9 @@
RSApriv* rsaprivalloc(void);
void rsaprivfree(RSApriv*);
RSApub* rsaprivtopub(RSApriv*);
+char* X509verify(CertX509*, CertX509*);
+CertX509* X509decode(uchar*, int);
+void X509free(CertX509*);
RSApub* X509toRSApub(uchar*, int, char*, int);
RSApub* X509reqtoRSApub(uchar*, int, char*, int);
RSApub* asn1toRSApub(uchar*, int);
@@ -375,7 +396,7 @@
char* X509rsaverify(uchar *cert, int ncert, RSApub *pk);
char* X509rsaverifydigest(uchar *sig, int siglen, uchar *edigest, int edigestlen, RSApub *pk);
-void X509dump(uchar *cert, int ncert);
+void X509dump(int fd, uchar *cert, int ncert);
mpint* pkcs1padbuf(uchar *buf, int len, mpint *modulus, int blocktype);
int pkcs1unpadbuf(uchar *buf, int len, mpint *modulus, int blocktype);
@@ -495,7 +516,51 @@
char *pskID;
} TLSconn;
+typedef struct TLSClientConf {
+ uchar *cert;
+ int ncert;
+ int noverify;
+ char *sessiontype;
+ int (*trace)(char*fmt, ...);
+ struct {
+ uchar *key;
+ int nkey;
+ char *id;
+ } psk;
+ struct {
+ int nkey;
+ char *constant;
+ } ttls;
+} TLSClientConf;
+
+typedef struct TLSServerConf {
+ PEMChain *certs;
+ char *sessiontype;
+ int (*trace)(char*fmt, ...);
+ struct {
+ uchar *key;
+ int nkey;
+ char *id;
+ } psk;
+ struct {
+ int nkey;
+ char *constant;
+ } ttls;
+} TLSServerConf;
+
+typedef struct TLSParams {
+ char dir[40]; /* connection directory */
+ PEMChain *certs;
+ struct {
+ uchar *key;
+ int nkey;
+ } ttls;
+} TLSParams;
+
/* tlshand.c */
+int tlsclient(int fd, char *srv, TLSClientConf *cfg, TLSParams **pparam);
+int tlsserver(int fd, TLSServerConf *cfg, TLSParams **pparam);
+void tlsparamfree(TLSParams *p);
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 @@
int erred; // set when tlsError called
int (*trace)(char*fmt, ...); // for debugging
int version; // protocol we are speaking
- Bytes *cert; // server certificate; only last - no chain
+ Bytes **certs; // server certificate; only last - no chain
+ int ncerts;
int cipher;
int nsecret; // amount of secret data to init keys
@@ -406,6 +407,8 @@
static Bytes* pkcs1_decrypt(TlsSec *sec, Bytes *data);
static Bytes* pkcs1_sign(TlsSec *sec, uchar *digest, int digestlen, int sigalg);
+static int validCert(char *rsrc, PEMChain *pc);
+
static void* emalloc(int);
static void* erealloc(void*, int);
static void put32(uchar *p, u32int);
@@ -424,6 +427,78 @@
//================= client/server ========================
+int
+tlsserver(int fd, TLSServerConf *cfg, TLSParams **pparam)
+{
+ char buf[8];
+ char dname[32];
+ uchar seed[2*RandomSize];
+ int n, data, ctl, hand;
+ TlsConnection *tls;
+ TLSParams *param;
+
+ param = emalloc(sizeof(TLSParams));
+ ctl = open("/net/tls/clone", ORDWR|OCEXEC);
+ if(ctl < 0)
+ return -1;
+ n = read(ctl, buf, sizeof(buf)-1);
+ if(n < 0){
+ close(ctl);
+ return -1;
+ }
+ buf[n] = 0;
+ snprint(param->dir, sizeof(param->dir), "/net/tls/%s", buf);
+ snprint(dname, sizeof(dname), "/net/tls/%s/hand", buf);
+ hand = open(dname, ORDWR|OCEXEC);
+ if(hand < 0){
+ close(ctl);
+ return -1;
+ }
+ data = -1;
+ fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion);
+ tls = tlsServer2(ctl, hand,
+ cfg->certs->pem, cfg->certs->pemlen,
+ cfg->psk.id, cfg->psk.key, cfg->psk.nkey,
+ cfg->trace, cfg->certs->next);
+ if(tls != nil){
+ snprint(dname, sizeof(dname), "/net/tls/%s/data", buf);
+ data = open(dname, ORDWR);
+ }
+ close(hand);
+ close(ctl);
+ if(data < 0){
+ tlsparamfree(param);
+ tlsConnectionFree(tls);
+ return -1;
+ }
+ param->certs = nil; // client certificates are not yet implemented
+ if(cfg->sessiontype != nil){
+ if(strcmp(cfg->sessiontype, "ttls") != 0 || cfg->ttls.nkey == 0){
+ werrstr("invalid tls session: %s", cfg->sessiontype);
+ close(data);
+ tlsparamfree(param);
+ tlsConnectionFree(tls);
+ return -1;
+ }
+ param->ttls.key = emalloc(param->ttls.nkey);
+ memmove(seed, tls->sec->crandom, RandomSize);
+ memmove(seed+RandomSize, tls->sec->srandom, RandomSize);
+ tls->sec->prf(
+ param->ttls.key, param->ttls.nkey,
+ tls->sec->sec, MasterSecretSize,
+ cfg->ttls.constant,
+ seed, sizeof(seed));
+ }
+ tlsConnectionFree(tls);
+ close(fd);
+ if(pparam == nil)
+ tlsparamfree(param);
+ else
+ *pparam = param;
+ return data;
+
+}
+
// push TLS onto fd, returning new (application) file descriptor
// or -1 if error.
int
@@ -491,7 +566,7 @@
}
static uchar*
-tlsClientExtensions(TLSconn *conn, int *plen)
+tlsClientExtensions(char *srvname, int *plen)
{
uchar *b, *p;
int i, n, m;
@@ -499,7 +574,7 @@
p = b = nil;
// RFC6066 - Server Name Identification
- if(conn->serverName != nil && (n = strlen(conn->serverName)) > 0){
+ if(srvname != nil && (n = strlen(srvname)) > 0){
m = p - b;
b = erealloc(b, m + 2+2+2+1+2+n);
p = b + m;
@@ -509,7 +584,7 @@
put16(p, 1+2+n), p += 2; /* Server Name list length */
*p++ = 0; /* Server Name Type: host_name */
put16(p, n), p += 2; /* Server Name length */
- memmove(p, conn->serverName, n);
+ memmove(p, srvname, n);
p += n;
}
@@ -557,6 +632,118 @@
return b;
}
+int
+tlsclient(int fd, char *srvname, TLSClientConf *cfg, TLSParams **pparam)
+{
+ char buf[8];
+ char dname[32];
+ uchar seed[2*RandomSize];
+ int i, n, data, ctl, hand;
+ TlsConnection *tls;
+ TLSParams *param;
+ PEMChain *pc, **ppc;
+ uchar *ext;
+
+ param = emalloc(sizeof(TLSParams));
+ ctl = open("/net/tls/clone", ORDWR|OCEXEC);
+ if(ctl < 0)
+ return -1;
+ n = read(ctl, buf, sizeof(buf)-1);
+ if(n < 0){
+ close(ctl);
+ return -1;
+ }
+ buf[n] = 0;
+ snprint(param->dir, sizeof(param->dir), "/net/tls/%s", buf);
+ snprint(dname, sizeof(dname), "/net/tls/%s/hand", buf);
+ hand = open(dname, ORDWR|OCEXEC);
+ if(hand < 0){
+ close(ctl);
+ return -1;
+ }
+ snprint(dname, sizeof(dname), "/net/tls/%s/data", buf);
+ data = open(dname, ORDWR);
+ if(data < 0){
+ close(hand);
+ close(ctl);
+ return -1;
+ }
+ fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion);
+ ext = tlsClientExtensions(srvname, &n);
+ tls = tlsClient2(ctl, hand,
+ cfg->cert, cfg->ncert,
+ cfg->psk.id, cfg->psk.key, cfg->psk.nkey,
+ ext, n, cfg->trace);
+ free(ext);
+ close(hand);
+ close(ctl);
+ if(tls == nil){
+ tlsparamfree(param);
+ close(data);
+ return -1;
+ }
+fprint(2, "certs: %#p, ncerts: %d\n", tls->certs, tls->ncerts);
+ if(tls->certs != nil){
+ ppc = ¶m->certs;
+ for(i = 0; i < tls->ncerts; i++){
+fprint(2, "add cert [%d]\n", i);
+ pc = emalloc(sizeof(PEMChain) + tls->certs[i]->len);
+ pc->next = nil;
+ pc->pem = (uchar*)(pc+1);
+ pc->pemlen = tls->certs[i]->len;
+ memcpy(pc->pem, tls->certs[i]->data, pc->pemlen);
+ *ppc = pc;
+ ppc = &pc->next;
+ }
+ } else {
+ param->certs = nil;
+ }
+ param->ttls.nkey = cfg->ttls.nkey;
+ if(cfg->sessiontype != nil){
+ if(strcmp(cfg->sessiontype, "ttls") != 0 || cfg->ttls.nkey == 0){
+ werrstr("invalid tls session: %s", cfg->sessiontype);
+ tlsparamfree(param);
+ close(data);
+ return -1;
+ }
+ param->ttls.key = emalloc(param->ttls.nkey);
+ memmove(seed, tls->sec->crandom, RandomSize);
+ memmove(seed+RandomSize, tls->sec->srandom, RandomSize);
+ tls->sec->prf(
+ param->ttls.key, param->ttls.nkey,
+ tls->sec->sec, MasterSecretSize,
+ cfg->ttls.constant,
+ seed, sizeof(seed));
+ }
+ tlsConnectionFree(tls);
+ close(fd);
+ if(cfg->noverify == 0
+ && cfg->psk.key == nil
+ && validCert("orib.dev", param->certs) == 0){
+ tlsparamfree(param);
+ close(data);
+ return -1;
+ }
+ if(pparam == nil)
+ tlsparamfree(param);
+ else
+ *pparam = param;
+ return data;
+}
+
+void
+tlsparamfree(TLSParams *param)
+{
+ PEMChain *pc, *pn;
+
+ for(pc = param->certs; pc != nil; pc = pn){
+ pn = pc->next;
+ free(pc);
+ }
+ free(param->ttls.key);
+ free(param);
+}
+
// push TLS onto fd, returning new (application) file descriptor
// or -1 if error.
int
@@ -595,7 +782,7 @@
return -1;
}
fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion);
- ext = tlsClientExtensions(conn, &n);
+ ext = tlsClientExtensions(conn->serverName, &n);
tls = tlsClient2(ctl, hand,
conn->cert, conn->certlen,
conn->pskID, conn->psk, conn->psklen,
@@ -608,10 +795,10 @@
return -1;
}
free(conn->cert);
- if(tls->cert != nil){
- conn->certlen = tls->cert->len;
+ if(tls->certs != nil){
+ conn->certlen = tls->certs[0]->len;
conn->cert = emalloc(conn->certlen);
- memcpy(conn->cert, tls->cert->data, conn->certlen);
+ memcpy(conn->cert, tls->certs[0]->data, conn->certlen);
} else {
conn->certlen = 0;
conn->cert = nil;
@@ -1042,7 +1229,7 @@
uchar *ext, int extlen,
int (*trace)(char*fmt, ...))
{
- int creq, dhx, cipher;
+ int i, creq, dhx, cipher;
TlsConnection *c;
Bytes *epm;
Msg m;
@@ -1057,7 +1244,7 @@
c->ctl = ctl;
c->hand = hand;
c->trace = trace;
- c->cert = nil;
+ c->certs = nil;
c->sendp = c->buf;
c->version = ProtocolVersion;
@@ -1118,11 +1305,15 @@
if(!msgRecv(c, &m))
goto Err;
if(m.tag == HCertificate){
+fprint(2, "here! %d\n", m.u.certificate.ncert);
if(m.u.certificate.ncert < 1) {
tlsError(c, EIllegalParameter, "runt certificate");
goto Err;
}
- c->cert = makebytes(m.u.certificate.certs[0]->data, m.u.certificate.certs[0]->len);
+ c->ncerts = m.u.certificate.ncert;
+ c->certs = emalloc(c->ncerts * sizeof(Bytes*));
+ for(i = 0; i < c->ncerts; i++)
+ c->certs[i] = makebytes(m.u.certificate.certs[i]->data, m.u.certificate.certs[i]->len);
if(!msgRecv(c, &m))
goto Err;
} else if(psklen == 0) {
@@ -1133,7 +1324,7 @@
if(dhx){
char *err = verifyDHparams(c->sec,
m.u.serverKeyExchange.dh_parameters,
- c->cert,
+ c->certs[0],
m.u.serverKeyExchange.dh_signature,
c->version<TLS12Version ? 0x01 : m.u.serverKeyExchange.sigalg);
if(err != nil){
@@ -1179,8 +1370,8 @@
msgClear(&m);
if(!dhx){
- if(c->cert != nil){
- epm = tlsSecRSAc(c->sec, c->cert->data, c->cert->len);
+ if(c->certs != nil){
+ epm = tlsSecRSAc(c->sec, c->certs[0]->data, c->certs[0]->len);
if(epm == nil){
tlsError(c, EBadCertificate, "bad certificate: %r");
goto Err;
@@ -2100,11 +2291,12 @@
static void
tlsConnectionFree(TlsConnection *c)
{
+ int i;
+
if(c == nil)
return;
dh_finish(&c->sec->dh, nil);
-
mpfree(c->sec->ec.Q.x);
mpfree(c->sec->ec.Q.y);
mpfree(c->sec->ec.Q.d);
@@ -2112,12 +2304,58 @@
factotum_rsa_close(c->sec->rpc);
rsapubfree(c->sec->rsapub);
- freebytes(c->cert);
+ for(i = 0; i < c->ncerts; i++)
+ freebytes(c->certs[i]);
+ free(c->certs);
memset(c, 0, sizeof(*c));
free(c);
}
+static int
+validCert(char *host, PEMChain *pc)
+{
+ char *q, *t, buf[64];
+ PEMChain *e;
+ int n, fd, r;
+
+print("host: %s\n", host);
+ if(host == nil)
+ return 0;
+ if((fd = open("/mnt/pki/new", ORDWR)) == -1)
+ return 0;
+ q = quotestrdup(host);
+ fprint(fd, "verify host %s", q);
+ free(q);
+
+ t = "cert";
+ for(e = pc; e != nil; e = e->next){
+fprint(2, "%s der %d\n", t, e->pemlen);
+ if((r = fprint(fd, "%s der %d\n", t, e->pemlen)) == -1){
+fprint(2, "nope0[%d]: %r", r);
+ close(fd);
+ return 0;
+ }
+ if((write(fd, e->pem, e->pemlen)) != e->pemlen){
+fprint(2, "nope1: %r");
+ close(fd);
+ return 0;
+ }
+ t = "icert";
+ }
+ fprint(fd, "done\n");
+ if((n = pread(fd, buf, sizeof(buf)-1, 0)) == -1){
+ close(fd);
+ return 0;
+ }
+ buf[n] = 0;
+ close(fd);
+ if(strcmp(buf, "accept") != 0){
+ werrstr("cert validation failed: %s", buf);
+ return 0;
+ }
+ return 1;
+}
//================= cipher choices ========================
--- a/sys/src/libsec/port/x509.c
+++ b/sys/src/libsec/port/x509.c
@@ -128,7 +128,7 @@
static int is_octetstring(Elem* pe, Bytes** poctets);
static int is_oid(Elem* pe, Ints** poid);
static int is_string(Elem* pe, char** pstring);
-static int is_time(Elem* pe, char** ptime);
+static int parse_time(Elem* pe, vlong* ptime);
static int decode(uchar* a, int alen, Elem* pelem);
static int encode(Elem e, Bytes** pbytes);
static int oid_lookup(Ints* o, Ints** tab);
@@ -1281,15 +1281,24 @@
}
static int
-is_time(Elem* pe, char** ptime)
+parse_time(Elem* pe, vlong* ptime)
{
- if(pe->tag.class == Universal
- && (pe->tag.num == UTCTime || pe->tag.num == GeneralizedTime)
- && pe->val.tag == VString) {
- *ptime = pe->val.u.stringval;
- return 1;
+ char *e, *fmt;
+ Tm t;
+
+ if(pe->tag.class != Universal)
+ return 0;
+ if(pe->val.tag != VString)
+ return 0;
+ switch(pe->tag.num){
+ case UTCTime: fmt = "YYMMDDhhmmss?Z"; break;
+ case GeneralizedTime: fmt = "YYYYMMDDhhmmss?Z"; break;
+ default: return 0; break;
}
- return 0;
+ if(tmparse(&t, fmt, pe->val.u.stringval, nil, &e) == nil)
+ return 0;
+ *ptime = tmnorm(&t);
+ return 1;
}
@@ -1585,20 +1594,6 @@
* revocationDate UTCTime}
*/
-typedef struct CertX509 {
- int serial;
- char* issuer;
- char* validity_start;
- char* validity_end;
- char* subject;
- int publickey_alg;
- Bits* publickey;
- int signature_alg;
- Bits* signature;
- int curve;
- Bytes* ext;
-} CertX509;
-
/* Algorithm object-ids */
enum {
ALG_rsaEncryption,
@@ -1734,14 +1729,12 @@
static void appendaltnames(char *name, int nname, Bytes *ext, int req);
-static void
-freecert(CertX509* c)
+void
+X509free(CertX509* c)
{
if(c == nil)
return;
free(c->issuer);
- free(c->validity_start);
- free(c->validity_end);
free(c->subject);
freebits(c->publickey);
freebits(c->signature);
@@ -1795,7 +1788,7 @@
el = el->tl;
}
if(i > 0) {
- ans = (char*)emalloc(plen);
+ ans = emalloc(plen);
*ans = '\0';
while(--i >= 0) {
s = parts[i];
@@ -1837,152 +1830,6 @@
return oid_lookup(oid, namedcurves_oid_tab);
}
-static CertX509*
-decode_cert(uchar *buf, int len)
-{
- int ok = 0;
- int n;
- Elem ecert;
- Elem* ecertinfo;
- Elem* esigalg;
- Elem* esig;
- Elem* eserial;
- Elem* eissuer;
- Elem* evalidity;
- Elem* esubj;
- Elem* epubkey;
- Elist* el;
- Elist* elcert = nil;
- Elist* elcertinfo = nil;
- Elist* elvalidity = nil;
- Elist* elpubkey = nil;
- Bits* bits = nil;
- Bytes* b;
- Elem* e;
- CertX509* c = nil;
-
- if(decode(buf, len, &ecert) != ASN_OK)
- goto errret;
-
- c = (CertX509*)emalloc(sizeof(CertX509));
- c->serial = -1;
- c->issuer = nil;
- c->validity_start = nil;
- c->validity_end = nil;
- c->subject = nil;
- c->publickey_alg = -1;
- c->publickey = nil;
- c->signature_alg = -1;
- c->signature = nil;
- c->ext = nil;
-
- /* Certificate */
- if(!is_seq(&ecert, &elcert) || elistlen(elcert) !=3)
- goto errret;
- ecertinfo = &elcert->hd;
- el = elcert->tl;
- esigalg = &el->hd;
- c->signature_alg = parse_alg(esigalg);
- el = el->tl;
- esig = &el->hd;
-
- /* Certificate Info */
- if(!is_seq(ecertinfo, &elcertinfo))
- goto errret;
- n = elistlen(elcertinfo);
- if(n < 6)
- goto errret;
- eserial =&elcertinfo->hd;
- el = elcertinfo->tl;
- /* check for optional version, marked by explicit context tag 0 */
- if(eserial->tag.class == Context && eserial->tag.num == 0) {
- eserial = &el->hd;
- if(n < 7)
- goto errret;
- el = el->tl;
- }
-
- if(parse_alg(&el->hd) != c->signature_alg)
- goto errret;
- el = el->tl;
- eissuer = &el->hd;
- el = el->tl;
- evalidity = &el->hd;
- el = el->tl;
- esubj = &el->hd;
- el = el->tl;
- epubkey = &el->hd;
- if(el->tl != nil
- && el->tl->hd.tag.class == Context
- && el->tl->hd.tag.num == 3
- && el->tl->hd.val.tag == VOctets){
- c->ext = el->tl->hd.val.u.octetsval;
- el->tl->hd.val.u.octetsval = nil; /* transfer ownership */
- }
- if(!is_int(eserial, &c->serial)) {
- if(!is_bigint(eserial, &b))
- goto errret;
- c->serial = -1; /* else we have to change cert struct */
- }
- c->issuer = parse_name(eissuer);
- if(c->issuer == nil)
- goto errret;
- /* Validity */
- if(!is_seq(evalidity, &elvalidity))
- goto errret;
- if(elistlen(elvalidity) != 2)
- goto errret;
- e = &elvalidity->hd;
- if(!is_time(e, &c->validity_start))
- goto errret;
- e->val.u.stringval = nil; /* string ownership transfer */
- e = &elvalidity->tl->hd;
- if(!is_time(e, &c->validity_end))
- goto errret;
- e->val.u.stringval = nil; /* string ownership transfer */
-
- /* resume CertificateInfo */
- c->subject = parse_name(esubj);
-
- /* SubjectPublicKeyInfo */
- if(!is_seq(epubkey, &elpubkey))
- goto errret;
- if(elistlen(elpubkey) != 2)
- goto errret;
-
- c->publickey_alg = parse_alg(&elpubkey->hd);
- if(c->publickey_alg < 0)
- goto errret;
- c->curve = -1;
- if(c->publickey_alg == ALG_ecPublicKey){
- c->curve = parse_curve(&elpubkey->hd);
- if(c->curve < 0)
- goto errret;
- }
- elpubkey = elpubkey->tl;
- if(!is_bitstring(&elpubkey->hd, &bits))
- goto errret;
- elpubkey->hd.val.u.bitstringval = nil; /* transfer ownership */
- c->publickey = bits;
-
- /*resume Certificate */
- if(c->signature_alg < 0)
- goto errret;
- if(!is_bitstring(esig, &bits))
- goto errret;
- esig->val.u.bitstringval = nil; /* transfer ownership */
- c->signature = bits;
- ok = 1;
-
-errret:
- freevalfields(&ecert.val); /* recurses through lists, too */
- if(!ok){
- freecert(c);
- c = nil;
- }
- return c;
-}
-
/*
* RSAPublickKey ::= SEQUENCE {
* modulus INTEGER,
@@ -2189,6 +2036,152 @@
static char Ebadsig[] = "bad signature";
+CertX509*
+X509decode(uchar *buf, int len)
+{
+ int ok = 0;
+ int n;
+ Elem ecert;
+ Elem* ecertinfo;
+ Elem* esigalg;
+ Elem* esig;
+ Elem* eserial;
+ Elem* eissuer;
+ Elem* evalidity;
+ Elem* esubj;
+ Elem* epubkey;
+ Elist* el;
+ Elist* elcert = nil;
+ Elist* elcertinfo = nil;
+ Elist* elvalidity = nil;
+ Elist* elpubkey = nil;
+ Bits* bits = nil;
+ Bytes* b;
+ Elem* e;
+ CertX509* c = nil;
+
+ if(decode(buf, len, &ecert) != ASN_OK)
+ goto errret;
+
+ c = (CertX509*)emalloc(sizeof(CertX509));
+ c->serial = -1;
+ c->issuer = nil;
+ c->validity_start = -1;
+ c->validity_end = -1;
+ c->subject = nil;
+ c->publickey_alg = -1;
+ c->publickey = nil;
+ c->signature_alg = -1;
+ c->signature = nil;
+ c->ext = nil;
+
+ /* Certificate */
+ if(!is_seq(&ecert, &elcert) || elistlen(elcert) !=3)
+ goto errret;
+ ecertinfo = &elcert->hd;
+ el = elcert->tl;
+ esigalg = &el->hd;
+ c->signature_alg = parse_alg(esigalg);
+ el = el->tl;
+ esig = &el->hd;
+
+ /* Certificate Info */
+ if(!is_seq(ecertinfo, &elcertinfo))
+ goto errret;
+ n = elistlen(elcertinfo);
+ if(n < 6)
+ goto errret;
+ eserial =&elcertinfo->hd;
+ el = elcertinfo->tl;
+ /* check for optional version, marked by explicit context tag 0 */
+ if(eserial->tag.class == Context && eserial->tag.num == 0) {
+ eserial = &el->hd;
+ if(n < 7)
+ goto errret;
+ el = el->tl;
+ }
+
+ if(parse_alg(&el->hd) != c->signature_alg)
+ goto errret;
+ el = el->tl;
+ eissuer = &el->hd;
+ el = el->tl;
+ evalidity = &el->hd;
+ el = el->tl;
+ esubj = &el->hd;
+ el = el->tl;
+ epubkey = &el->hd;
+ if(el->tl != nil
+ && el->tl->hd.tag.class == Context
+ && el->tl->hd.tag.num == 3
+ && el->tl->hd.val.tag == VOctets){
+ c->ext = el->tl->hd.val.u.octetsval;
+ el->tl->hd.val.u.octetsval = nil; /* transfer ownership */
+ }
+ if(!is_int(eserial, &c->serial)) {
+ if(!is_bigint(eserial, &b))
+ goto errret;
+ c->serial = -1; /* else we have to change cert struct */
+ }
+ c->issuer = parse_name(eissuer);
+ if(c->issuer == nil)
+ goto errret;
+ /* Validity */
+ if(!is_seq(evalidity, &elvalidity))
+ goto errret;
+ if(elistlen(elvalidity) != 2)
+ goto errret;
+ 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);
+
+ /* SubjectPublicKeyInfo */
+ if(!is_seq(epubkey, &elpubkey))
+ goto errret;
+ if(elistlen(elpubkey) != 2)
+ goto errret;
+
+ c->publickey_alg = parse_alg(&elpubkey->hd);
+ if(c->publickey_alg < 0)
+ goto errret;
+ c->curve = -1;
+ if(c->publickey_alg == ALG_ecPublicKey){
+ c->curve = parse_curve(&elpubkey->hd);
+ if(c->curve < 0)
+ goto errret;
+ }
+ elpubkey = elpubkey->tl;
+ if(!is_bitstring(&elpubkey->hd, &bits))
+ goto errret;
+ elpubkey->hd.val.u.bitstringval = nil; /* transfer ownership */
+ c->publickey = bits;
+
+ /*resume Certificate */
+ if(c->signature_alg < 0)
+ goto errret;
+ if(!is_bitstring(esig, &bits))
+ goto errret;
+ esig->val.u.bitstringval = nil; /* transfer ownership */
+ c->signature = bits;
+ ok = 1;
+
+errret:
+ freevalfields(&ecert.val); /* recurses through lists, too */
+ if(!ok){
+ X509free(c);
+ c = nil;
+ }
+ return c;
+}
+
char*
X509rsaverifydigest(uchar *sig, int siglen, uchar *edigest, int edigestlen, RSApub *pk)
{
@@ -2290,8 +2283,9 @@
{
CertX509 *c;
ECpub *pub;
+ Bits *pk;
- c = decode_cert(cert, ncert);
+ c = X509decode(cert, ncert);
if(c == nil)
return nil;
copysubject(name, nname, c->subject);
@@ -2299,11 +2293,12 @@
pub = nil;
if(c->publickey_alg == ALG_ecPublicKey){
ecdominit(dom, namedcurves[c->curve]);
- pub = ecdecodepub(dom, c->publickey->data, c->publickey->len);
+ pk = c->publickey;
+ pub = ecdecodepub(dom, pk->data, pk->len);
if(pub == nil)
ecdomfree(dom);
}
- freecert(c);
+ X509free(c);
return pub;
}
@@ -2311,20 +2306,22 @@
X509ecdsaverify(uchar *cert, int ncert, ECdomain *dom, ECpub *pk)
{
char *e;
+ Bits *sig;
CertX509 *c;
int digestlen;
uchar digest[MAXdlen];
- c = decode_cert(cert, ncert);
+ c = X509decode(cert, ncert);
if(c == nil)
return "cannot decode cert";
digestlen = digest_certinfo(cert, ncert, digestalg[c->signature_alg], digest);
if(digestlen <= 0){
- freecert(c);
+ X509free(c);
return "cannot decode certinfo";
}
- e = X509ecdsaverifydigest(c->signature->data, c->signature->len, digest, digestlen, dom, pk);
- freecert(c);
+ sig = c->signature;
+ e = X509ecdsaverifydigest(sig->data, sig->len, digest, digestlen, dom, pk);
+ X509free(c);
return e;
}
@@ -2333,40 +2330,71 @@
{
CertX509 *c;
RSApub *pub;
+ Bits *pk;
- c = decode_cert(cert, ncert);
+ c = X509decode(cert, ncert);
if(c == nil)
return nil;
copysubject(name, nname, c->subject);
appendaltnames(name, nname, c->ext, 0);
pub = nil;
+ pk = c->publickey;
if(c->publickey_alg == ALG_rsaEncryption)
- pub = asn1toRSApub(c->publickey->data, c->publickey->len);
- freecert(c);
+ pub = asn1toRSApub(pk->data, pk->len);
+ X509free(c);
return pub;
}
-char*
+char*
X509rsaverify(uchar *cert, int ncert, RSApub *pk)
{
char *e;
+ Bits *sig;
CertX509 *c;
int digestlen;
uchar digest[MAXdlen];
- c = decode_cert(cert, ncert);
+ c = X509decode(cert, ncert);
if(c == nil)
return "cannot decode cert";
digestlen = digest_certinfo(cert, ncert, digestalg[c->signature_alg], digest);
if(digestlen <= 0){
- freecert(c);
+ X509free(c);
return "cannot decode certinfo";
}
- e = X509rsaverifydigest(c->signature->data, c->signature->len, digest, digestlen, pk);
- freecert(c);
+ sig = c->signature;
+ e = X509rsaverifydigest(sig->data, sig->len, digest, digestlen, pk);
+ X509free(c);
return e;
}
+char*
+X509verify(CertX509 *crt, CertX509 *vrf)
+{
+ RSApub *rsapub;
+ ECpub *ecpub;
+ ECdomain ecdom;
+ Bits *pk, *sig;
+ char *e;
+
+ e = "unknown algorithm";
+ pk = vrf->publickey;
+ sig = crt->signature;
+ switch(vrf->publickey_alg){
+ case ALG_rsaEncryption:
+ rsapub = asn1toRSApub(pk->data, pk->len);
+ e = X509rsaverifydigest(sig->data, sig->len, crt->digest, crt->digestlen, rsapub);
+ break;
+ case ALG_ecPublicKey:
+ ecdominit(&ecdom, namedcurves[vrf->curve]);
+ ecpub = ecdecodepub(&ecdom, pk->data, pk->len);
+ e = X509ecdsaverifydigest(sig->data, sig->len, crt->digest, crt->digestlen, &ecdom, ecpub);
+ ecdomfree(&ecdom);
+ break;
+ }
+ return e;
+}
+
/* ------- Elem constructors ---------- */
static Elem
Null(void)
@@ -3125,14 +3153,16 @@
X509digestSPKI(uchar *cert, int ncert, DigestState* (*fun)(uchar*, ulong, uchar*, DigestState*), uchar *digest)
{
CertX509 *c;
+ Bits *pk;
- c = decode_cert(cert, ncert);
+ c = X509decode(cert, ncert);
if(c == nil){
werrstr("cannot decode cert");
return -1;
}
- digestSPKI(c->publickey_alg, c->publickey->data, c->publickey->len, fun, digest);
- freecert(c);
+ pk = c->publickey;
+ digestSPKI(c->publickey_alg, pk->data, pk->len, fun, digest);
+ X509free(c);
return 0;
}
@@ -3241,60 +3271,55 @@
}
void
-X509dump(uchar *cert, int ncert)
+X509dump(int fd, uchar *cert, int ncert)
{
char *e;
+ Bits *pk, *sig;
CertX509 *c;
RSApub *rsapub;
ECpub *ecpub;
ECdomain ecdom;
- int digestlen;
uchar digest[MAXdlen];
- print("begin X509dump\n");
- c = decode_cert(cert, ncert);
+ fprint(fd, "begin X509dump\n");
+ c = X509decode(cert, ncert);
if(c == nil){
- print("cannot decode cert\n");
+ fprint(fd, "cannot decode cert\n");
return;
}
- digestlen = digest_certinfo(cert, ncert, digestalg[c->signature_alg], digest);
- if(digestlen <= 0){
- freecert(c);
- print("cannot decode certinfo\n");
- return;
- }
+ pk = c->publickey;
+ sig = c->signature;
+ fprint(fd, "serial %d\n", c->serial);
+ fprint(fd, "issuer %s\n", c->issuer);
+ fprint(fd, "validity %lld %lld\n", c->validity_start, c->validity_end);
+ fprint(fd, "subject %s\n", c->subject);
+ fprint(fd, "sigalg=%d digest=%.*H\n", c->signature_alg, c->digestlen, c->digest);
+ fprint(fd, "publickey_alg=%d pubkey[%d] %.*H\n", c->publickey_alg, pk->len,
+ pk->len, pk->data);
- print("serial %d\n", c->serial);
- print("issuer %s\n", c->issuer);
- print("validity %s %s\n", c->validity_start, c->validity_end);
- print("subject %s\n", c->subject);
- print("sigalg=%d digest=%.*H\n", c->signature_alg, digestlen, digest);
- print("publickey_alg=%d pubkey[%d] %.*H\n", c->publickey_alg, c->publickey->len,
- c->publickey->len, c->publickey->data);
-
switch(c->publickey_alg){
case ALG_rsaEncryption:
- rsapub = asn1toRSApub(c->publickey->data, c->publickey->len);
+ rsapub = asn1toRSApub(pk->data, pk->len);
if(rsapub != nil){
- print("rsa pubkey e=%B n(%d)=%B\n", rsapub->ek, mpsignif(rsapub->n), rsapub->n);
- e = X509rsaverifydigest(c->signature->data, c->signature->len,
- digest, digestlen, rsapub);
+ fprint(fd, "rsa pubkey e=%B n(%d)=%B\n", rsapub->ek, mpsignif(rsapub->n), rsapub->n);
+ e = X509rsaverifydigest(sig->data, sig->len,
+ c->digest, c->digestlen, rsapub);
if(e==nil)
e = "nil (meaning ok)";
- print("self-signed X509rsaverifydigest returns: %s\n", e);
+ fprint(fd, "self-signed X509rsaverifydigest returns: %s\n", e);
rsapubfree(rsapub);
}
break;
case ALG_ecPublicKey:
ecdominit(&ecdom, namedcurves[c->curve]);
- ecpub = ecdecodepub(&ecdom, c->publickey->data, c->publickey->len);
+ ecpub = ecdecodepub(&ecdom, pk->data, pk->len);
if(ecpub != nil){
- e = X509ecdsaverifydigest(c->signature->data, c->signature->len,
- digest, digestlen, &ecdom, ecpub);
+ e = X509ecdsaverifydigest(sig->data, sig->len,
+ c->digest, c->digestlen, &ecdom, ecpub);
if(e==nil)
e = "nil (meaning ok)";
- print("self-signed X509ecdsaverifydigest returns: %s\n", e);
+ fprint(fd, "self-signed X509ecdsaverifydigest returns: %s\n", e);
ecpubfree(ecpub);
}
ecdomfree(&ecdom);
@@ -3301,15 +3326,15 @@
break;
}
- digestSPKI(c->publickey_alg, c->publickey->data, c->publickey->len, sha2_256, digest);
- print("publickey_thumbprint sha256=%.*[\n", SHA2_256dlen, digest);
+ digestSPKI(c->publickey_alg, pk->data, pk->len, sha2_256, c->digest);
+ fprint(fd, "publickey_thumbprint sha256=%.*[\n", SHA2_256dlen, c->digest);
sha2_256(cert, ncert, digest, nil);
- print("cert_thumbprint sha256=%.*[\n", SHA2_256dlen, digest);
+ fprint(fd, "cert_thumbprint sha256=%.*[\n", SHA2_256dlen, digest);
sha1(cert, ncert, digest, nil);
- print("cert_thumbprint sha1=%.*H\n", SHA1dlen, digest);
+ fprint(fd, "cert_thumbprint sha1=%.*H\n", SHA1dlen, digest);
- freecert(c);
- print("end X509dump\n");
+ X509free(c);
+ fprint(fd, "end X509dump\n");
}