/*~ Welcome to the hsm daemon: keeper of our secrets! * * This is a separate daemon which keeps a root secret from which all others * are generated. It starts with one client: lightningd, which can ask for * new sockets for other clients. Each client has a simple capability map * which indicates what it's allowed to ask for. We're entirely driven * by request, response. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*~ All gen_ files are autogenerated; in this case by tools/generate-wire.py */ #include #include #include #include #include #include #include #include #include #include #include /*~ Each subdaemon is started with stdin connected to lightningd (for status * messages), and stderr untouched (for emergency printing). File descriptors * 3 and beyond are set up on other sockets: for hsmd, fd 3 is the request * stream from lightningd. */ #define REQ_FD 3 /*~ Nobody will ever find it here! hsm_secret is our root secret, the bip32 * tree is derived from that, and cached here. */ static struct { struct secret hsm_secret; struct ext_key bip32; } secretstuff; /* Version codes for BIP32 extended keys in libwally-core. * It's not suitable to add this struct into client struct, * so set it static.*/ static struct bip32_key_version bip32_key_version; #if DEVELOPER /* If they specify --dev-force-privkey it ends up in here. */ static struct privkey *dev_force_privkey; /* If they specify --dev-force-bip32-seed it ends up in here. */ static struct secret *dev_force_bip32_seed; #endif /*~ We keep track of clients, but there's not much to keep. */ struct client { /* The ccan/io async io connection for this client: it closes, we die. */ struct io_conn *conn; /*~ io_read_wire needs a pointer to store incoming messages until * it has the complete thing; this is it. */ u8 *msg_in; /*~ Useful for logging, but also used to derive the per-channel seed. */ struct node_id id; /*~ This is a unique value handed to us from lightningd, used for * per-channel seed generation (a single id may have multiple channels * over time). * * It's actually zero for the initial lightningd client connection and * the ones for gossipd and connectd, which don't have channels * associated. */ u64 dbid; /* What is this client allowed to ask for? */ u64 capabilities; /* Params to apply to all transactions for this client */ const struct chainparams *chainparams; }; /*~ We keep a map of nonzero dbid -> clients, mainly for leak detection. * This is ccan/uintmap, which maps u64 to some (non-NULL) pointer. * I really dislike these kinds of declaration-via-magic macro things, as * tags can't find them without special hacks, but the payoff here is that * the map is typesafe: the compiler won't let you put anything in but a * struct client pointer. */ static UINTMAP(struct client *) clients; /*~ Plus the three zero-dbid clients: master, gossipd and connnectd. */ static struct client *dbid_zero_clients[3]; static size_t num_dbid_zero_clients; /*~ We need this deep inside bad_req_fmt, and for memleak, so we make it a * global. */ static struct daemon_conn *status_conn; /* This is used for various assertions and error cases. */ static bool is_lightningd(const struct client *client) { return client == dbid_zero_clients[0]; } /* FIXME: This is used by debug.c. Doesn't apply to us, but lets us link. */ extern void dev_disconnect_init(int fd); void dev_disconnect_init(int fd UNUSED) { } /* Pre-declare this, due to mutual recursion */ static struct io_plan *handle_client(struct io_conn *conn, struct client *c); /*~ ccan/compiler.h defines PRINTF_FMT as the gcc compiler hint so it will * check that fmt and other trailing arguments really are the correct type. * * This is a convenient helper to tell lightningd we've received a bad request * and closes the client connection. This should never happen, of course, but * we definitely want to log if it does. */ static struct io_plan *bad_req_fmt(struct io_conn *conn, struct client *c, const u8 *msg_in, const char *fmt, ...) PRINTF_FMT(4,5); static struct io_plan *bad_req_fmt(struct io_conn *conn, struct client *c, const u8 *msg_in, const char *fmt, ...) { va_list ap; char *str; va_start(ap, fmt); str = tal_fmt(tmpctx, fmt, ap); va_end(ap); /*~ If the client was actually lightningd, it's Game Over; we actually * fail in this case, and it will too. */ if (is_lightningd(c)) { status_broken("%s", str); master_badmsg(fromwire_peektype(msg_in), msg_in); } /*~ Nobody should give us bad requests; it's a sign something is broken */ status_broken("%s: %s", type_to_string(tmpctx, struct node_id, &c->id), str); /*~ Note the use of NULL as the ctx arg to towire_hsmstatus_: only * use NULL as the allocation when we're about to immediately free it * or hand it off with take(), as here. That makes it clear we don't * expect it to linger, and in fact our memleak detection will * complain if it does (unlike using the deliberately-transient * tmpctx). */ daemon_conn_send(status_conn, take(towire_hsmstatus_client_bad_request(NULL, &c->id, str, msg_in))); /*~ The way ccan/io works is that you return the "plan" for what to do * next (eg. io_read). io_close() is special: it means to close the * connection. */ return io_close(conn); } /* Convenience wrapper for when we simply can't parse. */ static struct io_plan *bad_req(struct io_conn *conn, struct client *c, const u8 *msg_in) { return bad_req_fmt(conn, c, msg_in, "could not parse request"); } /*~ This plan simply says: read the next packet into 'c->msg_in' (parent 'c'), * and then call handle_client with argument 'c' */ static struct io_plan *client_read_next(struct io_conn *conn, struct client *c) { return io_read_wire(conn, c, &c->msg_in, handle_client, c); } /*~ This is the destructor on our client: we may call it manually, but * generally it's called because the io_conn associated with the client is * closed by the other end. */ static void destroy_client(struct client *c) { if (!uintmap_del(&clients, c->dbid)) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Failed to remove client dbid %"PRIu64, c->dbid); } static struct client *new_client(const tal_t *ctx, const struct chainparams *chainparams, const struct node_id *id, u64 dbid, const u64 capabilities, int fd) { struct client *c = tal(ctx, struct client); /*~ All-zero pubkey is used for the initial master connection */ if (id) { c->id = *id; if (!node_id_valid(id)) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Invalid node id %s", type_to_string(tmpctx, struct node_id, id)); } else { memset(&c->id, 0, sizeof(c->id)); } c->dbid = dbid; c->capabilities = capabilities; c->chainparams = chainparams; /*~ This is the core of ccan/io: the connection creation calls a * callback which returns the initial plan to execute: in our case, * read a message.*/ c->conn = io_new_conn(ctx, fd, client_read_next, c); /*~ tal_steal() moves a pointer to a new parent. At this point, the * hierarchy is: * * ctx -> c * ctx -> c->conn * * We want to the c->conn to own 'c', so that if the io_conn closes, * the client is freed: * * ctx -> c->conn -> c. */ tal_steal(c->conn, c); /* We put the special zero-db HSM connections into an array, the rest * go into the map. */ if (dbid == 0) { assert(num_dbid_zero_clients < ARRAY_SIZE(dbid_zero_clients)); dbid_zero_clients[num_dbid_zero_clients++] = c; } else { struct client *old_client = uintmap_get(&clients, dbid); /* Close conn and free any old client of this dbid. */ if (old_client) io_close(old_client->conn); if (!uintmap_add(&clients, dbid, c)) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Failed inserting dbid %"PRIu64, dbid); tal_add_destructor(c, destroy_client); } return c; } /* This is the common pattern for the tail of each handler in this file. */ static struct io_plan *req_reply(struct io_conn *conn, struct client *c, const u8 *msg_out TAKES) { /*~ Write this out, then read the next one. This works perfectly for * a simple request/response system like this. * * Internally, the ccan/io subsystem gathers all the file descriptors, * figures out which want to write and read, asks the OS which ones * are available, and for those file descriptors, tries to do the * reads/writes we've asked it. It handles retry in the case where a * read or write is done partially. * * Since the OS does buffering internally (on my system, over 100k * worth) writes will normally succeed immediately. However, if the * client is slow or malicious, and doesn't read from the socket as * fast as we're writing, eventually the socket buffer will fill up; * we don't care, because ccan/io will wait until there's room to * write this reply before it will read again. The client just hurts * themselves, and there's no Denial of Service on us. * * If we were to queue outgoing messages ourselves, we *would* have to * consider such scenarios; this is why our daemons generally avoid * buffering from untrusted parties. */ return io_write_wire(conn, msg_out, client_read_next, c); } /*~ This returns the secret and/or public key for this node. */ static void node_key(struct privkey *node_privkey, struct pubkey *node_id) { u32 salt = 0; struct privkey unused_s; struct pubkey unused_k; /* If caller specifies NULL, they don't want the results. */ if (node_privkey == NULL) node_privkey = &unused_s; else if (node_id == NULL) node_id = &unused_k; /*~ So, there is apparently a 1 in 2^127 chance that a random value is * not a valid private key, so this never actually loops. */ do { /*~ ccan/crypto/hkdf_sha256 implements RFC5869 "Hardened Key * Derivation Functions". That means that if a derived key * leaks somehow, the other keys are not compromised. */ hkdf_sha256(node_privkey, sizeof(*node_privkey), &salt, sizeof(salt), &secretstuff.hsm_secret, sizeof(secretstuff.hsm_secret), "nodeid", 6); salt++; } while (!secp256k1_ec_pubkey_create(secp256k1_ctx, &node_id->pubkey, node_privkey->secret.data)); #if DEVELOPER /* In DEVELOPER mode, we can override with --dev-force-privkey */ if (dev_force_privkey) { *node_privkey = *dev_force_privkey; if (!secp256k1_ec_pubkey_create(secp256k1_ctx, &node_id->pubkey, node_privkey->secret.data)) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Failed to derive pubkey for dev_force_privkey"); } #endif } /*~ This secret is the basis for all per-channel secrets: the per-channel seeds * will be generated by mixing in the dbid and the peer node_id. */ static void hsm_channel_secret_base(struct secret *channel_seed_base) { hkdf_sha256(channel_seed_base, sizeof(struct secret), NULL, 0, &secretstuff.hsm_secret, sizeof(secretstuff.hsm_secret), /*~ Initially, we didn't support multiple channels per * peer at all: a channel had to be completely forgotten * before another could exist. That was slightly relaxed, * but the phrase "peer seed" is wired into the seed * generation here, so we need to keep it that way for * existing clients, rather than using "channel seed". */ "peer seed", strlen("peer seed")); } /*~ This gets the seed for this particular channel. */ static void get_channel_seed(const struct node_id *peer_id, u64 dbid, struct secret *channel_seed) { struct secret channel_base; u8 input[sizeof(peer_id->k) + sizeof(dbid)]; /*~ Again, "per-peer" should be "per-channel", but Hysterical Raisins */ const char *info = "per-peer seed"; /*~ We use the DER encoding of the pubkey, because it's platform * independent. Since the dbid is unique, however, it's completely * unnecessary, but again, existing users can't be broken. */ /* FIXME: lnd has a nicer BIP32 method for deriving secrets which we * should migrate to. */ hsm_channel_secret_base(&channel_base); memcpy(input, peer_id->k, sizeof(peer_id->k)); BUILD_ASSERT(sizeof(peer_id->k) == PUBKEY_CMPR_LEN); /*~ For all that talk about platform-independence, note that this * field is endian-dependent! But let's face it, little-endian won. * In related news, we don't support EBCDIC or middle-endian. */ memcpy(input + PUBKEY_CMPR_LEN, &dbid, sizeof(dbid)); hkdf_sha256(channel_seed, sizeof(*channel_seed), input, sizeof(input), &channel_base, sizeof(channel_base), info, strlen(info)); } /*~ Called at startup to derive the bip32 field. */ static void populate_secretstuff(void) { u8 bip32_seed[BIP32_ENTROPY_LEN_256]; u32 salt = 0; struct ext_key master_extkey, child_extkey; assert(bip32_key_version.bip32_pubkey_version == BIP32_VER_MAIN_PUBLIC || bip32_key_version.bip32_pubkey_version == BIP32_VER_TEST_PUBLIC); assert(bip32_key_version.bip32_privkey_version == BIP32_VER_MAIN_PRIVATE || bip32_key_version.bip32_privkey_version == BIP32_VER_TEST_PRIVATE); /* Fill in the BIP32 tree for bitcoin addresses. */ /* In libwally-core, the version BIP32_VER_TEST_PRIVATE is for testnet/regtest, * and BIP32_VER_MAIN_PRIVATE is for mainnet. For litecoin, we also set it like * bitcoin else.*/ do { hkdf_sha256(bip32_seed, sizeof(bip32_seed), &salt, sizeof(salt), &secretstuff.hsm_secret, sizeof(secretstuff.hsm_secret), "bip32 seed", strlen("bip32 seed")); salt++; } while (bip32_key_from_seed(bip32_seed, sizeof(bip32_seed), bip32_key_version.bip32_privkey_version, 0, &master_extkey) != WALLY_OK); #if DEVELOPER /* In DEVELOPER mode, we can override with --dev-force-bip32-seed */ if (dev_force_bip32_seed) { if (bip32_key_from_seed(dev_force_bip32_seed->data, sizeof(dev_force_bip32_seed->data), bip32_key_version.bip32_privkey_version, 0, &master_extkey) != WALLY_OK) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Can't derive bip32 master key"); } #endif /* DEVELOPER */ /* BIP 32: * * The default wallet layout * * An HDW is organized as several 'accounts'. Accounts are numbered, * the default account ("") being number 0. Clients are not required * to support more than one account - if not, they only use the * default account. * * Each account is composed of two keypair chains: an internal and an * external one. The external keychain is used to generate new public * addresses, while the internal keychain is used for all other * operations (change addresses, generation addresses, ..., anything * that doesn't need to be communicated). Clients that do not support * separate keychains for these should use the external one for * everything. * * - m/iH/0/k corresponds to the k'th keypair of the external chain of * account number i of the HDW derived from master m. */ /* Hence child 0, then child 0 again to get extkey to derive from. */ if (bip32_key_from_parent(&master_extkey, 0, BIP32_FLAG_KEY_PRIVATE, &child_extkey) != WALLY_OK) /*~ status_failed() is a helper which exits and sends lightningd * a message about what happened. For hsmd, that's fatal to * lightningd. */ status_failed(STATUS_FAIL_INTERNAL_ERROR, "Can't derive child bip32 key"); if (bip32_key_from_parent(&child_extkey, 0, BIP32_FLAG_KEY_PRIVATE, &secretstuff.bip32) != WALLY_OK) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Can't derive private bip32 key"); } /*~ Get the keys for this given BIP32 index: if privkey is NULL, we * don't fill it in. */ static void bitcoin_key(struct privkey *privkey, struct pubkey *pubkey, u32 index) { struct ext_key ext; struct privkey unused_priv; if (privkey == NULL) privkey = &unused_priv; if (index >= BIP32_INITIAL_HARDENED_CHILD) status_failed(STATUS_FAIL_MASTER_IO, "Index %u too great", index); /*~ This uses libwally, which doesn't dovetail directly with * libsecp256k1 even though it, too, uses it internally. */ if (bip32_key_from_parent(&secretstuff.bip32, index, BIP32_FLAG_KEY_PRIVATE, &ext) != WALLY_OK) status_failed(STATUS_FAIL_INTERNAL_ERROR, "BIP32 of %u failed", index); /* libwally says: The private key with prefix byte 0; remove it * for libsecp256k1. */ memcpy(privkey->secret.data, ext.priv_key+1, 32); if (!secp256k1_ec_pubkey_create(secp256k1_ctx, &pubkey->pubkey, privkey->secret.data)) status_failed(STATUS_FAIL_INTERNAL_ERROR, "BIP32 pubkey %u create failed", index); } /*~ This encrypts the content of the secretstuff and stores it in hsm_secret, * this is called instead of create_hsm() if `lightningd` is started with * --encrypted-hsm. */ static void create_encrypted_hsm(int fd, const struct secret *encryption_key) { crypto_secretstream_xchacha20poly1305_state crypto_state; u8 header[crypto_secretstream_xchacha20poly1305_HEADERBYTES]; /* The cipher size is static with xchacha20poly1305 */ u8 cipher[sizeof(struct secret) + crypto_secretstream_xchacha20poly1305_ABYTES]; crypto_secretstream_xchacha20poly1305_init_push(&crypto_state, header, encryption_key->data); crypto_secretstream_xchacha20poly1305_push(&crypto_state, cipher, NULL, secretstuff.hsm_secret.data, sizeof(secretstuff.hsm_secret.data), /* Additional data and tag */ NULL, 0, 0); if (!write_all(fd, header, sizeof(header))) { unlink_noerr("hsm_secret"); status_failed(STATUS_FAIL_INTERNAL_ERROR, "Writing header of encrypted secret: %s", strerror(errno)); } if (!write_all(fd, cipher, sizeof(cipher))) { unlink_noerr("hsm_secret"); status_failed(STATUS_FAIL_INTERNAL_ERROR, "Writing encrypted secret: %s", strerror(errno)); } } static void create_hsm(int fd) { /*~ ccan/read_write_all has a more convenient return than write() where * we'd have to check the return value == the length we gave: write() * can return short on normal files if we run out of disk space. */ if (!write_all(fd, &secretstuff.hsm_secret, sizeof(secretstuff.hsm_secret))) { /* ccan/noerr contains useful routines like this, which don't * clobber errno, so we can use it in our error report. */ unlink_noerr("hsm_secret"); status_failed(STATUS_FAIL_INTERNAL_ERROR, "writing: %s", strerror(errno)); } } /*~ We store our root secret in a "hsm_secret" file (like all of c-lightning, * we run in the user's .lightning directory). */ static void maybe_create_new_hsm(const struct secret *encryption_key, bool random_hsm) { /*~ Note that this is opened for write-only, even though the permissions * are set to read-only. That's perfectly valid! */ int fd = open("hsm_secret", O_CREAT|O_EXCL|O_WRONLY, 0400); if (fd < 0) { /* If this is not the first time we've run, it will exist. */ if (errno == EEXIST) return; status_failed(STATUS_FAIL_INTERNAL_ERROR, "creating: %s", strerror(errno)); } /*~ This is libsodium's cryptographic randomness routine: we assume * it's doing a good job. */ if (random_hsm) randombytes_buf(&secretstuff.hsm_secret, sizeof(secretstuff.hsm_secret)); /*~ If an encryption_key was provided, store an encrypted seed. */ if (encryption_key) create_encrypted_hsm(fd, encryption_key); /*~ Otherwise store the seed in clear.. */ else create_hsm(fd); /*~ fsync (mostly!) ensures that the file has reached the disk. */ if (fsync(fd) != 0) { unlink_noerr("hsm_secret"); status_failed(STATUS_FAIL_INTERNAL_ERROR, "fsync: %s", strerror(errno)); } /*~ This should never fail if fsync succeeded. But paranoia good, and * bugs exist. */ if (close(fd) != 0) { unlink_noerr("hsm_secret"); status_failed(STATUS_FAIL_INTERNAL_ERROR, "closing: %s", strerror(errno)); } /*~ We actually need to sync the *directory itself* to make sure the * file exists! You're only allowed to open directories read-only in * modern Unix though. */ fd = open(".", O_RDONLY); if (fd < 0) { status_failed(STATUS_FAIL_INTERNAL_ERROR, "opening: %s", strerror(errno)); } if (fsync(fd) != 0) { unlink_noerr("hsm_secret"); status_failed(STATUS_FAIL_INTERNAL_ERROR, "fsyncdir: %s", strerror(errno)); } close(fd); /*~ status_unusual() is good for things which are interesting and * definitely won't spam the logs. Only status_broken() is higher; * status_info() is lower, then status_debug() and finally * status_io(). */ status_unusual("HSM: created new hsm_secret file"); } /*~ We always load the HSM file, even if we just created it above. This * both unifies the code paths, and provides a nice sanity check that the * file contents are as they will be for future invocations. */ static void load_hsm(const struct secret *encryption_key) { struct stat st; int fd = open("hsm_secret", O_RDONLY); if (fd < 0) status_failed(STATUS_FAIL_INTERNAL_ERROR, "opening: %s", strerror(errno)); if (stat("hsm_secret", &st) != 0) status_failed(STATUS_FAIL_INTERNAL_ERROR, "stating: %s", strerror(errno)); /* If the seed is stored in clear. */ if (st.st_size <= 32) { if (!read_all(fd, &secretstuff.hsm_secret, sizeof(secretstuff.hsm_secret))) status_failed(STATUS_FAIL_INTERNAL_ERROR, "reading: %s", strerror(errno)); /* If an encryption key was passed with a not yet encrypted hsm_secret, * remove the old one and create an encrypted one. */ if (encryption_key) { if (close(fd) != 0) status_failed(STATUS_FAIL_INTERNAL_ERROR, "closing: %s", strerror(errno)); if (remove("hsm_secret") != 0) status_failed(STATUS_FAIL_INTERNAL_ERROR, "removing clear hsm_secret: %s", strerror(errno)); maybe_create_new_hsm(encryption_key, false); fd = open("hsm_secret", O_RDONLY); if (fd < 0) status_failed(STATUS_FAIL_INTERNAL_ERROR, "opening: %s", strerror(errno)); } } /*~ If an encryption key was passed and the `hsm_secret` is stored * encrypted, recover the seed from the cipher. */ if (encryption_key && st.st_size > 32) { crypto_secretstream_xchacha20poly1305_state crypto_state; u8 header[crypto_secretstream_xchacha20poly1305_HEADERBYTES]; /* The cipher size is static with xchacha20poly1305 */ u8 cipher[sizeof(struct secret) + crypto_secretstream_xchacha20poly1305_ABYTES]; if (!read_all(fd, &header, crypto_secretstream_xchacha20poly1305_HEADERBYTES)) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Reading xchacha20 header: %s", strerror(errno)); if (!read_all(fd, cipher, sizeof(cipher))) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Reading encrypted secret: %s", strerror(errno)); if (crypto_secretstream_xchacha20poly1305_init_pull(&crypto_state, header, encryption_key->data) != 0) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Initializing the crypto state: %s", strerror(errno)); if (crypto_secretstream_xchacha20poly1305_pull(&crypto_state, secretstuff.hsm_secret.data, NULL, 0, cipher, sizeof(cipher), NULL, 0) != 0) { /* Exit but don't throw a backtrace when the user made a mistake in typing * its password. Instead exit and `lightningd` will be able to give * an error message. */ exit(1); } } /* else { handled in hsm_control } */ close(fd); populate_secretstuff(); } /*~ This is the response to lightningd's HSM_INIT request, which is the first * thing it sends. */ static struct io_plan *init_hsm(struct io_conn *conn, struct client *c, const u8 *msg_in) { struct node_id node_id; struct pubkey key; struct privkey *privkey; struct secret *seed; struct secrets *secrets; struct sha256 *shaseed; struct secret *hsm_encryption_key; /* This must be lightningd. */ assert(is_lightningd(c)); /*~ The fromwire_* routines are autogenerated, based on the message * definitions in hsm_client_wire.csv. The format of those files is * an extension of the simple comma-separated format output by the * BOLT tools/extract-formats.py tool. */ if (!fromwire_hsm_init(NULL, msg_in, &bip32_key_version, &chainparams, &hsm_encryption_key, &privkey, &seed, &secrets, &shaseed)) return bad_req(conn, c, msg_in); /*~ The memory is actually copied in towire(), so lock the `hsm_secret` * encryption key (new) memory again here. */ if (hsm_encryption_key && sodium_mlock(hsm_encryption_key, sizeof(hsm_encryption_key)) != 0) status_failed(STATUS_FAIL_INTERNAL_ERROR, "Could not lock memory for hsm_secret encryption key."); /*~ Don't swap this. */ sodium_mlock(secretstuff.hsm_secret.data, sizeof(secretstuff.hsm_secret.data)); #if DEVELOPER dev_force_privkey = privkey; dev_force_bip32_seed = seed; dev_force_channel_secrets = secrets; dev_force_channel_secrets_shaseed = shaseed; #endif /* Once we have read the init message we know which params the master * will use */ c->chainparams = chainparams; maybe_create_new_hsm(hsm_encryption_key, true); load_hsm(hsm_encryption_key); /*~ We don't need the hsm_secret encryption key anymore. * Note that sodium_munlock() also zeroes the memory. */ if (hsm_encryption_key) { sodium_munlock(hsm_encryption_key, sizeof(*hsm_encryption_key)); tal_free(hsm_encryption_key); } /*~ We tell lightning our node id and (public) bip32 seed. */ node_key(NULL, &key); node_id_from_pubkey(&node_id, &key); /*~ Note: marshalling a bip32 tree only marshals the public side, * not the secrets! So we're not actually handing them out here! */ return req_reply(conn, c, take(towire_hsm_init_reply(NULL, &node_id, &secretstuff.bip32))); } /*~ The client has asked us to extract the shared secret from an EC Diffie * Hellman token. This doesn't leak any information, but requires the private * key, so the hsmd performs it. It's used to set up an encryption key for the * connection handshaking (BOLT #8) and for the onion wrapping (BOLT #4). */ static struct io_plan *handle_ecdh(struct io_conn *conn, struct client *c, const u8 *msg_in) { struct privkey privkey; struct pubkey point; struct secret ss; if (!fromwire_hsm_ecdh_req(msg_in, &point)) return bad_req(conn, c, msg_in); /*~ We simply use the secp256k1_ecdh function: if privkey.secret.data is invalid, * we kill them for bad randomness (~1 in 2^127 if privkey.secret.data is random) */ node_key(&privkey, NULL); if (secp256k1_ecdh(secp256k1_ctx, ss.data, &point.pubkey, privkey.secret.data, NULL, NULL) != 1) { return bad_req_fmt(conn, c, msg_in, "secp256k1_ecdh fail"); } /*~ In the normal case, we return the shared secret, and then read * the next msg. */ return req_reply(conn, c, take(towire_hsm_ecdh_resp(NULL, &ss))); } /*~ The specific routine to sign the channel_announcement message. This is * defined in BOLT #7, and requires *two* signatures: one from this node's key * (to prove it's from us), and one from the bitcoin key used to create the * funding transaction (to prove we own the output). */ static struct io_plan *handle_cannouncement_sig(struct io_conn *conn, struct client *c, const u8 *msg_in) { /*~ Our autogeneration code doesn't define field offsets, so we just * copy this from the spec itself. * * Note that 'check-source' will actually find and check this quote * against the spec (if available); whitespace is ignored and * "..." means some content is skipped, but it works remarkably well to * track spec changes. */ /* BOLT #7: * * - MUST compute the double-SHA256 hash `h` of the message, beginning * at offset 256, up to the end of the message. * - Note: the hash skips the 4 signatures but hashes the rest of the * message, including any future fields appended to the end. */ /* First type bytes are the msg type */ size_t offset = 2 + 256; struct privkey node_pkey; secp256k1_ecdsa_signature node_sig, bitcoin_sig; struct sha256_double hash; u8 *reply; u8 *ca; struct pubkey funding_pubkey; struct privkey funding_privkey; struct secret channel_seed; /*~ You'll find FIXMEs like this scattered through the code. * Sometimes they suggest simple improvements which someone like * yourself should go ahead an implement. Sometimes they're deceptive * quagmires which will cause you nothing but grief. You decide! */ /*~ Christian uses TODO(cdecker) or FIXME(cdecker), but I'm sure he won't * mind if you fix this for him! */ /* FIXME: We should cache these. */ get_channel_seed(&c->id, c->dbid, &channel_seed); derive_funding_key(&channel_seed, &funding_pubkey, &funding_privkey); /*~ fromwire_ routines which need to do allocation take a tal context * as their first field; tmpctx is good here since we won't need it * after this function. */ if (!fromwire_hsm_cannouncement_sig_req(tmpctx, msg_in, &ca)) return bad_req(conn, c, msg_in); if (tal_count(ca) < offset) return bad_req_fmt(conn, c, msg_in, "bad cannounce length %zu", tal_count(ca)); if (fromwire_peektype(ca) != WIRE_CHANNEL_ANNOUNCEMENT) return bad_req_fmt(conn, c, msg_in, "Invalid channel announcement"); node_key(&node_pkey, NULL); sha256_double(&hash, ca + offset, tal_count(ca) - offset); sign_hash(&node_pkey, &hash, &node_sig); sign_hash(&funding_privkey, &hash, &bitcoin_sig); reply = towire_hsm_cannouncement_sig_reply(NULL, &node_sig, &bitcoin_sig); return req_reply(conn, c, take(reply)); } /*~ The specific routine to sign the channel_update message. */ static struct io_plan *handle_channel_update_sig(struct io_conn *conn, struct client *c, const u8 *msg_in) { /* BOLT #7: * * - MUST set `signature` to the signature of the double-SHA256 of the * entire remaining packet after `signature`, using its own * `node_id`. */ /* 2 bytes msg type + 64 bytes signature */ size_t offset = 66; struct privkey node_pkey; struct sha256_double hash; secp256k1_ecdsa_signature sig; struct short_channel_id scid; u32 timestamp, fee_base_msat, fee_proportional_mill; struct amount_msat htlc_minimum, htlc_maximum; u8 message_flags, channel_flags; u16 cltv_expiry_delta; struct bitcoin_blkid chain_hash; u8 *cu; if (!fromwire_hsm_cupdate_sig_req(tmpctx, msg_in, &cu)) return bad_req(conn, c, msg_in); if (!fromwire_channel_update_option_channel_htlc_max(cu, &sig, &chain_hash, &scid, ×tamp, &message_flags, &channel_flags, &cltv_expiry_delta, &htlc_minimum, &fee_base_msat, &fee_proportional_mill, &htlc_maximum)) { return bad_req_fmt(conn, c, msg_in, "Bad inner channel_update"); } if (tal_count(cu) < offset) return bad_req_fmt(conn, c, msg_in, "inner channel_update too short"); node_key(&node_pkey, NULL); sha256_double(&hash, cu + offset, tal_count(cu) - offset); sign_hash(&node_pkey, &hash, &sig); cu = towire_channel_update_option_channel_htlc_max(tmpctx, &sig, &chain_hash, &scid, timestamp, message_flags, channel_flags, cltv_expiry_delta, htlc_minimum, fee_base_msat, fee_proportional_mill, htlc_maximum); return req_reply(conn, c, take(towire_hsm_cupdate_sig_reply(NULL, cu))); } /*~ This gets the basepoints for a channel; it's not private information really * (we tell the peer this to establish a channel, as it sets up the keys used * for each transaction). * * Note that this is asked by lightningd, so it tells us what channels it wants. */ static struct io_plan *handle_get_channel_basepoints(struct io_conn *conn, struct client *c, const u8 *msg_in) { struct node_id peer_id; u64 dbid; struct secret seed; struct basepoints basepoints; struct pubkey funding_pubkey; if (!fromwire_hsm_get_channel_basepoints(msg_in, &peer_id, &dbid)) return bad_req(conn, c, msg_in); get_channel_seed(&peer_id, dbid, &seed); derive_basepoints(&seed, &funding_pubkey, &basepoints, NULL, NULL); return req_reply(conn, c, take(towire_hsm_get_channel_basepoints_reply(NULL, &basepoints, &funding_pubkey))); } /*~ This is another lightningd-only interface; signing a commit transaction. * This is dangerous, since if we sign a revoked commitment tx we'll lose * funds, thus it's only available to lightningd. * * * Oh look, another FIXME! */ /* FIXME: Ensure HSM never does this twice for same dbid! */ static struct io_plan *handle_sign_commitment_tx(struct io_conn *conn, struct client *c, const u8 *msg_in) { struct pubkey remote_funding_pubkey, local_funding_pubkey; struct node_id peer_id; u64 dbid; struct amount_sat funding; struct secret channel_seed; struct bitcoin_tx *tx; struct bitcoin_signature sig; struct secrets secrets; const u8 *funding_wscript; if (!fromwire_hsm_sign_commitment_tx(tmpctx, msg_in, &peer_id, &dbid, &tx, &remote_funding_pubkey, &funding)) return bad_req(conn, c, msg_in); tx->chainparams = c->chainparams; /* Basic sanity checks. */ if (tx->wtx->num_inputs != 1) return bad_req_fmt(conn, c, msg_in, "tx must have 1 input"); if (tx->wtx->num_outputs == 0) return bad_req_fmt(conn, c, msg_in, "tx must have > 0 outputs"); get_channel_seed(&peer_id, dbid, &channel_seed); derive_basepoints(&channel_seed, &local_funding_pubkey, NULL, &secrets, NULL); /*~ Bitcoin signatures cover the (part of) the script they're * executing; the rules are a bit complex in general, but for * Segregated Witness it's simply the current script. */ funding_wscript = bitcoin_redeem_2of2(tmpctx, &local_funding_pubkey, &remote_funding_pubkey); /*~ Segregated Witness also added the input amount to the signing * algorithm; it's only part of the input implicitly (it's part of the * output it's spending), so in our 'bitcoin_tx' structure it's a * pointer, as we don't always know it (and zero is a valid amount, so * NULL is better to mean 'unknown' and has the nice property that * you'll crash if you assume it's there and you're wrong.) */ tx->input_amounts[0] = tal_dup(tx, struct amount_sat, &funding); sign_tx_input(tx, 0, NULL, funding_wscript, &secrets.funding_privkey, &local_funding_pubkey, SIGHASH_ALL, &sig); return req_reply(conn, c, take(towire_hsm_sign_commitment_tx_reply(NULL, &sig))); } /*~ This is used by channeld to create signatures for the remote peer's * commitment transaction. It's functionally identical to signing our own, * but we expect to do this repeatedly as commitment transactions are * updated. * * The HSM almost certainly *should* do more checks before signing! */ /* FIXME: make sure it meets some criteria? */ static struct io_plan *handle_sign_remote_commitment_tx(struct io_conn *conn, struct client *c, const u8 *msg_in) { struct pubkey remote_funding_pubkey, local_funding_pubkey; struct amount_sat funding; struct secret channel_seed; struct bitcoin_tx *tx; struct bitcoin_signature sig; struct secrets secrets; const u8 *funding_wscript; struct witscript **output_witscripts; struct pubkey remote_per_commit; bool option_static_remotekey; if (!fromwire_hsm_sign_remote_commitment_tx(tmpctx, msg_in, &tx, &remote_funding_pubkey, &funding, &output_witscripts, &remote_per_commit, &option_static_remotekey)) bad_req(conn, c, msg_in); tx->chainparams = c->chainparams; /* Basic sanity checks. */ if (tx->wtx->num_inputs != 1) return bad_req_fmt(conn, c, msg_in, "tx must have 1 input"); if (tx->wtx->num_outputs == 0) return bad_req_fmt(conn, c, msg_in, "tx must have > 0 outputs"); if (tal_count(output_witscripts) != tx->wtx->num_outputs) return bad_req_fmt(conn, c, msg_in, "tx must have matching witscripts"); get_channel_seed(&c->id, c->dbid, &channel_seed); derive_basepoints(&channel_seed, &local_funding_pubkey, NULL, &secrets, NULL); funding_wscript = bitcoin_redeem_2of2(tmpctx, &local_funding_pubkey, &remote_funding_pubkey); /* Need input amount for signing */ tx->input_amounts[0] = tal_dup(tx, struct amount_sat, &funding); sign_tx_input(tx, 0, NULL, funding_wscript, &secrets.funding_privkey, &local_funding_pubkey, SIGHASH_ALL, &sig); return req_reply(conn, c, take(towire_hsm_sign_tx_reply(NULL, &sig))); } /*~ This is used by channeld to create signatures for the remote peer's * HTLC transactions. */ static struct io_plan *handle_sign_remote_htlc_tx(struct io_conn *conn, struct client *c, const u8 *msg_in) { struct secret channel_seed; struct bitcoin_tx *tx; struct bitcoin_signature sig; struct secrets secrets; struct basepoints basepoints; struct pubkey remote_per_commit_point; struct amount_sat amount; u8 *wscript; struct privkey htlc_privkey; struct pubkey htlc_pubkey; if (!fromwire_hsm_sign_remote_htlc_tx(tmpctx, msg_in, &tx, &wscript, &amount, &remote_per_commit_point)) return bad_req(conn, c, msg_in); tx->chainparams = c->chainparams; get_channel_seed(&c->id, c->dbid, &channel_seed); derive_basepoints(&channel_seed, NULL, &basepoints, &secrets, NULL); if (!derive_simple_privkey(&secrets.htlc_basepoint_secret, &basepoints.htlc, &remote_per_commit_point, &htlc_privkey)) return bad_req_fmt(conn, c, msg_in, "Failed deriving htlc privkey"); if (!derive_simple_key(&basepoints.htlc, &remote_per_commit_point, &htlc_pubkey)) return bad_req_fmt(conn, c, msg_in, "Failed deriving htlc pubkey"); /* Need input amount for signing */ tx->input_amounts[0] = tal_dup(tx, struct amount_sat, &amount); sign_tx_input(tx, 0, NULL, wscript, &htlc_privkey, &htlc_pubkey, SIGHASH_ALL, &sig); return req_reply(conn, c, take(towire_hsm_sign_tx_reply(NULL, &sig))); } /*~ This covers several cases where onchaind is creating a transaction which * sends funds to our internal wallet. */ /* FIXME: Derive output address for this client, and check it here! */ static struct io_plan *handle_sign_to_us_tx(struct io_conn *conn, struct client *c, const u8 *msg_in, struct bitcoin_tx *tx, const struct privkey *privkey, const u8 *wscript, struct amount_sat input_sat) { struct bitcoin_signature sig; struct pubkey pubkey; if (!pubkey_from_privkey(privkey, &pubkey)) return bad_req_fmt(conn, c, msg_in, "bad pubkey_from_privkey"); if (tx->wtx->num_inputs != 1) return bad_req_fmt(conn, c, msg_in, "bad txinput count"); tx->input_amounts[0] = tal_dup(tx, struct amount_sat, &input_sat); sign_tx_input(tx, 0, NULL, wscript, privkey, &pubkey, SIGHASH_ALL, &sig); return req_reply(conn, c, take(towire_hsm_sign_tx_reply(NULL, &sig))); } /*~ When we send a commitment transaction onchain (unilateral close), there's * a delay before we can spend it. onchaind does an explicit transaction to * transfer it to the wallet so that doesn't need to remember how to spend * this complex transaction. */ static struct io_plan *handle_sign_delayed_payment_to_us(struct io_conn *conn, struct client *c, const u8 *msg_in) { u64 commit_num; struct amount_sat input_sat; struct secret channel_seed, basepoint_secret; struct pubkey basepoint; struct bitcoin_tx *tx; struct sha256 shaseed; struct pubkey per_commitment_point; struct privkey privkey; u8 *wscript; /*~ We don't derive the wscript ourselves, but perhaps we should? */ if (!fromwire_hsm_sign_delayed_payment_to_us(tmpctx, msg_in, &commit_num, &tx, &wscript, &input_sat)) return bad_req(conn, c, msg_in); tx->chainparams = c->chainparams; get_channel_seed(&c->id, c->dbid, &channel_seed); /*~ ccan/crypto/shachain how we efficiently derive 2^48 ordered * preimages from a single seed; the twist is that as the preimages * are revealed, you can generate the previous ones yourself, needing * to only keep log(N) of them at any time. */ if (!derive_shaseed(&channel_seed, &shaseed)) return bad_req_fmt(conn, c, msg_in, "bad derive_shaseed"); /*~ BOLT #3 describes exactly how this is used to generate the Nth * per-commitment point. */ if (!per_commit_point(&shaseed, &per_commitment_point, commit_num)) return bad_req_fmt(conn, c, msg_in, "bad per_commitment_point %"PRIu64, commit_num); /*~ ... which is combined with the basepoint to generate then N'th key. */ if (!derive_delayed_payment_basepoint(&channel_seed, &basepoint, &basepoint_secret)) return bad_req_fmt(conn, c, msg_in, "failed deriving basepoint"); if (!derive_simple_privkey(&basepoint_secret, &basepoint, &per_commitment_point, &privkey)) return bad_req_fmt(conn, c, msg_in, "failed deriving privkey"); return handle_sign_to_us_tx(conn, c, msg_in, tx, &privkey, wscript, input_sat); } /*~ This is used when a commitment transaction is onchain, and has an HTLC * output paying to us (because we have the preimage); this signs that * transaction, which lightningd will broadcast to collect the funds. */ static struct io_plan *handle_sign_remote_htlc_to_us(struct io_conn *conn, struct client *c, const u8 *msg_in) { struct amount_sat input_sat; struct secret channel_seed, htlc_basepoint_secret; struct pubkey htlc_basepoint; struct bitcoin_tx *tx; struct pubkey remote_per_commitment_point; struct privkey privkey; u8 *wscript; if (!fromwire_hsm_sign_remote_htlc_to_us(tmpctx, msg_in, &remote_per_commitment_point, &tx, &wscript, &input_sat)) return bad_req(conn, c, msg_in); tx->chainparams = c->chainparams; get_channel_seed(&c->id, c->dbid, &channel_seed); if (!derive_htlc_basepoint(&channel_seed, &htlc_basepoint, &htlc_basepoint_secret)) return bad_req_fmt(conn, c, msg_in, "Failed derive_htlc_basepoint"); if (!derive_simple_privkey(&htlc_basepoint_secret, &htlc_basepoint, &remote_per_commitment_point, &privkey)) return bad_req_fmt(conn, c, msg_in, "Failed deriving htlc privkey"); return handle_sign_to_us_tx(conn, c, msg_in, tx, &privkey, wscript, input_sat); } /*~ This is used when the remote peer's commitment transaction is revoked; * we can use the revocation secret to spend the outputs. For simplicity, * we do them one at a time, though. */ static struct io_plan *handle_sign_penalty_to_us(struct io_conn *conn, struct client *c, const u8 *msg_in) { struct amount_sat input_sat; struct secret channel_seed, revocation_secret, revocation_basepoint_secret; struct pubkey revocation_basepoint; struct bitcoin_tx *tx; struct pubkey point; struct privkey privkey; u8 *wscript; if (!fromwire_hsm_sign_penalty_to_us(tmpctx, msg_in, &revocation_secret, &tx, &wscript, &input_sat)) return bad_req(conn, c, msg_in); tx->chainparams = c->chainparams; if (!pubkey_from_secret(&revocation_secret, &point)) return bad_req_fmt(conn, c, msg_in, "Failed deriving pubkey"); get_channel_seed(&c->id, c->dbid, &channel_seed); if (!derive_revocation_basepoint(&channel_seed, &revocation_basepoint, &revocation_basepoint_secret)) return bad_req_fmt(conn, c, msg_in, "Failed deriving revocation basepoint"); if (!derive_revocation_privkey(&revocation_basepoint_secret, &revocation_secret, &revocation_basepoint, &point, &privkey)) return bad_req_fmt(conn, c, msg_in, "Failed deriving revocation privkey"); return handle_sign_to_us_tx(conn, c, msg_in, tx, &privkey, wscript, input_sat); } /*~ This is used when a commitment transaction is onchain, and has an HTLC * output paying to them, which has timed out; this signs that transaction, * which lightningd will broadcast to collect the funds. */ static struct io_plan *handle_sign_local_htlc_tx(struct io_conn *conn, struct client *c, const u8 *msg_in) { u64 commit_num; struct amount_sat input_sat; struct secret channel_seed, htlc_basepoint_secret; struct sha256 shaseed; struct pubkey per_commitment_point, htlc_basepoint; struct bitcoin_tx *tx; u8 *wscript; struct bitcoin_signature sig; struct privkey htlc_privkey; struct pubkey htlc_pubkey; if (!fromwire_hsm_sign_local_htlc_tx(tmpctx, msg_in, &commit_num, &tx, &wscript, &input_sat)) return bad_req(conn, c, msg_in); tx->chainparams = c->chainparams; get_channel_seed(&c->id, c->dbid, &channel_seed); if (!derive_shaseed(&channel_seed, &shaseed)) return bad_req_fmt(conn, c, msg_in, "bad derive_shaseed"); if (!per_commit_point(&shaseed, &per_commitment_point, commit_num)) return bad_req_fmt(conn, c, msg_in, "bad per_commitment_point %"PRIu64, commit_num); if (!derive_htlc_basepoint(&channel_seed, &htlc_basepoint, &htlc_basepoint_secret)) return bad_req_fmt(conn, c, msg_in, "Failed deriving htlc basepoint"); if (!derive_simple_privkey(&htlc_basepoint_secret, &htlc_basepoint, &per_commitment_point, &htlc_privkey)) return bad_req_fmt(conn, c, msg_in, "Failed deriving htlc privkey"); if (!pubkey_from_privkey(&htlc_privkey, &htlc_pubkey)) return bad_req_fmt(conn, c, msg_in, "bad pubkey_from_privkey"); if (tx->wtx->num_inputs != 1) return bad_req_fmt(conn, c, msg_in, "bad txinput count"); /* FIXME: Check that output script is correct! */ tx->input_amounts[0] = tal_dup(tx, struct amount_sat, &input_sat); sign_tx_input(tx, 0, NULL, wscript, &htlc_privkey, &htlc_pubkey, SIGHASH_ALL, &sig); return req_reply(conn, c, take(towire_hsm_sign_tx_reply(NULL, &sig))); } /*~ This get the Nth a per-commitment point, and for N > 2, returns the * grandparent per-commitment secret. This pattern is because after * negotiating commitment N-1, we send them the next per-commitment point, * and reveal the previous per-commitment secret as a promise not to spend * the previous commitment transaction. */ static struct io_plan *handle_get_per_commitment_point(struct io_conn *conn, struct client *c, const u8 *msg_in) { struct secret channel_seed; struct sha256 shaseed; struct pubkey per_commitment_point; u64 n; struct secret *old_secret; if (!fromwire_hsm_get_per_commitment_point(msg_in, &n)) return bad_req(conn, c, msg_in); get_channel_seed(&c->id, c->dbid, &channel_seed); if (!derive_shaseed(&channel_seed, &shaseed)) return bad_req_fmt(conn, c, msg_in, "bad derive_shaseed"); if (!per_commit_point(&shaseed, &per_commitment_point, n)) return bad_req_fmt(conn, c, msg_in, "bad per_commit_point %"PRIu64, n); if (n >= 2) { old_secret = tal(tmpctx, struct secret); if (!per_commit_secret(&shaseed, old_secret, n - 2)) { return bad_req_fmt(conn, c, msg_in, "Cannot derive secret %"PRIu64, n - 2); } } else old_secret = NULL; /*~ hsm_client_wire.csv marks the secret field here optional, so it only * gets included if the parameter is non-NULL. We violate 80 columns * pretty badly here, but it's a recommendation not a religion. */ return req_reply(conn, c, take(towire_hsm_get_per_commitment_point_reply(NULL, &per_commitment_point, old_secret))); } /*~ This is used when the remote peer claims to have knowledge of future * commitment states (option_data_loss_protect in the spec) which means we've * been restored from backup or something, and may have already revealed * secrets. We carefully check that this is true, here. */ static struct io_plan *handle_check_future_secret(struct io_conn *conn, struct client *c, const u8 *msg_in) { struct secret channel_seed; struct sha256 shaseed; u64 n; struct secret secret, suggested; if (!fromwire_hsm_check_future_secret(msg_in, &n, &suggested)) return bad_req(conn, c, msg_in); get_channel_seed(&c->id, c->dbid, &channel_seed); if (!derive_shaseed(&channel_seed, &shaseed)) return bad_req_fmt(conn, c, msg_in, "bad derive_shaseed"); if (!per_commit_secret(&shaseed, &secret, n)) return bad_req_fmt(conn, c, msg_in, "bad commit secret #%"PRIu64, n); /*~ Note the special secret_eq_consttime: we generate foo_eq for many * types using ccan/structeq, but not 'struct secret' because any * comparison risks leaking information about the secret if it is * timing dependent. */ return req_reply(conn, c, take(towire_hsm_check_future_secret_reply(NULL, secret_eq_consttime(&secret, &suggested)))); } /* This is used by closingd to sign off on a mutual close tx. */ static struct io_plan *handle_sign_mutual_close_tx(struct io_conn *conn, struct client *c, const u8 *msg_in) { struct secret channel_seed; struct bitcoin_tx *tx; struct pubkey remote_funding_pubkey, local_funding_pubkey; struct bitcoin_signature sig; struct secrets secrets; struct amount_sat funding; const u8 *funding_wscript; if (!fromwire_hsm_sign_mutual_close_tx(tmpctx, msg_in, &tx, &remote_funding_pubkey, &funding)) return bad_req(conn, c, msg_in); tx->chainparams = c->chainparams; /* FIXME: We should know dust level, decent fee range and * balances, and final_keyindex, and thus be able to check tx * outputs! */ get_channel_seed(&c->id, c->dbid, &channel_seed); derive_basepoints(&channel_seed, &local_funding_pubkey, NULL, &secrets, NULL); funding_wscript = bitcoin_redeem_2of2(tmpctx, &local_funding_pubkey, &remote_funding_pubkey); /* Need input amount for signing */ tx->input_amounts[0] = tal_dup(tx, struct amount_sat, &funding); sign_tx_input(tx, 0, NULL, funding_wscript, &secrets.funding_privkey, &local_funding_pubkey, SIGHASH_ALL, &sig); return req_reply(conn, c, take(towire_hsm_sign_tx_reply(NULL, &sig))); } /*~ Since we process requests then service them in strict order, and because * only lightningd can request a new client fd, we can get away with a global * here! But because we are being tricky, I set it to an invalid value when * not in use, and sprinkle assertions around. */ static int pending_client_fd = -1; /*~ This is the callback from below: having sent the reply, we now send the * fd for the client end of the new socketpair. */ static struct io_plan *send_pending_client_fd(struct io_conn *conn, struct client *master) { int fd = pending_client_fd; /* This must be the master. */ assert(is_lightningd(master)); assert(fd != -1); /* This sanity check shouldn't be necessary, but it's cheap. */ pending_client_fd = -1; /*~There's arcane UNIX magic to send an open file descriptor over a * UNIX domain socket. There's no great way to autogenerate this * though; especially for the receive side, so we always pass these * manually immediately following the message. * * io_send_fd()'s third parameter is whether to close the local one * after sending; that saves us YA callback. */ return io_send_fd(conn, fd, true, client_read_next, master); } /*~ This is used by the master to create a new client connection (which * becomes the HSM_FD for the subdaemon after forking). */ static struct io_plan *pass_client_hsmfd(struct io_conn *conn, struct client *c, const u8 *msg_in) { int fds[2]; u64 dbid, capabilities; struct node_id id; /* This must be lightningd itself. */ assert(is_lightningd(c)); if (!fromwire_hsm_client_hsmfd(msg_in, &id, &dbid, &capabilities)) return bad_req(conn, c, msg_in); /* socketpair is a bi-directional pipe, which is what we want. */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0) status_failed(STATUS_FAIL_INTERNAL_ERROR, "creating fds: %s", strerror(errno)); status_debug("new_client: %"PRIu64, dbid); new_client(c, c->chainparams, &id, dbid, capabilities, fds[0]); /*~ We stash this in a global, because we need to get both the fd and * the client pointer to the callback. The other way would be to * create a boutique structure and hand that, but we don't need to. */ pending_client_fd = fds[1]; return io_write_wire(conn, take(towire_hsm_client_hsmfd_reply(NULL)), send_pending_client_fd, c); } /*~ For almost every wallet tx we use the BIP32 seed, but not for onchain * unilateral closes from a peer: they (may) have an output to us using a * public key based on the channel basepoints. It's a bit spammy to spend * those immediately just to make the wallet simpler, and we didn't appreciate * the problem when we designed the protocol for commitment transaction keys. * * So we store just enough about the channel it came from (which may be * long-gone) to regenerate the keys here. That has the added advantage that * the secrets themselves stay within the HSM. */ static void hsm_unilateral_close_privkey(struct privkey *dst, struct unilateral_close_info *info) { struct secret channel_seed; struct basepoints basepoints; struct secrets secrets; get_channel_seed(&info->peer_id, info->channel_id, &channel_seed); derive_basepoints(&channel_seed, NULL, &basepoints, &secrets, NULL); /* BOLT #3: * * If `option_static_remotekey` is negotiated the `remotepubkey` * is simply the remote node's `payment_basepoint`, otherwise it is * calculated as above using the remote node's `payment_basepoint`. */ /* In our UTXO representation, this is indicated by a NULL * commitment_point. */ if (!info->commitment_point) dst->secret = secrets.payment_basepoint_secret; else if (!derive_simple_privkey(&secrets.payment_basepoint_secret, &basepoints.payment, info->commitment_point, dst)) { status_failed(STATUS_FAIL_INTERNAL_ERROR, "Deriving unilateral_close_privkey"); } } /* This gets the bitcoin private key needed to spend from our wallet. */ static void hsm_key_for_utxo(struct privkey *privkey, struct pubkey *pubkey, const struct utxo *utxo) { if (utxo->close_info != NULL) { /* This is a their_unilateral_close/to-us output, so * we need to derive the secret the long way */ status_debug("Unilateral close output, deriving secrets"); hsm_unilateral_close_privkey(privkey, utxo->close_info); pubkey_from_privkey(privkey, pubkey); status_debug("Derived public key %s from unilateral close", type_to_string(tmpctx, struct pubkey, pubkey)); } else { /* Simple case: just get derive via HD-derivation */ bitcoin_key(privkey, pubkey, utxo->keyindex); } } static void sign_input(struct bitcoin_tx *tx, struct utxo *in, struct pubkey *inkey, struct bitcoin_signature *sig, int index) { struct privkey inprivkey; u8 *subscript, *wscript, *script; /* Figure out keys to spend this. */ hsm_key_for_utxo(&inprivkey, inkey, in); /* It's either a p2wpkh or p2sh (we support that so people from * the last bitcoin era can put funds into the wallet) */ wscript = p2wpkh_scriptcode(tmpctx, inkey); if (in->is_p2sh) { /* For P2SH-wrapped Segwit, the (implied) redeemScript * is defined in BIP141 */ subscript = bitcoin_redeem_p2sh_p2wpkh(tmpctx, inkey); script = bitcoin_scriptsig_p2sh_p2wpkh(tx, inkey); bitcoin_tx_input_set_script(tx, index, script); } else { /* Pure segwit uses an empty inputScript; NULL has * tal_count() == 0, so it works great here. */ subscript = NULL; bitcoin_tx_input_set_script(tx, index, NULL); } /* This is the core crypto magic. */ sign_tx_input(tx, index, subscript, wscript, &inprivkey, inkey, SIGHASH_ALL, sig); /* The witness is [sig] [key] */ bitcoin_tx_input_set_witness( tx, index, take(bitcoin_witness_p2wpkh(tx, sig, inkey))); } /* This completes the tx by filling in the input scripts with signatures. */ static void sign_all_inputs(struct bitcoin_tx *tx, struct utxo **utxos) { /*~ Deep in my mind there's a continuous battle: should arrays be * named as singular or plural? Is consistency the sign of a weak * mind? * * ZmnSCPxj answers thusly: One must make peace with the fact, that * the array itself is singular, yet its contents are plural. Do you * name the array, or do you name its contents? Is the array itself * the thing and the whole of the thing, or is it its contents that * define what it is? * *... I'm not sure that helps! */ assert(tx->wtx->num_inputs == tal_count(utxos)); for (size_t i = 0; i < tal_count(utxos); i++) { struct pubkey inkey; struct bitcoin_signature sig; sign_input(tx, utxos[i], &inkey, &sig, i); } } /*~ lightningd asks us to sign the transaction to fund a channel; it feeds us * the set of inputs and the local and remote pubkeys, and we sign it. */ static struct io_plan *handle_sign_funding_tx(struct io_conn *conn, struct client *c, const u8 *msg_in) { struct amount_sat satoshi_out, change_out; u32 change_keyindex; struct pubkey local_pubkey, remote_pubkey; struct utxo **utxos; struct bitcoin_tx *tx; u16 outnum; struct pubkey *changekey; /* FIXME: Check fee is "reasonable" */ if (!fromwire_hsm_sign_funding(tmpctx, msg_in, &satoshi_out, &change_out, &change_keyindex, &local_pubkey, &remote_pubkey, &utxos)) return bad_req(conn, c, msg_in); if (amount_sat_greater(change_out, AMOUNT_SAT(0))) { changekey = tal(tmpctx, struct pubkey); bitcoin_key(NULL, changekey, change_keyindex); } else changekey = NULL; tx = funding_tx(tmpctx, c->chainparams, &outnum, /*~ For simplicity, our generated code is not const * correct. The C rules around const and * pointer-to-pointer are a bit weird, so we use * ccan/cast which ensures the type is correct and * we're not casting something random */ cast_const2(const struct utxo **, utxos), satoshi_out, &local_pubkey, &remote_pubkey, change_out, changekey, NULL); sign_all_inputs(tx, utxos); return req_reply(conn, c, take(towire_hsm_sign_funding_reply(NULL, tx))); } /*~ lightningd asks us to sign a withdrawal; same as above but in theory * we can do more to check the previous case is valid. */ static struct io_plan *handle_sign_withdrawal_tx(struct io_conn *conn, struct client *c, const u8 *msg_in) { struct amount_sat satoshi_out, change_out; u32 change_keyindex; struct utxo **utxos; struct bitcoin_tx *tx; struct pubkey changekey; struct bitcoin_tx_output **outputs; u32 nlocktime; if (!fromwire_hsm_sign_withdrawal(tmpctx, msg_in, &satoshi_out, &change_out, &change_keyindex, &outputs, &utxos, &nlocktime)) return bad_req(conn, c, msg_in); if (!bip32_pubkey(&secretstuff.bip32, &changekey, change_keyindex)) return bad_req_fmt(conn, c, msg_in, "Failed to get key %u", change_keyindex); tx = withdraw_tx(tmpctx, c->chainparams, cast_const2(const struct utxo **, utxos), outputs, &changekey, change_out, NULL, NULL, nlocktime); sign_all_inputs(tx, utxos); return req_reply(conn, c, take(towire_hsm_sign_withdrawal_reply(NULL, tx))); } /*~ Lightning invoices, defined by BOLT 11, are signed. This has been * surprisingly controversial; it means a node needs to be online to create * invoices. However, it seems clear to me that in a world without * intermedaries you need proof that you have received an offer (the * signature), as well as proof that you've paid it (the preimage). */ static struct io_plan *handle_sign_invoice(struct io_conn *conn, struct client *c, const u8 *msg_in) { /*~ We make up a 'u5' type to represent BOLT11's 5-bits-per-byte * format: it's only for human consumption, as typedefs are almost * entirely transparent to the C compiler. */ u5 *u5bytes; u8 *hrpu8; char *hrp; struct sha256 sha; secp256k1_ecdsa_recoverable_signature rsig; struct hash_u5 hu5; struct privkey node_pkey; if (!fromwire_hsm_sign_invoice(tmpctx, msg_in, &u5bytes, &hrpu8)) return bad_req(conn, c, msg_in); /* BOLT #11: * * A writer... MUST set `signature` to a valid 512-bit * secp256k1 signature of the SHA2 256-bit hash of the * human-readable part, represented as UTF-8 bytes, * concatenated with the data part (excluding the signature) * with 0 bits appended to pad the data to the next byte * boundary, with a trailing byte containing the recovery ID * (0, 1, 2, or 3). */ /* FIXME: Check invoice! */ /*~ tal_dup_arr() does what you'd expect: allocate an array by copying * another; the cast is needed because the hrp is a 'char' array, not * a 'u8' (unsigned char) as it's the "human readable" part. * * The final arg of tal_dup_arr() is how many extra bytes to allocate: * it's so often zero that I've thought about dropping the argument, but * in cases like this (adding a NUL terminator) it's perfect. */ hrp = tal_dup_arr(tmpctx, char, (char *)hrpu8, tal_count(hrpu8), 1); hrp[tal_count(hrpu8)] = '\0'; hash_u5_init(&hu5, hrp); hash_u5(&hu5, u5bytes, tal_count(u5bytes)); hash_u5_done(&hu5, &sha); node_key(&node_pkey, NULL); /*~ By no small coincidence, this libsecp routine uses the exact * recovery signature format mandated by BOLT 11. */ if (!secp256k1_ecdsa_sign_recoverable(secp256k1_ctx, &rsig, (const u8 *)&sha, node_pkey.secret.data, NULL, NULL)) { return bad_req_fmt(conn, c, msg_in, "Failed to sign invoice"); } return req_reply(conn, c, take(towire_hsm_sign_invoice_reply(NULL, &rsig))); } /*~ It's optional for nodes to send node_announcement, but it lets us set our * favourite color and cool alias! Plus other minor details like how to * connect to us. */ static struct io_plan *handle_sign_node_announcement(struct io_conn *conn, struct client *c, const u8 *msg_in) { /* BOLT #7: * * The origin node: *... * - MUST set `signature` to the signature of the double-SHA256 of the * entire remaining packet after `signature` (using the key given by * `node_id`). */ /* 2 bytes msg type + 64 bytes signature */ size_t offset = 66; struct sha256_double hash; struct privkey node_pkey; secp256k1_ecdsa_signature sig; u8 *reply; u8 *ann; if (!fromwire_hsm_node_announcement_sig_req(tmpctx, msg_in, &ann)) return bad_req(conn, c, msg_in); if (tal_count(ann) < offset) return bad_req_fmt(conn, c, msg_in, "Node announcement too short"); if (fromwire_peektype(ann) != WIRE_NODE_ANNOUNCEMENT) return bad_req_fmt(conn, c, msg_in, "Invalid announcement"); node_key(&node_pkey, NULL); sha256_double(&hash, ann + offset, tal_count(ann) - offset); sign_hash(&node_pkey, &hash, &sig); reply = towire_hsm_node_announcement_sig_reply(NULL, &sig); return req_reply(conn, c, take(reply)); } /*~ lightningd asks us to sign a message. I tweeted the spec * in https://twitter.com/rusty_twit/status/1182102005914800128: * * @roasbeef & @bitconner point out that #lnd algo is: * zbase32(SigRec(SHA256(SHA256("Lightning Signed Message:" + msg)))). * zbase32 from https://philzimmermann.com/docs/human-oriented-base-32-encoding.txt * and SigRec has first byte 31 + recovery id, followed by 64 byte sig. #specinatweet */ static struct io_plan *handle_sign_message(struct io_conn *conn, struct client *c, const u8 *msg_in) { u8 *msg; struct sha256_ctx sctx = SHA256_INIT; struct sha256_double shad; secp256k1_ecdsa_recoverable_signature rsig; struct privkey node_pkey; if (!fromwire_hsm_sign_message(tmpctx, msg_in, &msg)) return bad_req(conn, c, msg_in); /* Prefixing by a known string means we'll never be convinced * to sign some gossip message, etc. */ sha256_update(&sctx, "Lightning Signed Message:", strlen("Lightning Signed Message:")); sha256_update(&sctx, msg, tal_count(msg)); sha256_double_done(&sctx, &shad); node_key(&node_pkey, NULL); /*~ By no small coincidence, this libsecp routine uses the exact * recovery signature format mandated by BOLT 11. */ if (!secp256k1_ecdsa_sign_recoverable(secp256k1_ctx, &rsig, shad.sha.u.u8, node_pkey.secret.data, NULL, NULL)) { return bad_req_fmt(conn, c, msg_in, "Failed to sign message"); } return req_reply(conn, c, take(towire_hsm_sign_message_reply(NULL, &rsig))); } #if DEVELOPER static struct io_plan *handle_memleak(struct io_conn *conn, struct client *c, const u8 *msg_in) { struct htable *memtable; bool found_leak; u8 *reply; memtable = memleak_enter_allocations(tmpctx, msg_in, msg_in); /* Now delete clients and anything they point to. */ memleak_remove_referenced(memtable, c); memleak_scan_region(memtable, dbid_zero_clients, sizeof(dbid_zero_clients)); memleak_remove_uintmap(memtable, &clients); memleak_scan_region(memtable, status_conn, tal_bytelen(status_conn)); memleak_scan_region(memtable, dev_force_privkey, 0); memleak_scan_region(memtable, dev_force_bip32_seed, 0); found_leak = dump_memleak(memtable); reply = towire_hsm_dev_memleak_reply(NULL, found_leak); return req_reply(conn, c, take(reply)); } #endif /* DEVELOPER */ /*~ This routine checks that a client is allowed to call the handler. */ static bool check_client_capabilities(struct client *client, enum hsm_wire_type t) { /*~ Here's a useful trick: enums in C are not real types, they're * semantic sugar sprinkled over an int, bascally (in fact, older * versions of gcc used to convert the values ints in the parser!). * * But GCC will do one thing for us: if we have a switch statement * with a controlling expression which is an enum, it will warn us * if a declared enum value is *not* handled in the switch, eg: * enumeration value ‘FOOBAR’ not handled in switch [-Werror=switch] * * This only works if there's no 'default' label, which is sometimes * hard, as we *can* have non-enum values in our enum. But the tradeoff * is worth it so the compiler tells us everywhere we have to fix when * we add a new enum identifier! */ switch (t) { case WIRE_HSM_ECDH_REQ: return (client->capabilities & HSM_CAP_ECDH) != 0; case WIRE_HSM_CANNOUNCEMENT_SIG_REQ: case WIRE_HSM_CUPDATE_SIG_REQ: case WIRE_HSM_NODE_ANNOUNCEMENT_SIG_REQ: return (client->capabilities & HSM_CAP_SIGN_GOSSIP) != 0; case WIRE_HSM_SIGN_DELAYED_PAYMENT_TO_US: case WIRE_HSM_SIGN_REMOTE_HTLC_TO_US: case WIRE_HSM_SIGN_PENALTY_TO_US: case WIRE_HSM_SIGN_LOCAL_HTLC_TX: return (client->capabilities & HSM_CAP_SIGN_ONCHAIN_TX) != 0; case WIRE_HSM_GET_PER_COMMITMENT_POINT: case WIRE_HSM_CHECK_FUTURE_SECRET: return (client->capabilities & HSM_CAP_COMMITMENT_POINT) != 0; case WIRE_HSM_SIGN_REMOTE_COMMITMENT_TX: case WIRE_HSM_SIGN_REMOTE_HTLC_TX: return (client->capabilities & HSM_CAP_SIGN_REMOTE_TX) != 0; case WIRE_HSM_SIGN_MUTUAL_CLOSE_TX: return (client->capabilities & HSM_CAP_SIGN_CLOSING_TX) != 0; case WIRE_HSM_INIT: case WIRE_HSM_CLIENT_HSMFD: case WIRE_HSM_SIGN_FUNDING: case WIRE_HSM_SIGN_WITHDRAWAL: case WIRE_HSM_SIGN_INVOICE: case WIRE_HSM_SIGN_COMMITMENT_TX: case WIRE_HSM_GET_CHANNEL_BASEPOINTS: case WIRE_HSM_DEV_MEMLEAK: case WIRE_HSM_SIGN_MESSAGE: return (client->capabilities & HSM_CAP_MASTER) != 0; /*~ These are messages sent by the HSM so we should never receive them. */ /* FIXME: Since we autogenerate these, we should really generate separate * enums for replies to avoid this kind of clutter! */ case WIRE_HSM_ECDH_RESP: case WIRE_HSM_CANNOUNCEMENT_SIG_REPLY: case WIRE_HSM_CUPDATE_SIG_REPLY: case WIRE_HSM_CLIENT_HSMFD_REPLY: case WIRE_HSM_SIGN_FUNDING_REPLY: case WIRE_HSM_NODE_ANNOUNCEMENT_SIG_REPLY: case WIRE_HSM_SIGN_WITHDRAWAL_REPLY: case WIRE_HSM_SIGN_INVOICE_REPLY: case WIRE_HSM_INIT_REPLY: case WIRE_HSMSTATUS_CLIENT_BAD_REQUEST: case WIRE_HSM_SIGN_COMMITMENT_TX_REPLY: case WIRE_HSM_SIGN_TX_REPLY: case WIRE_HSM_GET_PER_COMMITMENT_POINT_REPLY: case WIRE_HSM_CHECK_FUTURE_SECRET_REPLY: case WIRE_HSM_GET_CHANNEL_BASEPOINTS_REPLY: case WIRE_HSM_DEV_MEMLEAK_REPLY: case WIRE_HSM_SIGN_MESSAGE_REPLY: break; } return false; } /*~ This is the core of the HSM daemon: handling requests. */ static struct io_plan *handle_client(struct io_conn *conn, struct client *c) { enum hsm_wire_type t = fromwire_peektype(c->msg_in); status_debug("Client: Received message %d from client", t); /* Before we do anything else, is this client allowed to do * what he asks for? */ if (!check_client_capabilities(c, t)) return bad_req_fmt(conn, c, c->msg_in, "does not have capability to run %d", t); /* Now actually go and do what the client asked for */ switch (t) { case WIRE_HSM_INIT: return init_hsm(conn, c, c->msg_in); case WIRE_HSM_CLIENT_HSMFD: return pass_client_hsmfd(conn, c, c->msg_in); case WIRE_HSM_GET_CHANNEL_BASEPOINTS: return handle_get_channel_basepoints(conn, c, c->msg_in); case WIRE_HSM_ECDH_REQ: return handle_ecdh(conn, c, c->msg_in); case WIRE_HSM_CANNOUNCEMENT_SIG_REQ: return handle_cannouncement_sig(conn, c, c->msg_in); case WIRE_HSM_CUPDATE_SIG_REQ: return handle_channel_update_sig(conn, c, c->msg_in); case WIRE_HSM_SIGN_FUNDING: return handle_sign_funding_tx(conn, c, c->msg_in); case WIRE_HSM_NODE_ANNOUNCEMENT_SIG_REQ: return handle_sign_node_announcement(conn, c, c->msg_in); case WIRE_HSM_SIGN_INVOICE: return handle_sign_invoice(conn, c, c->msg_in); case WIRE_HSM_SIGN_WITHDRAWAL: return handle_sign_withdrawal_tx(conn, c, c->msg_in); case WIRE_HSM_SIGN_COMMITMENT_TX: return handle_sign_commitment_tx(conn, c, c->msg_in); case WIRE_HSM_SIGN_DELAYED_PAYMENT_TO_US: return handle_sign_delayed_payment_to_us(conn, c, c->msg_in); case WIRE_HSM_SIGN_REMOTE_HTLC_TO_US: return handle_sign_remote_htlc_to_us(conn, c, c->msg_in); case WIRE_HSM_SIGN_PENALTY_TO_US: return handle_sign_penalty_to_us(conn, c, c->msg_in); case WIRE_HSM_SIGN_LOCAL_HTLC_TX: return handle_sign_local_htlc_tx(conn, c, c->msg_in); case WIRE_HSM_GET_PER_COMMITMENT_POINT: return handle_get_per_commitment_point(conn, c, c->msg_in); case WIRE_HSM_CHECK_FUTURE_SECRET: return handle_check_future_secret(conn, c, c->msg_in); case WIRE_HSM_SIGN_REMOTE_COMMITMENT_TX: return handle_sign_remote_commitment_tx(conn, c, c->msg_in); case WIRE_HSM_SIGN_REMOTE_HTLC_TX: return handle_sign_remote_htlc_tx(conn, c, c->msg_in); case WIRE_HSM_SIGN_MUTUAL_CLOSE_TX: return handle_sign_mutual_close_tx(conn, c, c->msg_in); case WIRE_HSM_SIGN_MESSAGE: return handle_sign_message(conn, c, c->msg_in); #if DEVELOPER case WIRE_HSM_DEV_MEMLEAK: return handle_memleak(conn, c, c->msg_in); #else case WIRE_HSM_DEV_MEMLEAK: #endif /* DEVELOPER */ case WIRE_HSM_ECDH_RESP: case WIRE_HSM_CANNOUNCEMENT_SIG_REPLY: case WIRE_HSM_CUPDATE_SIG_REPLY: case WIRE_HSM_CLIENT_HSMFD_REPLY: case WIRE_HSM_SIGN_FUNDING_REPLY: case WIRE_HSM_NODE_ANNOUNCEMENT_SIG_REPLY: case WIRE_HSM_SIGN_WITHDRAWAL_REPLY: case WIRE_HSM_SIGN_INVOICE_REPLY: case WIRE_HSM_INIT_REPLY: case WIRE_HSMSTATUS_CLIENT_BAD_REQUEST: case WIRE_HSM_SIGN_COMMITMENT_TX_REPLY: case WIRE_HSM_SIGN_TX_REPLY: case WIRE_HSM_GET_PER_COMMITMENT_POINT_REPLY: case WIRE_HSM_CHECK_FUTURE_SECRET_REPLY: case WIRE_HSM_GET_CHANNEL_BASEPOINTS_REPLY: case WIRE_HSM_DEV_MEMLEAK_REPLY: case WIRE_HSM_SIGN_MESSAGE_REPLY: break; } return bad_req_fmt(conn, c, c->msg_in, "Unknown request"); } static void master_gone(struct io_conn *unused UNUSED, struct client *c UNUSED) { daemon_shutdown(); /* Can't tell master, it's gone. */ exit(2); } int main(int argc, char *argv[]) { struct client *master; setup_locale(); /* This sets up tmpctx, various DEVELOPER options, backtraces, etc. */ subdaemon_setup(argc, argv); /* A trivial daemon_conn just for writing. */ status_conn = daemon_conn_new(NULL, STDIN_FILENO, NULL, NULL, NULL); status_setup_async(status_conn); uintmap_init(&clients); master = new_client(NULL, NULL, NULL, 0, HSM_CAP_MASTER | HSM_CAP_SIGN_GOSSIP | HSM_CAP_ECDH, REQ_FD); /* First client == lightningd. */ assert(is_lightningd(master)); /* When conn closes, everything is freed. */ io_set_finish(master->conn, master_gone, master); /*~ The two NULL args are a list of timers, and the timer which expired: * we don't have any timers. */ io_loop(NULL, NULL); /*~ This should never be reached: io_loop only exits on io_break which * we don't call, a timer expiry which we don't have, or all connections * being closed, and closing the master calls master_gone. */ abort(); } /*~ Congratulations on making it through the first of the seven dwarves! * (And Christian wondered why I'm so fond of having separate daemons!). * * We continue our story in the next-more-complex daemon: connectd/connectd.c */