libs.nfc/NFC.PCSC/NFCService.cs

317 lines
11 KiB
C#
Raw Normal View History

2023-01-30 23:27:00 +01:00
using NFC.Interfaces;
using PCSClib = PCSC;
using PCSCIso7816 = PCSC.Iso7816;
using System;
using System.Collections.Generic;
using PCSC.Exceptions;
using NFC.Exceptions;
using PCSC.Iso7816;
namespace NFC.PCSC
{
public class NFCService : INFCService
{
#region Private Members
private PCSCIso7816.IsoReader _IsoReader;
private PCSClib.IContextFactory _ContextFactory;
private PCSClib.ISCardContext _SCardContext;
#endregion
#region Constructors
public NFCService()
{
_ContextFactory = PCSClib.ContextFactory.Instance;
_SCardContext = _ContextFactory.Establish(PCSClib.SCardScope.System);
}
#endregion
#region Members
/// <summary>
/// Indicates if NFC Hardware is available
/// </summary>
public bool IsAvailable
{
get
{
return true;
}
}
/// <summary>
/// Indicates if NFC Hardware is enabled
/// </summary>
public bool IsEnabled
{
get
{
return true;
}
}
/// <summary>
/// Indicates if NFC Card is connected
/// </summary>
public bool IsConnected
{
get
{
return _IsoReader != null;
}
}
#endregion
#region Methods
/// <summary>
/// Get a list of availible NFC ReaderIDs
/// </summary>
public IList<string> GetReaderIDs()
{
return new List<string>(_SCardContext.GetReaders());
}
/// <summary>
/// Connect with ReaderID to NFC Card
/// </summary>
/// <param name="readerID">ReaderID from GetReaderIDs</param>
/// <exception cref="ReaderUnavailableException"></exception>
/// <exception cref="CardException"></exception>
/// <exception cref="ConnectionException"></exception>
/// <exception cref="ArgumentNullException"></exception>
public void Connect(string readerID)
{
if(string.IsNullOrEmpty(readerID))
{
throw new ArgumentNullException();
}
try
{
_IsoReader = new PCSCIso7816.IsoReader(_SCardContext);
_IsoReader.Connect(readerID, PCSClib.SCardShareMode.Shared, PCSClib.SCardProtocol.Any);
}
catch (Exception exception)
{
switch(exception)
{
case InvalidContextException _:
case InvalidProtocolException _:
case InvalidValueException _:
case UnsupportedFeatureException _:
case CommunicationErrorException _:
case InternalErrorException _:
case WinErrorInsufficientBufferException _:
case InsufficientBufferException _:
throw new ConnectionException("Connect failed", exception);
case NoServiceException _:
case NoReadersAvailableException _:
case NotReadyException _:
case PCSClib.Exceptions.ReaderUnavailableException _:
case SharingViolationException _:
case UnknownReaderException _:
throw new NFC.Exceptions.ReaderException("Reader connecting failed", exception);
case NoSmartcardException _:
case UnpoweredCardException _:
case UnresponsiveCardException _:
case RemovedCardException _:
throw new CardException("Reader connecting failed", exception);
case PCSCException _:
default:
throw new ConnectionException("Connect failed", exception);
}
}
}
/// <summary>
/// Disconnects Reader from NFC Card
/// </summary>
/// <exception cref="InvalidOperationException"></exception>
/// <exception cref="ConnectionException"></exception>
public void Disconnect()
{
if(_IsoReader == null)
{
throw new InvalidOperationException();
}
try
{
_IsoReader.Disconnect(PCSClib.SCardReaderDisposition.Eject);
}
catch(Exception exception)
{
throw new ConnectionException("Disconnect failed", exception);
}
finally
{
_IsoReader.Dispose();
_IsoReader = null;
}
}
/// <summary>
/// Transmit APDUCommand to Card if connected
/// </summary>
/// <exception cref="InvalidOperationException"></exception>
/// <exception cref="TransmitException"></exception>
/// <exception cref="CardException"></exception>
/// <exception cref="ReaderException"></exception>
/// <exception cref="ArgumentNullException"></exception>
public APDUResponse Transmit(APDUCommand command)
{
if(_IsoReader == null)
{
throw new InvalidOperationException();
}
if(command == null)
{
throw new ArgumentNullException();
}
try
{
PCSCIso7816.Response response = _IsoReader.Transmit(ConvertAPDUCommand(command));
return Convert(response);
}
catch(Exception exception)
{
switch (exception)
{
case InvalidContextException _:
case InvalidProtocolException _:
case InvalidValueException _:
case UnsupportedFeatureException _:
case InternalErrorException _:
case WinErrorInsufficientBufferException _:
throw new ConnectionException("Connect failed", exception);
case InvalidApduException _:
case InsufficientBufferException _:
case CommunicationErrorException _:
throw new ConnectionException("Transmit failed", exception);
case NoServiceException _:
case NoReadersAvailableException _:
case NotReadyException _:
case ReaderUnavailableException _:
case SharingViolationException _:
case UnknownReaderException _:
throw new ReaderException("Reader connecting failed", exception);
case NoSmartcardException _:
case UnpoweredCardException _:
case UnresponsiveCardException _:
case RemovedCardException _:
throw new CardException("Reader connecting failed", exception);
case PCSCException _:
default:
throw new ConnectionException("Connect failed", exception);
}
}
}
#endregion
#region Convert Methods
public PCSCIso7816.CommandApdu ConvertAPDUCommand(APDUCommand apdu_cmd)
{
switch (apdu_cmd.Case)
{
case NFC.IsoCase.Case1:
return new PCSCIso7816.CommandApdu(ConvertISOCase(apdu_cmd.Case), ConvertSCardProtocol(apdu_cmd.Protocol))
{
CLA = apdu_cmd.CLA,
INS = apdu_cmd.INS,
P1 = apdu_cmd.P1,
P2 = apdu_cmd.P2
};
case NFC.IsoCase.Case2Short:
return new PCSCIso7816.CommandApdu(ConvertISOCase(apdu_cmd.Case), ConvertSCardProtocol(apdu_cmd.Protocol))
{
CLA = apdu_cmd.CLA,
INS = apdu_cmd.INS,
P1 = apdu_cmd.P1,
P2 = apdu_cmd.P2,
Le = apdu_cmd.LE
};
case NFC.IsoCase.Case3Short:
return new PCSCIso7816.CommandApdu(ConvertISOCase(apdu_cmd.Case), ConvertSCardProtocol(apdu_cmd.Protocol))
{
CLA = apdu_cmd.CLA,
INS = apdu_cmd.INS,
P1 = apdu_cmd.P1,
P2 = apdu_cmd.P2,
Data = apdu_cmd.Data
};
case NFC.IsoCase.Case4Short:
return new PCSCIso7816.CommandApdu(ConvertISOCase(apdu_cmd.Case), ConvertSCardProtocol(apdu_cmd.Protocol))
{
CLA = apdu_cmd.CLA,
INS = apdu_cmd.INS,
P1 = apdu_cmd.P1,
P2 = apdu_cmd.P2,
Data = apdu_cmd.Data,
Le = apdu_cmd.LE
};
default:
throw new Exception("Unknown IsoCase");
}
}
public PCSCIso7816.IsoCase ConvertISOCase(NFC.IsoCase isoCase)
{
switch (isoCase)
{
case NFC.IsoCase.Case1:
return PCSCIso7816.IsoCase.Case1;
case NFC.IsoCase.Case2Short:
return PCSCIso7816.IsoCase.Case2Short;
case NFC.IsoCase.Case3Short:
return PCSCIso7816.IsoCase.Case3Short;
case NFC.IsoCase.Case4Short:
return PCSCIso7816.IsoCase.Case4Short;
default:
throw new Exception("Unknown IsoCase");
}
}
public PCSClib.SCardProtocol ConvertSCardProtocol(NFC.SCardProtocol sCardProtocol)
{
switch (sCardProtocol)
{
case NFC.SCardProtocol.UNSET:
return PCSClib.SCardProtocol.Unset;
case NFC.SCardProtocol.T0:
return PCSClib.SCardProtocol.T0;
case NFC.SCardProtocol.T1:
return PCSClib.SCardProtocol.T1;
case NFC.SCardProtocol.RAW:
return PCSClib.SCardProtocol.Raw;
case NFC.SCardProtocol.T15:
return PCSClib.SCardProtocol.T15;
case NFC.SCardProtocol.ANY:
return PCSClib.SCardProtocol.Any;
default:
throw new NotSupportedException("Unknown SCardProtocol");
}
}
public APDUResponse Convert(PCSCIso7816.Response response)
{
PCSCIso7816.ResponseApdu responseApdu = response.Get(0);
APDUResponse apduResponse = new APDUResponse()
{
SW1 = responseApdu.SW1,
SW2 = responseApdu.SW2,
Body = responseApdu.GetData()
};
return apduResponse;
}
#endregion
}
}