commit 3edf959aa0976e7dd209d71e9895fd524023f7f6
parent 9d1251e9dec600e08da7dbe7484aeb82967d3ef2
Author: William Casarin <jb55@jb55.com>
Date: Fri, 14 Jan 2022 16:48:50 -0800
another initiator step
Diffstat:
7 files changed, 125 insertions(+), 30 deletions(-)
diff --git a/Makefile b/Makefile
@@ -4,7 +4,7 @@ LDFLAGS=
ARS=deps/secp256k1/.libs/libsecp256k1.a deps/libsodium/src/libsodium/.libs/libsodium.a
OBJS=sha256.o hkdf.o hmac.o sha512.o
-DEPS=$(ARS) $(OBJS) config.h
+DEPS=$(OBJS) config.h
all: lnsocket
@@ -14,6 +14,10 @@ config.h: configurator
configurator: configurator.c
$(CC) $< -o $@
+%.o: %.c config.h
+ @echo "cc $<"
+ @$(CC) $(CFLAGS) -c $< -o $@
+
deps/secp256k1/src/libsecp256k1-config.h: deps/secp256k1/configure
./configure --enable-module-ecdh
@@ -29,19 +33,21 @@ deps/secp256k1/.libs/libsecp256k1.a: deps/secp256k1/configure
cd deps/secp256k1; \
make -j2 libsecp256k1.la
-
deps/libsodium/src/libsodium/.libs/libsodium.a: deps/libsodium/configure
cd deps/libsodium/src/libsodium; \
make -j2 libsodium.la
-lnsocket: lnsocket.c $(DEPS)
+lnsocket: lnsocket.c $(DEPS) $(ARS)
$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@
tags: fake
find . -name '*.c' -or -name '*.h' | xargs ctags
clean: fake
- rm -f lnsocket $(DEPS) deps/secp256k1/src/libsecp256k1-config.h
+ rm -f lnsocket $(DEPS)
+
+deepclean: clean
+ rm -f $(ARS) deps/secp256k1/src/libsecp256k1-config.h
cd deps/secp256k1; \
make clean
cd deps/libsodium; \
diff --git a/compiler.h b/compiler.h
@@ -54,4 +54,32 @@
#define memclear_2(m1, s1, m2, s2) { memclear(m1, s1); memclear(m2, s2); }
#define memclear_3(m1, s1, m2, s2, m3, s3) { memclear(m1, s1); memclear(m2, s2); memclear(m3, s3); }
+static inline void *memcheck_(const void *data, size_t len)
+{
+ (void)len;
+ return (void *)data;
+}
+
+#if HAVE_TYPEOF
+/**
+ * memcheck - check that a memory region is initialized
+ * @data: start of region
+ * @len: length in bytes
+ *
+ * When running under valgrind, this causes an error to be printed
+ * if the entire region is not defined. Otherwise valgrind only
+ * reports an error when an undefined value is used for a branch, or
+ * written out.
+ *
+ * Example:
+ * // Search for space, but make sure it's all initialized.
+ * if (memchr(memcheck(somebytes, bytes_len), ' ', bytes_len)) {
+ * printf("space was found!\n");
+ * }
+ */
+#define memcheck(data, len) ((__typeof__((data)+0))memcheck_((data), (len)))
+#else
+#define memcheck(data, len) memcheck_((data), (len))
+#endif
+
#endif /* COMPILER_H */
diff --git a/config.h b/config.h
@@ -10,4 +10,9 @@
#define HAVE_CCAN 1
#define HAVE_UNALIGNED_ACCESS 1
+#define HAVE_TYPEOF 1
+#define HAVE_BIG_ENDIAN 0
+#define HAVE_BYTESWAP_H 1
+#define HAVE_BSWAP_64 1
+#define HAVE_LITTLE_ENDIAN 1
#endif /* CCAN_CONFIG_H */
diff --git a/configurator.c b/configurator.c
@@ -119,7 +119,26 @@ static const struct test base_tests[] = {
" int *x = (int *)pad, *y = (int *)(pad + 1);\n"
" return *x == *y;\n"
"}\n" },
-
+ { "HAVE_TYPEOF", "__typeof__ support",
+ "INSIDE_MAIN", NULL, NULL,
+ "__typeof__(argc) i; i = argc; return i == argc ? 0 : 1;" },
+ { "HAVE_BIG_ENDIAN", "big endian",
+ "INSIDE_MAIN|EXECUTE", NULL, NULL,
+ "union { int i; char c[sizeof(int)]; } u;\n"
+ "u.i = 0x01020304;\n"
+ "return u.c[0] == 0x01 && u.c[1] == 0x02 && u.c[2] == 0x03 && u.c[3] == 0x04 ? 0 : 1;" },
+ { "HAVE_BYTESWAP_H", "<byteswap.h>",
+ "OUTSIDE_MAIN", NULL, NULL,
+ "#include <byteswap.h>\n" },
+ { "HAVE_BSWAP_64", "bswap64 in byteswap.h",
+ "DEFINES_FUNC", "HAVE_BYTESWAP_H", NULL,
+ "#include <byteswap.h>\n"
+ "static int func(int x) { return bswap_64(x); }" },
+ { "HAVE_LITTLE_ENDIAN", "little endian",
+ "INSIDE_MAIN|EXECUTE", NULL, NULL,
+ "union { int i; char c[sizeof(int)]; } u;\n"
+ "u.i = 0x01020304;\n"
+ "return u.c[0] == 0x04 && u.c[1] == 0x03 && u.c[2] == 0x02 && u.c[3] == 0x01 ? 0 : 1;" },
/*
{ "HAVE_32BIT_OFF_T", "off_t is 32 bits",
"DEFINES_EVERYTHING|EXECUTE|MAY_NOT_COMPILE", NULL, NULL,
@@ -186,15 +205,6 @@ static const struct test base_tests[] = {
" void *bt[10];\n"
" return backtrace(bt, 10) < x;\n"
"}" },
- { "HAVE_BIG_ENDIAN", "big endian",
- "INSIDE_MAIN|EXECUTE", NULL, NULL,
- "union { int i; char c[sizeof(int)]; } u;\n"
- "u.i = 0x01020304;\n"
- "return u.c[0] == 0x01 && u.c[1] == 0x02 && u.c[2] == 0x03 && u.c[3] == 0x04 ? 0 : 1;" },
- { "HAVE_BSWAP_64", "bswap64 in byteswap.h",
- "DEFINES_FUNC", "HAVE_BYTESWAP_H", NULL,
- "#include <byteswap.h>\n"
- "static int func(int x) { return bswap_64(x); }" },
{ "HAVE_BUILTIN_CHOOSE_EXPR", "__builtin_choose_expr support",
"INSIDE_MAIN", NULL, NULL,
"return __builtin_choose_expr(1, 0, \"garbage\");" },
@@ -249,9 +259,6 @@ static const struct test base_tests[] = {
"int func(int v) {\n"
" return __CLZ(__RBIT(v));\n"
"}" },
- { "HAVE_BYTESWAP_H", "<byteswap.h>",
- "OUTSIDE_MAIN", NULL, NULL,
- "#include <byteswap.h>\n" },
{ "HAVE_CLOCK_GETTIME", "clock_gettime() declaration",
"DEFINES_FUNC", "HAVE_STRUCT_TIMESPEC", NULL,
"#include <time.h>\n"
@@ -325,11 +332,6 @@ static const struct test base_tests[] = {
"#endif\n"
"#include <ctype.h>\n"
"static int func(void) { return isblank(' '); }" },
- { "HAVE_LITTLE_ENDIAN", "little endian",
- "INSIDE_MAIN|EXECUTE", NULL, NULL,
- "union { int i; char c[sizeof(int)]; } u;\n"
- "u.i = 0x01020304;\n"
- "return u.c[0] == 0x04 && u.c[1] == 0x03 && u.c[2] == 0x02 && u.c[3] == 0x01 ? 0 : 1;" },
{ "HAVE_MEMMEM", "memmem in <string.h>",
"DEFINES_FUNC", NULL, NULL,
"#ifndef _GNU_SOURCE\n"
@@ -416,9 +418,6 @@ static const struct test base_tests[] = {
{ "HAVE_SYS_UNISTD_H", "<sys/unistd.h>",
"OUTSIDE_MAIN", NULL, NULL,
"#include <sys/unistd.h>\n" },
- { "HAVE_TYPEOF", "__typeof__ support",
- "INSIDE_MAIN", NULL, NULL,
- "__typeof__(argc) i; i = argc; return i == argc ? 0 : 1;" },
{ "HAVE_UTIME", "utime() declaration",
"DEFINES_FUNC", NULL, NULL,
"#include <sys/types.h>\n"
diff --git a/endian.h b/endian.h
@@ -1,7 +1,8 @@
-/* CC0 (Public domain) */
+/* CC0 (Public domain) - see LICENSE file for details */
#ifndef CCAN_ENDIAN_H
#define CCAN_ENDIAN_H
#include <stdint.h>
+#include "config.h"
/**
* BSWAP_16 - reverse bytes in a constant uint16_t value.
@@ -107,7 +108,9 @@ static inline uint64_t bswap_64(uint64_t val)
#define __BIG_ENDIAN 4321
/* Sanity check the defines. We don't handle weird endianness. */
-#if HAVE_LITTLE_ENDIAN && HAVE_BIG_ENDIAN
+#if !HAVE_LITTLE_ENDIAN && !HAVE_BIG_ENDIAN
+#error "Unknown endian"
+#elif HAVE_LITTLE_ENDIAN && HAVE_BIG_ENDIAN
#error "Can't compile for both big and little endian."
#elif HAVE_LITTLE_ENDIAN
#ifndef __BYTE_ORDER
@@ -341,8 +344,6 @@ static inline uint16_t be16_to_cpu(beint16_t be_val)
return BE16_TO_CPU(be_val);
}
-/* Whichever they include first, they get these definitions. */
-#ifdef CCAN_SHORT_TYPES_H
/**
* be64/be32/be16 - 64/32/16 bit big-endian representation.
*/
@@ -356,5 +357,4 @@ typedef beint16_t be16;
typedef leint64_t le64;
typedef leint32_t le32;
typedef leint16_t le16;
-#endif
#endif /* CCAN_ENDIAN_H */
diff --git a/lnsocket.c b/lnsocket.c
@@ -15,8 +15,10 @@
#include <sodium/randombytes.h>
#include "sha256.h"
+#include "compiler.h"
#include "hkdf.h"
#include "handshake.h"
+#include "endian.h"
#define array_len(x) (sizeof(x)/sizeof(x[0]))
@@ -109,6 +111,53 @@ static void hkdf_two_keys(struct secret *out1, struct secret *out2,
*out2 = okm[1];
}
+
+static void le64_nonce(unsigned char *npub, u64 nonce)
+{
+ /* BOLT #8:
+ *
+ * ...with nonce `n` encoded as 32 zero bits, followed by a
+ * *little-endian* 64-bit value. Note: this follows the Noise Protocol
+ * convention, rather than our normal endian
+ */
+ le64 le_nonce = cpu_to_le64(nonce);
+ const size_t zerolen = crypto_aead_chacha20poly1305_ietf_NPUBBYTES - sizeof(le_nonce);
+
+ BUILD_ASSERT(crypto_aead_chacha20poly1305_ietf_NPUBBYTES >= sizeof(le_nonce));
+ /* First part is 0, followed by nonce. */
+ memset(npub, 0, zerolen);
+ memcpy(npub + zerolen, &le_nonce, sizeof(le_nonce));
+}
+
+/* BOLT #8:
+ * * `encryptWithAD(k, n, ad, plaintext)`: outputs `encrypt(k, n, ad,
+ * plaintext)`
+ * * Where `encrypt` is an evaluation of `ChaCha20-Poly1305` (IETF
+ * variant) with the passed arguments, with nonce `n`
+ */
+static void encrypt_ad(const struct secret *k, u64 nonce,
+ const void *additional_data, size_t additional_data_len,
+ const void *plaintext, size_t plaintext_len,
+ void *output, size_t outputlen)
+{
+ unsigned char npub[crypto_aead_chacha20poly1305_ietf_NPUBBYTES];
+ unsigned long long clen;
+ int ret;
+
+ assert(outputlen == plaintext_len + crypto_aead_chacha20poly1305_ietf_ABYTES);
+ le64_nonce(npub, nonce);
+ BUILD_ASSERT(sizeof(*k) == crypto_aead_chacha20poly1305_ietf_KEYBYTES);
+
+ ret = crypto_aead_chacha20poly1305_ietf_encrypt(
+ output, &clen, memcheck(plaintext, plaintext_len),
+ plaintext_len, additional_data, additional_data_len,
+ NULL, npub, k->data);
+
+ assert(ret == 0);
+ assert(clen == plaintext_len + crypto_aead_chacha20poly1305_ietf_ABYTES);
+}
+
+
int act_one_initiator(struct lnsocket *ln, struct handshake *h)
{
h->e = generate_key(ln->secp_ctx);
@@ -140,6 +189,13 @@ int act_one_initiator(struct lnsocket *ln, struct handshake *h)
*/
hkdf_two_keys(&h->ck, &h->temp_k, &h->ck, &h->ss, sizeof(h->ss));
+ /* BOLT #8:
+ * 5. `c = encryptWithAD(temp_k1, 0, h, zero)`
+ * * where `zero` is a zero-length plaintext
+ */
+ encrypt_ad(&h->temp_k, 0, &h->h, sizeof(h->h), NULL, 0,
+ h->act1.tag, sizeof(h->act1.tag));
+
return 1;
}
diff --git a/types.h b/types.h
@@ -3,5 +3,6 @@
#define LNSOCKET_TYPES_H
typedef unsigned char u8;
+typedef uint64_t u64;
#endif /* LNSOCKET_TYPES_H */