From 3fed84ed7e7cd55e5992f2cc61ebcc86be437bce Mon Sep 17 00:00:00 2001 From: Marko Bencun Date: Thu, 1 May 2025 17:05:03 +0200 Subject: [PATCH] api/firmware: add Bluetooth info to DeviceInfo --- api/firmware/device.go | 8 ++ api/firmware/messages/bitbox02_system.pb.go | 143 +++++++++++++++----- api/firmware/messages/bitbox02_system.proto | 6 + api/firmware/system.go | 10 ++ cmd/playground/main.go | 4 +- 5 files changed, 139 insertions(+), 32 deletions(-) diff --git a/api/firmware/device.go b/api/firmware/device.go index cc9c9c1..726616b 100644 --- a/api/firmware/device.go +++ b/api/firmware/device.go @@ -103,6 +103,12 @@ type Device struct { log Logger } +// BluetoothInfo contains Bluetooth-related info. +type BluetoothInfo struct { + // FirmwareHash is the hex-encoded 32 byte Bluetooth firmware hash. + FirmwareHash string `json:"firmwareHash"` +} + // DeviceInfo is the data returned from the device info api call. type DeviceInfo struct { Name string `json:"name"` @@ -112,6 +118,8 @@ type DeviceInfo struct { // This information is only available since firmwae v9.6.0. Will be an empty string for older // firmware versions. SecurechipModel string `json:"securechipModel"` + // Available on Bluetooth-enabled devices, Will be `nil` otherwise. + Bluetooth *BluetoothInfo `json:"bluetooth"` } // NewDevice creates a new instance of Device. diff --git a/api/firmware/messages/bitbox02_system.pb.go b/api/firmware/messages/bitbox02_system.pb.go index 05a575a..90fb58f 100644 --- a/api/firmware/messages/bitbox02_system.pb.go +++ b/api/firmware/messages/bitbox02_system.pb.go @@ -215,6 +215,8 @@ type DeviceInfoResponse struct { MonotonicIncrementsRemaining uint32 `protobuf:"varint,5,opt,name=monotonic_increments_remaining,json=monotonicIncrementsRemaining,proto3" json:"monotonic_increments_remaining,omitempty"` // From v9.6.0: "ATECC608A" or "ATECC608B". SecurechipModel string `protobuf:"bytes,6,opt,name=securechip_model,json=securechipModel,proto3" json:"securechip_model,omitempty"` + // Only present in Bluetooth-enabled devices. + Bluetooth *DeviceInfoResponse_Bluetooth `protobuf:"bytes,7,opt,name=bluetooth,proto3,oneof" json:"bluetooth,omitempty"` } func (x *DeviceInfoResponse) Reset() { @@ -291,6 +293,13 @@ func (x *DeviceInfoResponse) GetSecurechipModel() string { return "" } +func (x *DeviceInfoResponse) GetBluetooth() *DeviceInfoResponse_Bluetooth { + if x != nil { + return x.Bluetooth + } + return nil +} + type InsertRemoveSDCardRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -517,6 +526,54 @@ func (x *SetPasswordRequest) GetEntropy() []byte { return nil } +type DeviceInfoResponse_Bluetooth struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Hash of the currently active Bluetooth firmware on the device. + FirmwareHash []byte `protobuf:"bytes,1,opt,name=firmware_hash,json=firmwareHash,proto3" json:"firmware_hash,omitempty"` +} + +func (x *DeviceInfoResponse_Bluetooth) Reset() { + *x = DeviceInfoResponse_Bluetooth{} + if protoimpl.UnsafeEnabled { + mi := &file_bitbox02_system_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeviceInfoResponse_Bluetooth) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeviceInfoResponse_Bluetooth) ProtoMessage() {} + +func (x *DeviceInfoResponse_Bluetooth) ProtoReflect() protoreflect.Message { + mi := &file_bitbox02_system_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeviceInfoResponse_Bluetooth.ProtoReflect.Descriptor instead. +func (*DeviceInfoResponse_Bluetooth) Descriptor() ([]byte, []int) { + return file_bitbox02_system_proto_rawDescGZIP(), []int{3, 0} +} + +func (x *DeviceInfoResponse_Bluetooth) GetFirmwareHash() []byte { + if x != nil { + return x.FirmwareHash + } + return nil +} + var File_bitbox02_system_proto protoreflect.FileDescriptor var file_bitbox02_system_proto_rawDesc = []byte{ @@ -528,7 +585,7 @@ var file_bitbox02_system_proto_rawDesc = []byte{ 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x65, 0x64, 0x22, 0x13, 0x0a, 0x11, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x95, 0x02, 0x0a, 0x12, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xac, 0x03, 0x0a, 0x12, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x6e, 0x69, 0x74, 0x69, 0x61, @@ -546,28 +603,37 @@ var file_bitbox02_system_proto_rawDesc = []byte{ 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x29, 0x0a, 0x10, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x63, 0x68, 0x69, 0x70, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x65, 0x63, 0x68, 0x69, 0x70, 0x4d, 0x6f, - 0x64, 0x65, 0x6c, 0x22, 0xa3, 0x01, 0x0a, 0x19, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x52, 0x65, - 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x44, 0x43, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x54, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x3c, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, - 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x52, - 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x44, 0x43, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x2e, 0x53, 0x44, 0x43, 0x61, 0x72, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x30, 0x0a, 0x0c, 0x53, 0x44, 0x43, 0x61, 0x72, - 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0f, 0x0a, 0x0b, 0x52, 0x45, 0x4d, 0x4f, 0x56, - 0x45, 0x5f, 0x43, 0x41, 0x52, 0x44, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x4e, 0x53, 0x45, - 0x52, 0x54, 0x5f, 0x43, 0x41, 0x52, 0x44, 0x10, 0x01, 0x22, 0x0e, 0x0a, 0x0c, 0x52, 0x65, 0x73, - 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x36, 0x0a, 0x18, 0x53, 0x65, 0x74, - 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, - 0x65, 0x22, 0x2a, 0x0a, 0x14, 0x53, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, - 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x2e, 0x0a, - 0x12, 0x53, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x6f, 0x70, 0x79, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x64, 0x65, 0x6c, 0x12, 0x55, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x2e, 0x42, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6c, + 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x88, 0x01, 0x01, 0x1a, 0x30, 0x0a, 0x09, 0x42, 0x6c, + 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x69, 0x72, 0x6d, 0x77, + 0x61, 0x72, 0x65, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, + 0x66, 0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x48, 0x61, 0x73, 0x68, 0x42, 0x0c, 0x0a, 0x0a, + 0x5f, 0x62, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x22, 0xa3, 0x01, 0x0a, 0x19, 0x49, + 0x6e, 0x73, 0x65, 0x72, 0x74, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x44, 0x43, 0x61, 0x72, + 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x54, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x3c, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, + 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, + 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x44, 0x43, 0x61, + 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x53, 0x44, 0x43, 0x61, 0x72, 0x64, + 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x30, + 0x0a, 0x0c, 0x53, 0x44, 0x43, 0x61, 0x72, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0f, + 0x0a, 0x0b, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, 0x5f, 0x43, 0x41, 0x52, 0x44, 0x10, 0x00, 0x12, + 0x0f, 0x0a, 0x0b, 0x49, 0x4e, 0x53, 0x45, 0x52, 0x54, 0x5f, 0x43, 0x41, 0x52, 0x44, 0x10, 0x01, + 0x22, 0x0e, 0x0a, 0x0c, 0x52, 0x65, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x22, 0x36, 0x0a, 0x18, 0x53, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x61, 0x6e, + 0x67, 0x75, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, + 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x22, 0x2a, 0x0a, 0x14, 0x53, 0x65, 0x74, 0x44, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x2e, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, + 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, + 0x74, 0x72, 0x6f, 0x70, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x6e, 0x74, + 0x72, 0x6f, 0x70, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -583,7 +649,7 @@ func file_bitbox02_system_proto_rawDescGZIP() []byte { } var file_bitbox02_system_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_bitbox02_system_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_bitbox02_system_proto_msgTypes = make([]protoimpl.MessageInfo, 10) var file_bitbox02_system_proto_goTypes = []any{ (InsertRemoveSDCardRequest_SDCardAction)(0), // 0: shiftcrypto.bitbox02.InsertRemoveSDCardRequest.SDCardAction (*CheckSDCardRequest)(nil), // 1: shiftcrypto.bitbox02.CheckSDCardRequest @@ -595,14 +661,16 @@ var file_bitbox02_system_proto_goTypes = []any{ (*SetDeviceLanguageRequest)(nil), // 7: shiftcrypto.bitbox02.SetDeviceLanguageRequest (*SetDeviceNameRequest)(nil), // 8: shiftcrypto.bitbox02.SetDeviceNameRequest (*SetPasswordRequest)(nil), // 9: shiftcrypto.bitbox02.SetPasswordRequest + (*DeviceInfoResponse_Bluetooth)(nil), // 10: shiftcrypto.bitbox02.DeviceInfoResponse.Bluetooth } var file_bitbox02_system_proto_depIdxs = []int32{ - 0, // 0: shiftcrypto.bitbox02.InsertRemoveSDCardRequest.action:type_name -> shiftcrypto.bitbox02.InsertRemoveSDCardRequest.SDCardAction - 1, // [1:1] is the sub-list for method output_type - 1, // [1:1] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name + 10, // 0: shiftcrypto.bitbox02.DeviceInfoResponse.bluetooth:type_name -> shiftcrypto.bitbox02.DeviceInfoResponse.Bluetooth + 0, // 1: shiftcrypto.bitbox02.InsertRemoveSDCardRequest.action:type_name -> shiftcrypto.bitbox02.InsertRemoveSDCardRequest.SDCardAction + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name } func init() { file_bitbox02_system_proto_init() } @@ -719,14 +787,27 @@ func file_bitbox02_system_proto_init() { return nil } } + file_bitbox02_system_proto_msgTypes[9].Exporter = func(v any, i int) any { + switch v := v.(*DeviceInfoResponse_Bluetooth); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } + file_bitbox02_system_proto_msgTypes[3].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_bitbox02_system_proto_rawDesc, NumEnums: 1, - NumMessages: 9, + NumMessages: 10, NumExtensions: 0, NumServices: 0, }, diff --git a/api/firmware/messages/bitbox02_system.proto b/api/firmware/messages/bitbox02_system.proto index a51acee..8473148 100644 --- a/api/firmware/messages/bitbox02_system.proto +++ b/api/firmware/messages/bitbox02_system.proto @@ -26,6 +26,10 @@ message DeviceInfoRequest { } message DeviceInfoResponse { + message Bluetooth { + // Hash of the currently active Bluetooth firmware on the device. + bytes firmware_hash = 1; + } string name = 1; bool initialized = 2; string version = 3; @@ -33,6 +37,8 @@ message DeviceInfoResponse { uint32 monotonic_increments_remaining = 5; // From v9.6.0: "ATECC608A" or "ATECC608B". string securechip_model = 6; + // Only present in Bluetooth-enabled devices. + optional Bluetooth bluetooth = 7; } message InsertRemoveSDCardRequest { diff --git a/api/firmware/system.go b/api/firmware/system.go index c290e15..700595b 100644 --- a/api/firmware/system.go +++ b/api/firmware/system.go @@ -15,6 +15,8 @@ package firmware import ( + "encoding/hex" + "github.com/BitBoxSwiss/bitbox02-api-go/api/firmware/messages" "github.com/BitBoxSwiss/bitbox02-api-go/util/errp" "github.com/BitBoxSwiss/bitbox02-api-go/util/semver" @@ -64,12 +66,20 @@ func (device *Device) DeviceInfo() (*DeviceInfo, error) { return nil, errp.New("Failed to retrieve device info") } + var bluetooth *BluetoothInfo + if deviceInfoResponse.DeviceInfo.Bluetooth != nil { + bluetooth = &BluetoothInfo{ + FirmwareHash: hex.EncodeToString(deviceInfoResponse.DeviceInfo.Bluetooth.FirmwareHash), + } + } + deviceInfo := &DeviceInfo{ Name: deviceInfoResponse.DeviceInfo.Name, Version: deviceInfoResponse.DeviceInfo.Version, Initialized: deviceInfoResponse.DeviceInfo.Initialized, MnemonicPassphraseEnabled: deviceInfoResponse.DeviceInfo.MnemonicPassphraseEnabled, SecurechipModel: deviceInfoResponse.DeviceInfo.SecurechipModel, + Bluetooth: bluetooth, } return deviceInfo, nil diff --git a/cmd/playground/main.go b/cmd/playground/main.go index aae3dce..5afa278 100644 --- a/cmd/playground/main.go +++ b/cmd/playground/main.go @@ -211,7 +211,9 @@ func main() { info, err := device.DeviceInfo() errpanic(err) - fmt.Printf("Device info: %+v", info) + infoJson, err := json.MarshalIndent(info, "", " ") + errpanic(err) + fmt.Printf("Device info: %s", infoJson) //signFromTxID(device, "48e83b2a44c21dab01fc7bad0df1b1d7a59e48af79069454a8320ec6a9d1aefb") sig, err := device.ETHSignEIP1559(