/// <inheritdoc /> public ICardHandle Connect(string readerName, SCardShareMode mode, SCardProtocol preferredProtocol) { ThrowOnInvalidContext(); var handle = new CardHandle(_api, this); handle.Connect(readerName, mode, preferredProtocol); return(handle); }
protected override void EstablishContext() { A.CallTo(() => CardHandle.Reconnect(A <SCardShareMode> .Ignored, A <SCardProtocol> .Ignored, A <SCardReaderDisposition> .Ignored)) .Invokes(call => { A.CallTo(() => CardHandle.Mode).Returns(call.Arguments.Get <SCardShareMode>(0)); A.CallTo(() => CardHandle.Protocol).Returns(call.Arguments.Get <SCardProtocol>(1)); }); _oldReaderName = Sut.Name; _isConnected = Sut.IsConnected; }
public void It_should_throw(string readerName, Type expectedException) { var sut = new CardHandle(_context); try { sut.Connect(readerName, SCardShareMode.Shared, SCardProtocol.Any); } catch (Exception exception) { exception.Should().BeOfType(expectedException); return; } throw new Exception($"Expected to throw {expectedException.Name} but did not!"); }
private void disconnectCard() { try { CardHandle ch = _terminalManager.Cards[_currentTerminalName]; ch.CardTerminal.Disconnect(SCardDisposition.EjectCard); ResetData(); //Console.WriteLine("Odłączono kartę"); _terminalManager.StopPolling(); } catch (Exception exception) { //Console.WriteLine("Nie udało się odłączyć karty. Wyjmij kartę z czytnika."); } }
protected override void EstablishContext() { A.CallTo(() => _context.Handle).Returns((IntPtr)1); A.CallTo(() => _context.IsValid()).Returns(true); // let the request exit with INVALID_HANDLE IntPtr handle; SCardProtocol protocol; A.CallTo(() => _api.Connect(A <IntPtr> ._, A <string> ._, A <SCardShareMode> ._, A <SCardProtocol> ._, out handle, out protocol)) .WithAnyArguments() .Returns(SCardError.InvalidHandle); _sut = new CardHandle(_api, _context); }
protected override void EstablishContext() { A.CallTo(() => _context.Handle).Returns((IntPtr)1); A.CallTo(() => _context.IsValid()).Returns(true); IntPtr handle; SCardProtocol protocol; A.CallTo(() => _api.Connect(A <IntPtr> ._, A <string> ._, A <SCardShareMode> ._, A <SCardProtocol> ._, out handle, out protocol)) .WithAnyArguments() .Returns(SCardError.Success) .AssignsOutAndRefParametersLazily(_ => new object[] { (IntPtr)123, SCardProtocol.T1 }); _sut = new CardHandle(_api, _context); }
protected override void EstablishContext() { A.CallTo(() => _context.Handle).Returns((IntPtr)1); A.CallTo(() => _context.IsValid()).Returns(true); IntPtr handle; SCardProtocol protocol; A.CallTo(() => _api.Connect(A <IntPtr> ._, A <string> ._, A <SCardShareMode> ._, A <SCardProtocol> ._, out handle, out protocol)) .WithAnyArguments() .Returns(SCardError.Success) .AssignsOutAndRefParametersLazily(_ => new object[] { (IntPtr)123, SCardProtocol.T1 }); protocol = default(SCardProtocol); A.CallTo(() => _api.Reconnect((IntPtr)123, SCardShareMode.Direct, SCardProtocol.Any, SCardReaderDisposition.Reset, out protocol)) .Returns(SCardError.Success) .AssignsOutAndRefParametersLazily(_ => new object[] { SCardProtocol.T15 }); _sut = new CardHandle(_api, _context); _sut.Connect("MyReader", SCardShareMode.Shared, SCardProtocol.Any); }
public void Should_the_card_handle_be_disconnected() { A.CallTo(() => CardHandle.Disconnect(SCardReaderDisposition.Eject)) .MustHaveHappened(Repeated.Exactly.Once); }
protected override void EstablishContext() { A.CallTo(() => CardHandle.Disconnect(A <SCardReaderDisposition> .Ignored)) .Invokes(_ => A.CallTo(() => CardHandle.IsConnected).Returns(false)); }
public void Should_it_reconnect_the_card_handle() { A.CallTo(() => CardHandle.Reconnect(A <SCardShareMode> .Ignored, A <SCardProtocol> .Ignored, A <SCardReaderDisposition> .Ignored)) .MustHaveHappened(); }
protected override void EstablishContext() { A.CallTo(() => _context.Handle).Returns(IntPtr.Zero); _sut = new CardHandle(_context); }
public CardHelper(CardHandle aCard) { if (aCard == null) { throw new ArgumentNullException("invalid card handle"); } m_aCard = aCard; CardPcscPart3 pcscPart3Info = new CardPcscPart3(aCard.GetATR()); if (pcscPart3Info.isValid) { m_isContactless = pcscPart3Info.isContactless; m_cardInfo += "PC/SC 2.01 compliant ATR detected\n"; m_cardInfo += "interface: "; if (m_isContactless == true) { m_cardInfo += "contactless\n"; } else { m_cardInfo += "contact\n"; } m_cardInfo += "protocol: " + pcscPart3Info.CardProtocol + "\n"; m_cardInfo += "card type: " + pcscPart3Info.CardName + "\n"; } else { //m_cardInfo += "ATR is not PC/SC 2.01 part 3 compliant\n"; //m_cardInfo += "processor card or proprietary storage card\n"; } // at this time we know: it is NOT a contactless or contact storage card as defined in PC/SC part 3 // Let's try to find out more by analyzing the reader name. We may get lucky. Note though, that there is // no clean, standards-based way to determine the card interface this way. if (m_isContactless == false) { if (aCard.Slot.CardTerminalName.Contains("OMNIKEY") && aCard.Slot.CardTerminalName.Contains("CL")) { if (aCard.Slot.CardTerminalName.Contains("5x25")) { m_isProxViaATR = true; m_cardInfo += "125 KHz PROX via ATR historical bytes\n"; } else { m_isContactless = true; m_cardInfo += "contactless based on reader name\n"; } } } if (m_isContactless == false) { if (aCard.Slot.CardTerminalName.ToUpper().Contains("CONTACTLESS") == true) // SCM readers contain this string { m_isContactless = true; m_cardInfo += "contactless based on reader name\n"; } } if (m_isContactless == false && m_isProxViaATR == false) { // we could start an analysis based onm an ATR mask here m_cardInfo += "unknown card interface (fall back)\n"; } // let us know if you are using a reader that could be handled here // [email protected] m_cardInfo += "end of card info "; }
/// <summary> /// Łączy z kartą /// </summary> /// <param name="force">Wymuszenie zresetowania karty</param> /// <returns>Nr ATR karty</returns> public ByteArray ConnectCard(bool force = false) { if (CardHandle != null) { if (CardHandle.IsValid && !force) { return(new ByteArray(CardHandle.ATR)); } else { CardHandle.Dispose(); CardHandle = null; } } int tryCounter = 5; do { try { CardHandle = CardTerminalManager.Singleton.AcquireCard(TerminalName); } catch (System.Runtime.InteropServices.COMException comException) { CardHandle = null; tryCounter--; if (tryCounter == 0) { throw new Exception("Sprzętowy błąd wykonywania komendy APDU (Message: " + comException.Message + ", HResult: " + comException.ErrorCode + ")"); } } catch (SCardException scException) { CardHandle = null; tryCounter--; if (tryCounter == 0) { throw new Exception("Sprzętowy błąd wykonywania komendy APDU (Kod: " + scException.ResponseCode + ").", scException); } } catch (Exception terminalException) { CardHandle = null; tryCounter--; if (tryCounter == 0) { throw new Exception("Sprzętowy błąd wykonywania komendy APDU.", terminalException); } } finally { if (CardHandle == null) { tryCounter--; if (tryCounter == 0) { throw new Exception("Nie znaleziono karty w czytniku."); } } } if (CardHandle != null) { return(new ByteArray(CardHandle.ATR)); } Thread.Sleep(1000); } while (true); }
/// <summary> /// Wysyła do karty polecenie APDU /// </summary> /// <param name="command">Polecenie APDU</param> /// <param name="checkSuccessful">Ma sprawdzać, czy odpowiedź jest poprawna (90 00)</param> /// <exception cref="APDUException"></exception> /// <returns>Odpowiedź na polecenie APDU</returns> public ByteArray SendCommand(ByteArray command, bool checkSuccessful = true) { ConnectCard(false); CardCommandAPDU apdu = null; if (command.Length == 4) { apdu = new CardCommandAPDU(command[0], command[1], command[2], command[3]); } else if (command.Length == 5) { apdu = new CardCommandAPDU(command[0], command[1], command[2], command[3], command[4]); } else if (command.Length > 5) { ByteArray data = command.Extract(5, command[4]); int length = 5 + command[4]; if (length == command.Length) { apdu = new CardCommandAPDU(command[0], command[1], command[2], command[3], data.ByteData); } else { apdu = new CardCommandAPDU(command[0], command[1], command[2], command[3], data.ByteData, command[command.Length - 1]); } } if (apdu == null) { throw new Exception("Nieprawidłowa komenda APDU: " + command); } int tryCounter = 5; CardResponseAPDU response = null; do { try { Logger.Log("[Encoder] -> " + command); response = CardHandle.SendCommand(apdu); break; } catch (System.Runtime.InteropServices.COMException comException) { tryCounter--; if (tryCounter == 0) { throw new Exception("Sprzętowy błąd wykonywania komendy APDU (Message: " + comException.Message + ", HResult: " + comException.ErrorCode + ")"); } } catch (SCardException scException) { tryCounter--; if (tryCounter == 0) { throw new Exception("Sprzętowy błąd wykonywania komendy APDU (Kod: " + scException.ResponseCode + ").", scException); } } catch (Exception terminalException) { tryCounter--; if (tryCounter == 0) { throw new Exception("Sprzętowy błąd wykonywania komendy APDU.", terminalException); } } } while (true); ByteArray result = new ByteArray(response.GenerateBytes()); Logger.Log("[Encoder] <- " + result); if (checkSuccessful && !response.IsSuccessful && !response.IsWarning) { throw new APDUException("Błąd wykonywania komendy APDU", command, new ByteArray(response.GenerateBytes()), response.SW1, response.SW2); } return(result); }
/// <summary> /// /// </summary> /// <param name="aCardSlot"></param> public void AnalyzeCard(CardTerminalSlot aCardSlot) { // Acquire any processor card (T=0 or T=1) that may be present in the given card // terminal slot string readerName = aCardSlot.CardTerminalName; CardActivationResult nActivationResult; DisplayText("Reader Name: " + readerName); //aCardSlot.CardTerminal.Config CardHandle aCard = aCardSlot.AcquireCard((CardTypes.T0 | CardTypes.T1), out nActivationResult); if (nActivationResult != CardActivationResult.Success) { Debug.Assert(aCard == null); switch (nActivationResult) { case CardActivationResult.NoCard: m_aPromptLabel.Text = readerName + ": Please insert card ..."; break; case CardActivationResult.UnresponsiveCard: m_aPromptLabel.Text = readerName + ": Unresponsive card."; break; case CardActivationResult.InUse: m_aPromptLabel.Text = readerName + ": Card in use"; break; default: m_aPromptLabel.Text = readerName + ": Can't power up card!"; break; } return; } m_aPromptLabel.Text = aCardSlot.CardTerminalName + ": Found card"; DisplayText("Found card in reader " + aCardSlot.CardTerminalName); DisplayReaderProperties(aCardSlot); aCardSlot.BeginTransaction(); try // We are doing a few things here that any card system should support. // Note that the CardHandle represents the combination of card terminal and // powered-up card. { // =========================== ATR DETECTION ====================================== // Every card accessed through PC/SC must return an Answer To Reset (ATR). // So let's see what we've got here. byte[] atr = aCard.GetATR(); if (atr.Length == 0) { throw new Exception("Invalid ATR"); } DisplayText("ATR: " + CardHex.FromByteArray(atr, 0, atr.Length)); // ================================================================================ // Go a little deeper: is this a contact or contactless card system we are dealing with? CardHelper cardHelper = new CardHelper(aCard); DisplayText(cardHelper.cardInfo); if (cardHelper.isContactless) { // =========================== APDU EXCHANGE ================================== // Now we can try to get a unique identifier (UID). Any contactless card with a // PC/C 2.01 compliant card reader should be able to generate a UID. But never mind, // even if this fails it still shows how to create a command APDU with our SmartCardAPI // frameqwork and get a response APDU back from a card. // // Known issues: // SendCommand with CLA=0xFF can cause an exception with some smart card systems, // triggered by an "Unknown Error" (-2146435025) on PC/SC level. // Therefore this code should only be run if we are accessing a contactless reader // interface that is PC/SC 2.01 compliant // ============================================================================ byte CL_CLA = 0xFF; byte CL_INS_GET_UID = 0xCA; byte P1 = 0; byte P2 = 0; CardCommandAPDU aCmdAPDU = new CardCommandAPDU(CL_CLA, CL_INS_GET_UID, P1, P2, 256); CardResponseAPDU aRespAPDU; aRespAPDU = aCard.SendCommand(aCmdAPDU); if (!aRespAPDU.IsSuccessful) { DisplayText("WARNING: can't get a UID - this might be a contact card."); } else { byte[] uidWithSw12 = aRespAPDU.GenerateBytes(); if (uidWithSw12.Length < 2) { throw new Exception("Invalid UID"); } var uid = CardHex.FromByteArray(uidWithSw12, 0, uidWithSw12.Length - 2); DisplayText("UID: " + uid); if (uid.Length > 0) { _reader.SendRFID(uid); } } } aCardSlot.EndTransaction(); } catch (Exception x) { Trace.WriteLine(x.ToString()); DisplayText(x.ToString()); m_aPromptLabel.Text = "Card access error"; } finally { aCard.Dispose(); // release card handle } }