~moody/drawterm

df9c9a8f7c088cb52d5feb0757b51e69bffd380d — cinap_lenrek 6 months ago 368599d
libsec: move zero check to curve25519_dh_finish()

As checking for all zero has to be done in a timing-safe
way to avoid a side channel, it is best todo this here
instead of letting the caller deal with it.

This adds a return type of int to curve25519_dh_finish()
where returning 0 means we got a all zero shared key.

RFC7748 states:

The check for the all-zero value results from the fact
that the X25519 function produces that value if it
operates on an input corresponding to a point with small
order, where the order divides the cofactor of the curve.
3 files changed, 7 insertions(+), 12 deletions(-)

M include/libsec.h
M libsec/curve25519_dh.c
M libsec/tlshand.c
M include/libsec.h => include/libsec.h +1 -1
@@ 570,7 570,7 @@ void curve25519(uchar mypublic[32], uchar secret[32], uchar basepoint[32]);

/* Curve25519 diffie hellman */
void curve25519_dh_new(uchar x[32], uchar y[32]);
void curve25519_dh_finish(uchar x[32], uchar y[32], uchar z[32]);
int curve25519_dh_finish(uchar x[32], uchar y[32], uchar z[32]);

/* password-based key derivation function 2 (rfc2898) */
void pbkdf2_x(uchar *p, ulong plen, uchar *s, ulong slen, ulong rounds, uchar *d, ulong dlen,

M libsec/curve25519_dh.c => libsec/curve25519_dh.c +4 -1
@@ 3,6 3,7 @@
#include <libsec.h>

static uchar nine[32] = {9};
static uchar zero[32] = {0};

void
curve25519_dh_new(uchar x[32], uchar y[32])


@@ 20,7 21,7 @@ curve25519_dh_new(uchar x[32], uchar y[32])
	y[31] |= b & 0x80;
}

void
int
curve25519_dh_finish(uchar x[32], uchar y[32], uchar z[32])
{
	/* remove the random bit */


@@ 31,4 32,6 @@ curve25519_dh_finish(uchar x[32], uchar y[32], uchar z[32])

	memset(x, 0, 32);
	memset(y, 0, 32);

	return tsmemcmp(z, zero, 32) != 0;
}

M libsec/tlshand.c => libsec/tlshand.c +2 -10
@@ 952,7 952,6 @@ Out:
static Bytes*
tlsSecECDHEc(TlsSec *sec, int curve, Bytes *Ys)
{
	static char zero[32] = {0};
	ECdomain *dom = &sec->ec.dom;
	ECpriv *Q = &sec->ec.Q;
	ECpub *pub;


@@ 971,10 970,7 @@ tlsSecECDHEc(TlsSec *sec, int curve, Bytes *Ys)
		Yc = newbytes(32);
		curve25519_dh_new(sec->X, Yc->data);
		Z = newbytes(32);
		curve25519_dh_finish(sec->X, Ys->data, Z->data);
		// rfc wants us to terminate the connection if
		// shared secret == all zeroes.
		if(tsmemcmp(Z->data, zero, Z->len) == 0){
		if(!curve25519_dh_finish(sec->X, Ys->data, Z->data)){
			freebytes(Yc);
			freebytes(Z);
			return nil;


@@ 2577,7 2573,6 @@ tlsSecECDHEs1(TlsSec *sec)
static int
tlsSecECDHEs2(TlsSec *sec, Bytes *Yc)
{
	static char zero[32] = {0};
	ECdomain *dom = &sec->ec.dom;
	ECpriv *Q = &sec->ec.Q;
	ECpoint K;


@@ 2595,10 2590,7 @@ tlsSecECDHEs2(TlsSec *sec, Bytes *Yc)
			return -1;
		}
		Z = newbytes(32);
		curve25519_dh_finish(sec->X, Yc->data, Z->data);
		// rfc wants us to terminate the connection if
		// shared secret == all zeroes.
		if(tsmemcmp(Z->data, zero, Z->len) == 0){
		if(!curve25519_dh_finish(sec->X, Yc->data, Z->data)){
			werrstr("unlucky shared key");
			freebytes(Z);
			return -1;