@@ -19,6 +19,7 @@ package ledger_go
19
19
import (
20
20
"encoding/binary"
21
21
"fmt"
22
+
22
23
"github.com/pkg/errors"
23
24
)
24
25
@@ -42,7 +43,7 @@ func ErrorMessage(errorCode uint16) string {
42
43
case 0x6985 :
43
44
return "[APDU_CODE_CONDITIONS_NOT_SATISFIED] Conditions of use not satisfied"
44
45
case 0x6986 :
45
- return "[APDU_CODE_COMMAND_NOT_ALLOWED] Command not allowed (no current EF)"
46
+ return "[APDU_CODE_COMMAND_NOT_ALLOWED] Command not allowed / User Rejected (no current EF)"
46
47
case 0x6A80 :
47
48
return "[APDU_CODE_BAD_KEY_HANDLE] The parameters in the data field are incorrect"
48
49
case 0x6B00 :
@@ -51,6 +52,8 @@ func ErrorMessage(errorCode uint16) string {
51
52
return "[APDU_CODE_INS_NOT_SUPPORTED] Instruction code not supported or invalid"
52
53
case 0x6E00 :
53
54
return "[APDU_CODE_CLA_NOT_SUPPORTED] CLA not supported"
55
+ case 0x6E01 :
56
+ return "[APDU_CODE_APP_NOT_OPEN] Ledger Connected but Chain Specific App Not Open"
54
57
case 0x6F00 :
55
58
return "APDU_CODE_UNKNOWN"
56
59
case 0x6F01 :
@@ -105,26 +108,35 @@ func SerializePacket(
105
108
func DeserializePacket (
106
109
channel uint16 ,
107
110
buffer []byte ,
108
- sequenceIdx uint16 ) (result []byte , totalResponseLength uint16 , err error ) {
111
+ sequenceIdx uint16 ) (result []byte , totalResponseLength uint16 , isSequenceZero bool , err error ) {
112
+
113
+ isSequenceZero = false
109
114
110
115
if (sequenceIdx == 0 && len (buffer ) < 7 ) || (sequenceIdx > 0 && len (buffer ) < 5 ) {
111
- return nil , 0 , errors .New ("Cannot deserialize the packet. Header information is missing." )
116
+ return nil , 0 , isSequenceZero , errors .New ("Cannot deserialize the packet. Header information is missing." )
112
117
}
113
118
114
119
var headerOffset uint8
115
120
116
121
if codec .Uint16 (buffer ) != channel {
117
- return nil , 0 , errors .New ("Invalid channel" )
122
+ return nil , 0 , isSequenceZero , errors .New (fmt . Sprintf ( "Invalid channel. Expected %d, Got: %d" , channel , codec . Uint16 ( buffer )) )
118
123
}
119
124
headerOffset += 2
120
125
121
126
if buffer [headerOffset ] != 0x05 {
122
- return nil , 0 , errors .New ("Invalid tag" )
127
+ return nil , 0 , isSequenceZero , errors .New (fmt . Sprintf ( "Invalid tag. Expected %d, Got: %d" , 0x05 , buffer [ headerOffset ]) )
123
128
}
124
129
headerOffset ++
125
130
126
- if codec .Uint16 (buffer [headerOffset :]) != sequenceIdx {
127
- return nil , 0 , errors .New ("Wrong sequenceIdx" )
131
+ foundSequenceIdx := codec .Uint16 (buffer [headerOffset :])
132
+ if foundSequenceIdx == 0 {
133
+ isSequenceZero = true
134
+ } else {
135
+ isSequenceZero = false
136
+ }
137
+
138
+ if foundSequenceIdx != sequenceIdx {
139
+ return nil , 0 , isSequenceZero , errors .New (fmt .Sprintf ("Wrong sequenceIdx. Expected %d, Got: %d" , sequenceIdx , foundSequenceIdx ))
128
140
}
129
141
headerOffset += 2
130
142
@@ -136,7 +148,7 @@ func DeserializePacket(
136
148
result = make ([]byte , len (buffer )- int (headerOffset ))
137
149
copy (result , buffer [headerOffset :])
138
150
139
- return result , totalResponseLength , nil
151
+ return result , totalResponseLength , isSequenceZero , nil
140
152
}
141
153
142
154
// WrapCommandAPDU turns the command into a sequence of 64 byte packets
@@ -170,15 +182,32 @@ func UnwrapResponseAPDU(channel uint16, pipe <-chan []byte, packetSize int) ([]b
170
182
var totalSize uint16
171
183
var done = false
172
184
185
+ // return values from DeserializePacket
186
+ var result []byte
187
+ var responseSize uint16
188
+ var err error
189
+
190
+ foundZeroSequence := false
191
+ isSequenceZero := false
192
+
173
193
for ! done {
174
194
// Read next packet from the channel
175
195
buffer := <- pipe
176
196
177
- result , responseSize , err : = DeserializePacket (channel , buffer , sequenceIdx )
197
+ result , responseSize , isSequenceZero , err = DeserializePacket (channel , buffer , sequenceIdx ) // this may fail if the wrong sequence arrives (espeically if left over all 0000 was in the buffer from the last tx )
178
198
if err != nil {
179
199
return nil , err
180
200
}
181
- if sequenceIdx == 0 {
201
+
202
+ // Recover from a known error condition:
203
+ // * Discard messages left over from previous exchange until isSequenceZero == true
204
+ if foundZeroSequence == false && isSequenceZero == false {
205
+ continue
206
+ }
207
+ foundZeroSequence = true
208
+
209
+ // Initialize totalSize (previously we did this if sequenceIdx == 0, but sometimes Nano X can provide the first sequenceIdx == 0 packet with all zeros, then a useful packet with sequenceIdx == 1
210
+ if totalSize == 0 {
182
211
totalSize = responseSize
183
212
}
184
213
0 commit comments