Rusty Russell
7 years ago
committed by
Christian Decker
4 changed files with 1487 additions and 0 deletions
@ -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); |
|||
} |
@ -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 */ |
@ -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(); |
|||
} |
@ -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(); |
|||
} |
Loading…
Reference in new issue