FreeRDP
smartcard_virtual_gids.c
1 
22 #include <freerdp/config.h>
23 
24 #include <winpr/wlog.h>
25 #include <winpr/stream.h>
26 #include <winpr/collections.h>
27 
28 #include <freerdp/crypto/crypto.h>
29 
30 #include <zlib.h>
31 
32 #include "../../crypto/certificate.h"
33 #include "../../crypto/privatekey.h"
34 #include "smartcard_virtual_gids.h"
35 
36 #define TAG CHANNELS_TAG("smartcard.vgids")
37 
38 #define VGIDS_EFID_MASTER 0xA000
39 #define VGIDS_EFID_COMMON 0xA010
40 // #define VGIDS_EFID_CARDCF VGIDS_EFID_COMMON
41 // #define VGIDS_EFID_CARDAPPS VGIDS_EFID_COMMON
42 // #define VGIDS_EFID_CMAPFILE VGIDS_EFID_COMMON
43 #define VGIDS_EFID_CARDID 0xA012
44 // #define VGIDS_EFID_KXC00 VGIDS_EFID_COMMON
45 #define VGIDS_EFID_CURRENTDF 0x3FFF
46 
47 #define VGIDS_DO_FILESYSTEMTABLE 0xDF1F
48 #define VGIDS_DO_KEYMAP 0xDF20
49 #define VGIDS_DO_CARDID 0xDF20
50 #define VGIDS_DO_CARDAPPS 0xDF21
51 #define VGIDS_DO_CARDCF 0xDF22
52 #define VGIDS_DO_CMAPFILE 0xDF23
53 #define VGIDS_DO_KXC00 0xDF24
54 
55 #define VGIDS_CARDID_SIZE 16
56 #define VGIDS_MAX_PIN_SIZE 127
57 
58 #define VGIDS_DEFAULT_RETRY_COUNTER 3
59 
60 #define VGIDS_KEY_TYPE_KEYEXCHANGE 0x9A
61 // #define VGIDS_KEY_TYPE_SIGNATURE 0x9C
62 
63 #define VGIDS_ALGID_RSA_1024 0x06
64 #define VGIDS_ALGID_RSA_2048 0x07
65 #define VGIDS_ALGID_RSA_3072 0x08
66 #define VGIDS_ALGID_RSA_4096 0x09
67 
68 // #define VGIDS_SE_CRT_AUTH 0xA4
69 #define VGIDS_SE_CRT_SIGN 0xB6
70 #define VGIDS_SE_CRT_CONF 0xB8
71 
72 #define VGIDS_SE_ALGOID_CT_PAD_PKCS1 0x40
73 #define VGIDS_SE_ALGOID_CT_PAD_OAEP 0x80
74 // #define VGIDS_SE_ALGOID_CT_RSA_1024 0x06
75 // #define VGIDS_SE_ALGOID_CT_RSA_2048 0x07
76 // #define VGIDS_SE_ALGOID_CT_RSA_3072 0x08
77 // #define VGIDS_SE_ALGOID_CT_RSA_4096 0x09
78 
79 #define VGIDS_SE_ALGOID_DST_PAD_PKCS1 0x40
80 #define VGIDS_SE_ALGOID_DST_RSA_1024 0x06
81 #define VGIDS_SE_ALGOID_DST_RSA_2048 0x07
82 #define VGIDS_SE_ALGOID_DST_RSA_3072 0x08
83 #define VGIDS_SE_ALGOID_DST_RSA_4096 0x09
84 #define VGIDS_SE_ALGOID_DST_ECDSA_P192 0x0A
85 #define VGIDS_SE_ALGOID_DST_ECDSA_P224 0x0B
86 #define VGIDS_SE_ALGOID_DST_ECDSA_P256 0x0C
87 #define VGIDS_SE_ALGOID_DST_ECDSA_P384 0x0D
88 #define VGIDS_SE_ALGOID_DST_ECDSA_P512 0x0E
89 
90 #define VGIDS_DEFAULT_KEY_REF 0x81
91 
92 #define ISO_INS_SELECT 0xA4
93 #define ISO_INS_GETDATA 0xCB
94 #define ISO_INS_GETRESPONSE 0xC0
95 #define ISO_INS_MSE 0x22
96 #define ISO_INS_PSO 0x2A
97 #define ISO_INS_VERIFY 0x20
98 
99 #define ISO_STATUS_MORE_DATA 0x6100
100 #define ISO_STATUS_VERIFYFAILED 0x6300
101 #define ISO_STATUS_WRONGLC 0x6700
102 #define ISO_STATUS_COMMANDNOTALLOWED 0x6900
103 #define ISO_STATUS_SECURITYSTATUSNOTSATISFIED 0x6982
104 #define ISO_STATUS_AUTHMETHODBLOCKED 0x6983
105 #define ISO_STATUS_INVALIDCOMMANDDATA 0x6A80
106 #define ISO_STATUS_FILENOTFOUND 0x6A82
107 #define ISO_STATUS_INVALIDP1P2 0x6A86
108 #define ISO_STATUS_INVALIDLC 0x6A87
109 #define ISO_STATUS_REFERENCEDATANOTFOUND 0x6A88
110 #define ISO_STATUS_SUCCESS 0x9000
111 
112 #define ISO_AID_MAX_SIZE 16
113 
114 #define ISO_FID_MF 0x3F00
115 
116 struct vgids_ef
117 {
118  UINT16 id;
119  UINT16 dirID;
120  wStream* data;
121 };
122 typedef struct vgids_ef vgidsEF;
123 
124 struct vgids_se
125 {
126  BYTE crt; /* control reference template tag */
127  BYTE algoId; /* Algorithm ID */
128  BYTE keyRef; /* Key reference */
129 };
130 typedef struct vgids_se vgidsSE;
131 
132 struct vgids_context
133 {
134  UINT16 currentDF;
135  char* pin;
136  UINT16 curRetryCounter;
137  UINT16 retryCounter;
138  wStream* commandData;
139  wStream* responseData;
140  BOOL pinVerified;
141  vgidsSE currentSE;
142 
143  rdpCertificate* certificate;
144  rdpPrivateKey* privateKey;
145 
146  wArrayList* files;
147 };
148 
149 /* PKCS 1.5 DER encoded digest information */
150 #define VGIDS_MAX_DIGEST_INFO 7
151 
152 static const BYTE g_PKCS1_SHA1[] = { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,
153  0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 };
154 static const BYTE g_PKCS1_SHA224[] = { 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
155  0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c };
156 static const BYTE g_PKCS1_SHA256[] = { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
157  0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 };
158 static const BYTE g_PKCS1_SHA384[] = { 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
159  0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30 };
160 static const BYTE g_PKCS1_SHA512[] = { 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
161  0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40 };
162 static const BYTE g_PKCS1_SHA512_224[] = { 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60,
163  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02,
164  0x05, 0x05, 0x00, 0x04, 0x1c };
165 static const BYTE g_PKCS1_SHA512_256[] = { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60,
166  0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02,
167  0x06, 0x05, 0x00, 0x04, 0x20 };
168 
169 /* Helper struct to map PKCS1.5 digest info to OpenSSL EVP_MD */
170 struct vgids_digest_info_map
171 {
172  const BYTE* info;
173  size_t infoSize;
174  const EVP_MD* digest;
175 };
176 typedef struct vgids_digest_info_map vgidsDigestInfoMap;
177 
178 /* MS GIDS AID */
179 /* xx: Used by the Windows smart card framework for the GIDS version number. This byte must be set
180  * to the GIDS specification revision number which is either 0x01 or 0x02.
181  * yy: Reserved for use by the card application (set to 01)
182  */
183 static const BYTE g_MsGidsAID[] = {
184  0xA0, 0x00, 0x00, 0x03, 0x97, 0x42, 0x54, 0x46, 0x59, 0x02, 0x01
185 };
186 
187 /* GIDS APP File Control Parameter:
188  FD-Byte (82): 38 (not shareable-DF)
189  Sec Attr (8C): 03 30 30 Create/Delete File(03) Ext/User-Auth (30)
190 */
191 static const BYTE g_GidsAppFCP[] = { 0x62, 0x08, 0x82, 0x01, 0x38, 0x8C, 0x03, 0x03, 0x30, 0x30 };
192 /* GIDS APP File Control Information:
193  AppID (4F, Len 0B): A0 00 00 03 97 42 54 46 59 02 01
194  Discretionary DOs (73, Len 03): 40 01 C0
195  Supported Auth Protocols (40, Len 01): C0 Mutual/External-Auth
196  */
197 static const BYTE g_GidsAppFCI[] = { 0x61, 0x12, 0x4F, 0x0B, 0xA0, 0x00, 0x00, 0x03, 0x97, 0x42,
198  0x54, 0x46, 0x59, 0x02, 0x01, 0x73, 0x03, 0x40, 0x01, 0xC0 };
199 
200 /*
201 typedef struct
202 {
203  BYTE bVersion; // Cache version
204  BYTE bPinsFreshness; // Card PIN
205  WORD wContainersFreshness;
206  WORD wFilesFreshness;
207 } CARD_CACHE_FILE_FORMAT, *PCARD_CACHE_FILE_FORMAT; */
208 static const BYTE g_CardCFContents[] = { 0x00, 0x00, 0x01, 0x00, 0x04, 0x00 };
209 
210 /* {‘mscp’,0,0,0,0} */
211 static const BYTE g_CardAppsContents[] = { 0x6d, 0x73, 0x63, 0x70, 0x00, 0x00, 0x00, 0x00 };
212 
213 #pragma pack(push, 1)
214 
215 /* Type: CONTAINER_MAP_RECORD (taken from Windows Smart Card Minidriver Specification)
216 
217  This structure describes the format of the Base CSP's
218  container map file, stored on the card. This is wellknown
219  logical file wszCONTAINER_MAP_FILE. The file consists of
220  zero or more of these records. */
221 #define MAX_CONTAINER_NAME_LEN 39
222 
223 /* This flag is set in the CONTAINER_MAP_RECORD bFlags
224  member if the corresponding container is valid and currently
225  exists on the card. // If the container is deleted, its
226  bFlags field must be cleared. */
227 #define CONTAINER_MAP_VALID_CONTAINER 1
228 
229 /* This flag is set in the CONTAINER_MAP_RECORD bFlags
230  member if the corresponding container is the default
231  container on the card. */
232 #define CONTAINER_MAP_DEFAULT_CONTAINER 2
233 
234 struct vgids_container_map_entry
235 {
236  WCHAR wszGuid[MAX_CONTAINER_NAME_LEN + 1];
237  BYTE bFlags;
238  BYTE bReserved;
239  WORD wSigKeySizeBits;
240  WORD wKeyExchangeKeySizeBits;
241 };
242 typedef struct vgids_container_map_entry vgidsContainerMapEntry;
243 
244 struct vgids_filesys_table_entry
245 {
246  char directory[9];
247  char filename[9];
248  UINT16 pad0;
249  UINT16 dataObjectIdentifier;
250  UINT16 pad1;
251  UINT16 fileIdentifier;
252  UINT16 unknown;
253 };
254 typedef struct vgids_filesys_table_entry vgidsFilesysTableEntry;
255 
256 struct vgids_keymap_record
257 {
258  UINT32 state;
259  BYTE algid;
260  BYTE keytype;
261  UINT16 keyref;
262  UINT16 unknownWithFFFF;
263  UINT16 unknownWith0000;
264 };
265 typedef struct vgids_keymap_record vgidsKeymapRecord;
266 
267 #pragma pack(pop)
268 
269 static void vgids_ef_free(void* ptr);
270 
271 static vgidsEF* vgids_ef_new(vgidsContext* ctx, USHORT id)
272 {
273  vgidsEF* ef = calloc(1, sizeof(vgidsEF));
274 
275  ef->id = id;
276  ef->data = Stream_New(NULL, 1024);
277  if (!ef->data)
278  {
279  WLog_ERR(TAG, "Failed to create file data stream");
280  goto create_failed;
281  }
282  Stream_SetLength(ef->data, 0);
283 
284  if (!ArrayList_Append(ctx->files, ef))
285  {
286  WLog_ERR(TAG, "Failed to add new ef to file list");
287  goto create_failed;
288  }
289 
290  return ef;
291 
292 create_failed:
293  vgids_ef_free(ef);
294  return NULL;
295 }
296 
297 static BOOL vgids_write_tlv(wStream* s, UINT16 tag, const void* data, size_t dataSize)
298 {
299  WINPR_ASSERT(dataSize <= UINT16_MAX);
300 
301  /* A maximum of 5 additional bytes is needed */
302  if (!Stream_EnsureRemainingCapacity(s, dataSize + 5))
303  {
304  WLog_ERR(TAG, "Failed to ensure capacity of DO stream");
305  return FALSE;
306  }
307 
308  /* BER encoding: If the most-significant bit is set (0x80) the length is encoded in the
309  * remaining bits. So lengths < 128 bytes can be set directly, all others are encoded */
310  if (tag > 0xFF)
311  Stream_Write_UINT16_BE(s, tag);
312  else
313  Stream_Write_UINT8(s, (BYTE)tag);
314  if (dataSize < 128)
315  {
316  Stream_Write_UINT8(s, (BYTE)dataSize);
317  }
318  else if (dataSize < 256)
319  {
320  Stream_Write_UINT8(s, 0x81);
321  Stream_Write_UINT8(s, (BYTE)dataSize);
322  }
323  else
324  {
325  Stream_Write_UINT8(s, 0x82);
326  Stream_Write_UINT16_BE(s, (UINT16)dataSize);
327  }
328  Stream_Write(s, data, dataSize);
329  Stream_SealLength(s);
330  return TRUE;
331 }
332 
333 static BOOL vgids_ef_write_do(vgidsEF* ef, UINT16 doID, const void* data, DWORD dataSize)
334 {
335  /* Write DO to end of file: 2-Byte ID, 1-Byte Len, Data */
336  return vgids_write_tlv(ef->data, doID, data, dataSize);
337 }
338 
339 static BOOL vgids_ef_read_do(vgidsEF* ef, UINT16 doID, BYTE** data, DWORD* dataSize)
340 {
341  /* Read the given DO from the file: 2-Byte ID, 1-Byte Len, Data */
342  if (!Stream_SetPosition(ef->data, 0))
343  {
344  WLog_ERR(TAG, "Failed to seek to front of file");
345  return FALSE;
346  }
347 
348  /* Look for the requested DO */
349  while (Stream_GetRemainingLength(ef->data) > 3)
350  {
351  BYTE len = 0;
352  size_t curPos = 0;
353  UINT16 doSize = 0;
354  UINT16 nextDOID = 0;
355 
356  curPos = Stream_GetPosition(ef->data);
357  Stream_Read_UINT16_BE(ef->data, nextDOID);
358  Stream_Read_UINT8(ef->data, len);
359  if ((len & 0x80))
360  {
361  BYTE lenSize = len & 0x7F;
362  if (!Stream_CheckAndLogRequiredLength(TAG, ef->data, lenSize))
363  return FALSE;
364 
365  switch (lenSize)
366  {
367  case 1:
368  Stream_Read_UINT8(ef->data, doSize);
369  break;
370  case 2:
371  Stream_Read_UINT16_BE(ef->data, doSize);
372  break;
373  default:
374  WLog_ERR(TAG, "Unexpected tag length %" PRIu8, lenSize);
375  return FALSE;
376  }
377  }
378  else
379  doSize = len;
380 
381  if (!Stream_CheckAndLogRequiredLength(TAG, ef->data, doSize))
382  return FALSE;
383 
384  if (nextDOID == doID)
385  {
386  BYTE* outData = NULL;
387 
388  /* Include Tag and length in result */
389  doSize += (UINT16)(Stream_GetPosition(ef->data) - curPos);
390  outData = malloc(doSize);
391  if (!outData)
392  {
393  WLog_ERR(TAG, "Failed to allocate output buffer");
394  return FALSE;
395  }
396 
397  Stream_SetPosition(ef->data, curPos);
398  Stream_Read(ef->data, outData, doSize);
399  *data = outData;
400  *dataSize = doSize;
401  return TRUE;
402  }
403  else
404  {
405  /* Skip DO */
406  if (!Stream_SafeSeek(ef->data, doSize))
407  return FALSE;
408  }
409  }
410 
411  return FALSE;
412 }
413 
414 void vgids_ef_free(void* ptr)
415 {
416  vgidsEF* ef = ptr;
417  if (ef)
418  {
419  Stream_Free(ef->data, TRUE);
420  free(ef);
421  }
422 }
423 
424 static BOOL vgids_prepare_fstable(const vgidsFilesysTableEntry* fstable, DWORD numEntries,
425  BYTE** outData, DWORD* outDataSize)
426 {
427  /* Filesystem table:
428  BYTE unkonwn: 0x01
429  Array of vgidsFilesysTableEntry
430  */
431  BYTE* data = malloc(sizeof(vgidsFilesysTableEntry) * numEntries + 1);
432  if (!data)
433  {
434  WLog_ERR(TAG, "Failed to allocate filesystem table data blob");
435  return FALSE;
436  }
437 
438  *data = 0x01;
439  for (UINT32 i = 0; i < numEntries; ++i)
440  memcpy(data + 1 + (sizeof(vgidsFilesysTableEntry) * i), &fstable[i],
441  sizeof(vgidsFilesysTableEntry));
442 
443  *outData = data;
444  *outDataSize = sizeof(vgidsFilesysTableEntry) * numEntries + 1;
445 
446  return TRUE;
447 }
448 
449 static BOOL vgids_prepare_certificate(const rdpCertificate* cert, BYTE** kxc, DWORD* kxcSize)
450 {
451  /* Key exchange container:
452  UINT16 compression version: 0001
453  UINT16 source size
454  ZLIB compressed cert
455  */
456  uLongf destSize = 0;
457  wStream* s = NULL;
458  BYTE* comprData = NULL;
459 
460  WINPR_ASSERT(cert);
461 
462  size_t certSize = 0;
463  BYTE* certData = freerdp_certificate_get_der(cert, &certSize);
464  if (!certData || (certSize == 0))
465  {
466  WLog_ERR(TAG, "Failed to get certificate size");
467  goto handle_error;
468  }
469 
470  comprData = malloc(certSize);
471  if (!comprData)
472  {
473  WLog_ERR(TAG, "Failed to allocate certificate buffer");
474  goto handle_error;
475  }
476 
477  /* compress certificate data */
478  destSize = certSize;
479  if (compress(comprData, &destSize, certData, certSize) != Z_OK)
480  {
481  WLog_ERR(TAG, "Failed to compress certificate data");
482  goto handle_error;
483  }
484 
485  /* Write container data */
486  s = Stream_New(NULL, destSize + 4);
487  Stream_Write_UINT16(s, 0x0001);
488  Stream_Write_UINT16(s, (UINT16)certSize);
489  Stream_Write(s, comprData, destSize);
490  Stream_SealLength(s);
491 
492  *kxc = Stream_Buffer(s);
493  *kxcSize = (DWORD)Stream_Length(s);
494 
495  Stream_Free(s, FALSE);
496  free(certData);
497  free(comprData);
498  return TRUE;
499 
500 handle_error:
501  Stream_Free(s, TRUE);
502  free(certData);
503  free(comprData);
504  return FALSE;
505 }
506 
507 static size_t get_rsa_key_size(const rdpPrivateKey* privateKey)
508 {
509  WINPR_ASSERT(privateKey);
510 
511  return freerdp_key_get_bits(privateKey) / 8;
512 }
513 
514 static BYTE vgids_get_algid(vgidsContext* p_Ctx)
515 {
516  WINPR_ASSERT(p_Ctx);
517 
518  switch (get_rsa_key_size(p_Ctx->privateKey))
519  {
520  case (1024 / 8):
521  return VGIDS_ALGID_RSA_1024;
522  case (2048 / 8):
523  return VGIDS_ALGID_RSA_2048;
524  case (3072 / 8):
525  return VGIDS_ALGID_RSA_3072;
526  case (4096 / 8):
527  return VGIDS_ALGID_RSA_4096;
528  default:
529  WLog_ERR(TAG, "Failed to determine algid for private key");
530  break;
531  }
532 
533  return 0;
534 }
535 
536 static BOOL vgids_prepare_keymap(vgidsContext* context, BYTE** outData, DWORD* outDataSize)
537 {
538  /* Key map record table:
539  BYTE unkonwn (count?): 0x01
540  Array of vgidsKeymapRecord
541  */
542  BYTE* data = NULL;
543  vgidsKeymapRecord record = {
544  1, /* state */
545  0, /* algo */
546  VGIDS_KEY_TYPE_KEYEXCHANGE, /* keytpe */
547  (0xB000 | VGIDS_DEFAULT_KEY_REF), /* keyref */
548  0xFFFF, /* unknown FFFF */
549  0x0000 /* unknown 0000 */
550  };
551 
552  /* Determine algo */
553  BYTE algid = vgids_get_algid(context);
554  if (algid == 0)
555  return FALSE;
556 
557  data = malloc(sizeof(record) + 1);
558  if (!data)
559  {
560  WLog_ERR(TAG, "Failed to allocate filesystem table data blob");
561  return FALSE;
562  }
563 
564  *data = 0x01;
565  record.algid = algid;
566  memcpy(data + 1, &record, sizeof(record));
567 
568  *outData = data;
569  *outDataSize = sizeof(record) + 1;
570 
571  return TRUE;
572 }
573 
574 static BOOL vgids_parse_apdu_header(wStream* s, BYTE* cla, BYTE* ins, BYTE* p1, BYTE* p2, BYTE* lc,
575  BYTE* le)
576 {
577  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
578  return FALSE;
579 
580  /* Read and verify APDU data */
581  if (cla)
582  Stream_Read_UINT8(s, *cla);
583  else
584  Stream_Seek(s, 1);
585  if (ins)
586  Stream_Read_UINT8(s, *ins);
587  else
588  Stream_Seek(s, 1);
589  if (p1)
590  Stream_Read_UINT8(s, *p1);
591  else
592  Stream_Seek(s, 1);
593  if (p2)
594  Stream_Read_UINT8(s, *p2);
595  else
596  Stream_Seek(s, 1);
597 
598  /* If LC is requested - check remaining length and read as well */
599  if (lc)
600  {
601  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
602  return FALSE;
603 
604  Stream_Read_UINT8(s, *lc);
605  if (!Stream_CheckAndLogRequiredLength(TAG, s, *lc))
606  return FALSE;
607  }
608 
609  /* read LE */
610  if (le)
611  {
612  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
613  return FALSE;
614  Stream_Read_UINT8(s, *le);
615  }
616 
617  return TRUE;
618 }
619 
620 static BOOL vgids_create_response(UINT16 status, const BYTE* answer, DWORD answerSize,
621  BYTE** outData, DWORD* outDataSize)
622 {
623  BYTE* out = malloc(answerSize + 2);
624  if (!out)
625  {
626  WLog_ERR(TAG, "Failed to allocate memory for response data");
627  return FALSE;
628  }
629 
630  *outData = out;
631  if (answer)
632  {
633  memcpy(out, answer, answerSize);
634  out += answerSize;
635  }
636 
637  *out = (BYTE)((status >> 8) & 0xFF);
638  *(out + 1) = (BYTE)(status & 0xFF);
639  *outDataSize = answerSize + 2;
640  return TRUE;
641 }
642 
643 static BOOL vgids_read_do_fkt(void* data, size_t index, va_list ap)
644 {
645  BYTE* response = NULL;
646  DWORD responseSize = 0;
647  vgidsEF* file = (vgidsEF*)data;
648  vgidsContext* context = va_arg(ap, vgidsContext*);
649  UINT16 efID = (UINT16)va_arg(ap, unsigned);
650  UINT16 doID = (UINT16)va_arg(ap, unsigned);
651  WINPR_UNUSED(index);
652 
653  if (efID == 0x3FFF || efID == file->id)
654  {
655  /* If the DO was successfully read - abort file enum */
656  if (vgids_ef_read_do(file, doID, &response, &responseSize))
657  {
658  context->responseData = Stream_New(response, (size_t)responseSize);
659  return FALSE;
660  }
661  }
662 
663  return TRUE;
664 }
665 
666 static void vgids_read_do(vgidsContext* context, UINT16 efID, UINT16 doID)
667 {
668  ArrayList_ForEach(context->files, vgids_read_do_fkt, context, efID, doID);
669 }
670 
671 static void vgids_reset_context_response(vgidsContext* context)
672 {
673  Stream_Free(context->responseData, TRUE);
674  context->responseData = NULL;
675 }
676 
677 static void vgids_reset_context_command_data(vgidsContext* context)
678 {
679  Stream_Free(context->commandData, TRUE);
680  context->commandData = NULL;
681 }
682 
683 static BOOL vgids_ins_select(vgidsContext* context, wStream* s, BYTE** response,
684  DWORD* responseSize)
685 {
686  BYTE p1 = 0;
687  BYTE p2 = 0;
688  BYTE lc = 0;
689  DWORD resultDataSize = 0;
690  const BYTE* resultData = NULL;
691  UINT16 status = ISO_STATUS_SUCCESS;
692 
693  /* The only select operations performed are either select by AID or select 3FFF (return
694  * information about the currently selected DF) */
695  if (!vgids_parse_apdu_header(s, NULL, NULL, &p1, &p2, &lc, NULL))
696  return FALSE;
697 
698  /* Check P1 for selection mode */
699  switch (p1)
700  {
701  /* Select by AID */
702  case 0x04:
703  {
704  /* read AID from APDU */
705  BYTE aid[ISO_AID_MAX_SIZE] = { 0 };
706  if (lc > ISO_AID_MAX_SIZE)
707  {
708  WLog_ERR(TAG, "The LC byte is greater than the maximum AID length");
709  status = ISO_STATUS_INVALIDLC;
710  break;
711  }
712 
713  /* Check if we select MS GIDS App (only one we know) */
714  Stream_Read(s, aid, lc);
715  if (memcmp(aid, g_MsGidsAID, lc) != 0)
716  {
717  status = ISO_STATUS_FILENOTFOUND;
718  break;
719  }
720 
721  /* Return FCI or FCP for MsGids App */
722  switch (p2)
723  {
724  /* Return FCI information */
725  case 0x00:
726  {
727  resultData = g_GidsAppFCI;
728  resultDataSize = sizeof(g_GidsAppFCI);
729  break;
730  }
731  /* Return FCP information */
732  case 0x04:
733  {
734  resultData = g_GidsAppFCP;
735  resultDataSize = sizeof(g_GidsAppFCP);
736  break;
737  }
738  default:
739  status = ISO_STATUS_INVALIDP1P2;
740  break;
741  }
742 
743  if (resultData)
744  context->currentDF = ISO_FID_MF;
745  break;
746  }
747  /* Select by FID */
748  case 0x00:
749  {
750  /* read FID from APDU */
751  UINT16 fid = 0;
752  if (lc > 2)
753  {
754  WLog_ERR(TAG, "The LC byte for the file ID is greater than 2");
755  status = ISO_STATUS_INVALIDLC;
756  break;
757  }
758 
759  Stream_Read_UINT16_BE(s, fid);
760  if (fid != VGIDS_EFID_CURRENTDF || context->currentDF == 0)
761  {
762  status = ISO_STATUS_FILENOTFOUND;
763  break;
764  }
765  break;
766  }
767  default:
768  {
769  /* P1 P2 combination not supported */
770  status = ISO_STATUS_INVALIDP1P2;
771  break;
772  }
773  }
774 
775  return vgids_create_response(status, resultData, resultDataSize, response, responseSize);
776 }
777 
778 static UINT16 vgids_handle_chained_response(vgidsContext* context, const BYTE** response,
779  DWORD* responseSize)
780 {
781  /* Cap to a maximum of 256 bytes and set status to more data */
782  UINT16 status = ISO_STATUS_SUCCESS;
783  DWORD remainingBytes = (DWORD)Stream_Length(context->responseData);
784  if (remainingBytes > 256)
785  {
786  status = ISO_STATUS_MORE_DATA;
787  remainingBytes = 256;
788  }
789 
790  *response = Stream_Buffer(context->responseData);
791  *responseSize = remainingBytes;
792  Stream_Seek(context->responseData, remainingBytes);
793 
794  /* Check if there are more than 256 bytes left or if we can already provide the remaining length
795  * in the status word */
796  remainingBytes = (DWORD)(Stream_Length(context->responseData) - remainingBytes);
797  if (remainingBytes < 256 && remainingBytes != 0)
798  status |= (remainingBytes & 0xFF);
799  return status;
800 }
801 
802 static BOOL vgids_get_public_key(vgidsContext* context, UINT16 doTag)
803 {
804  BOOL rc = FALSE;
805  wStream* pubKey = NULL;
806  wStream* response = NULL;
807 
808  WINPR_ASSERT(context);
809 
810  /* Get key components */
811  size_t nSize = 0;
812  size_t eSize = 0;
813 
814  char* n = freerdp_certificate_get_param(context->certificate, FREERDP_CERT_RSA_N, &nSize);
815  char* e = freerdp_certificate_get_param(context->certificate, FREERDP_CERT_RSA_E, &eSize);
816 
817  if (!n || !e)
818  goto handle_error;
819 
820  pubKey = Stream_New(NULL, nSize + eSize + 0x10);
821  if (!pubKey)
822  {
823  WLog_ERR(TAG, "Failed to allocate public key stream");
824  goto handle_error;
825  }
826 
827  response = Stream_New(NULL, Stream_Capacity(pubKey) + 0x10);
828  if (!response)
829  {
830  WLog_ERR(TAG, "Failed to allocate response stream");
831  goto handle_error;
832  }
833 
834  /* write modulus and exponent DOs */
835  if (!vgids_write_tlv(pubKey, 0x81, n, nSize))
836  goto handle_error;
837 
838  if (!vgids_write_tlv(pubKey, 0x82, e, eSize))
839  goto handle_error;
840 
841  /* write ISO public key template */
842  if (!vgids_write_tlv(response, doTag, Stream_Buffer(pubKey), (DWORD)Stream_Length(pubKey)))
843  goto handle_error;
844 
845  /* set response data */
846  Stream_SetPosition(response, 0);
847  context->responseData = response;
848  response = NULL;
849 
850  rc = TRUE;
851 handle_error:
852  free(n);
853  free(e);
854  Stream_Free(pubKey, TRUE);
855  Stream_Free(response, TRUE);
856  return rc;
857 }
858 
859 static BOOL vgids_ins_getdata(vgidsContext* context, wStream* s, BYTE** response,
860  DWORD* responseSize)
861 {
862  UINT16 doId = 0;
863  UINT16 fileId = 0;
864  BYTE p1 = 0;
865  BYTE p2 = 0;
866  BYTE lc = 0;
867  DWORD resultDataSize = 0;
868  const BYTE* resultData = NULL;
869  UINT16 status = ISO_STATUS_SUCCESS;
870 
871  /* GetData is called a lot!
872  - To retrieve DOs from files
873  - To retrieve public key information
874  */
875  if (!vgids_parse_apdu_header(s, NULL, NULL, &p1, &p2, &lc, NULL))
876  return FALSE;
877 
878  /* free any previous queried data */
879  vgids_reset_context_response(context);
880 
881  /* build up file identifier */
882  fileId = (UINT16)(((UINT16)p1 << 8) | p2);
883 
884  /* Do we have a DO reference? */
885  switch (lc)
886  {
887  case 4:
888  {
889  BYTE tag = 0;
890  BYTE length = 0;
891  Stream_Read_UINT8(s, tag);
892  Stream_Read_UINT8(s, length);
893  if (tag != 0x5C && length != 0x02)
894  {
895  status = ISO_STATUS_INVALIDCOMMANDDATA;
896  break;
897  }
898 
899  Stream_Read_UINT16_BE(s, doId);
900  vgids_read_do(context, fileId, doId);
901  break;
902  }
903  case 0xA:
904  {
905  UINT16 pubKeyDO = 0;
906  BYTE tag = 0;
907  BYTE length = 0;
908  BYTE keyRef = 0;
909 
910  /* We want to retrieve the public key? */
911  if (p1 != 0x3F && p2 != 0xFF)
912  {
913  status = ISO_STATUS_INVALIDP1P2;
914  break;
915  }
916 
917  /* read parent tag/length */
918  Stream_Read_UINT8(s, tag);
919  Stream_Read_UINT8(s, length);
920  if (tag != 0x70 || length != 0x08)
921  {
922  status = ISO_STATUS_INVALIDCOMMANDDATA;
923  break;
924  }
925 
926  /* read key reference TLV */
927  Stream_Read_UINT8(s, tag);
928  Stream_Read_UINT8(s, length);
929  Stream_Read_UINT8(s, keyRef);
930  if (tag != 0x84 || length != 0x01 || keyRef != VGIDS_DEFAULT_KEY_REF)
931  {
932  status = ISO_STATUS_INVALIDCOMMANDDATA;
933  break;
934  }
935 
936  /* read key value template TLV */
937  Stream_Read_UINT8(s, tag);
938  Stream_Read_UINT8(s, length);
939  if (tag != 0xA5 || length != 0x03)
940  {
941  status = ISO_STATUS_INVALIDCOMMANDDATA;
942  break;
943  }
944 
945  Stream_Read_UINT16_BE(s, pubKeyDO);
946  Stream_Read_UINT8(s, length);
947  if (pubKeyDO != 0x7F49 || length != 0x80)
948  {
949  status = ISO_STATUS_INVALIDCOMMANDDATA;
950  break;
951  }
952 
953  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
954  {
955  status = ISO_STATUS_INVALIDLC;
956  break;
957  }
958 
959  /* Return public key value */
960  vgids_get_public_key(context, pubKeyDO);
961  break;
962  }
963  default:
964  status = ISO_STATUS_INVALIDCOMMANDDATA;
965  break;
966  }
967 
968  /* If we have response data, make it ready for return */
969  if (context->responseData)
970  status = vgids_handle_chained_response(context, &resultData, &resultDataSize);
971  else if (status == ISO_STATUS_SUCCESS)
972  status = ISO_STATUS_REFERENCEDATANOTFOUND;
973 
974  return vgids_create_response(status, resultData, resultDataSize, response, responseSize);
975 }
976 
977 static BOOL vgids_ins_manage_security_environment(vgidsContext* context, wStream* s,
978  BYTE** response, DWORD* responseSize)
979 {
980  BYTE tag = 0;
981  BYTE length = 0;
982  BYTE p1 = 0;
983  BYTE p2 = 0;
984  BYTE lc = 0;
985  DWORD resultDataSize = 0;
986  const BYTE* resultData = NULL;
987  UINT16 status = ISO_STATUS_SUCCESS;
988 
989  vgids_reset_context_command_data(context);
990  vgids_reset_context_response(context);
991 
992  /* Manage security environment prepares the card for performing crypto operations. */
993  if (!vgids_parse_apdu_header(s, NULL, NULL, &p1, &p2, &lc, NULL))
994  return FALSE;
995 
996  /* Check APDU params */
997  /* P1: Set Computation, decipherment, Internal Auth */
998  /* P2: Digital Signature (B6), Confidentiality (B8) */
999  if (p1 != 0x41 && p2 != 0xB6 && p2 != 0xB8)
1000  {
1001  status = ISO_STATUS_INVALIDP1P2;
1002  goto create_response;
1003  }
1004 
1005  if (lc != 6)
1006  {
1007  status = ISO_STATUS_WRONGLC;
1008  goto create_response;
1009  }
1010 
1011  context->currentSE.crt = p2;
1012 
1013  /* parse command buffer */
1014  /* Read algo ID */
1015  Stream_Read_UINT8(s, tag);
1016  Stream_Read_UINT8(s, length);
1017  if (tag != 0x80 || length != 0x01)
1018  {
1019  status = ISO_STATUS_INVALIDCOMMANDDATA;
1020  goto create_response;
1021  }
1022  Stream_Read_UINT8(s, context->currentSE.algoId);
1023 
1024  /* Read private key reference */
1025  Stream_Read_UINT8(s, tag);
1026  Stream_Read_UINT8(s, length);
1027  if (tag != 0x84 || length != 0x01)
1028  {
1029  status = ISO_STATUS_INVALIDCOMMANDDATA;
1030  goto create_response;
1031  }
1032  Stream_Read_UINT8(s, context->currentSE.keyRef);
1033 
1034 create_response:
1035  /* If an error occured reset SE */
1036  if (status != ISO_STATUS_SUCCESS)
1037  memset(&context->currentSE, 0, sizeof(context->currentSE));
1038  return vgids_create_response(status, resultData, resultDataSize, response, responseSize);
1039 }
1040 
1041 static BOOL vgids_perform_digital_signature(vgidsContext* context)
1042 {
1043  size_t sigSize = 0;
1044  size_t msgSize = 0;
1045  EVP_PKEY_CTX* ctx = NULL;
1046  EVP_PKEY* pk = freerdp_key_get_evp_pkey(context->privateKey);
1047  const vgidsDigestInfoMap gidsDigestInfo[VGIDS_MAX_DIGEST_INFO] = {
1048  { g_PKCS1_SHA1, sizeof(g_PKCS1_SHA1), EVP_sha1() },
1049  { g_PKCS1_SHA224, sizeof(g_PKCS1_SHA224), EVP_sha224() },
1050  { g_PKCS1_SHA256, sizeof(g_PKCS1_SHA256), EVP_sha256() },
1051  { g_PKCS1_SHA384, sizeof(g_PKCS1_SHA384), EVP_sha384() },
1052  { g_PKCS1_SHA512, sizeof(g_PKCS1_SHA512), EVP_sha512() },
1053 #if OPENSSL_VERSION_NUMBER >= 0x10101000L
1054  { g_PKCS1_SHA512_224, sizeof(g_PKCS1_SHA512_224), EVP_sha512_224() },
1055  { g_PKCS1_SHA512_256, sizeof(g_PKCS1_SHA512_256), EVP_sha512_256() }
1056 #endif
1057  };
1058 
1059  if (!pk)
1060  {
1061  WLog_ERR(TAG, "Failed to create PKEY");
1062  return FALSE;
1063  }
1064 
1065  vgids_reset_context_response(context);
1066 
1067  /* for each digest info */
1068  Stream_SetPosition(context->commandData, 0);
1069  for (int i = 0; i < VGIDS_MAX_DIGEST_INFO; ++i)
1070  {
1071  /* have we found our digest? */
1072  const vgidsDigestInfoMap* digest = &gidsDigestInfo[i];
1073  if (Stream_Length(context->commandData) >= digest->infoSize &&
1074  memcmp(Stream_Buffer(context->commandData), digest->info, digest->infoSize) == 0)
1075  {
1076  /* skip digest info and calculate message size */
1077  Stream_Seek(context->commandData, digest->infoSize);
1078  if (!Stream_CheckAndLogRequiredLength(TAG, context->commandData, 2))
1079  goto sign_failed;
1080  msgSize = Stream_GetRemainingLength(context->commandData);
1081 
1082  /* setup signing context */
1083  ctx = EVP_PKEY_CTX_new(pk, NULL);
1084  if (!ctx)
1085  {
1086  WLog_ERR(TAG, "Failed to create signing context");
1087  goto sign_failed;
1088  }
1089 
1090  if (EVP_PKEY_sign_init(ctx) <= 0)
1091  {
1092  WLog_ERR(TAG, "Failed to init signing context");
1093  goto sign_failed;
1094  }
1095 
1096  /* set padding and signature algo */
1097  if (context->currentSE.algoId & VGIDS_SE_ALGOID_DST_PAD_PKCS1)
1098  {
1099  if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)
1100  {
1101  WLog_ERR(TAG, "Failed to set padding mode");
1102  goto sign_failed;
1103  }
1104  }
1105 
1106  if (EVP_PKEY_CTX_set_signature_md(ctx, digest->digest) <= 0)
1107  {
1108  WLog_ERR(TAG, "Failed to set signing mode");
1109  goto sign_failed;
1110  }
1111 
1112  /* Determine buffer length */
1113  if (EVP_PKEY_sign(ctx, NULL, &sigSize, Stream_Pointer(context->commandData), msgSize) <=
1114  0)
1115  {
1116  WLog_ERR(TAG, "Failed to determine signature size");
1117  goto sign_failed;
1118  }
1119 
1120  context->responseData = Stream_New(NULL, sigSize);
1121  if (!context->responseData)
1122  {
1123  WLog_ERR(TAG, "Failed to allocate signing buffer");
1124  goto sign_failed;
1125  }
1126 
1127  /* sign */
1128  if (EVP_PKEY_sign(ctx, Stream_Buffer(context->responseData), &sigSize,
1129  Stream_Pointer(context->commandData), msgSize) <= 0)
1130  {
1131  WLog_ERR(TAG, "Failed to create signature");
1132  goto sign_failed;
1133  }
1134 
1135  Stream_SetLength(context->responseData, sigSize);
1136  EVP_PKEY_CTX_free(ctx);
1137  break;
1138  }
1139  }
1140 
1141  EVP_PKEY_free(pk);
1142  vgids_reset_context_command_data(context);
1143  return TRUE;
1144 
1145 sign_failed:
1146  vgids_reset_context_command_data(context);
1147  vgids_reset_context_response(context);
1148  EVP_PKEY_CTX_free(ctx);
1149  EVP_PKEY_free(pk);
1150  return FALSE;
1151 }
1152 
1153 static BOOL vgids_perform_decrypt(vgidsContext* context)
1154 {
1155  EVP_PKEY_CTX* ctx = NULL;
1156  BOOL rc = FALSE;
1157  int res = 0;
1158  int padding = RSA_NO_PADDING;
1159 
1160  vgids_reset_context_response(context);
1161 
1162  /* determine padding */
1163  if (context->currentSE.algoId & VGIDS_SE_ALGOID_CT_PAD_PKCS1)
1164  padding = RSA_PKCS1_PADDING;
1165  else if (context->currentSE.algoId & VGIDS_SE_ALGOID_CT_PAD_OAEP)
1166  padding = RSA_PKCS1_OAEP_PADDING;
1167 
1168  /* init response buffer */
1169  EVP_PKEY* pkey = freerdp_key_get_evp_pkey(context->privateKey);
1170  if (!pkey)
1171  goto decrypt_failed;
1172  ctx = EVP_PKEY_CTX_new(pkey, NULL);
1173  if (!ctx)
1174  goto decrypt_failed;
1175  if (EVP_PKEY_decrypt_init(ctx) <= 0)
1176  goto decrypt_failed;
1177  if (EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0)
1178  goto decrypt_failed;
1179 
1180  /* Determine buffer length */
1181  const size_t inlen = Stream_Length(context->commandData);
1182  size_t outlen = 0;
1183  res = EVP_PKEY_decrypt(ctx, NULL, &outlen, Stream_Buffer(context->commandData), inlen);
1184  if (res < 0)
1185  {
1186  WLog_ERR(TAG, "Failed to decrypt data");
1187  goto decrypt_failed;
1188  }
1189 
1190  /* Prepare output buffer */
1191  context->responseData = Stream_New(NULL, outlen);
1192  if (!context->responseData)
1193  {
1194  WLog_ERR(TAG, "Failed to create decryption buffer");
1195  goto decrypt_failed;
1196  }
1197 
1198  /* Decrypt */
1199  res = EVP_PKEY_decrypt(ctx, Stream_Buffer(context->responseData), &outlen,
1200  Stream_Buffer(context->commandData), inlen);
1201 
1202  if (res < 0)
1203  {
1204  WLog_ERR(TAG, "Failed to decrypt data");
1205  goto decrypt_failed;
1206  }
1207 
1208  Stream_SetLength(context->responseData, outlen);
1209  rc = TRUE;
1210 
1211 decrypt_failed:
1212  EVP_PKEY_CTX_free(ctx);
1213  EVP_PKEY_free(pkey);
1214  vgids_reset_context_command_data(context);
1215  if (!rc)
1216  vgids_reset_context_response(context);
1217  return rc;
1218 }
1219 
1220 static BOOL vgids_ins_perform_security_operation(vgidsContext* context, wStream* s, BYTE** response,
1221  DWORD* responseSize)
1222 {
1223  BYTE cla = 0;
1224  BYTE p1 = 0;
1225  BYTE p2 = 0;
1226  BYTE lc = 0;
1227  DWORD resultDataSize = 0;
1228  const BYTE* resultData = NULL;
1229  UINT16 status = ISO_STATUS_SUCCESS;
1230 
1231  /* Perform security operation */
1232  if (!vgids_parse_apdu_header(s, &cla, NULL, &p1, &p2, &lc, NULL))
1233  return FALSE;
1234 
1235  if (lc == 0)
1236  {
1237  status = ISO_STATUS_WRONGLC;
1238  goto create_response;
1239  }
1240 
1241  /* Is our default key referenced? */
1242  if (context->currentSE.keyRef != VGIDS_DEFAULT_KEY_REF)
1243  {
1244  status = ISO_STATUS_SECURITYSTATUSNOTSATISFIED;
1245  goto create_response;
1246  }
1247 
1248  /* is the pin protecting the key verified? */
1249  if (!context->pinVerified)
1250  {
1251  status = ISO_STATUS_SECURITYSTATUSNOTSATISFIED;
1252  goto create_response;
1253  }
1254 
1255  /* Append the data to the context command buffer (PSO might chain command data) */
1256  if (!context->commandData)
1257  {
1258  context->commandData = Stream_New(NULL, lc);
1259  if (!context->commandData)
1260  return FALSE;
1261  }
1262  else if (!Stream_EnsureRemainingCapacity(context->commandData, lc))
1263  return FALSE;
1264 
1265  Stream_Write(context->commandData, Stream_Pointer(s), lc);
1266  Stream_SealLength(context->commandData);
1267 
1268  /* Check if the correct operation is requested for our current SE */
1269  switch (context->currentSE.crt)
1270  {
1271  case VGIDS_SE_CRT_SIGN:
1272  {
1273  if (p1 != 0x9E || p2 != 0x9A)
1274  {
1275  status = ISO_STATUS_INVALIDP1P2;
1276  break;
1277  }
1278 
1279  /* If chaining is over perform op */
1280  if (!(cla & 0x10))
1281  vgids_perform_digital_signature(context);
1282  break;
1283  }
1284  case VGIDS_SE_CRT_CONF:
1285  {
1286  if ((p1 != 0x86 || p2 != 0x80) && (p1 != 0x80 || p2 != 0x86))
1287  {
1288  status = ISO_STATUS_INVALIDP1P2;
1289  break;
1290  }
1291 
1292  /* If chaining is over perform op */
1293  if (!(cla & 0x10))
1294  vgids_perform_decrypt(context);
1295  break;
1296  }
1297  default:
1298  status = ISO_STATUS_INVALIDP1P2;
1299  break;
1300  }
1301 
1302  /* Do chaining of response data if necessary */
1303  if (status == ISO_STATUS_SUCCESS && context->responseData)
1304  status = vgids_handle_chained_response(context, &resultData, &resultDataSize);
1305 
1306  /* Check APDU params */
1307 create_response:
1308  return vgids_create_response(status, resultData, resultDataSize, response, responseSize);
1309 }
1310 
1311 static BOOL vgids_ins_getresponse(vgidsContext* context, wStream* s, BYTE** response,
1312  DWORD* responseSize)
1313 {
1314  BYTE p1 = 0;
1315  BYTE p2 = 0;
1316  BYTE le = 0;
1317  DWORD resultDataSize = 0;
1318  const BYTE* resultData = NULL;
1319  DWORD expectedLen = 0;
1320  DWORD remainingSize = 0;
1321  UINT16 status = ISO_STATUS_SUCCESS;
1322 
1323  /* Get response continues data transfer after a previous get data command */
1324  /* Check if there is any data to transfer left */
1325  if (!context->responseData || !Stream_CheckAndLogRequiredLength(TAG, context->responseData, 1))
1326  {
1327  status = ISO_STATUS_COMMANDNOTALLOWED;
1328  goto create_response;
1329  }
1330 
1331  if (!vgids_parse_apdu_header(s, NULL, NULL, &p1, &p2, NULL, &le))
1332  return FALSE;
1333 
1334  /* Check APDU params */
1335  if (p1 != 00 || p2 != 0x00)
1336  {
1337  status = ISO_STATUS_INVALIDP1P2;
1338  goto create_response;
1339  }
1340 
1341  /* LE = 0 means 256 bytes expected */
1342  expectedLen = le;
1343  if (expectedLen == 0)
1344  expectedLen = 256;
1345 
1346  /* prepare response size and update offset */
1347  remainingSize = (DWORD)Stream_GetRemainingLength(context->responseData);
1348  if (remainingSize < expectedLen)
1349  expectedLen = remainingSize;
1350 
1351  resultData = Stream_Pointer(context->responseData);
1352  resultDataSize = expectedLen;
1353  Stream_Seek(context->responseData, expectedLen);
1354 
1355  /* If more data is left return 61XX - otherwise 9000 */
1356  remainingSize = (DWORD)Stream_GetRemainingLength(context->responseData);
1357  if (remainingSize > 0)
1358  {
1359  status = ISO_STATUS_MORE_DATA;
1360  if (remainingSize < 256)
1361  status |= (remainingSize & 0xFF);
1362  }
1363 
1364 create_response:
1365  return vgids_create_response(status, resultData, resultDataSize, response, responseSize);
1366 }
1367 
1368 static BOOL vgids_ins_verify(vgidsContext* context, wStream* s, BYTE** response,
1369  DWORD* responseSize)
1370 {
1371  BYTE ins = 0;
1372  BYTE p1 = 0;
1373  BYTE p2 = 0;
1374  BYTE lc = 0;
1375  UINT16 status = ISO_STATUS_SUCCESS;
1376  char pin[VGIDS_MAX_PIN_SIZE + 1] = { 0 };
1377 
1378  /* Verify is always called for the application password (PIN) P2=0x80 */
1379  if (!vgids_parse_apdu_header(s, NULL, &ins, &p1, &p2, NULL, NULL))
1380  return FALSE;
1381 
1382  /* Check APDU params */
1383  if (p1 != 00 && p2 != 0x80 && p2 != 0x82)
1384  {
1385  status = ISO_STATUS_INVALIDP1P2;
1386  goto create_response;
1387  }
1388 
1389  /* shall we reset the security state? */
1390  if (p2 == 0x82)
1391  {
1392  context->pinVerified = FALSE;
1393  goto create_response;
1394  }
1395 
1396  /* Check if pin is not already blocked */
1397  if (context->curRetryCounter == 0)
1398  {
1399  status = ISO_STATUS_AUTHMETHODBLOCKED;
1400  goto create_response;
1401  }
1402 
1403  /* Read and verify LC */
1404  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
1405  {
1406  status = ISO_STATUS_INVALIDLC;
1407  goto create_response;
1408  }
1409 
1410  Stream_Read_UINT8(s, lc);
1411  if (!Stream_CheckAndLogRequiredLength(TAG, s, lc) || (lc > VGIDS_MAX_PIN_SIZE))
1412  {
1413  status = ISO_STATUS_INVALIDLC;
1414  goto create_response;
1415  }
1416 
1417  /* read and verify pin */
1418  Stream_Read(s, pin, lc);
1419  if (strcmp(context->pin, pin) != 0)
1420  {
1421  /* retries are encoded in the lowest 4-bit of the status code */
1422  --context->curRetryCounter;
1423  context->pinVerified = FALSE;
1424  status = (ISO_STATUS_VERIFYFAILED | (context->curRetryCounter & 0xFF));
1425  }
1426  else
1427  {
1428  /* reset retry counter and mark pin as verified */
1429  context->curRetryCounter = context->retryCounter;
1430  context->pinVerified = TRUE;
1431  }
1432 
1433 create_response:
1434  return vgids_create_response(status, NULL, 0, response, responseSize);
1435 }
1436 
1437 vgidsContext* vgids_new(void)
1438 {
1439  wObject* obj = NULL;
1440  vgidsContext* ctx = calloc(1, sizeof(vgidsContext));
1441 
1442  ctx->files = ArrayList_New(FALSE);
1443  if (!ctx->files)
1444  {
1445  WLog_ERR(TAG, "Failed to create files array list");
1446  goto create_failed;
1447  }
1448 
1449  obj = ArrayList_Object(ctx->files);
1450  obj->fnObjectFree = vgids_ef_free;
1451 
1452  return ctx;
1453 
1454 create_failed:
1455  vgids_free(ctx);
1456  return NULL;
1457 }
1458 
1459 BOOL vgids_init(vgidsContext* ctx, const char* cert, const char* privateKey, const char* pin)
1460 {
1461  DWORD kxcSize = 0;
1462  DWORD keymapSize = 0;
1463  DWORD fsTableSize = 0;
1464  BOOL rc = FALSE;
1465  BYTE* kxc = NULL;
1466  BYTE* keymap = NULL;
1467  BYTE* fsTable = NULL;
1468  vgidsEF* masterEF = NULL;
1469  vgidsEF* cardidEF = NULL;
1470  vgidsEF* commonEF = NULL;
1471  BYTE cardid[VGIDS_CARDID_SIZE] = { 0 };
1472  vgidsContainerMapEntry cmrec = { { 'P', 'r', 'i', 'v', 'a', 't', 'e', ' ', 'K', 'e', 'y', ' ',
1473  '0', '0' },
1474  CONTAINER_MAP_VALID_CONTAINER |
1475  CONTAINER_MAP_DEFAULT_CONTAINER,
1476  0,
1477  0,
1478  0x00 /* key-size in bits - filled out later */ };
1479  vgidsFilesysTableEntry filesys[] = {
1480  { "mscp", "", 0, 0, 0, 0xA000, 0 },
1481  { "", "cardid", 0, 0xDF20, 0, 0xA012, 0 },
1482  { "", "cardapps", 0, 0xDF21, 0, 0xA010, 0 },
1483  { "", "cardcf", 0, 0xDF22, 0, 0xA010, 0 },
1484  { "mscp", "cmapfile", 0, 0xDF23, 0, 0xA010, 0 },
1485  { "mscp", "kxc00", 0, 0xDF24, 0, 0xA010, 0 },
1486  };
1487 
1488  /* Check params */
1489  if (!cert || !privateKey || !pin)
1490  {
1491  WLog_DBG(TAG, "Passed invalid NULL argument: cert=%p, privateKey=%p, pin=%p", cert,
1492  privateKey, pin);
1493  goto init_failed;
1494  }
1495 
1496  /* Convert PEM input to DER certificate/public key/private key */
1497  ctx->certificate = freerdp_certificate_new_from_pem(cert);
1498  if (!ctx->certificate)
1499  goto init_failed;
1500 
1501  ctx->privateKey = freerdp_key_new_from_pem(privateKey);
1502  if (!ctx->privateKey)
1503  goto init_failed;
1504 
1505  /* create masterfile */
1506  // NOLINTNEXTLINE(clang-analyzer-unix.Malloc)
1507  masterEF = vgids_ef_new(ctx, VGIDS_EFID_MASTER);
1508  if (!masterEF)
1509  goto init_failed;
1510 
1511  /* create cardid file with cardid DO */
1512  // NOLINTNEXTLINE(clang-analyzer-unix.Malloc)
1513  cardidEF = vgids_ef_new(ctx, VGIDS_EFID_CARDID);
1514  if (!cardidEF)
1515  goto init_failed;
1516  winpr_RAND(cardid, sizeof(cardid));
1517  if (!vgids_ef_write_do(cardidEF, VGIDS_DO_CARDID, cardid, sizeof(cardid)))
1518  goto init_failed;
1519 
1520  /* create user common file */
1521  // NOLINTNEXTLINE(clang-analyzer-unix.Malloc)
1522  commonEF = vgids_ef_new(ctx, VGIDS_EFID_COMMON);
1523  if (!commonEF)
1524  goto init_failed;
1525 
1526  /* write card cache DO */
1527  if (!vgids_ef_write_do(commonEF, VGIDS_DO_CARDCF, g_CardCFContents, sizeof(g_CardCFContents)))
1528  goto init_failed;
1529 
1530  /* write container map DO */
1531  const size_t size = get_rsa_key_size(ctx->privateKey);
1532  if ((size == 0) || (size > UINT16_MAX / 8))
1533  goto init_failed;
1534 
1535  cmrec.wKeyExchangeKeySizeBits = (WORD)size * 8;
1536  if (!vgids_ef_write_do(commonEF, VGIDS_DO_CMAPFILE, &cmrec, sizeof(cmrec)))
1537  goto init_failed;
1538 
1539  /* write cardapps DO */
1540  if (!vgids_ef_write_do(commonEF, VGIDS_DO_CARDAPPS, g_CardAppsContents,
1541  sizeof(g_CardAppsContents)))
1542  goto init_failed;
1543 
1544  /* convert and write certificate to key exchange container */
1545  if (!vgids_prepare_certificate(ctx->certificate, &kxc, &kxcSize))
1546  goto init_failed;
1547  if (!vgids_ef_write_do(commonEF, VGIDS_DO_KXC00, kxc, kxcSize))
1548  goto init_failed;
1549 
1550  /* prepare and write file system table */
1551  if (!vgids_prepare_fstable(filesys, ARRAYSIZE(filesys), &fsTable, &fsTableSize))
1552  goto init_failed;
1553  if (!vgids_ef_write_do(masterEF, VGIDS_DO_FILESYSTEMTABLE, fsTable, fsTableSize))
1554  goto init_failed;
1555 
1556  /* vgids_prepare_keymap and write to masterEF */
1557  if (!vgids_prepare_keymap(ctx, &keymap, &keymapSize))
1558  goto init_failed;
1559  if (!vgids_ef_write_do(masterEF, VGIDS_DO_KEYMAP, keymap, keymapSize))
1560  goto init_failed;
1561 
1562  /* store user pin */
1563  ctx->curRetryCounter = ctx->retryCounter = VGIDS_DEFAULT_RETRY_COUNTER;
1564  ctx->pin = _strdup(pin);
1565  if (!ctx->pin)
1566  goto init_failed;
1567 
1568  rc = TRUE;
1569 
1570 init_failed:
1571  // ArrayList_Append in vgids_ef_new takes ownership
1572  // of cardidEF, commonEF, masterEF
1573  // NOLINTNEXTLINE(clang-analyzer-unix.Malloc)
1574  free(kxc);
1575  free(keymap);
1576  free(fsTable);
1577  return rc;
1578 }
1579 
1580 BOOL vgids_process_apdu(vgidsContext* context, const BYTE* data, DWORD dataSize, BYTE** response,
1581  DWORD* responseSize)
1582 {
1583  wStream s;
1584  static int x = 1;
1585 
1586  /* Check params */
1587  if (!context || !data || !response || !responseSize)
1588  {
1589  WLog_ERR(TAG, "Invalid NULL pointer passed");
1590  return FALSE;
1591  }
1592 
1593  if (dataSize < 4)
1594  {
1595  WLog_ERR(TAG, "APDU buffer is less than 4 bytes: %" PRIu32, dataSize);
1596  return FALSE;
1597  }
1598 
1599  /* Examine INS byte */
1600  Stream_StaticConstInit(&s, data, dataSize);
1601  if (x++ == 0xe)
1602  x = 0xe + 1;
1603  switch (data[1])
1604  {
1605  case ISO_INS_SELECT:
1606  return vgids_ins_select(context, &s, response, responseSize);
1607  case ISO_INS_GETDATA:
1608  return vgids_ins_getdata(context, &s, response, responseSize);
1609  case ISO_INS_GETRESPONSE:
1610  return vgids_ins_getresponse(context, &s, response, responseSize);
1611  case ISO_INS_MSE:
1612  return vgids_ins_manage_security_environment(context, &s, response, responseSize);
1613  case ISO_INS_PSO:
1614  return vgids_ins_perform_security_operation(context, &s, response, responseSize);
1615  case ISO_INS_VERIFY:
1616  return vgids_ins_verify(context, &s, response, responseSize);
1617  default:
1618  break;
1619  }
1620 
1621  /* return command not allowed */
1622  return vgids_create_response(ISO_STATUS_COMMANDNOTALLOWED, NULL, 0, response, responseSize);
1623 }
1624 
1625 void vgids_free(vgidsContext* context)
1626 {
1627  if (context)
1628  {
1629  freerdp_key_free(context->privateKey);
1630  freerdp_certificate_free(context->certificate);
1631  Stream_Free(context->commandData, TRUE);
1632  Stream_Free(context->responseData, TRUE);
1633  free(context->pin);
1634  ArrayList_Free(context->files);
1635  free(context);
1636  }
1637 }
This struct contains function pointer to initialize/free objects.
Definition: collections.h:57