|
4 | 4 | #include <ccan/array_size/array_size.h>
|
5 | 5 | #include <ccan/cast/cast.h>
|
6 | 6 | #include <common/addr.h>
|
| 7 | +#include <common/base64.h> |
7 | 8 | #include <common/bech32.h>
|
8 | 9 | #include <common/configdir.h>
|
9 | 10 | #include <common/json_command.h>
|
@@ -1066,3 +1067,117 @@ static const struct json_command sendpsbt_command = {
|
1066 | 1067 | };
|
1067 | 1068 |
|
1068 | 1069 | AUTODATA(json_command, &sendpsbt_command);
|
| 1070 | + |
| 1071 | +static struct command_result * |
| 1072 | +json_signmessagewithkey(struct command *cmd, const char *buffer, |
| 1073 | + const jsmntok_t *obj UNNEEDED, const jsmntok_t *params) |
| 1074 | +{ |
| 1075 | + /* decoding the address */ |
| 1076 | + const u8 *scriptpubkey; |
| 1077 | + const char *message; |
| 1078 | + |
| 1079 | + /* from wallet BIP32 */ |
| 1080 | + struct pubkey pubkey; |
| 1081 | + |
| 1082 | + if (!param( |
| 1083 | + cmd, buffer, params, |
| 1084 | + p_req("message", param_string, &message), |
| 1085 | + p_req("address", param_bitcoin_address, &scriptpubkey), |
| 1086 | + NULL)) |
| 1087 | + return command_param_failed(); |
| 1088 | + |
| 1089 | + const size_t script_len = tal_bytelen(scriptpubkey); |
| 1090 | + |
| 1091 | + /* FIXME: we already had the address from the input */ |
| 1092 | + char *addr; |
| 1093 | + addr = encode_scriptpubkey_to_addr(tmpctx, chainparams, scriptpubkey); |
| 1094 | + |
| 1095 | + if (!is_p2wpkh(scriptpubkey, script_len, NULL)) { |
| 1096 | + /* FIXME add support for BIP 322 */ |
| 1097 | + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, |
| 1098 | + "Address is not p2wpkh and " |
| 1099 | + "it is not supported for signing"); |
| 1100 | + } |
| 1101 | + |
| 1102 | + if (!hsm_capable(cmd->ld, WIRE_HSMD_BIP137_SIGN_MESSAGE)) { |
| 1103 | + return command_fail( |
| 1104 | + cmd, JSONRPC2_INVALID_PARAMS, |
| 1105 | + "HSM does not support signing BIP137 signing."); |
| 1106 | + } |
| 1107 | + |
| 1108 | + const u32 bip32_max_index = |
| 1109 | + db_get_intvar(cmd->ld->wallet->db, "bip32_max_index", 0); |
| 1110 | + bool match_found = false; |
| 1111 | + u32 keyidx; |
| 1112 | + enum addrtype addrtype; |
| 1113 | + |
| 1114 | + /* loop over all generated keys, find a matching key */ |
| 1115 | + for (keyidx = 1; keyidx <= bip32_max_index; keyidx++) { |
| 1116 | + bip32_pubkey(cmd->ld, &pubkey, keyidx); |
| 1117 | + u8 *redeemscript_p2wpkh; |
| 1118 | + char *out_p2wpkh = encode_pubkey_to_addr( |
| 1119 | + cmd, &pubkey, ADDR_BECH32, &redeemscript_p2wpkh); |
| 1120 | + if (!out_p2wpkh) { |
| 1121 | + abort(); |
| 1122 | + } |
| 1123 | + /* wallet_get_addrtype fails for entries prior to v24.11, all |
| 1124 | + * address types are assumed in that case. */ |
| 1125 | + if (!wallet_get_addrtype(cmd->ld->wallet, keyidx, &addrtype)) |
| 1126 | + addrtype = ADDR_ALL; |
| 1127 | + if (streq(addr, out_p2wpkh) && |
| 1128 | + (addrtype == ADDR_BECH32 || addrtype == ADDR_ALL)) { |
| 1129 | + match_found = true; |
| 1130 | + break; |
| 1131 | + } |
| 1132 | + } |
| 1133 | + |
| 1134 | + if (!match_found) { |
| 1135 | + return command_fail( |
| 1136 | + cmd, JSONRPC2_INVALID_PARAMS, |
| 1137 | + "Address is not found in the wallet's database"); |
| 1138 | + } |
| 1139 | + |
| 1140 | + /* wire to hsmd a sign request */ |
| 1141 | + u8 *msg = towire_hsmd_bip137_sign_message( |
| 1142 | + cmd, tal_dup_arr(tmpctx, u8, (u8 *)message, strlen(message), 0), |
| 1143 | + keyidx); |
| 1144 | + if (!wire_sync_write(cmd->ld->hsm_fd, take(msg))) { |
| 1145 | + fatal("Could not write sign_with_key to HSM: %s", |
| 1146 | + strerror(errno)); |
| 1147 | + } |
| 1148 | + |
| 1149 | + /* read form hsmd a sign reply */ |
| 1150 | + msg = wire_sync_read(cmd, cmd->ld->hsm_fd); |
| 1151 | + |
| 1152 | + int recid; |
| 1153 | + u8 sig[65]; |
| 1154 | + secp256k1_ecdsa_recoverable_signature rsig; |
| 1155 | + |
| 1156 | + if (!fromwire_hsmd_bip137_sign_message_reply(msg, &rsig)) { |
| 1157 | + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, |
| 1158 | + "HSM gave bad sign_with_key_reply %s", |
| 1159 | + tal_hex(tmpctx, msg)); |
| 1160 | + } |
| 1161 | + |
| 1162 | + secp256k1_ecdsa_recoverable_signature_serialize_compact( |
| 1163 | + secp256k1_ctx, sig + 1, &recid, &rsig); |
| 1164 | + /* this is the header value for P2WPKH specified in BIP137 */ |
| 1165 | + sig[0] = recid + 39; |
| 1166 | + |
| 1167 | + /* FIXME: Given the fact that we plan to extend support for BIP322 |
| 1168 | + * signature in the future making a pubkey output here makes less sense. */ |
| 1169 | + struct json_stream *response; |
| 1170 | + response = json_stream_success(cmd); |
| 1171 | + json_add_string(response, "address", addr); |
| 1172 | + json_add_pubkey(response, "pubkey", &pubkey); |
| 1173 | + json_add_hex(response, "signature", sig, sizeof(sig)); |
| 1174 | + json_add_string(response, "base64", |
| 1175 | + b64_encode(tmpctx, sig, sizeof(sig))); |
| 1176 | + return command_success(cmd, response); |
| 1177 | +} |
| 1178 | + |
| 1179 | +static const struct json_command signmessagewithkey_command = { |
| 1180 | + "signmessagewithkey", |
| 1181 | + json_signmessagewithkey |
| 1182 | +}; |
| 1183 | +AUTODATA(json_command, &signmessagewithkey_command); |
0 commit comments