|
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,123 @@ 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 | + enum addrtype addrtype; |
| 1095 | + |
| 1096 | + if (is_p2tr(scriptpubkey, script_len, NULL)) |
| 1097 | + addrtype = ADDR_P2TR; |
| 1098 | + else if (is_p2wpkh(scriptpubkey, script_len, NULL)) |
| 1099 | + addrtype = ADDR_BECH32; |
| 1100 | + else { |
| 1101 | + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, |
| 1102 | + "address %s is neither p2wpkh nor p2tr and " |
| 1103 | + "it is not supported", |
| 1104 | + addr); |
| 1105 | + } |
| 1106 | + |
| 1107 | + u32 keyidx; |
| 1108 | + |
| 1109 | + /* loop over all generated keys, find a matching key */ |
| 1110 | + /* FIXME: alternatively, can we use the our_addresses hash table? |
| 1111 | + *struct script_with_len *key; |
| 1112 | + *struct wallet_address *addr = |
| 1113 | + * wallet_address_htable_get(cmd->ld->wallet->our_addresses, key); |
| 1114 | + */ |
| 1115 | + struct issued_address_type *listaddrtypes = |
| 1116 | + wallet_list_addresses(tmpctx, cmd->ld->wallet, 1, NULL); |
| 1117 | + for (size_t i = 0; i < tal_count(listaddrtypes); i++) { |
| 1118 | + if (listaddrtypes[i].keyidx == BIP32_INITIAL_HARDENED_CHILD) { |
| 1119 | + break; |
| 1120 | + } |
| 1121 | + bip32_pubkey(cmd->ld, &pubkey, listaddrtypes[i].keyidx); |
| 1122 | + char *out_p2wpkh = ""; |
| 1123 | + char *out_p2tr = ""; |
| 1124 | + if (listaddrtypes[i].addrtype == ADDR_BECH32 || |
| 1125 | + listaddrtypes[i].addrtype == ADDR_ALL) { |
| 1126 | + u8 *redeemscript_p2wpkh; |
| 1127 | + out_p2wpkh = encode_pubkey_to_addr( |
| 1128 | + cmd, &pubkey, ADDR_BECH32, &redeemscript_p2wpkh); |
| 1129 | + if (!out_p2wpkh) { |
| 1130 | + abort(); |
| 1131 | + } |
| 1132 | + } |
| 1133 | + if (listaddrtypes[i].addrtype == ADDR_P2TR || |
| 1134 | + listaddrtypes[i].addrtype == ADDR_ALL) { |
| 1135 | + out_p2tr = |
| 1136 | + encode_pubkey_to_addr(cmd, &pubkey, ADDR_P2TR, |
| 1137 | + /* out_redeemscript */ NULL); |
| 1138 | + if (!out_p2tr) { |
| 1139 | + abort(); |
| 1140 | + } |
| 1141 | + } |
| 1142 | + |
| 1143 | + if (streq(addr, out_p2wpkh) || streq(addr, out_p2tr)) { |
| 1144 | + keyidx = listaddrtypes[i].keyidx; |
| 1145 | + break; |
| 1146 | + } |
| 1147 | + } |
| 1148 | + |
| 1149 | + /* wire to hsmd a sign request */ |
| 1150 | + u8 *msg = towire_hsmd_sign_message_with_key( |
| 1151 | + cmd, tal_dup_arr(tmpctx, u8, (u8 *)message, strlen(message), 0), |
| 1152 | + keyidx); |
| 1153 | + if (!wire_sync_write(cmd->ld->hsm_fd, take(msg))) { |
| 1154 | + fatal("Could not write sign_with_key to HSM: %s", |
| 1155 | + strerror(errno)); |
| 1156 | + } |
| 1157 | + |
| 1158 | + /* read form hsmd a sign reply */ |
| 1159 | + msg = wire_sync_read(cmd, cmd->ld->hsm_fd); |
| 1160 | + |
| 1161 | + size_t len = 72; |
| 1162 | + u8 der[72]; |
| 1163 | + secp256k1_ecdsa_signature signature; |
| 1164 | + |
| 1165 | + if (!fromwire_hsmd_sign_message_with_key_reply(msg, &signature)) { |
| 1166 | + return command_fail(cmd, JSONRPC2_INVALID_PARAMS, |
| 1167 | + "HSM gave bad sign_with_key_reply %s", |
| 1168 | + tal_hex(tmpctx, msg)); |
| 1169 | + } |
| 1170 | + |
| 1171 | + secp256k1_ecdsa_signature_serialize_der(secp256k1_ctx, der, &len, |
| 1172 | + &signature); |
| 1173 | + |
| 1174 | + struct json_stream *response; |
| 1175 | + response = json_stream_success(cmd); |
| 1176 | + if (addrtype & ADDR_BECH32) |
| 1177 | + json_add_string(response, "bech32", addr); |
| 1178 | + if (addrtype & ADDR_P2TR) |
| 1179 | + json_add_string(response, "p2tr", addr); |
| 1180 | + json_add_u32(response, "keyidx", keyidx); |
| 1181 | + json_add_string(response, "signature", b64_encode(tmpctx, der, len)); |
| 1182 | + return command_success(cmd, response); |
| 1183 | +} |
| 1184 | + |
| 1185 | +static const struct json_command signmessagewithkey_command = { |
| 1186 | + "signmessagewithkey", |
| 1187 | + json_signmessagewithkey |
| 1188 | +}; |
| 1189 | +AUTODATA(json_command, &signmessagewithkey_command); |
0 commit comments