22 #include <freerdp/config.h>
24 #include <winpr/wlog.h>
25 #include <winpr/stream.h>
26 #include <winpr/collections.h>
28 #include <freerdp/crypto/crypto.h>
32 #include "../../crypto/certificate.h"
33 #include "../../crypto/privatekey.h"
34 #include "smartcard_virtual_gids.h"
36 #define TAG CHANNELS_TAG("smartcard.vgids")
38 #define VGIDS_EFID_MASTER 0xA000
39 #define VGIDS_EFID_COMMON 0xA010
43 #define VGIDS_EFID_CARDID 0xA012
45 #define VGIDS_EFID_CURRENTDF 0x3FFF
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
55 #define VGIDS_CARDID_SIZE 16
56 #define VGIDS_MAX_PIN_SIZE 127
58 #define VGIDS_DEFAULT_RETRY_COUNTER 3
60 #define VGIDS_KEY_TYPE_KEYEXCHANGE 0x9A
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
69 #define VGIDS_SE_CRT_SIGN 0xB6
70 #define VGIDS_SE_CRT_CONF 0xB8
72 #define VGIDS_SE_ALGOID_CT_PAD_PKCS1 0x40
73 #define VGIDS_SE_ALGOID_CT_PAD_OAEP 0x80
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
90 #define VGIDS_DEFAULT_KEY_REF 0x81
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
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
112 #define ISO_AID_MAX_SIZE 16
114 #define ISO_FID_MF 0x3F00
122 typedef struct vgids_ef vgidsEF;
130 typedef struct vgids_se vgidsSE;
136 UINT16 curRetryCounter;
143 rdpCertificate* certificate;
144 rdpPrivateKey* privateKey;
150 #define VGIDS_MAX_DIGEST_INFO 7
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 };
170 struct vgids_digest_info_map
174 const EVP_MD* digest;
176 typedef struct vgids_digest_info_map vgidsDigestInfoMap;
183 static const BYTE g_MsGidsAID[] = {
184 0xA0, 0x00, 0x00, 0x03, 0x97, 0x42, 0x54, 0x46, 0x59, 0x02, 0x01
191 static const BYTE g_GidsAppFCP[] = { 0x62, 0x08, 0x82, 0x01, 0x38, 0x8C, 0x03, 0x03, 0x30, 0x30 };
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 };
208 static const BYTE g_CardCFContents[] = { 0x00, 0x00, 0x01, 0x00, 0x04, 0x00 };
211 static const BYTE g_CardAppsContents[] = { 0x6d, 0x73, 0x63, 0x70, 0x00, 0x00, 0x00, 0x00 };
213 #pragma pack(push, 1)
221 #define MAX_CONTAINER_NAME_LEN 39
227 #define CONTAINER_MAP_VALID_CONTAINER 1
232 #define CONTAINER_MAP_DEFAULT_CONTAINER 2
234 struct vgids_container_map_entry
236 WCHAR wszGuid[MAX_CONTAINER_NAME_LEN + 1];
239 WORD wSigKeySizeBits;
240 WORD wKeyExchangeKeySizeBits;
242 typedef struct vgids_container_map_entry vgidsContainerMapEntry;
244 struct vgids_filesys_table_entry
249 UINT16 dataObjectIdentifier;
251 UINT16 fileIdentifier;
254 typedef struct vgids_filesys_table_entry vgidsFilesysTableEntry;
256 struct vgids_keymap_record
262 UINT16 unknownWithFFFF;
263 UINT16 unknownWith0000;
265 typedef struct vgids_keymap_record vgidsKeymapRecord;
269 static void vgids_ef_free(
void* ptr);
271 static vgidsEF* vgids_ef_new(vgidsContext* ctx, USHORT
id)
273 vgidsEF* ef = calloc(1,
sizeof(vgidsEF));
276 ef->data = Stream_New(NULL, 1024);
279 WLog_ERR(TAG,
"Failed to create file data stream");
282 Stream_SetLength(ef->data, 0);
284 if (!ArrayList_Append(ctx->files, ef))
286 WLog_ERR(TAG,
"Failed to add new ef to file list");
297 static BOOL vgids_write_tlv(
wStream* s, UINT16 tag,
const void* data,
size_t dataSize)
299 WINPR_ASSERT(dataSize <= UINT16_MAX);
302 if (!Stream_EnsureRemainingCapacity(s, dataSize + 5))
304 WLog_ERR(TAG,
"Failed to ensure capacity of DO stream");
311 Stream_Write_UINT16_BE(s, tag);
313 Stream_Write_UINT8(s, (BYTE)tag);
316 Stream_Write_UINT8(s, (BYTE)dataSize);
318 else if (dataSize < 256)
320 Stream_Write_UINT8(s, 0x81);
321 Stream_Write_UINT8(s, (BYTE)dataSize);
325 Stream_Write_UINT8(s, 0x82);
326 Stream_Write_UINT16_BE(s, (UINT16)dataSize);
328 Stream_Write(s, data, dataSize);
329 Stream_SealLength(s);
333 static BOOL vgids_ef_write_do(vgidsEF* ef, UINT16 doID,
const void* data, DWORD dataSize)
336 return vgids_write_tlv(ef->data, doID, data, dataSize);
339 static BOOL vgids_ef_read_do(vgidsEF* ef, UINT16 doID, BYTE** data, DWORD* dataSize)
342 if (!Stream_SetPosition(ef->data, 0))
344 WLog_ERR(TAG,
"Failed to seek to front of file");
349 while (Stream_GetRemainingLength(ef->data) > 3)
356 curPos = Stream_GetPosition(ef->data);
357 Stream_Read_UINT16_BE(ef->data, nextDOID);
358 Stream_Read_UINT8(ef->data, len);
361 BYTE lenSize = len & 0x7F;
362 if (!Stream_CheckAndLogRequiredLength(TAG, ef->data, lenSize))
368 Stream_Read_UINT8(ef->data, doSize);
371 Stream_Read_UINT16_BE(ef->data, doSize);
374 WLog_ERR(TAG,
"Unexpected tag length %" PRIu8, lenSize);
381 if (!Stream_CheckAndLogRequiredLength(TAG, ef->data, doSize))
384 if (nextDOID == doID)
386 BYTE* outData = NULL;
389 doSize += (UINT16)(Stream_GetPosition(ef->data) - curPos);
390 outData = malloc(doSize);
393 WLog_ERR(TAG,
"Failed to allocate output buffer");
397 Stream_SetPosition(ef->data, curPos);
398 Stream_Read(ef->data, outData, doSize);
406 if (!Stream_SafeSeek(ef->data, doSize))
414 void vgids_ef_free(
void* ptr)
419 Stream_Free(ef->data, TRUE);
424 static BOOL vgids_prepare_fstable(
const vgidsFilesysTableEntry* fstable, DWORD numEntries,
425 BYTE** outData, DWORD* outDataSize)
431 BYTE* data = malloc(
sizeof(vgidsFilesysTableEntry) * numEntries + 1);
434 WLog_ERR(TAG,
"Failed to allocate filesystem table data blob");
439 for (UINT32 i = 0; i < numEntries; ++i)
440 memcpy(data + 1 + (
sizeof(vgidsFilesysTableEntry) * i), &fstable[i],
441 sizeof(vgidsFilesysTableEntry));
444 *outDataSize =
sizeof(vgidsFilesysTableEntry) * numEntries + 1;
449 static BOOL vgids_prepare_certificate(
const rdpCertificate* cert, BYTE** kxc, DWORD* kxcSize)
458 BYTE* comprData = NULL;
463 BYTE* certData = freerdp_certificate_get_der(cert, &certSize);
464 if (!certData || (certSize == 0))
466 WLog_ERR(TAG,
"Failed to get certificate size");
470 comprData = malloc(certSize);
473 WLog_ERR(TAG,
"Failed to allocate certificate buffer");
479 if (compress(comprData, &destSize, certData, certSize) != Z_OK)
481 WLog_ERR(TAG,
"Failed to compress certificate 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);
492 *kxc = Stream_Buffer(s);
493 *kxcSize = (DWORD)Stream_Length(s);
495 Stream_Free(s, FALSE);
501 Stream_Free(s, TRUE);
507 static size_t get_rsa_key_size(
const rdpPrivateKey* privateKey)
509 WINPR_ASSERT(privateKey);
511 return freerdp_key_get_bits(privateKey) / 8;
514 static BYTE vgids_get_algid(vgidsContext* p_Ctx)
518 switch (get_rsa_key_size(p_Ctx->privateKey))
521 return VGIDS_ALGID_RSA_1024;
523 return VGIDS_ALGID_RSA_2048;
525 return VGIDS_ALGID_RSA_3072;
527 return VGIDS_ALGID_RSA_4096;
529 WLog_ERR(TAG,
"Failed to determine algid for private key");
536 static BOOL vgids_prepare_keymap(vgidsContext* context, BYTE** outData, DWORD* outDataSize)
543 vgidsKeymapRecord record = {
546 VGIDS_KEY_TYPE_KEYEXCHANGE,
547 (0xB000 | VGIDS_DEFAULT_KEY_REF),
553 BYTE algid = vgids_get_algid(context);
557 data = malloc(
sizeof(record) + 1);
560 WLog_ERR(TAG,
"Failed to allocate filesystem table data blob");
565 record.algid = algid;
566 memcpy(data + 1, &record,
sizeof(record));
569 *outDataSize =
sizeof(record) + 1;
574 static BOOL vgids_parse_apdu_header(
wStream* s, BYTE* cla, BYTE* ins, BYTE* p1, BYTE* p2, BYTE* lc,
577 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
582 Stream_Read_UINT8(s, *cla);
586 Stream_Read_UINT8(s, *ins);
590 Stream_Read_UINT8(s, *p1);
594 Stream_Read_UINT8(s, *p2);
601 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
604 Stream_Read_UINT8(s, *lc);
605 if (!Stream_CheckAndLogRequiredLength(TAG, s, *lc))
612 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
614 Stream_Read_UINT8(s, *le);
620 static BOOL vgids_create_response(UINT16 status,
const BYTE* answer, DWORD answerSize,
621 BYTE** outData, DWORD* outDataSize)
623 BYTE* out = malloc(answerSize + 2);
626 WLog_ERR(TAG,
"Failed to allocate memory for response data");
633 memcpy(out, answer, answerSize);
637 *out = (BYTE)((status >> 8) & 0xFF);
638 *(out + 1) = (BYTE)(status & 0xFF);
639 *outDataSize = answerSize + 2;
643 static BOOL vgids_read_do_fkt(
void* data,
size_t index, va_list ap)
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);
653 if (efID == 0x3FFF || efID == file->id)
656 if (vgids_ef_read_do(file, doID, &response, &responseSize))
658 context->responseData = Stream_New(response, (
size_t)responseSize);
666 static void vgids_read_do(vgidsContext* context, UINT16 efID, UINT16 doID)
668 ArrayList_ForEach(context->files, vgids_read_do_fkt, context, efID, doID);
671 static void vgids_reset_context_response(vgidsContext* context)
673 Stream_Free(context->responseData, TRUE);
674 context->responseData = NULL;
677 static void vgids_reset_context_command_data(vgidsContext* context)
679 Stream_Free(context->commandData, TRUE);
680 context->commandData = NULL;
683 static BOOL vgids_ins_select(vgidsContext* context,
wStream* s, BYTE** response,
689 DWORD resultDataSize = 0;
690 const BYTE* resultData = NULL;
691 UINT16 status = ISO_STATUS_SUCCESS;
695 if (!vgids_parse_apdu_header(s, NULL, NULL, &p1, &p2, &lc, NULL))
705 BYTE aid[ISO_AID_MAX_SIZE] = { 0 };
706 if (lc > ISO_AID_MAX_SIZE)
708 WLog_ERR(TAG,
"The LC byte is greater than the maximum AID length");
709 status = ISO_STATUS_INVALIDLC;
714 Stream_Read(s, aid, lc);
715 if (memcmp(aid, g_MsGidsAID, lc) != 0)
717 status = ISO_STATUS_FILENOTFOUND;
727 resultData = g_GidsAppFCI;
728 resultDataSize =
sizeof(g_GidsAppFCI);
734 resultData = g_GidsAppFCP;
735 resultDataSize =
sizeof(g_GidsAppFCP);
739 status = ISO_STATUS_INVALIDP1P2;
744 context->currentDF = ISO_FID_MF;
754 WLog_ERR(TAG,
"The LC byte for the file ID is greater than 2");
755 status = ISO_STATUS_INVALIDLC;
759 Stream_Read_UINT16_BE(s, fid);
760 if (fid != VGIDS_EFID_CURRENTDF || context->currentDF == 0)
762 status = ISO_STATUS_FILENOTFOUND;
770 status = ISO_STATUS_INVALIDP1P2;
775 return vgids_create_response(status, resultData, resultDataSize, response, responseSize);
778 static UINT16 vgids_handle_chained_response(vgidsContext* context,
const BYTE** response,
782 UINT16 status = ISO_STATUS_SUCCESS;
783 DWORD remainingBytes = (DWORD)Stream_Length(context->responseData);
784 if (remainingBytes > 256)
786 status = ISO_STATUS_MORE_DATA;
787 remainingBytes = 256;
790 *response = Stream_Buffer(context->responseData);
791 *responseSize = remainingBytes;
792 Stream_Seek(context->responseData, remainingBytes);
796 remainingBytes = (DWORD)(Stream_Length(context->responseData) - remainingBytes);
797 if (remainingBytes < 256 && remainingBytes != 0)
798 status |= (remainingBytes & 0xFF);
802 static BOOL vgids_get_public_key(vgidsContext* context, UINT16 doTag)
808 WINPR_ASSERT(context);
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);
820 pubKey = Stream_New(NULL, nSize + eSize + 0x10);
823 WLog_ERR(TAG,
"Failed to allocate public key stream");
827 response = Stream_New(NULL, Stream_Capacity(pubKey) + 0x10);
830 WLog_ERR(TAG,
"Failed to allocate response stream");
835 if (!vgids_write_tlv(pubKey, 0x81, n, nSize))
838 if (!vgids_write_tlv(pubKey, 0x82, e, eSize))
842 if (!vgids_write_tlv(response, doTag, Stream_Buffer(pubKey), (DWORD)Stream_Length(pubKey)))
846 Stream_SetPosition(response, 0);
847 context->responseData = response;
854 Stream_Free(pubKey, TRUE);
855 Stream_Free(response, TRUE);
859 static BOOL vgids_ins_getdata(vgidsContext* context,
wStream* s, BYTE** response,
867 DWORD resultDataSize = 0;
868 const BYTE* resultData = NULL;
869 UINT16 status = ISO_STATUS_SUCCESS;
875 if (!vgids_parse_apdu_header(s, NULL, NULL, &p1, &p2, &lc, NULL))
879 vgids_reset_context_response(context);
882 fileId = (UINT16)(((UINT16)p1 << 8) | p2);
891 Stream_Read_UINT8(s, tag);
892 Stream_Read_UINT8(s, length);
893 if (tag != 0x5C && length != 0x02)
895 status = ISO_STATUS_INVALIDCOMMANDDATA;
899 Stream_Read_UINT16_BE(s, doId);
900 vgids_read_do(context, fileId, doId);
911 if (p1 != 0x3F && p2 != 0xFF)
913 status = ISO_STATUS_INVALIDP1P2;
918 Stream_Read_UINT8(s, tag);
919 Stream_Read_UINT8(s, length);
920 if (tag != 0x70 || length != 0x08)
922 status = ISO_STATUS_INVALIDCOMMANDDATA;
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)
932 status = ISO_STATUS_INVALIDCOMMANDDATA;
937 Stream_Read_UINT8(s, tag);
938 Stream_Read_UINT8(s, length);
939 if (tag != 0xA5 || length != 0x03)
941 status = ISO_STATUS_INVALIDCOMMANDDATA;
945 Stream_Read_UINT16_BE(s, pubKeyDO);
946 Stream_Read_UINT8(s, length);
947 if (pubKeyDO != 0x7F49 || length != 0x80)
949 status = ISO_STATUS_INVALIDCOMMANDDATA;
953 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
955 status = ISO_STATUS_INVALIDLC;
960 vgids_get_public_key(context, pubKeyDO);
964 status = ISO_STATUS_INVALIDCOMMANDDATA;
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;
974 return vgids_create_response(status, resultData, resultDataSize, response, responseSize);
977 static BOOL vgids_ins_manage_security_environment(vgidsContext* context,
wStream* s,
978 BYTE** response, DWORD* responseSize)
985 DWORD resultDataSize = 0;
986 const BYTE* resultData = NULL;
987 UINT16 status = ISO_STATUS_SUCCESS;
989 vgids_reset_context_command_data(context);
990 vgids_reset_context_response(context);
993 if (!vgids_parse_apdu_header(s, NULL, NULL, &p1, &p2, &lc, NULL))
999 if (p1 != 0x41 && p2 != 0xB6 && p2 != 0xB8)
1001 status = ISO_STATUS_INVALIDP1P2;
1002 goto create_response;
1007 status = ISO_STATUS_WRONGLC;
1008 goto create_response;
1011 context->currentSE.crt = p2;
1015 Stream_Read_UINT8(s, tag);
1016 Stream_Read_UINT8(s, length);
1017 if (tag != 0x80 || length != 0x01)
1019 status = ISO_STATUS_INVALIDCOMMANDDATA;
1020 goto create_response;
1022 Stream_Read_UINT8(s, context->currentSE.algoId);
1025 Stream_Read_UINT8(s, tag);
1026 Stream_Read_UINT8(s, length);
1027 if (tag != 0x84 || length != 0x01)
1029 status = ISO_STATUS_INVALIDCOMMANDDATA;
1030 goto create_response;
1032 Stream_Read_UINT8(s, context->currentSE.keyRef);
1036 if (status != ISO_STATUS_SUCCESS)
1037 memset(&context->currentSE, 0,
sizeof(context->currentSE));
1038 return vgids_create_response(status, resultData, resultDataSize, response, responseSize);
1041 static BOOL vgids_perform_digital_signature(vgidsContext* context)
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() }
1061 WLog_ERR(TAG,
"Failed to create PKEY");
1065 vgids_reset_context_response(context);
1068 Stream_SetPosition(context->commandData, 0);
1069 for (
int i = 0; i < VGIDS_MAX_DIGEST_INFO; ++i)
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)
1077 Stream_Seek(context->commandData, digest->infoSize);
1078 if (!Stream_CheckAndLogRequiredLength(TAG, context->commandData, 2))
1080 msgSize = Stream_GetRemainingLength(context->commandData);
1083 ctx = EVP_PKEY_CTX_new(pk, NULL);
1086 WLog_ERR(TAG,
"Failed to create signing context");
1090 if (EVP_PKEY_sign_init(ctx) <= 0)
1092 WLog_ERR(TAG,
"Failed to init signing context");
1097 if (context->currentSE.algoId & VGIDS_SE_ALGOID_DST_PAD_PKCS1)
1099 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)
1101 WLog_ERR(TAG,
"Failed to set padding mode");
1106 if (EVP_PKEY_CTX_set_signature_md(ctx, digest->digest) <= 0)
1108 WLog_ERR(TAG,
"Failed to set signing mode");
1113 if (EVP_PKEY_sign(ctx, NULL, &sigSize, Stream_Pointer(context->commandData), msgSize) <=
1116 WLog_ERR(TAG,
"Failed to determine signature size");
1120 context->responseData = Stream_New(NULL, sigSize);
1121 if (!context->responseData)
1123 WLog_ERR(TAG,
"Failed to allocate signing buffer");
1128 if (EVP_PKEY_sign(ctx, Stream_Buffer(context->responseData), &sigSize,
1129 Stream_Pointer(context->commandData), msgSize) <= 0)
1131 WLog_ERR(TAG,
"Failed to create signature");
1135 Stream_SetLength(context->responseData, sigSize);
1136 EVP_PKEY_CTX_free(ctx);
1142 vgids_reset_context_command_data(context);
1146 vgids_reset_context_command_data(context);
1147 vgids_reset_context_response(context);
1148 EVP_PKEY_CTX_free(ctx);
1153 static BOOL vgids_perform_decrypt(vgidsContext* context)
1155 EVP_PKEY_CTX* ctx = NULL;
1158 int padding = RSA_NO_PADDING;
1160 vgids_reset_context_response(context);
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;
1169 EVP_PKEY* pkey = freerdp_key_get_evp_pkey(context->privateKey);
1171 goto decrypt_failed;
1172 ctx = EVP_PKEY_CTX_new(pkey, NULL);
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;
1181 const size_t inlen = Stream_Length(context->commandData);
1183 res = EVP_PKEY_decrypt(ctx, NULL, &outlen, Stream_Buffer(context->commandData), inlen);
1186 WLog_ERR(TAG,
"Failed to decrypt data");
1187 goto decrypt_failed;
1191 context->responseData = Stream_New(NULL, outlen);
1192 if (!context->responseData)
1194 WLog_ERR(TAG,
"Failed to create decryption buffer");
1195 goto decrypt_failed;
1199 res = EVP_PKEY_decrypt(ctx, Stream_Buffer(context->responseData), &outlen,
1200 Stream_Buffer(context->commandData), inlen);
1204 WLog_ERR(TAG,
"Failed to decrypt data");
1205 goto decrypt_failed;
1208 Stream_SetLength(context->responseData, outlen);
1212 EVP_PKEY_CTX_free(ctx);
1213 EVP_PKEY_free(pkey);
1214 vgids_reset_context_command_data(context);
1216 vgids_reset_context_response(context);
1220 static BOOL vgids_ins_perform_security_operation(vgidsContext* context,
wStream* s, BYTE** response,
1221 DWORD* responseSize)
1227 DWORD resultDataSize = 0;
1228 const BYTE* resultData = NULL;
1229 UINT16 status = ISO_STATUS_SUCCESS;
1232 if (!vgids_parse_apdu_header(s, &cla, NULL, &p1, &p2, &lc, NULL))
1237 status = ISO_STATUS_WRONGLC;
1238 goto create_response;
1242 if (context->currentSE.keyRef != VGIDS_DEFAULT_KEY_REF)
1244 status = ISO_STATUS_SECURITYSTATUSNOTSATISFIED;
1245 goto create_response;
1249 if (!context->pinVerified)
1251 status = ISO_STATUS_SECURITYSTATUSNOTSATISFIED;
1252 goto create_response;
1256 if (!context->commandData)
1258 context->commandData = Stream_New(NULL, lc);
1259 if (!context->commandData)
1262 else if (!Stream_EnsureRemainingCapacity(context->commandData, lc))
1265 Stream_Write(context->commandData, Stream_Pointer(s), lc);
1266 Stream_SealLength(context->commandData);
1269 switch (context->currentSE.crt)
1271 case VGIDS_SE_CRT_SIGN:
1273 if (p1 != 0x9E || p2 != 0x9A)
1275 status = ISO_STATUS_INVALIDP1P2;
1281 vgids_perform_digital_signature(context);
1284 case VGIDS_SE_CRT_CONF:
1286 if ((p1 != 0x86 || p2 != 0x80) && (p1 != 0x80 || p2 != 0x86))
1288 status = ISO_STATUS_INVALIDP1P2;
1294 vgids_perform_decrypt(context);
1298 status = ISO_STATUS_INVALIDP1P2;
1303 if (status == ISO_STATUS_SUCCESS && context->responseData)
1304 status = vgids_handle_chained_response(context, &resultData, &resultDataSize);
1308 return vgids_create_response(status, resultData, resultDataSize, response, responseSize);
1311 static BOOL vgids_ins_getresponse(vgidsContext* context,
wStream* s, BYTE** response,
1312 DWORD* responseSize)
1317 DWORD resultDataSize = 0;
1318 const BYTE* resultData = NULL;
1319 DWORD expectedLen = 0;
1320 DWORD remainingSize = 0;
1321 UINT16 status = ISO_STATUS_SUCCESS;
1325 if (!context->responseData || !Stream_CheckAndLogRequiredLength(TAG, context->responseData, 1))
1327 status = ISO_STATUS_COMMANDNOTALLOWED;
1328 goto create_response;
1331 if (!vgids_parse_apdu_header(s, NULL, NULL, &p1, &p2, NULL, &le))
1335 if (p1 != 00 || p2 != 0x00)
1337 status = ISO_STATUS_INVALIDP1P2;
1338 goto create_response;
1343 if (expectedLen == 0)
1347 remainingSize = (DWORD)Stream_GetRemainingLength(context->responseData);
1348 if (remainingSize < expectedLen)
1349 expectedLen = remainingSize;
1351 resultData = Stream_Pointer(context->responseData);
1352 resultDataSize = expectedLen;
1353 Stream_Seek(context->responseData, expectedLen);
1356 remainingSize = (DWORD)Stream_GetRemainingLength(context->responseData);
1357 if (remainingSize > 0)
1359 status = ISO_STATUS_MORE_DATA;
1360 if (remainingSize < 256)
1361 status |= (remainingSize & 0xFF);
1365 return vgids_create_response(status, resultData, resultDataSize, response, responseSize);
1368 static BOOL vgids_ins_verify(vgidsContext* context,
wStream* s, BYTE** response,
1369 DWORD* responseSize)
1375 UINT16 status = ISO_STATUS_SUCCESS;
1376 char pin[VGIDS_MAX_PIN_SIZE + 1] = { 0 };
1379 if (!vgids_parse_apdu_header(s, NULL, &ins, &p1, &p2, NULL, NULL))
1383 if (p1 != 00 && p2 != 0x80 && p2 != 0x82)
1385 status = ISO_STATUS_INVALIDP1P2;
1386 goto create_response;
1392 context->pinVerified = FALSE;
1393 goto create_response;
1397 if (context->curRetryCounter == 0)
1399 status = ISO_STATUS_AUTHMETHODBLOCKED;
1400 goto create_response;
1404 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
1406 status = ISO_STATUS_INVALIDLC;
1407 goto create_response;
1410 Stream_Read_UINT8(s, lc);
1411 if (!Stream_CheckAndLogRequiredLength(TAG, s, lc) || (lc > VGIDS_MAX_PIN_SIZE))
1413 status = ISO_STATUS_INVALIDLC;
1414 goto create_response;
1418 Stream_Read(s, pin, lc);
1419 if (strcmp(context->pin, pin) != 0)
1422 --context->curRetryCounter;
1423 context->pinVerified = FALSE;
1424 status = (ISO_STATUS_VERIFYFAILED | (context->curRetryCounter & 0xFF));
1429 context->curRetryCounter = context->retryCounter;
1430 context->pinVerified = TRUE;
1434 return vgids_create_response(status, NULL, 0, response, responseSize);
1437 vgidsContext* vgids_new(
void)
1440 vgidsContext* ctx = calloc(1,
sizeof(vgidsContext));
1442 ctx->files = ArrayList_New(FALSE);
1445 WLog_ERR(TAG,
"Failed to create files array list");
1449 obj = ArrayList_Object(ctx->files);
1450 obj->fnObjectFree = vgids_ef_free;
1459 BOOL vgids_init(vgidsContext* ctx,
const char* cert,
const char* privateKey,
const char* pin)
1462 DWORD keymapSize = 0;
1463 DWORD fsTableSize = 0;
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',
' ',
1474 CONTAINER_MAP_VALID_CONTAINER |
1475 CONTAINER_MAP_DEFAULT_CONTAINER,
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 },
1489 if (!cert || !privateKey || !pin)
1491 WLog_DBG(TAG,
"Passed invalid NULL argument: cert=%p, privateKey=%p, pin=%p", cert,
1497 ctx->certificate = freerdp_certificate_new_from_pem(cert);
1498 if (!ctx->certificate)
1501 ctx->privateKey = freerdp_key_new_from_pem(privateKey);
1502 if (!ctx->privateKey)
1507 masterEF = vgids_ef_new(ctx, VGIDS_EFID_MASTER);
1513 cardidEF = vgids_ef_new(ctx, VGIDS_EFID_CARDID);
1516 winpr_RAND(cardid,
sizeof(cardid));
1517 if (!vgids_ef_write_do(cardidEF, VGIDS_DO_CARDID, cardid,
sizeof(cardid)))
1522 commonEF = vgids_ef_new(ctx, VGIDS_EFID_COMMON);
1527 if (!vgids_ef_write_do(commonEF, VGIDS_DO_CARDCF, g_CardCFContents,
sizeof(g_CardCFContents)))
1531 const size_t size = get_rsa_key_size(ctx->privateKey);
1532 if ((size == 0) || (size > UINT16_MAX / 8))
1535 cmrec.wKeyExchangeKeySizeBits = (WORD)size * 8;
1536 if (!vgids_ef_write_do(commonEF, VGIDS_DO_CMAPFILE, &cmrec,
sizeof(cmrec)))
1540 if (!vgids_ef_write_do(commonEF, VGIDS_DO_CARDAPPS, g_CardAppsContents,
1541 sizeof(g_CardAppsContents)))
1545 if (!vgids_prepare_certificate(ctx->certificate, &kxc, &kxcSize))
1547 if (!vgids_ef_write_do(commonEF, VGIDS_DO_KXC00, kxc, kxcSize))
1551 if (!vgids_prepare_fstable(filesys, ARRAYSIZE(filesys), &fsTable, &fsTableSize))
1553 if (!vgids_ef_write_do(masterEF, VGIDS_DO_FILESYSTEMTABLE, fsTable, fsTableSize))
1557 if (!vgids_prepare_keymap(ctx, &keymap, &keymapSize))
1559 if (!vgids_ef_write_do(masterEF, VGIDS_DO_KEYMAP, keymap, keymapSize))
1563 ctx->curRetryCounter = ctx->retryCounter = VGIDS_DEFAULT_RETRY_COUNTER;
1564 ctx->pin = _strdup(pin);
1580 BOOL vgids_process_apdu(vgidsContext* context,
const BYTE* data, DWORD dataSize, BYTE** response,
1581 DWORD* responseSize)
1587 if (!context || !data || !response || !responseSize)
1589 WLog_ERR(TAG,
"Invalid NULL pointer passed");
1595 WLog_ERR(TAG,
"APDU buffer is less than 4 bytes: %" PRIu32, dataSize);
1600 Stream_StaticConstInit(&s, data, dataSize);
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);
1612 return vgids_ins_manage_security_environment(context, &s, response, responseSize);
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);
1622 return vgids_create_response(ISO_STATUS_COMMANDNOTALLOWED, NULL, 0, response, responseSize);
1625 void vgids_free(vgidsContext* context)
1629 freerdp_key_free(context->privateKey);
1630 freerdp_certificate_free(context->certificate);
1631 Stream_Free(context->commandData, TRUE);
1632 Stream_Free(context->responseData, TRUE);
1634 ArrayList_Free(context->files);
This struct contains function pointer to initialize/free objects.