mirror of
https://gitlab.com/fabinfra/fabaccess/nfc.git
synced 2025-03-12 06:41:48 +01:00
317 lines
11 KiB
C#
317 lines
11 KiB
C#
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
|
|
}
|
|
}
|