mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-22 16:44:20 +01:00
gossipd: include ccan/io version of handshake code, with tests.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
committed by
Christian Decker
parent
98ad6b9231
commit
a88ac22711
990
gossipd/handshake.c
Normal file
990
gossipd/handshake.c
Normal file
@@ -0,0 +1,990 @@
|
||||
#include <assert.h>
|
||||
#include <bitcoin/privkey.h>
|
||||
#include <bitcoin/pubkey.h>
|
||||
#include <ccan/build_assert/build_assert.h>
|
||||
#include <ccan/crypto/hkdf_sha256/hkdf_sha256.h>
|
||||
#include <ccan/endian/endian.h>
|
||||
#include <ccan/io/io.h>
|
||||
#include <ccan/mem/mem.h>
|
||||
#include <common/crypto_state.h>
|
||||
#include <common/status.h>
|
||||
#include <common/type_to_string.h>
|
||||
#include <common/utils.h>
|
||||
#include <errno.h>
|
||||
#include <gossipd/handshake.h>
|
||||
#include <hsmd/client.h>
|
||||
#include <secp256k1.h>
|
||||
#include <secp256k1_ecdh.h>
|
||||
#include <sodium/crypto_aead_chacha20poly1305.h>
|
||||
#include <sodium/randombytes.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define HSM_FD 3
|
||||
|
||||
#ifndef SUPERVERBOSE
|
||||
#define SUPERVERBOSE(...)
|
||||
#endif
|
||||
|
||||
enum bolt8_side {
|
||||
INITIATOR,
|
||||
RESPONDER
|
||||
};
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* Act One is sent from initiator tog responder. During `Act One`, the
|
||||
* initiator attempts to satisfy an implicit challenge by the responder. To
|
||||
* complete this challenge, the initiator _must_ know the static public key of
|
||||
* the responder.
|
||||
*/
|
||||
struct act_one {
|
||||
u8 v;
|
||||
u8 pubkey[PUBKEY_DER_LEN];
|
||||
u8 tag[crypto_aead_chacha20poly1305_ietf_ABYTES];
|
||||
};
|
||||
|
||||
/* BOLT #8: The handshake message is _exactly_ `50 bytes` */
|
||||
#define ACT_ONE_SIZE 50 /* ARM's stupid ABI adds padding. */
|
||||
|
||||
static inline void check_act_one(const struct act_one *act1)
|
||||
{
|
||||
/* BOLT #8:
|
||||
*
|
||||
* : `1 byte` for the handshake version, `33 bytes` for the compressed
|
||||
* ephemeral public key of the initiator, and `16 bytes` for the
|
||||
* `poly1305` tag.
|
||||
*/
|
||||
BUILD_ASSERT(sizeof(act1->v) == 1);
|
||||
BUILD_ASSERT(sizeof(act1->pubkey) == 33);
|
||||
BUILD_ASSERT(sizeof(act1->tag) == 16);
|
||||
}
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* `Act Two` is sent from the responder to the initiator. `Act Two` will
|
||||
* _only_ take place if `Act One` was successful. `Act One` was successful if
|
||||
* the responder was able to properly decrypt and check the `MAC` of the tag
|
||||
* sent at the end of `Act One`.
|
||||
*/
|
||||
struct act_two {
|
||||
u8 v;
|
||||
u8 pubkey[PUBKEY_DER_LEN];
|
||||
u8 tag[crypto_aead_chacha20poly1305_ietf_ABYTES];
|
||||
};
|
||||
|
||||
/* BOLT #8: The handshake is _exactly_ `50 bytes:` */
|
||||
#define ACT_TWO_SIZE 50 /* ARM's stupid ABI adds padding. */
|
||||
|
||||
static inline void check_act_two(const struct act_two *act2)
|
||||
{
|
||||
/* BOLT #8:
|
||||
* `1 byte` for the handshake version,
|
||||
* `33 bytes` for the compressed ephemeral public key of the initiator, and
|
||||
* `16 bytes` for the `poly1305` tag.
|
||||
*/
|
||||
BUILD_ASSERT(sizeof(act2->v) == 1);
|
||||
BUILD_ASSERT(sizeof(act2->pubkey) == 33);
|
||||
BUILD_ASSERT(sizeof(act2->tag) == 16);
|
||||
}
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* `Act Three` is the final phase in the authenticated key agreement described
|
||||
* in this section. This act is sent from the initiator to the responder as a
|
||||
* final concluding step. `Act Three` is only executed `iff` `Act Two` was
|
||||
* successful. During `Act Three`, the initiator transports its static public
|
||||
* key to the responder encrypted with _strong_ forward secrecy using the
|
||||
* accumulated `HKDF` derived secret key at this point of the handshake.
|
||||
*/
|
||||
struct act_three {
|
||||
u8 v;
|
||||
u8 ciphertext[PUBKEY_DER_LEN + crypto_aead_chacha20poly1305_ietf_ABYTES];
|
||||
u8 tag[crypto_aead_chacha20poly1305_ietf_ABYTES];
|
||||
};
|
||||
|
||||
/* BOLT #8: The handshake is _exactly_ `66 bytes` */
|
||||
#define ACT_THREE_SIZE 66 /* ARM's stupid ABI adds padding. */
|
||||
|
||||
static inline void check_act_three(const struct act_three *act3)
|
||||
{
|
||||
/* BOLT #8:
|
||||
*
|
||||
* `1 byte` for the handshake version, `33 bytes` for the ephemeral
|
||||
* public key encrypted with the `ChaCha20` stream cipher, `16 bytes`
|
||||
* for the encrypted public key's tag generated via the `AEAD`
|
||||
* construction, and `16 bytes` for a final authenticating tag.
|
||||
*/
|
||||
BUILD_ASSERT(sizeof(act3->v) == 1);
|
||||
BUILD_ASSERT(sizeof(act3->ciphertext) == 33 + 16);
|
||||
BUILD_ASSERT(sizeof(act3->tag) == 16);
|
||||
}
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `generateKey()`
|
||||
* * where generateKey generates and returns a fresh `secp256k1` keypair
|
||||
* * the object returned by `generateKey` has two attributes:
|
||||
* * `.pub`: which returns an abstract object representing the
|
||||
* public key
|
||||
* * `.priv`: which represents the private key used to generate the
|
||||
* public key
|
||||
*/
|
||||
struct keypair {
|
||||
struct pubkey pub;
|
||||
struct privkey priv;
|
||||
};
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* Throughout the handshake process, each side maintains these variables:
|
||||
*
|
||||
* * `ck`: The **chaining key**. This value is the accumulated hash of all
|
||||
* previous ECDH outputs. At the end of the handshake, `ck` is used to
|
||||
* derive the encryption keys for lightning messages.
|
||||
*
|
||||
* * `h`: The **handshake hash**. This value is the accumulated hash of _all_
|
||||
* handshake data that has been sent and received so far during the
|
||||
* handshake process.
|
||||
*
|
||||
* * `temp_k1`, `temp_k2`, `temp_k3`: **intermediate keys** used to
|
||||
* encrypt/decrypt the zero-length AEAD payloads at the end of each
|
||||
* handshake message.
|
||||
*
|
||||
* * `e`: A party's **ephemeral keypair**. For each session a node MUST
|
||||
* generate a new ephemeral key with strong cryptographic randomness.
|
||||
*
|
||||
* * `s`: A party's **static public key** (`ls` for local, `rs` for remote)
|
||||
*/
|
||||
struct handshake {
|
||||
struct secret ck;
|
||||
struct secret temp_k;
|
||||
struct sha256 h;
|
||||
struct keypair e;
|
||||
struct secret ss;
|
||||
|
||||
/* Used between the Acts */
|
||||
struct pubkey re;
|
||||
struct act_one act1;
|
||||
struct act_two act2;
|
||||
struct act_three act3;
|
||||
|
||||
/* Who we are */
|
||||
struct pubkey my_id;
|
||||
/* Who they are: set already if we're initiator. */
|
||||
struct pubkey their_id;
|
||||
|
||||
/* Are we initiator or responder. */
|
||||
enum bolt8_side side;
|
||||
|
||||
/* Function to call once handshake complete. */
|
||||
struct io_plan *(*cb)(struct io_conn *conn,
|
||||
const struct pubkey *their_id,
|
||||
const struct crypto_state *cs,
|
||||
void *cbarg);
|
||||
void *cbarg;
|
||||
};
|
||||
|
||||
static struct keypair generate_key(void)
|
||||
{
|
||||
struct keypair k;
|
||||
|
||||
do {
|
||||
randombytes_buf(k.priv.secret.data, sizeof(k.priv.secret.data));
|
||||
} while (!secp256k1_ec_pubkey_create(secp256k1_ctx,
|
||||
&k.pub.pubkey, k.priv.secret.data));
|
||||
return k;
|
||||
}
|
||||
|
||||
/* h = SHA-256(h || data) */
|
||||
static void sha_mix_in(struct sha256 *h, const void *data, size_t len)
|
||||
{
|
||||
struct sha256_ctx shactx;
|
||||
|
||||
sha256_init(&shactx);
|
||||
sha256_update(&shactx, h, sizeof(*h));
|
||||
sha256_update(&shactx, data, len);
|
||||
sha256_done(&shactx, h);
|
||||
}
|
||||
|
||||
/* h = SHA-256(h || pub.serializeCompressed()) */
|
||||
static void sha_mix_in_key(struct sha256 *h, const struct pubkey *key)
|
||||
{
|
||||
u8 der[PUBKEY_DER_LEN];
|
||||
size_t len = sizeof(der);
|
||||
|
||||
secp256k1_ec_pubkey_serialize(secp256k1_ctx, der, &len, &key->pubkey,
|
||||
SECP256K1_EC_COMPRESSED);
|
||||
assert(len == sizeof(der));
|
||||
sha_mix_in(h, der, sizeof(der));
|
||||
}
|
||||
|
||||
/* out1, out2 = HKDF(in1, in2)` */
|
||||
static void hkdf_two_keys(struct secret *out1, struct secret *out2,
|
||||
const struct secret *in1,
|
||||
const void *in2, size_t in2_size)
|
||||
{
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `HKDF(salt,ikm)`: a function is defined in [3](#reference-3),
|
||||
* evaluated with a zero-length `info` field.
|
||||
* * All invocations of the `HKDF` implicitly return `64-bytes`
|
||||
* of cryptographic randomness using the extract-and-expand
|
||||
* component of the `HKDF`.
|
||||
*/
|
||||
struct secret okm[2];
|
||||
|
||||
SUPERVERBOSE("# HKDF(0x%s,%s%s)",
|
||||
tal_hexstr(trc, in1, sizeof(*in1)),
|
||||
in2_size ? "0x" : "zero",
|
||||
tal_hexstr(trc, in2, in2_size));
|
||||
BUILD_ASSERT(sizeof(okm) == 64);
|
||||
hkdf_sha256(okm, sizeof(okm), in1, sizeof(*in1), in2, in2_size,
|
||||
NULL, 0);
|
||||
*out1 = okm[0];
|
||||
*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 (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);
|
||||
SUPERVERBOSE("# encryptWithAD(0x%s, 0x%s, 0x%s, %s%s)",
|
||||
tal_hexstr(trc, k, sizeof(*k)),
|
||||
tal_hexstr(trc, npub, sizeof(npub)),
|
||||
tal_hexstr(trc, additional_data, additional_data_len),
|
||||
plaintext_len ? "0x" : "<empty>",
|
||||
tal_hexstr(trc, plaintext, plaintext_len));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* BOLT #8:
|
||||
* * `decryptWithAD(k, n, ad, ciphertext)`: outputs `decrypt(k, n, ad,
|
||||
* ciphertext)`
|
||||
* * where `decrypt` is an evaluation of `ChaCha20-Poly1305` (IETF
|
||||
* variant) with the passed arguments, with nonce `n`
|
||||
*/
|
||||
static bool decrypt(const struct secret *k, u64 nonce,
|
||||
const void *additional_data, size_t additional_data_len,
|
||||
const void *ciphertext, size_t ciphertext_len,
|
||||
void *output, size_t outputlen)
|
||||
{
|
||||
unsigned char npub[crypto_aead_chacha20poly1305_ietf_NPUBBYTES];
|
||||
unsigned long long mlen;
|
||||
|
||||
assert(outputlen == ciphertext_len - crypto_aead_chacha20poly1305_ietf_ABYTES);
|
||||
|
||||
le64_nonce(npub, nonce);
|
||||
BUILD_ASSERT(sizeof(*k) == crypto_aead_chacha20poly1305_ietf_KEYBYTES);
|
||||
SUPERVERBOSE("# decryptWithAD(0x%s, 0x%s, 0x%s, 0x%s)",
|
||||
tal_hexstr(trc, k, sizeof(*k)),
|
||||
tal_hexstr(trc, npub, sizeof(npub)),
|
||||
tal_hexstr(trc, additional_data, additional_data_len),
|
||||
tal_hexstr(trc, ciphertext, ciphertext_len));
|
||||
if (crypto_aead_chacha20poly1305_ietf_decrypt(output, &mlen, NULL,
|
||||
memcheck(ciphertext, ciphertext_len),
|
||||
ciphertext_len,
|
||||
additional_data, additional_data_len,
|
||||
npub, k->data) != 0)
|
||||
return false;
|
||||
|
||||
assert(mlen == ciphertext_len - crypto_aead_chacha20poly1305_ietf_ABYTES);
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct io_plan *handshake_failed_(struct io_conn *conn,
|
||||
struct handshake *h,
|
||||
const char *function, int line)
|
||||
{
|
||||
status_trace("%s: handshake failed %s:%u",
|
||||
h->side == RESPONDER ? "Responder" : "Initiator",
|
||||
function, line);
|
||||
return io_close(conn);
|
||||
}
|
||||
#define handshake_failed(conn, h) \
|
||||
handshake_failed_((conn), (h), __func__, __LINE__)
|
||||
|
||||
static struct io_plan *handshake_succeeded(struct io_conn *conn,
|
||||
struct handshake *h)
|
||||
{
|
||||
struct crypto_state cs;
|
||||
struct io_plan *(*cb)(struct io_conn *conn,
|
||||
const struct pubkey *their_id,
|
||||
const struct crypto_state *cs,
|
||||
void *cbarg);
|
||||
void *cbarg;
|
||||
struct pubkey their_id;
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `rk, sk = HKDF(ck, zero)`
|
||||
* * where `zero` is a zero-length plaintext, `rk` is the key to
|
||||
* be used by the responder to decrypt the messages sent by the
|
||||
* initiator, and `sk` is the key to be used by the responder
|
||||
* to encrypt messages to the initiator,
|
||||
*
|
||||
* * This step generates the final encryption keys to be used for
|
||||
* sending and receiving messages for the duration of the
|
||||
* session.
|
||||
*/
|
||||
if (h->side == RESPONDER)
|
||||
hkdf_two_keys(&cs.rk, &cs.sk, &h->ck, NULL, 0);
|
||||
else
|
||||
hkdf_two_keys(&cs.sk, &cs.rk, &h->ck, NULL, 0);
|
||||
|
||||
cs.rn = cs.sn = 0;
|
||||
cs.r_ck = cs.s_ck = h->ck;
|
||||
|
||||
cb = h->cb;
|
||||
cbarg = h->cbarg;
|
||||
their_id = h->their_id;
|
||||
|
||||
tal_free(h);
|
||||
return cb(conn, &their_id, &cs, cbarg);
|
||||
}
|
||||
|
||||
static struct handshake *new_handshake(const tal_t *ctx,
|
||||
const struct pubkey *responder_id)
|
||||
{
|
||||
struct handshake *handshake = tal(ctx, struct handshake);
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* Before the start of the first act, both sides initialize their
|
||||
* per-sessions state as follows:
|
||||
*
|
||||
* 1. `h = SHA-256(protocolName)`
|
||||
* * where `protocolName = "Noise_XK_secp256k1_ChaChaPoly_SHA256"`
|
||||
* encoded as an ASCII string.
|
||||
*/
|
||||
sha256(&handshake->h, "Noise_XK_secp256k1_ChaChaPoly_SHA256",
|
||||
strlen("Noise_XK_secp256k1_ChaChaPoly_SHA256"));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* 2. `ck = h`
|
||||
*/
|
||||
BUILD_ASSERT(sizeof(handshake->h) == sizeof(handshake->ck));
|
||||
memcpy(&handshake->ck, &handshake->h, sizeof(handshake->ck));
|
||||
SUPERVERBOSE("# ck=%s",
|
||||
tal_hexstr(trc, &handshake->ck, sizeof(handshake->ck)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* 3. `h = SHA-256(h || prologue)`
|
||||
* * where `prologue` is the ASCII string: `lightning`.
|
||||
*/
|
||||
sha_mix_in(&handshake->h, "lightning", strlen("lightning"));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* As a concluding step, both sides mix the responder's public key
|
||||
* into the handshake digest:
|
||||
*
|
||||
* * The initiating node mixes in the responding node's static public
|
||||
* key serialized in Bitcoin's DER compressed format:
|
||||
* * `h = SHA-256(h || rs.pub.serializeCompressed())`
|
||||
*
|
||||
* * The responding node mixes in their local static public key
|
||||
* serialized in Bitcoin's DER compressed format:
|
||||
* * `h = SHA-256(h || ls.pub.serializeCompressed())`
|
||||
*/
|
||||
sha_mix_in_key(&handshake->h, responder_id);
|
||||
SUPERVERBOSE("# h=%s",
|
||||
tal_hexstr(trc, &handshake->h, sizeof(handshake->h)));
|
||||
|
||||
return handshake;
|
||||
}
|
||||
|
||||
static struct io_plan *act_three_initiator(struct io_conn *conn,
|
||||
struct handshake *h)
|
||||
{
|
||||
u8 spub[PUBKEY_DER_LEN];
|
||||
size_t len = sizeof(spub);
|
||||
|
||||
status_trace("Initiator: Act 3");
|
||||
|
||||
/* BOLT #8:
|
||||
* * `c = encryptWithAD(temp_k2, 1, h, s.pub.serializeCompressed())`
|
||||
* * where `s` is the static public key of the initiator.
|
||||
*/
|
||||
secp256k1_ec_pubkey_serialize(secp256k1_ctx, spub, &len,
|
||||
&h->my_id.pubkey,
|
||||
SECP256K1_EC_COMPRESSED);
|
||||
encrypt_ad(&h->temp_k, 1, &h->h, sizeof(h->h), spub, sizeof(spub),
|
||||
h->act3.ciphertext, sizeof(h->act3.ciphertext));
|
||||
SUPERVERBOSE("# c=0x%s",
|
||||
tal_hexstr(trc,h->act3.ciphertext,sizeof(h->act3.ciphertext)));
|
||||
|
||||
/* BOLT #8:
|
||||
* * `h = SHA-256(h || c)`
|
||||
*/
|
||||
sha_mix_in(&h->h, h->act3.ciphertext, sizeof(h->act3.ciphertext));
|
||||
SUPERVERBOSE("# h=0x%s", tal_hexstr(trc, &h->h, sizeof(h->h)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `ss = ECDH(re, s.priv)`
|
||||
* * where `re` is the ephemeral public key of the responder.
|
||||
*
|
||||
*/
|
||||
if (!hsm_do_ecdh(&h->ss, &h->re))
|
||||
return handshake_failed(conn, h);
|
||||
|
||||
SUPERVERBOSE("# ss=0x%s", tal_hexstr(trc, &h->ss, sizeof(h->ss)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `ck, temp_k3 = HKDF(ck, ss)`
|
||||
* * Mix the final intermediate shared secret into the running chaining key.
|
||||
*/
|
||||
hkdf_two_keys(&h->ck, &h->temp_k, &h->ck, &h->ss, sizeof(h->ss));
|
||||
SUPERVERBOSE("# ck,temp_k3=0x%s,0x%s",
|
||||
tal_hexstr(trc, &h->ck, sizeof(h->ck)),
|
||||
tal_hexstr(trc, &h->temp_k, sizeof(h->temp_k)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `t = encryptWithAD(temp_k3, 0, h, zero)`
|
||||
* * where `zero` is a zero-length plaintext
|
||||
*
|
||||
*/
|
||||
encrypt_ad(&h->temp_k, 0, &h->h, sizeof(h->h), NULL, 0,
|
||||
h->act3.tag, sizeof(h->act3.tag));
|
||||
SUPERVERBOSE("# t=0x%s",
|
||||
tal_hexstr(trc, h->act3.tag, sizeof(h->act3.tag)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * Send `m = 0 || c || t` over the network buffer.
|
||||
*
|
||||
*/
|
||||
h->act3.v = 0;
|
||||
|
||||
SUPERVERBOSE("output: 0x%s", tal_hexstr(trc, &h->act3, ACT_THREE_SIZE));
|
||||
return io_write(conn, &h->act3, ACT_THREE_SIZE, handshake_succeeded, h);
|
||||
}
|
||||
|
||||
static struct io_plan *act_two_initiator2(struct io_conn *conn,
|
||||
struct handshake *h)
|
||||
{
|
||||
SUPERVERBOSE("input: 0x%s", tal_hexstr(trc, &h->act2, ACT_TWO_SIZE));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * If `v` is an unrecognized handshake version, then the responder
|
||||
* MUST abort the connection attempt.
|
||||
*/
|
||||
if (h->act2.v != 0)
|
||||
return handshake_failed(conn, h);
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * The raw bytes of the remote party's ephemeral public key
|
||||
* (`re`) are to be deserialized into a point on the curve using
|
||||
* affine coordinates as encoded by the key's serialized
|
||||
* composed format.
|
||||
*/
|
||||
if (secp256k1_ec_pubkey_parse(secp256k1_ctx, &h->re.pubkey,
|
||||
h->act2.pubkey, sizeof(h->act2.pubkey)) != 1)
|
||||
return handshake_failed(conn, h);
|
||||
|
||||
SUPERVERBOSE("# re=0x%s", type_to_string(trc, struct pubkey, &h->re));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `h = SHA-256(h || re.serializeCompressed())`
|
||||
*/
|
||||
sha_mix_in_key(&h->h, &h->re);
|
||||
SUPERVERBOSE("# h=0x%s", tal_hexstr(trc, &h->h, sizeof(h->h)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `ss = ECDH(re, e.priv)`
|
||||
*/
|
||||
if (!secp256k1_ecdh(secp256k1_ctx, h->ss.data, &h->re.pubkey,
|
||||
h->e.priv.secret.data))
|
||||
return handshake_failed(conn, h);
|
||||
|
||||
SUPERVERBOSE("# ss=0x%s", tal_hexstr(trc, &h->ss, sizeof(h->ss)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `ck, temp_k2 = HKDF(ck, ss)`
|
||||
* * This phase generates a new temporary encryption key
|
||||
* which is used to generate the authenticating MAC.
|
||||
*/
|
||||
hkdf_two_keys(&h->ck, &h->temp_k, &h->ck, &h->ss, sizeof(h->ss));
|
||||
SUPERVERBOSE("# ck,temp_k2=0x%s,0x%s",
|
||||
tal_hexstr(trc, &h->ck, sizeof(h->ck)),
|
||||
tal_hexstr(trc, &h->temp_k, sizeof(h->temp_k)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `p = decryptWithAD(temp_k2, 0, h, c)`
|
||||
* * If the MAC check in this operation fails, then the initiator
|
||||
* MUST terminate the connection without any further messages.
|
||||
*/
|
||||
if (!decrypt(&h->temp_k, 0, &h->h, sizeof(h->h),
|
||||
h->act2.tag, sizeof(h->act2.tag), NULL, 0))
|
||||
return handshake_failed(conn, h);
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `h = SHA-256(h || c)`
|
||||
* * Mix the received ciphertext into the handshake digest. This
|
||||
* step serves to ensure the payload wasn't modified by a MiTM.
|
||||
*/
|
||||
sha_mix_in(&h->h, h->act2.tag, sizeof(h->act2.tag));
|
||||
SUPERVERBOSE("# h=0x%s", tal_hexstr(trc, &h->h, sizeof(h->h)));
|
||||
|
||||
return act_three_initiator(conn, h);
|
||||
}
|
||||
|
||||
static struct io_plan *act_two_initiator(struct io_conn *conn,
|
||||
struct handshake *h)
|
||||
{
|
||||
status_trace("Initiator: Act 2");
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * Read _exactly_ `50-bytes` from the network buffer.
|
||||
*
|
||||
* * Parse out the read message (`m`) into `v = m[0]`, `re = m[1:33]`
|
||||
* and `c = m[34:]`
|
||||
* * where `m[0]` is the _first_ byte of `m`, `m[1:33]` are the
|
||||
* next `33` bytes of `m` and `m[34:]` is the last 16 bytes of
|
||||
* `m`
|
||||
*/
|
||||
return io_read(conn, &h->act2, ACT_TWO_SIZE, act_two_initiator2, h);
|
||||
}
|
||||
|
||||
static struct io_plan *act_one_initiator(struct io_conn *conn,
|
||||
struct handshake *h)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
status_trace("Initiator: Act 1");
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* **Sender Actions:**
|
||||
*
|
||||
* * `e = generateKey()`
|
||||
*/
|
||||
h->e = generate_key();
|
||||
SUPERVERBOSE("e.priv: 0x%s",
|
||||
tal_hexstr(trc, &h->e.priv, sizeof(h->e.priv)));
|
||||
SUPERVERBOSE("e.pub: 0x%s",
|
||||
type_to_string(trc, struct pubkey, &h->e.pub));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `h = SHA-256(h || e.pub.serializeCompressed())`
|
||||
* * The newly generated ephemeral key is accumulated into our
|
||||
* running handshake digest.
|
||||
*/
|
||||
sha_mix_in_key(&h->h, &h->e.pub);
|
||||
SUPERVERBOSE("# h=0x%s", tal_hexstr(trc, &h->h, sizeof(h->h)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `ss = ECDH(rs, e.priv)`
|
||||
* * The initiator performs a `ECDH` between its newly generated
|
||||
* ephemeral key with the remote node's static public key.
|
||||
*/
|
||||
if (!secp256k1_ecdh(secp256k1_ctx, h->ss.data,
|
||||
&h->their_id.pubkey, h->e.priv.secret.data))
|
||||
return handshake_failed(conn, h);
|
||||
|
||||
SUPERVERBOSE("# ss=0x%s", tal_hexstr(trc, h->ss.data, sizeof(h->ss.data)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `ck, temp_k1 = HKDF(ck, ss)`
|
||||
* * This phase generates a new temporary encryption key
|
||||
* which is used to generate the authenticating MAC.
|
||||
*/
|
||||
hkdf_two_keys(&h->ck, &h->temp_k, &h->ck, &h->ss, sizeof(h->ss));
|
||||
SUPERVERBOSE("# ck,temp_k1=0x%s,0x%s",
|
||||
tal_hexstr(trc, &h->ck, sizeof(h->ck)),
|
||||
tal_hexstr(trc, &h->temp_k, sizeof(h->temp_k)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `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));
|
||||
SUPERVERBOSE("# c=%s",
|
||||
tal_hexstr(trc, h->act1.tag, sizeof(h->act1.tag)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `h = SHA-256(h || c)`
|
||||
* * Finally, the generated ciphertext is accumulated into the
|
||||
* authenticating handshake digest.
|
||||
*/
|
||||
sha_mix_in(&h->h, h->act1.tag, sizeof(h->act1.tag));
|
||||
SUPERVERBOSE("# h=0x%s", tal_hexstr(trc, &h->h, sizeof(h->h)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * Send `m = 0 || e.pub.serializeCompressed() || c` to the responder over the network buffer.
|
||||
*/
|
||||
h->act1.v = 0;
|
||||
len = sizeof(h->act1.pubkey);
|
||||
secp256k1_ec_pubkey_serialize(secp256k1_ctx, h->act1.pubkey, &len,
|
||||
&h->e.pub.pubkey,
|
||||
SECP256K1_EC_COMPRESSED);
|
||||
SUPERVERBOSE("output: 0x%s", tal_hexstr(trc, &h->act1, ACT_ONE_SIZE));
|
||||
|
||||
return io_write(conn, &h->act1, ACT_ONE_SIZE, act_two_initiator, h);
|
||||
}
|
||||
|
||||
static struct io_plan *act_three_responder2(struct io_conn *conn,
|
||||
struct handshake *h)
|
||||
{
|
||||
u8 der[PUBKEY_DER_LEN];
|
||||
|
||||
SUPERVERBOSE("input: 0x%s", tal_hexstr(trc, &h->act3, ACT_THREE_SIZE));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * Parse out the read message (`m`) into `v = m[0]`, `c = m[1:49]` and `t = m[50:]`
|
||||
*/
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * If `v` is an unrecognized handshake version, then the responder MUST
|
||||
* abort the connection attempt.
|
||||
*/
|
||||
if (h->act3.v != 0)
|
||||
return handshake_failed(conn, h);
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `rs = decryptWithAD(temp_k2, 1, h, c)`
|
||||
* * At this point, the responder has recovered the static public key of the
|
||||
* initiator.
|
||||
*/
|
||||
if (!decrypt(&h->temp_k, 1, &h->h, sizeof(h->h),
|
||||
h->act3.ciphertext, sizeof(h->act3.ciphertext),
|
||||
der, sizeof(der)))
|
||||
return handshake_failed(conn, h);
|
||||
|
||||
SUPERVERBOSE("# rs=0x%s", tal_hexstr(trc, der, sizeof(der)));
|
||||
|
||||
if (secp256k1_ec_pubkey_parse(secp256k1_ctx, &h->their_id.pubkey,
|
||||
der, sizeof(der)) != 1)
|
||||
return handshake_failed(conn, h);
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `h = SHA-256(h || c)`
|
||||
*
|
||||
*/
|
||||
sha_mix_in(&h->h, h->act3.ciphertext, sizeof(h->act3.ciphertext));
|
||||
SUPERVERBOSE("# h=0x%s", tal_hexstr(trc, &h->h, sizeof(h->h)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `ss = ECDH(rs, e.priv)`
|
||||
* * where `e` is the responder's original ephemeral key
|
||||
*/
|
||||
if (!secp256k1_ecdh(secp256k1_ctx, h->ss.data, &h->their_id.pubkey,
|
||||
h->e.priv.secret.data))
|
||||
return handshake_failed(conn, h);
|
||||
|
||||
SUPERVERBOSE("# ss=0x%s", tal_hexstr(trc, &h->ss, sizeof(h->ss)));
|
||||
|
||||
/* BOLT #8:
|
||||
* * `ck, temp_k3 = HKDF(ck, ss)`
|
||||
*/
|
||||
hkdf_two_keys(&h->ck, &h->temp_k, &h->ck, &h->ss, sizeof(h->ss));
|
||||
SUPERVERBOSE("# ck,temp_k3=0x%s,0x%s",
|
||||
tal_hexstr(trc, &h->ck, sizeof(h->ck)),
|
||||
tal_hexstr(trc, &h->temp_k, sizeof(h->temp_k)));
|
||||
|
||||
/* BOLT #8:
|
||||
* * `p = decryptWithAD(temp_k3, 0, h, t)`
|
||||
* * If the MAC check in this operation fails, then the responder MUST
|
||||
* terminate the connection without any further messages.
|
||||
*
|
||||
*/
|
||||
if (!decrypt(&h->temp_k, 0, &h->h, sizeof(h->h),
|
||||
h->act3.tag, sizeof(h->act3.tag), NULL, 0))
|
||||
return handshake_failed(conn, h);
|
||||
|
||||
return handshake_succeeded(conn, h);
|
||||
}
|
||||
|
||||
static struct io_plan *act_three_responder(struct io_conn *conn,
|
||||
struct handshake *h)
|
||||
{
|
||||
status_trace("Responder: Act 3");
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* **Receiver Actions:**
|
||||
*
|
||||
* * Read _exactly_ `66-bytes` from the network buffer.
|
||||
*/
|
||||
return io_read(conn, &h->act3, ACT_THREE_SIZE, act_three_responder2, h);
|
||||
}
|
||||
|
||||
static struct io_plan *act_two_responder(struct io_conn *conn,
|
||||
struct handshake *h)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
status_trace("Responder: Act 2");
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* **Sender Actions:**
|
||||
*
|
||||
* * `e = generateKey()`
|
||||
*/
|
||||
h->e = generate_key();
|
||||
SUPERVERBOSE("# e.pub=0x%s e.priv=0x%s",
|
||||
type_to_string(trc, struct pubkey, &h->e.pub),
|
||||
tal_hexstr(trc, &h->e.priv, sizeof(h->e.priv)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `h = SHA-256(h || e.pub.serializeCompressed())`
|
||||
* * The newly generated ephemeral key is accumulated into our
|
||||
* running handshake digest.
|
||||
*/
|
||||
sha_mix_in_key(&h->h, &h->e.pub);
|
||||
SUPERVERBOSE("# h=0x%s", tal_hexstr(trc, &h->h, sizeof(h->h)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `ss = ECDH(re, e.priv)`
|
||||
* * where `re` is the ephemeral key of the initiator which was
|
||||
* received during `ActOne`.
|
||||
*/
|
||||
if (!secp256k1_ecdh(secp256k1_ctx, h->ss.data, &h->re.pubkey,
|
||||
h->e.priv.secret.data))
|
||||
return handshake_failed(conn, h);
|
||||
SUPERVERBOSE("# ss=0x%s", tal_hexstr(trc, &h->ss, sizeof(h->ss)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `ck, temp_k2 = HKDF(ck, ss)`
|
||||
* * This phase generates a new temporary encryption key
|
||||
* which is used to generate the authenticating MAC.
|
||||
*/
|
||||
hkdf_two_keys(&h->ck, &h->temp_k, &h->ck, &h->ss, sizeof(h->ss));
|
||||
SUPERVERBOSE("# ck,temp_k2=0x%s,0x%s",
|
||||
tal_hexstr(trc, &h->ck, sizeof(h->ck)),
|
||||
tal_hexstr(trc, &h->temp_k, sizeof(h->temp_k)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `c = encryptWithAD(temp_k2, 0, h, zero)`
|
||||
* * where `zero` is a zero-length plaintext
|
||||
*/
|
||||
encrypt_ad(&h->temp_k, 0, &h->h, sizeof(h->h), NULL, 0,
|
||||
h->act2.tag, sizeof(h->act2.tag));
|
||||
SUPERVERBOSE("# c=0x%s", tal_hexstr(trc, h->act2.tag, sizeof(h->act2.tag)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `h = SHA-256(h || c)`
|
||||
* * Finally, the generated ciphertext is accumulated into the
|
||||
* authenticating handshake digest.
|
||||
*/
|
||||
sha_mix_in(&h->h, h->act2.tag, sizeof(h->act2.tag));
|
||||
SUPERVERBOSE("# h=0x%s", tal_hexstr(trc, &h->h, sizeof(h->h)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * Send `m = 0 || e.pub.serializeCompressed() || c` to the initiator over the network buffer.
|
||||
*/
|
||||
h->act2.v = 0;
|
||||
len = sizeof(h->act2.pubkey);
|
||||
secp256k1_ec_pubkey_serialize(secp256k1_ctx, h->act2.pubkey, &len,
|
||||
&h->e.pub.pubkey,
|
||||
SECP256K1_EC_COMPRESSED);
|
||||
SUPERVERBOSE("output: 0x%s", tal_hexstr(trc, &h->act2, ACT_TWO_SIZE));
|
||||
|
||||
return io_write(conn, &h->act2, ACT_TWO_SIZE, act_three_responder, h);
|
||||
}
|
||||
|
||||
|
||||
static struct io_plan *act_one_responder2(struct io_conn *conn,
|
||||
struct handshake *h)
|
||||
{
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * If `v` is an unrecognized handshake version, then the responder
|
||||
* MUST abort the connection attempt.
|
||||
*/
|
||||
if (h->act1.v != 0)
|
||||
return handshake_failed(conn, h);
|
||||
|
||||
/* BOLT #8:
|
||||
* * The raw bytes of the remote party's ephemeral public key
|
||||
* (`e`) are to be deserialized into a point on the curve using
|
||||
* affine coordinates as encoded by the key's serialized
|
||||
* composed format.
|
||||
*/
|
||||
if (secp256k1_ec_pubkey_parse(secp256k1_ctx, &h->re.pubkey,
|
||||
h->act1.pubkey, sizeof(h->act1.pubkey)) != 1)
|
||||
return handshake_failed(conn, h);
|
||||
|
||||
SUPERVERBOSE("# re=0x%s", type_to_string(trc, struct pubkey, &h->re));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `h = SHA-256(h || re.serializeCompressed())`
|
||||
* * Accumulate the initiator's ephemeral key into the
|
||||
* authenticating handshake digest.
|
||||
*/
|
||||
sha_mix_in_key(&h->h, &h->re);
|
||||
SUPERVERBOSE("# h=0x%s", tal_hexstr(trc, &h->h, sizeof(h->h)));
|
||||
|
||||
/* BOLT #8:
|
||||
* * `ss = ECDH(re, s.priv)`
|
||||
* * The responder performs an `ECDH` between its static public
|
||||
* key and the initiator's ephemeral public key.
|
||||
*/
|
||||
if (!hsm_do_ecdh(&h->ss, &h->re))
|
||||
return handshake_failed(conn, h);
|
||||
|
||||
SUPERVERBOSE("# ss=0x%s", tal_hexstr(trc, &h->ss, sizeof(h->ss)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `ck, temp_k1 = HKDF(ck, ss)`
|
||||
* * This phase generates a new temporary encryption key
|
||||
* which will be used to shortly check the
|
||||
* authenticating MAC.
|
||||
*/
|
||||
hkdf_two_keys(&h->ck, &h->temp_k, &h->ck, &h->ss, sizeof(h->ss));
|
||||
SUPERVERBOSE("# ck,temp_k1=0x%s,0x%s",
|
||||
tal_hexstr(trc, &h->ck, sizeof(h->ck)),
|
||||
tal_hexstr(trc, &h->temp_k, sizeof(h->temp_k)));
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `p = decryptWithAD(temp_k1, 0, h, c)`
|
||||
* * If the MAC check in this operation fails, then the initiator
|
||||
* does _not_ know our static public key. If so, then the
|
||||
* responder MUST terminate the connection without any further
|
||||
* messages.
|
||||
*/
|
||||
if (!decrypt(&h->temp_k, 0, &h->h, sizeof(h->h),
|
||||
h->act1.tag, sizeof(h->act1.tag), NULL, 0))
|
||||
return handshake_failed(conn, h);
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * `h = SHA-256(h || c)`
|
||||
* * Mix the received ciphertext into the handshake digest. This
|
||||
* step serves to ensure the payload wasn't modified by a MiTM.
|
||||
*/
|
||||
sha_mix_in(&h->h, h->act1.tag, sizeof(h->act1.tag));
|
||||
SUPERVERBOSE("# h=0x%s", tal_hexstr(trc, &h->h, sizeof(h->h)));
|
||||
|
||||
return act_two_responder(conn, h);
|
||||
}
|
||||
|
||||
static struct io_plan *act_one_responder(struct io_conn *conn,
|
||||
struct handshake *h)
|
||||
{
|
||||
|
||||
status_trace("Responder: Act 1");
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* * Read _exactly_ `50-bytes` from the network buffer.
|
||||
*
|
||||
* * Parse out the read message (`m`) into `v = m[0]`, `re =
|
||||
* m[1:33]` and `c = m[34:]`
|
||||
* * where `m[0]` is the _first_ byte of `m`, `m[1:33]` are the
|
||||
* next `33` bytes of `m` and `m[34:]` is the last 16 bytes of
|
||||
* `m`
|
||||
*/
|
||||
return io_read(conn, &h->act1, ACT_ONE_SIZE, act_one_responder2, h);
|
||||
}
|
||||
|
||||
struct io_plan *responder_handshake_(struct io_conn *conn,
|
||||
const struct pubkey *my_id,
|
||||
struct io_plan *(*cb)(struct io_conn *,
|
||||
const struct pubkey *,
|
||||
const struct crypto_state *,
|
||||
void *cbarg),
|
||||
void *cbarg)
|
||||
{
|
||||
struct handshake *h = new_handshake(conn, my_id);
|
||||
|
||||
h->side = RESPONDER;
|
||||
h->my_id = *my_id;
|
||||
h->cbarg = cbarg;
|
||||
h->cb = cb;
|
||||
|
||||
return act_one_responder(conn, h);
|
||||
}
|
||||
|
||||
struct io_plan *initiator_handshake_(struct io_conn *conn,
|
||||
const struct pubkey *my_id,
|
||||
const struct pubkey *their_id,
|
||||
struct io_plan *(*cb)(struct io_conn *,
|
||||
const struct pubkey *,
|
||||
const struct crypto_state *,
|
||||
void *cbarg),
|
||||
void *cbarg)
|
||||
{
|
||||
struct handshake *h = new_handshake(conn, their_id);
|
||||
|
||||
h->side = INITIATOR;
|
||||
h->my_id = *my_id;
|
||||
h->their_id = *their_id;
|
||||
h->cbarg = cbarg;
|
||||
h->cb = cb;
|
||||
|
||||
return act_one_initiator(conn, h);
|
||||
}
|
||||
47
gossipd/handshake.h
Normal file
47
gossipd/handshake.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef LIGHTNING_LIGHTNINGD_GOSSIP_HANDSHAKE_H
|
||||
#define LIGHTNING_LIGHTNINGD_GOSSIP_HANDSHAKE_H
|
||||
#include "config.h"
|
||||
#include <ccan/typesafe_cb/typesafe_cb.h>
|
||||
|
||||
struct crypto_state;
|
||||
struct io_conn;
|
||||
struct pubkey;
|
||||
|
||||
#define initiator_handshake(conn, my_id, their_id, cb, cbarg) \
|
||||
initiator_handshake_((conn), (my_id), (their_id), \
|
||||
typesafe_cb_preargs(struct io_plan *, void *, \
|
||||
(cb), (cbarg), \
|
||||
struct io_conn *, \
|
||||
const struct pubkey *, \
|
||||
const struct crypto_state *), \
|
||||
(cbarg))
|
||||
|
||||
|
||||
struct io_plan *initiator_handshake_(struct io_conn *conn,
|
||||
const struct pubkey *my_id,
|
||||
const struct pubkey *their_id,
|
||||
struct io_plan *(*cb)(struct io_conn *,
|
||||
const struct pubkey *,
|
||||
const struct crypto_state *,
|
||||
void *cbarg),
|
||||
void *cbarg);
|
||||
|
||||
|
||||
#define responder_handshake(conn, my_id, cb, cbarg) \
|
||||
responder_handshake_((conn), (my_id), \
|
||||
typesafe_cb_preargs(struct io_plan *, void *, \
|
||||
(cb), (cbarg), \
|
||||
struct io_conn *, \
|
||||
const struct pubkey *, \
|
||||
const struct crypto_state *), \
|
||||
(cbarg))
|
||||
|
||||
struct io_plan *responder_handshake_(struct io_conn *conn,
|
||||
const struct pubkey *my_id,
|
||||
struct io_plan *(*cb)(struct io_conn *,
|
||||
const struct pubkey *,
|
||||
const struct crypto_state *,
|
||||
void *cbarg),
|
||||
void *cbarg);
|
||||
|
||||
#endif /* LIGHTNING_LIGHTNINGD_GOSSIP_HANDSHAKE_H */
|
||||
227
gossipd/test/run-initiator-success.c
Normal file
227
gossipd/test/run-initiator-success.c
Normal file
@@ -0,0 +1,227 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <unistd.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/io/io.h>
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include <common/status.h>
|
||||
|
||||
/* AUTOGENERATED MOCKS START */
|
||||
/* AUTOGENERATED MOCKS END */
|
||||
|
||||
/* No randomness please, we want to replicate test vectors. */
|
||||
#include <sodium/randombytes.h>
|
||||
|
||||
static void seed_randomness(u8 *secret, size_t len);
|
||||
#define randombytes_buf(secret, len) seed_randomness((secret), (len))
|
||||
|
||||
struct handshake;
|
||||
static struct io_plan *test_write(struct io_conn *conn,
|
||||
const void *data, size_t len,
|
||||
struct io_plan *(*next)(struct io_conn *,
|
||||
struct handshake *),
|
||||
struct handshake *h);
|
||||
|
||||
static struct io_plan *test_read(struct io_conn *conn,
|
||||
void *data, size_t len,
|
||||
struct io_plan *(*next)(struct io_conn *,
|
||||
struct handshake *),
|
||||
struct handshake *h);
|
||||
|
||||
#define SUPERVERBOSE status_trace
|
||||
void status_trace(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vprintf(fmt, ap);
|
||||
printf("\n");
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#undef io_write
|
||||
#undef io_read
|
||||
|
||||
#define io_write(conn, data, len, cb, cb_arg) \
|
||||
test_write((conn), (data), (len), (cb), (cb_arg))
|
||||
|
||||
#define io_read(conn, data, len, cb, cb_arg) \
|
||||
test_read((conn), (data), (len), (cb), (cb_arg))
|
||||
|
||||
#include "../handshake.c"
|
||||
#include <common/utils.h>
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
|
||||
static struct pubkey pubkey(const char *str)
|
||||
{
|
||||
struct pubkey p;
|
||||
if (!pubkey_from_hexstr(str, strlen(str), &p))
|
||||
abort();
|
||||
return p;
|
||||
}
|
||||
|
||||
static struct privkey privkey(const char *str)
|
||||
{
|
||||
struct privkey p;
|
||||
if (!hex_decode(str, strlen(str), &p, sizeof(p)))
|
||||
abort();
|
||||
return p;
|
||||
}
|
||||
|
||||
static bool secret_eq(const struct secret *s, const char *str)
|
||||
{
|
||||
struct secret expect;
|
||||
if (!hex_decode(str, strlen(str), &expect, sizeof(expect)))
|
||||
abort();
|
||||
return structeq(s, &expect);
|
||||
}
|
||||
|
||||
secp256k1_context *secp256k1_ctx;
|
||||
const void *trc;
|
||||
static struct pubkey rs_pub, ls_pub, e_pub;
|
||||
static struct privkey ls_priv, e_priv;
|
||||
|
||||
static void seed_randomness(u8 *secret, size_t len)
|
||||
{
|
||||
assert(len == sizeof(e_priv));
|
||||
memcpy(secret, &e_priv, len);
|
||||
}
|
||||
|
||||
/* BOLT #8:
|
||||
* # Act One
|
||||
* # h=0x9e0e7de8bb75554f21db034633de04be41a2b8a18da7a319a03c803bf02b396c
|
||||
* # ss=0x1e2fb3c8fe8fb9f262f649f64d26ecf0f2c0a805a767cf02dc2d77a6ef1fdcc3
|
||||
* # HKDF(0x2640f52eebcd9e882958951c794250eedb28002c05d7dc2ea0f195406042caf1,0x1e2fb3c8fe8fb9f262f649f64d26ecf0f2c0a805a767cf02dc2d77a6ef1fdcc3)
|
||||
* # ck,temp_k1=0xb61ec1191326fa240decc9564369dbb3ae2b34341d1e11ad64ed89f89180582f,0xe68f69b7f096d7917245f5e5cf8ae1595febe4d4644333c99f9c4a1282031c9f
|
||||
* # encryptWithAD(0xe68f69b7f096d7917245f5e5cf8ae1595febe4d4644333c99f9c4a1282031c9f, 0x000000000000000000000000, 0x9e0e7de8bb75554f21db034633de04be41a2b8a18da7a319a03c803bf02b396c, <empty>)
|
||||
* # c=0df6086551151f58b8afe6c195782c6a
|
||||
* # h=0x9d1ffbb639e7e20021d9259491dc7b160aab270fb1339ef135053f6f2cebe9ce
|
||||
* output: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
|
||||
* # Act Two
|
||||
* input: 0x0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae
|
||||
* # re=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27
|
||||
* # h=0x38122f669819f906000621a14071802f93f2ef97df100097bcac3ae76c6dc0bf
|
||||
* # ss=0xc06363d6cc549bcb7913dbb9ac1c33fc1158680c89e972000ecd06b36c472e47
|
||||
* # HKDF(0xb61ec1191326fa240decc9564369dbb3ae2b34341d1e11ad64ed89f89180582f,0xc06363d6cc549bcb7913dbb9ac1c33fc1158680c89e972000ecd06b36c472e47)
|
||||
* # ck,temp_k2=0xe89d31033a1b6bf68c07d22e08ea4d7884646c4b60a9528598ccb4ee2c8f56ba,0x908b166535c01a935cf1e130a5fe895ab4e6f3ef8855d87e9b7581c4ab663ddc
|
||||
* # decryptWithAD(0x908b166535c01a935cf1e130a5fe895ab4e6f3ef8855d87e9b7581c4ab663ddc, 0x000000000000000000000000, 0x38122f669819f906000621a14071802f93f2ef97df100097bcac3ae76c6dc0bf, 0x6e2470b93aac583c9ef6eafca3f730ae)
|
||||
* # h=0x90578e247e98674e661013da3c5c1ca6a8c8f48c90b485c0dfa1494e23d56d72
|
||||
* # Act Three
|
||||
* # encryptWithAD(0x908b166535c01a935cf1e130a5fe895ab4e6f3ef8855d87e9b7581c4ab663ddc, 0x000000000100000000000000, 0x90578e247e98674e661013da3c5c1ca6a8c8f48c90b485c0dfa1494e23d56d72, 0x034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa)
|
||||
* # c=0xb9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c3822
|
||||
* # h=0x5dcb5ea9b4ccc755e0e3456af3990641276e1d5dc9afd82f974d90a47c918660
|
||||
* # ss=0xb36b6d195982c5be874d6d542dc268234379e1ae4ff1709402135b7de5cf0766
|
||||
* # HKDF(0xe89d31033a1b6bf68c07d22e08ea4d7884646c4b60a9528598ccb4ee2c8f56ba,0xb36b6d195982c5be874d6d542dc268234379e1ae4ff1709402135b7de5cf0766)
|
||||
* # ck,temp_k3=0x919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01,0x981a46c820fb7a241bc8184ba4bb1f01bcdfafb00dde80098cb8c38db9141520
|
||||
* # encryptWithAD(0x981a46c820fb7a241bc8184ba4bb1f01bcdfafb00dde80098cb8c38db9141520, 0x000000000000000000000000, 0x5dcb5ea9b4ccc755e0e3456af3990641276e1d5dc9afd82f974d90a47c918660, <empty>)
|
||||
* # t=0x8dc68b1c466263b47fdf31e560e139ba
|
||||
* output: 0x00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba
|
||||
* # HKDF(0x919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01,zero)
|
||||
* output: sk,rk=0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9,0xbb9020b8965f4df047e07f955f3c4b88418984aadc5cdb35096b9ea8fa5c3442
|
||||
*/
|
||||
|
||||
/* Here's what we expect: */
|
||||
static const char *expect_output[] = {
|
||||
"00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a",
|
||||
"00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba"
|
||||
};
|
||||
|
||||
static const char *expect_input[] = {
|
||||
"0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae"
|
||||
};
|
||||
|
||||
static const char expect_sk[] =
|
||||
"969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9";
|
||||
static const char expect_rk[] =
|
||||
"bb9020b8965f4df047e07f955f3c4b88418984aadc5cdb35096b9ea8fa5c3442";
|
||||
|
||||
static struct io_plan *test_write(struct io_conn *conn,
|
||||
const void *data, size_t len,
|
||||
struct io_plan *(*next)(struct io_conn *,
|
||||
struct handshake *),
|
||||
struct handshake *h)
|
||||
{
|
||||
static int upto;
|
||||
char *got;
|
||||
|
||||
assert(upto < ARRAY_SIZE(expect_output));
|
||||
got = tal_hexstr(NULL, data, len);
|
||||
assert(streq(expect_output[upto], got));
|
||||
tal_free(got);
|
||||
upto++;
|
||||
|
||||
return next(conn, h);
|
||||
}
|
||||
|
||||
static struct io_plan *test_read(struct io_conn *conn,
|
||||
void *data, size_t len,
|
||||
struct io_plan *(*next)(struct io_conn *,
|
||||
struct handshake *),
|
||||
struct handshake *h)
|
||||
{
|
||||
static int upto;
|
||||
|
||||
assert(upto < ARRAY_SIZE(expect_input));
|
||||
if (!hex_decode(expect_input[upto], strlen(expect_input[upto]),
|
||||
data, len))
|
||||
abort();
|
||||
upto++;
|
||||
|
||||
return next(conn, h);
|
||||
}
|
||||
|
||||
static struct io_plan *success(struct io_conn *conn,
|
||||
const struct pubkey *them,
|
||||
const struct crypto_state *cs,
|
||||
void *ctx)
|
||||
{
|
||||
assert(pubkey_eq(them, &rs_pub));
|
||||
|
||||
assert(secret_eq(&cs->sk, expect_sk));
|
||||
assert(secret_eq(&cs->rk, expect_rk));
|
||||
|
||||
/* No memory leaks please */
|
||||
secp256k1_context_destroy(secp256k1_ctx);
|
||||
tal_free(ctx);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
bool hsm_do_ecdh(struct secret *ss, const struct pubkey *point)
|
||||
{
|
||||
return secp256k1_ecdh(secp256k1_ctx, ss->data, &point->pubkey,
|
||||
ls_priv.secret.data) == 1;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
tal_t *ctx = tal_tmpctx(NULL);
|
||||
|
||||
trc = tal_tmpctx(ctx);
|
||||
|
||||
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY
|
||||
| SECP256K1_CONTEXT_SIGN);
|
||||
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* name: transport-initiator successful handshake
|
||||
* rs.pub: 0x028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
|
||||
* ls.priv: 0x1111111111111111111111111111111111111111111111111111111111111111
|
||||
* ls.pub: 0x034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa
|
||||
* e.priv: 0x1212121212121212121212121212121212121212121212121212121212121212
|
||||
* e.pub: 0x036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7
|
||||
*/
|
||||
rs_pub = pubkey("028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7");
|
||||
ls_priv = privkey("1111111111111111111111111111111111111111111111111111111111111111");
|
||||
ls_pub = pubkey("034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa");
|
||||
e_priv = privkey("1212121212121212121212121212121212121212121212121212121212121212");
|
||||
e_pub = pubkey("036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7");
|
||||
|
||||
initiator_handshake(ctx, &ls_pub, &rs_pub, success, ctx);
|
||||
/* Should not exit! */
|
||||
abort();
|
||||
}
|
||||
223
gossipd/test/run-responder-success.c
Normal file
223
gossipd/test/run-responder-success.c
Normal file
@@ -0,0 +1,223 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <unistd.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/io/io.h>
|
||||
#include <ccan/structeq/structeq.h>
|
||||
#include <common/status.h>
|
||||
|
||||
/* AUTOGENERATED MOCKS START */
|
||||
/* AUTOGENERATED MOCKS END */
|
||||
|
||||
/* No randomness please, we want to replicate test vectors. */
|
||||
#include <sodium/randombytes.h>
|
||||
|
||||
static void seed_randomness(u8 *secret, size_t len);
|
||||
#define randombytes_buf(secret, len) seed_randomness((secret), (len))
|
||||
|
||||
struct handshake;
|
||||
static struct io_plan *test_write(struct io_conn *conn,
|
||||
const void *data, size_t len,
|
||||
struct io_plan *(*next)(struct io_conn *,
|
||||
struct handshake *),
|
||||
struct handshake *h);
|
||||
|
||||
static struct io_plan *test_read(struct io_conn *conn,
|
||||
void *data, size_t len,
|
||||
struct io_plan *(*next)(struct io_conn *,
|
||||
struct handshake *),
|
||||
struct handshake *h);
|
||||
|
||||
#define SUPERVERBOSE status_trace
|
||||
void status_trace(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vprintf(fmt, ap);
|
||||
printf("\n");
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#undef io_write
|
||||
#undef io_read
|
||||
|
||||
#define io_write(conn, data, len, cb, cb_arg) \
|
||||
test_write((conn), (data), (len), (cb), (cb_arg))
|
||||
|
||||
#define io_read(conn, data, len, cb, cb_arg) \
|
||||
test_read((conn), (data), (len), (cb), (cb_arg))
|
||||
|
||||
#include "../handshake.c"
|
||||
#include <common/utils.h>
|
||||
#include <ccan/array_size/array_size.h>
|
||||
#include <ccan/str/hex/hex.h>
|
||||
|
||||
static struct pubkey pubkey(const char *str)
|
||||
{
|
||||
struct pubkey p;
|
||||
if (!pubkey_from_hexstr(str, strlen(str), &p))
|
||||
abort();
|
||||
return p;
|
||||
}
|
||||
|
||||
static struct privkey privkey(const char *str)
|
||||
{
|
||||
struct privkey p;
|
||||
if (!hex_decode(str, strlen(str), &p, sizeof(p)))
|
||||
abort();
|
||||
return p;
|
||||
}
|
||||
|
||||
static bool secret_eq(const struct secret *s, const char *str)
|
||||
{
|
||||
struct secret expect;
|
||||
if (!hex_decode(str, strlen(str), &expect, sizeof(expect)))
|
||||
abort();
|
||||
return structeq(s, &expect);
|
||||
}
|
||||
|
||||
secp256k1_context *secp256k1_ctx;
|
||||
const void *trc;
|
||||
static struct pubkey ls_pub, e_pub;
|
||||
static struct privkey ls_priv, e_priv;
|
||||
|
||||
static void seed_randomness(u8 *secret, size_t len)
|
||||
{
|
||||
assert(len == sizeof(e_priv));
|
||||
memcpy(secret, &e_priv, len);
|
||||
}
|
||||
|
||||
/* BOLT #8:
|
||||
* # Act One
|
||||
* input: 0x00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a
|
||||
* # re=0x036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f7
|
||||
* # h=0x9e0e7de8bb75554f21db034633de04be41a2b8a18da7a319a03c803bf02b396c
|
||||
* # ss=0x1e2fb3c8fe8fb9f262f649f64d26ecf0f2c0a805a767cf02dc2d77a6ef1fdcc3
|
||||
* # HKDF(0x2640f52eebcd9e882958951c794250eedb28002c05d7dc2ea0f195406042caf1,0x1e2fb3c8fe8fb9f262f649f64d26ecf0f2c0a805a767cf02dc2d77a6ef1fdcc3)
|
||||
* # ck,temp_k1=0xb61ec1191326fa240decc9564369dbb3ae2b34341d1e11ad64ed89f89180582f,0xe68f69b7f096d7917245f5e5cf8ae1595febe4d4644333c99f9c4a1282031c9f
|
||||
* # decryptWithAD(0xe68f69b7f096d7917245f5e5cf8ae1595febe4d4644333c99f9c4a1282031c9f, 0x000000000000000000000000, 0x9e0e7de8bb75554f21db034633de04be41a2b8a18da7a319a03c803bf02b396c, 0x0df6086551151f58b8afe6c195782c6a)
|
||||
* # h=0x9d1ffbb639e7e20021d9259491dc7b160aab270fb1339ef135053f6f2cebe9ce
|
||||
* # Act Two
|
||||
* # e.pub=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27 e.priv=0x2222222222222222222222222222222222222222222222222222222222222222
|
||||
* # h=0x38122f669819f906000621a14071802f93f2ef97df100097bcac3ae76c6dc0bf
|
||||
* # ss=0xc06363d6cc549bcb7913dbb9ac1c33fc1158680c89e972000ecd06b36c472e47
|
||||
* # HKDF(0xb61ec1191326fa240decc9564369dbb3ae2b34341d1e11ad64ed89f89180582f,0xc06363d6cc549bcb7913dbb9ac1c33fc1158680c89e972000ecd06b36c472e47)
|
||||
* # ck,temp_k2=0xe89d31033a1b6bf68c07d22e08ea4d7884646c4b60a9528598ccb4ee2c8f56ba,0x908b166535c01a935cf1e130a5fe895ab4e6f3ef8855d87e9b7581c4ab663ddc
|
||||
* # encryptWithAD(0x908b166535c01a935cf1e130a5fe895ab4e6f3ef8855d87e9b7581c4ab663ddc, 0x000000000000000000000000, 0x38122f669819f906000621a14071802f93f2ef97df100097bcac3ae76c6dc0bf, <empty>)
|
||||
* # c=0x6e2470b93aac583c9ef6eafca3f730ae
|
||||
* # h=0x90578e247e98674e661013da3c5c1ca6a8c8f48c90b485c0dfa1494e23d56d72
|
||||
* output: 0x0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae
|
||||
* # Act Three
|
||||
* input: 0x00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba
|
||||
* # decryptWithAD(0x908b166535c01a935cf1e130a5fe895ab4e6f3ef8855d87e9b7581c4ab663ddc, 0x000000000100000000000000, 0x90578e247e98674e661013da3c5c1ca6a8c8f48c90b485c0dfa1494e23d56d72, 0xb9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c3822)
|
||||
* # rs=0x034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa
|
||||
* # h=0x5dcb5ea9b4ccc755e0e3456af3990641276e1d5dc9afd82f974d90a47c918660
|
||||
* # ss=0xb36b6d195982c5be874d6d542dc268234379e1ae4ff1709402135b7de5cf0766
|
||||
* # HKDF(0xe89d31033a1b6bf68c07d22e08ea4d7884646c4b60a9528598ccb4ee2c8f56ba,0xb36b6d195982c5be874d6d542dc268234379e1ae4ff1709402135b7de5cf0766)
|
||||
* # ck,temp_k3=0x919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01,0x981a46c820fb7a241bc8184ba4bb1f01bcdfafb00dde80098cb8c38db9141520
|
||||
* # decryptWithAD(0x981a46c820fb7a241bc8184ba4bb1f01bcdfafb00dde80098cb8c38db9141520, 0x000000000000000000000000, 0x5dcb5ea9b4ccc755e0e3456af3990641276e1d5dc9afd82f974d90a47c918660, 0x8dc68b1c466263b47fdf31e560e139ba)
|
||||
* # HKDF(0x919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01,zero)
|
||||
* output: rk,sk=0x969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9,0xbb9020b8965f4df047e07f955f3c4b88418984aadc5cdb35096b9ea8fa5c3442
|
||||
*/
|
||||
|
||||
/* Here's what we expect: */
|
||||
static const char *expect_output[] = {
|
||||
"0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae"
|
||||
};
|
||||
|
||||
static const char *expect_input[] = {
|
||||
"00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a",
|
||||
"00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba"
|
||||
};
|
||||
|
||||
static const char expect_sk[] =
|
||||
"bb9020b8965f4df047e07f955f3c4b88418984aadc5cdb35096b9ea8fa5c3442";
|
||||
static const char expect_rk[] =
|
||||
"969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9";
|
||||
|
||||
static struct io_plan *test_write(struct io_conn *conn,
|
||||
const void *data, size_t len,
|
||||
struct io_plan *(*next)(struct io_conn *,
|
||||
struct handshake *),
|
||||
struct handshake *h)
|
||||
{
|
||||
static int upto;
|
||||
char *got;
|
||||
|
||||
assert(upto < ARRAY_SIZE(expect_output));
|
||||
got = tal_hexstr(NULL, data, len);
|
||||
assert(streq(expect_output[upto], got));
|
||||
tal_free(got);
|
||||
upto++;
|
||||
|
||||
return next(conn, h);
|
||||
}
|
||||
|
||||
static struct io_plan *test_read(struct io_conn *conn,
|
||||
void *data, size_t len,
|
||||
struct io_plan *(*next)(struct io_conn *,
|
||||
struct handshake *),
|
||||
struct handshake *h)
|
||||
{
|
||||
static int upto;
|
||||
|
||||
assert(upto < ARRAY_SIZE(expect_input));
|
||||
if (!hex_decode(expect_input[upto], strlen(expect_input[upto]),
|
||||
data, len))
|
||||
abort();
|
||||
upto++;
|
||||
|
||||
return next(conn, h);
|
||||
}
|
||||
|
||||
static struct io_plan *success(struct io_conn *conn,
|
||||
const struct pubkey *them,
|
||||
const struct crypto_state *cs,
|
||||
void *ctx)
|
||||
{
|
||||
assert(secret_eq(&cs->sk, expect_sk));
|
||||
assert(secret_eq(&cs->rk, expect_rk));
|
||||
|
||||
/* No memory leaks please */
|
||||
secp256k1_context_destroy(secp256k1_ctx);
|
||||
tal_free(ctx);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
bool hsm_do_ecdh(struct secret *ss, const struct pubkey *point)
|
||||
{
|
||||
return secp256k1_ecdh(secp256k1_ctx, ss->data, &point->pubkey,
|
||||
ls_priv.secret.data) == 1;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
tal_t *ctx = tal_tmpctx(NULL);
|
||||
|
||||
trc = tal_tmpctx(ctx);
|
||||
|
||||
secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY
|
||||
| SECP256K1_CONTEXT_SIGN);
|
||||
|
||||
|
||||
/* BOLT #8:
|
||||
*
|
||||
* name: transport-responder successful handshake
|
||||
* ls.priv=2121212121212121212121212121212121212121212121212121212121212121
|
||||
* ls.pub=028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7
|
||||
* e.priv=0x2222222222222222222222222222222222222222222222222222222222222222
|
||||
* e.pub=0x02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27
|
||||
*/
|
||||
ls_priv = privkey("2121212121212121212121212121212121212121212121212121212121212121");
|
||||
ls_pub = pubkey("028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7");
|
||||
e_priv = privkey("2222222222222222222222222222222222222222222222222222222222222222");
|
||||
e_pub = pubkey("02466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27");
|
||||
|
||||
responder_handshake(ctx, &ls_pub, success, ctx);
|
||||
/* Should not exit! */
|
||||
abort();
|
||||
}
|
||||
Reference in New Issue
Block a user