|
16 | 16 | using Microsoft.Extensions.Logging;
|
17 | 17 | using Yubico.Core.Iso7816;
|
18 | 18 | using Yubico.Core.Logging;
|
| 19 | +using Yubico.YubiKey.Otp; |
19 | 20 | using Yubico.YubiKey.Otp.Commands;
|
20 | 21 |
|
21 | 22 | namespace Yubico.YubiKey.Pipelines
|
@@ -57,25 +58,36 @@ public ResponseApdu Invoke(CommandApdu command, Type commandType, Type responseT
|
57 | 58 | try
|
58 | 59 | {
|
59 | 60 | var responseApdu = _nextTransform.Invoke(command, commandType, responseType);
|
60 |
| - int afterSequence = new ReadStatusResponse(responseApdu).GetData().SequenceNumber; |
61 |
| - int expectedSequence = (beforeSequence + 1) % 0x100; |
| 61 | + var readStatusResponse = new ReadStatusResponse(responseApdu); |
| 62 | + var otpStatus = readStatusResponse.GetData(); |
| 63 | + byte nextSequence = otpStatus.SequenceNumber; |
62 | 64 |
|
63 | 65 | // If we see the sequence number change, we can assume that the configuration was applied successfully. Otherwise
|
64 | 66 | // we just invent an error in the response.
|
65 |
| - return afterSequence != expectedSequence |
66 |
| - ? new ResponseApdu(responseApdu.Data.ToArray(), SWConstants.WarningNvmUnchanged) |
67 |
| - : responseApdu; |
| 67 | + return IsValidSequenceProgression(beforeSequence, nextSequence, otpStatus) |
| 68 | + ? responseApdu |
| 69 | + : FailedApdu(responseApdu.Data.ToArray()); |
68 | 70 | }
|
69 | 71 | catch (KeyboardConnectionException e)
|
70 | 72 | {
|
71 | 73 | _logger.LogWarning(e, "Handling keyboard connection exception. Translating to APDU response.");
|
72 | 74 |
|
73 |
| - return new ResponseApdu(Array.Empty<byte>(), SWConstants.WarningNvmUnchanged); |
| 75 | + return FailedApdu([]); |
74 | 76 | }
|
| 77 | + |
| 78 | + static ResponseApdu FailedApdu(byte[] data) => new(data, SWConstants.WarningNvmUnchanged); |
75 | 79 | }
|
76 | 80 |
|
77 | 81 | public void Setup() => _nextTransform.Setup();
|
78 | 82 |
|
79 | 83 | public void Cleanup() => _nextTransform.Cleanup();
|
| 84 | + |
| 85 | + private static bool IsValidSequenceProgression(int beforeSequence, int nextSequence, OtpStatus afterStatus) |
| 86 | + { |
| 87 | + const int configStatusMask = 0x1F; |
| 88 | + |
| 89 | + return nextSequence == beforeSequence + 1 || // Normal increment |
| 90 | + (beforeSequence > 0 && nextSequence == 0 && (afterStatus.TouchLevel & configStatusMask) == 0); // When deleting the "last" slot |
| 91 | + } |
80 | 92 | }
|
81 | 93 | }
|
0 commit comments