| 41 | } |
| 42 | |
| 43 | static struct command_result *json_exposesecret(struct command *cmd, |
| 44 | const char *buffer, |
| 45 | const jsmntok_t *params) |
| 46 | { |
| 47 | const struct exposesecret *exposesecret = exposesecret_data(cmd->plugin); |
| 48 | struct json_stream *js; |
| 49 | u8 *contents; |
| 50 | const char *id, *passphrase; |
| 51 | enum hsm_secret_error err; |
| 52 | struct hsm_secret *hsms; |
| 53 | struct privkey node_privkey; |
| 54 | struct pubkey node_id; |
| 55 | char *bip93; |
| 56 | u32 salt = 0; |
| 57 | |
| 58 | if (!param_check(cmd, buffer, params, |
| 59 | p_req("passphrase", param_string, &passphrase), |
| 60 | p_opt("identifier", param_string, &id), |
| 61 | NULL)) |
| 62 | return command_param_failed(); |
| 63 | |
| 64 | if (!exposesecret->exposure_passphrase) |
| 65 | return command_fail(cmd, LIGHTNINGD, "exposesecrets-passphrase is not set"); |
| 66 | |
| 67 | /* Technically, this could become a timing oracle. */ |
| 68 | if (!compare_passphrases(exposesecret->exposure_passphrase, passphrase)) |
| 69 | return command_fail(cmd, LIGHTNINGD, "passphrase does not match exposesecrets-passphrase"); |
| 70 | |
| 71 | contents = grab_file_raw(tmpctx, "hsm_secret"); |
| 72 | if (!contents) |
| 73 | return command_fail(cmd, LIGHTNINGD, "Could not open hsm_secret: %s", strerror(errno)); |
| 74 | |
| 75 | /* Check if the HSM secret needs a passphrase */ |
| 76 | if (hsm_secret_needs_passphrase(contents, tal_bytelen(contents))) { |
| 77 | return command_fail(cmd, LIGHTNINGD, "Secret with passphrase is not supported"); |
| 78 | } |
| 79 | |
| 80 | /* Extract the HSM secret without passphrase */ |
| 81 | hsms = extract_hsm_secret(tmpctx, contents, tal_bytelen(contents), NULL, &err); |
| 82 | |
| 83 | if (!hsms) |
| 84 | return command_fail(cmd, LIGHTNINGD, "Could not parse hsm_secret: %s", hsm_secret_error_str(err)); |
| 85 | |
| 86 | /* Before we expose it, check it's correct! */ |
| 87 | hkdf_sha256(&node_privkey, sizeof(node_privkey), |
| 88 | &salt, sizeof(salt), |
| 89 | hsms->secret_data, |
| 90 | 32, |
| 91 | "nodeid", 6); |
| 92 | |
| 93 | /* Should not happen! */ |
| 94 | if (!pubkey_from_privkey(&node_privkey, &node_id)) |
| 95 | return command_fail(cmd, LIGHTNINGD, "Invalid private key?"); |
| 96 | |
| 97 | if (!pubkey_eq(&node_id, &exposesecret->our_node_id)) |
| 98 | return command_fail(cmd, LIGHTNINGD, "This hsm_secret is not for the current node"); |
| 99 | |
| 100 | /* If they didn't give an identifier, we make an appropriate one! */ |
nothing calls this directly
no test coverage detected