-
Notifications
You must be signed in to change notification settings - Fork 1
/
CardManager.cs
126 lines (115 loc) · 5.65 KB
/
CardManager.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
using Org.BouncyCastle.Utilities.Encoders;
using Securo.GlobalPlatform.Commands;
using Securo.GlobalPlatform.Interfaces;
using Securo.GlobalPlatform.Model;
using Securo.GlobalPlatform.SecureMessaging;
using System;
namespace Securo.GlobalPlatform
{
public class CardManager : ICardManager
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private readonly IApduTransmit apduTransmit;
private readonly ISecureSessionDetailsCreator secureSessionDetailsCreator;
private readonly IScpInfoProvider scpInfoProvider;
private readonly ICardResponseParser cardResponseParser;
private readonly ISecureContextProviderFactory secureContextProviderFactory;
private ISecureContextProvider secureContextProvider;
private IAuthenticationCryptogramProvider<Scp03CardAuthenticationCryptogramData> cardAuthenticationCryptogramProvider;
private ScpInfo ScpInfo { get; set; }
public SecureSessionDetails SecureSessionDetails { get; private set; }
public string Aid { get; private set; }
const string GetDataApdu = "80CA006600";
public CardManager(
IApduTransmit apduTransmit,
IGpMasterKeysProvider gpMasterKeysProvider)
{
this.apduTransmit = apduTransmit;
this.secureSessionDetailsCreator = new SecureSessionDetailsCreator();
this.scpInfoProvider = new ScpInfoProvider();
this.cardResponseParser = new CardResponseParser();
this.secureContextProviderFactory = new SecureContextProviderFactory(gpMasterKeysProvider);
}
public void Select(string aid)
{
var selectCommand = new SelectApduCommand(0x04, 0x00, aid).Build();
var cardResponse = apduTransmit.Send(selectCommand);
if (cardResponse.StatusWord == 0x9000)
{
this.Aid = aid;
var cardRecogntionData = apduTransmit.Send(GetDataApdu);
if (cardRecogntionData.StatusWord == 0x9000)
{
this.ScpInfo = this.scpInfoProvider.Provide(Hex.Decode(cardRecogntionData.Data));
}
else
{
throw new InvalidOperationException("Can't perform Get Data command");
}
}
else
{
throw new InvalidOperationException($"Applet not found: {aid}");
}
}
public void InitializeUpdate(byte keySetVersion, byte keyIdentifier, string hostChallenge)
{
var command = new InitalizeUpdateCommand(keySetVersion, keyIdentifier, hostChallenge).Build();
var cardResponse = this.apduTransmit.Send(command);
if (cardResponse.StatusWord == 0x9000)
{
this.SecureSessionDetails = this.secureSessionDetailsCreator.Create(cardResponse.Data);
this.SecureSessionDetails.HostChallenge = hostChallenge;
this.SecureSessionDetails.ScpInfo = this.ScpInfo;
this.secureContextProvider = this.secureContextProviderFactory
.Provide((ScpMode)this.SecureSessionDetails.ScpInfo.ScpIdentifier);
this.secureContextProvider.InitializeSecureContext(this.SecureSessionDetails);
}
else
{
throw new InvalidOperationException($"Error in InitializeUpdate: SW={cardResponse.StatusWord.ToString("X2")}");
}
}
public void ExternalAuthenticate(SecurityLevel securityLevel)
{
var hostAuthCryptogram = this.secureContextProvider.CalculateHostCrypogram().Result;
var command = new ExternalAuthenticateCommand((byte)securityLevel, hostAuthCryptogram).Build();
var wrappedCommand = this.secureContextProvider.Wrap(SecurityLevel.Mac, command).Result;
var cardResponse = this.apduTransmit.Send(wrappedCommand);
if (cardResponse.StatusWord != 0x9000)
{
throw new InvalidOperationException($"Error in ExternalAuthenticate: SW={cardResponse.StatusWord.ToString("X2")}");
}
}
public void StoreData(string data)
{
var command = new StoreDataCommand(0x00, 0x00, data).Build();
var wrappedCommand = this.secureContextProvider.Wrap(SecurityLevel.Mac, command).Result;
var cardResponse = this.apduTransmit.Send(wrappedCommand);
if (cardResponse.StatusWord != 0x9000)
{
throw new InvalidOperationException($"Error in StoreData: SW={cardResponse.StatusWord.ToString("X2")}");
}
}
public string GetData(byte tagMsb, byte tagLsb)
{
throw new NotImplementedException();
}
public CardResponse TransmitApdu(SecurityLevel securityLevel, string command)
{
log.Info($"TX-Plain -> {command}");
var wrappedCommand = this.secureContextProvider.Wrap(securityLevel, command).Result;
var cardResponse = this.apduTransmit.Send(wrappedCommand);
if (cardResponse.StatusWord != 0x9000)
{
throw new InvalidOperationException($"Error in TransmitApdu: SW={cardResponse.StatusWord.ToString("X2")}");
}
else
{
var unwrappedResponse = this.secureContextProvider.Unwrap(securityLevel, cardResponse.FullResponse).Result.ToUpper();
log.Info($"RX-Plain -> {unwrappedResponse}");
return this.cardResponseParser.Parse(unwrappedResponse);
}
}
}
}