Fix potential NRE in the PCSC transport, retry spurious failure of authentication in AuthenticateEV2First
This commit is contained in:
parent
ae80f9ab79
commit
a329fa2f03
25
src/BTCPayServer.NTag424.PCSC/Extensions.cs
Normal file
25
src/BTCPayServer.NTag424.PCSC/Extensions.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using PCSC;
|
||||
using PCSC.Exceptions;
|
||||
using PCSC.Extensions;
|
||||
|
||||
namespace BTCPayServer.NTag424.PCSC;
|
||||
internal static class Extensions
|
||||
{
|
||||
public static void ThrowEx(this SCardError sc)
|
||||
{
|
||||
try
|
||||
{
|
||||
sc.Throw();
|
||||
}
|
||||
catch (NullReferenceException)
|
||||
{
|
||||
throw new PCSCException(sc, $"Unknown PCSC error: {(int)sc}");
|
||||
}
|
||||
throw new PCSCException(sc);
|
||||
}
|
||||
}
|
||||
@ -24,7 +24,7 @@ public class PCSCAPDUTransport : IAPDUTransport
|
||||
int received = resp.Length;
|
||||
var sc = CardReader.Transmit(apdu, resp, ref received);
|
||||
if (sc != SCardError.Success)
|
||||
sc.Throw();
|
||||
sc.ThrowEx();
|
||||
var sw1sw2 = (ushort)(resp[received - 2] << 8 | resp[received - 1]);
|
||||
var data = resp[..(received - 2)];
|
||||
return new NtagResponse(data, sw1sw2);
|
||||
|
||||
@ -125,13 +125,14 @@ public class Ntag424
|
||||
{
|
||||
return AuthenticateEV2(keyNo, key, false, cancellationToken);
|
||||
}
|
||||
public Task<Session> AuthenticateEV2First(int keyNo, AESKey key, CancellationToken cancellationToken = default)
|
||||
public Task<Session> AuthenticateEV2First(int keyNo, AESKey? key, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return AuthenticateEV2(keyNo, key, true, cancellationToken);
|
||||
}
|
||||
async Task<Session> AuthenticateEV2(int keyNo, AESKey key, bool first, CancellationToken cancellationToken = default)
|
||||
async Task<Session> AuthenticateEV2(int keyNo, AESKey? key, bool first, CancellationToken cancellationToken = default)
|
||||
{
|
||||
int sessionCounter = CurrentSession?.Counter ?? 0;
|
||||
key ??= AESKey.Default;
|
||||
int sessionCounter;
|
||||
if (first)
|
||||
{
|
||||
await IsoSelectFile(ISOLevel.Application);
|
||||
@ -143,7 +144,8 @@ public class Ntag424
|
||||
throw new InvalidOperationException("Authentication required for AuthenticateEV2NonFirst");
|
||||
sessionCounter = CurrentSession.Counter;
|
||||
}
|
||||
|
||||
bool illegalCommandThrown = false;
|
||||
retry:
|
||||
NtagResponse resp;
|
||||
if (first)
|
||||
{
|
||||
@ -164,10 +166,19 @@ public class Ntag424
|
||||
var rndA = RandomNumberGenerator.GetBytes(16);
|
||||
var encRnd = key.Encrypt(Concat(rndA, rndBp));
|
||||
var secondPart = first ? NtagCommands.AuthenticateEV2FirstPart2 : NtagCommands.AuthenticateEV2NonFirstPart2;
|
||||
resp = await SendAPDU(secondPart with
|
||||
try
|
||||
{
|
||||
Data = encRnd
|
||||
}, cancellationToken);
|
||||
resp = await SendAPDU(secondPart with
|
||||
{
|
||||
Data = encRnd
|
||||
}, cancellationToken);
|
||||
}
|
||||
// Sometimes, the card returns this error, unsure why, but retrying the auth seems to work
|
||||
catch (UnexpectedStatusException ex) when (first && !illegalCommandThrown && ex.Details?.Code.Equals("ILLEGAL_COMMAND_CODE", StringComparison.Ordinal) is true)
|
||||
{
|
||||
illegalCommandThrown = true;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
var data = key.Decrypt(resp.Data);
|
||||
var rndAp = RotateLeft(rndA);
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("BTCPayServer.NTag424.Tests")]
|
||||
[assembly: InternalsVisibleTo("BTCPayServer.NTag424.PCSC")]
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user