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
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
122typedef struct vgids_ef vgidsEF;
130typedef struct vgids_se vgidsSE;
136 UINT16 curRetryCounter;
143 rdpCertificate* certificate;
144 rdpPrivateKey* privateKey;
150#define VGIDS_MAX_DIGEST_INFO 7
152static const BYTE g_PKCS1_SHA1[] = { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,
153 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 };
154static 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 };
156static 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 };
158static 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 };
160static 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 };
162static 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 };
165static 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 };
170struct vgids_digest_info_map
174 const EVP_MD* digest;
176typedef struct vgids_digest_info_map vgidsDigestInfoMap;
183static const BYTE g_MsGidsAID[] = {
184 0xA0, 0x00, 0x00, 0x03, 0x97, 0x42, 0x54, 0x46, 0x59, 0x02, 0x01
191static const BYTE g_GidsAppFCP[] = { 0x62, 0x08, 0x82, 0x01, 0x38, 0x8C, 0x03, 0x03, 0x30, 0x30 };
197static 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 };
208static const BYTE g_CardCFContents[] = { 0x00, 0x00, 0x01, 0x00, 0x04, 0x00 };
211static const BYTE g_CardAppsContents[] = { 0x6d, 0x73, 0x63, 0x70, 0x00, 0x00, 0x00, 0x00 };
221#define MAX_CONTAINER_NAME_LEN 39
227#define CONTAINER_MAP_VALID_CONTAINER 1
232#define CONTAINER_MAP_DEFAULT_CONTAINER 2
234struct vgids_container_map_entry
236 WCHAR wszGuid[MAX_CONTAINER_NAME_LEN + 1];
239 WORD wSigKeySizeBits;
240 WORD wKeyExchangeKeySizeBits;
242typedef struct vgids_container_map_entry vgidsContainerMapEntry;
244struct vgids_filesys_table_entry
249 UINT16 dataObjectIdentifier;
251 UINT16 fileIdentifier;
254typedef struct vgids_filesys_table_entry vgidsFilesysTableEntry;
256struct vgids_keymap_record
262 UINT16 unknownWithFFFF;
263 UINT16 unknownWith0000;
265typedef struct vgids_keymap_record vgidsKeymapRecord;
269static void vgids_ef_free(
void* ptr);
271static vgidsEF* vgids_ef_new(vgidsContext* ctx, USHORT
id)
273 vgidsEF* ef = calloc(1,
sizeof(vgidsEF));
276 ef->data = Stream_New(
nullptr, 1024);
279 WLog_ERR(TAG,
"Failed to create file data stream");
282 if (!Stream_SetLength(ef->data, 0))
285 if (!ArrayList_Append(ctx->files, ef))
287 WLog_ERR(TAG,
"Failed to add new ef to file list");
298static BOOL vgids_write_tlv(
wStream* s, UINT16 tag,
const void* data,
size_t dataSize)
300 WINPR_ASSERT(dataSize <= UINT16_MAX);
303 if (!Stream_EnsureRemainingCapacity(s, dataSize + 5))
305 WLog_ERR(TAG,
"Failed to ensure capacity of DO stream");
312 Stream_Write_UINT16_BE(s, tag);
314 Stream_Write_UINT8(s, (BYTE)tag);
317 Stream_Write_UINT8(s, (BYTE)dataSize);
319 else if (dataSize < 256)
321 Stream_Write_UINT8(s, 0x81);
322 Stream_Write_UINT8(s, (BYTE)dataSize);
326 Stream_Write_UINT8(s, 0x82);
327 Stream_Write_UINT16_BE(s, (UINT16)dataSize);
329 Stream_Write(s, data, dataSize);
330 Stream_SealLength(s);
334static BOOL vgids_ef_write_do(vgidsEF* ef, UINT16 doID,
const void* data, DWORD dataSize)
337 return vgids_write_tlv(ef->data, doID, data, dataSize);
340static BOOL vgids_ef_read_do(vgidsEF* ef, UINT16 doID, BYTE** data, DWORD* dataSize)
343 Stream_ResetPosition(ef->data);
346 while (Stream_GetRemainingLength(ef->data) > 3)
353 curPos = Stream_GetPosition(ef->data);
354 Stream_Read_UINT16_BE(ef->data, nextDOID);
355 Stream_Read_UINT8(ef->data, len);
358 BYTE lenSize = len & 0x7F;
359 if (!Stream_CheckAndLogRequiredLength(TAG, ef->data, lenSize))
365 Stream_Read_UINT8(ef->data, doSize);
368 Stream_Read_UINT16_BE(ef->data, doSize);
371 WLog_ERR(TAG,
"Unexpected tag length %" PRIu8, lenSize);
378 if (!Stream_CheckAndLogRequiredLength(TAG, ef->data, doSize))
381 if (nextDOID == doID)
383 BYTE* outData =
nullptr;
386 doSize += (UINT16)(Stream_GetPosition(ef->data) - curPos);
387 if (!Stream_SetPosition(ef->data, curPos))
390 outData = malloc(doSize);
393 WLog_ERR(TAG,
"Failed to allocate output buffer");
397 Stream_Read(ef->data, outData, doSize);
405 if (!Stream_SafeSeek(ef->data, doSize))
413void vgids_ef_free(
void* ptr)
418 Stream_Free(ef->data, TRUE);
423static BOOL vgids_prepare_fstable(
const vgidsFilesysTableEntry* fstable, DWORD numEntries,
424 BYTE** outData, DWORD* outDataSize)
430 BYTE* data = malloc(
sizeof(vgidsFilesysTableEntry) * numEntries + 1);
433 WLog_ERR(TAG,
"Failed to allocate filesystem table data blob");
438 for (UINT32 i = 0; i < numEntries; ++i)
439 memcpy(data + 1 + (
sizeof(vgidsFilesysTableEntry) * i), &fstable[i],
440 sizeof(vgidsFilesysTableEntry));
443 *outDataSize =
sizeof(vgidsFilesysTableEntry) * numEntries + 1;
448static BOOL vgids_prepare_certificate(
const rdpCertificate* cert, BYTE** kxc, DWORD* kxcSize)
457 BYTE* comprData =
nullptr;
462 BYTE* certData = freerdp_certificate_get_der(cert, &certSize);
463 if (!certData || (certSize == 0) || (certSize > UINT16_MAX))
465 WLog_ERR(TAG,
"Failed to get certificate size");
469 comprData = malloc(certSize);
472 WLog_ERR(TAG,
"Failed to allocate certificate buffer");
477 destSize = WINPR_ASSERTING_INT_CAST(uint16_t, certSize);
478 if (compress(comprData, &destSize, certData, WINPR_ASSERTING_INT_CAST(uint16_t, certSize)) !=
481 WLog_ERR(TAG,
"Failed to compress certificate data");
486 s = Stream_New(
nullptr, destSize + 4);
487 Stream_Write_UINT16(s, 0x0001);
488 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, 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);
507static size_t get_rsa_key_size(
const rdpPrivateKey* privateKey)
509 WINPR_ASSERT(privateKey);
511 return freerdp_key_get_bits(privateKey) / 8;
514static 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");
536static BOOL vgids_prepare_keymap(vgidsContext* context, BYTE** outData, DWORD* outDataSize)
542 BYTE* data =
nullptr;
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;
574static 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);
620static 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;
643static BOOL vgids_read_do_fkt(
void* data,
size_t index, va_list ap)
645 BYTE* response =
nullptr;
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);
666static BOOL vgids_read_do(vgidsContext* context, UINT16 efID, UINT16 doID)
668 return ArrayList_ForEach(context->files, vgids_read_do_fkt, context, efID, doID);
671static void vgids_reset_context_response(vgidsContext* context)
673 Stream_Free(context->responseData, TRUE);
674 context->responseData =
nullptr;
677static void vgids_reset_context_command_data(vgidsContext* context)
679 Stream_Free(context->commandData, TRUE);
680 context->commandData =
nullptr;
683static BOOL vgids_ins_select(vgidsContext* context,
wStream* s, BYTE** response,
689 DWORD resultDataSize = 0;
690 const BYTE* resultData =
nullptr;
691 UINT16 status = ISO_STATUS_SUCCESS;
695 if (!vgids_parse_apdu_header(s,
nullptr,
nullptr, &p1, &p2, &lc,
nullptr))
705 BYTE aid[ISO_AID_MAX_SIZE] = WINPR_C_ARRAY_INIT;
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);
778static 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);
802static 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(
nullptr, nSize + eSize + 0x10);
823 WLog_ERR(TAG,
"Failed to allocate public key stream");
827 response = Stream_New(
nullptr, 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_ResetPosition(response);
847 context->responseData = response;
854 Stream_Free(pubKey, TRUE);
855 Stream_Free(response, TRUE);
859static BOOL vgids_ins_getdata(vgidsContext* context,
wStream* s, BYTE** response,
867 DWORD resultDataSize = 0;
868 const BYTE* resultData =
nullptr;
869 UINT16 status = ISO_STATUS_SUCCESS;
875 if (!vgids_parse_apdu_header(s,
nullptr,
nullptr, &p1, &p2, &lc,
nullptr))
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);
903 (void)vgids_read_do(context, fileId, doId);
914 if (p1 != 0x3F && p2 != 0xFF)
916 status = ISO_STATUS_INVALIDP1P2;
921 Stream_Read_UINT8(s, tag);
922 Stream_Read_UINT8(s, length);
923 if (tag != 0x70 || length != 0x08)
925 status = ISO_STATUS_INVALIDCOMMANDDATA;
930 Stream_Read_UINT8(s, tag);
931 Stream_Read_UINT8(s, length);
932 Stream_Read_UINT8(s, keyRef);
933 if (tag != 0x84 || length != 0x01 || keyRef != VGIDS_DEFAULT_KEY_REF)
935 status = ISO_STATUS_INVALIDCOMMANDDATA;
940 Stream_Read_UINT8(s, tag);
941 Stream_Read_UINT8(s, length);
942 if (tag != 0xA5 || length != 0x03)
944 status = ISO_STATUS_INVALIDCOMMANDDATA;
948 Stream_Read_UINT16_BE(s, pubKeyDO);
949 Stream_Read_UINT8(s, length);
950 if (pubKeyDO != 0x7F49 || length != 0x80)
952 status = ISO_STATUS_INVALIDCOMMANDDATA;
956 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
958 status = ISO_STATUS_INVALIDLC;
963 vgids_get_public_key(context, pubKeyDO);
967 status = ISO_STATUS_INVALIDCOMMANDDATA;
972 if (context->responseData)
973 status = vgids_handle_chained_response(context, &resultData, &resultDataSize);
974 else if (status == ISO_STATUS_SUCCESS)
975 status = ISO_STATUS_REFERENCEDATANOTFOUND;
977 return vgids_create_response(status, resultData, resultDataSize, response, responseSize);
980static BOOL vgids_ins_manage_security_environment(vgidsContext* context,
wStream* s,
981 BYTE** response, DWORD* responseSize)
988 DWORD resultDataSize = 0;
989 const BYTE* resultData =
nullptr;
990 UINT16 status = ISO_STATUS_SUCCESS;
992 vgids_reset_context_command_data(context);
993 vgids_reset_context_response(context);
996 if (!vgids_parse_apdu_header(s,
nullptr,
nullptr, &p1, &p2, &lc,
nullptr))
1002 if (p1 != 0x41 && p2 != 0xB6 && p2 != 0xB8)
1004 status = ISO_STATUS_INVALIDP1P2;
1005 goto create_response;
1010 status = ISO_STATUS_WRONGLC;
1011 goto create_response;
1014 context->currentSE.crt = p2;
1018 Stream_Read_UINT8(s, tag);
1019 Stream_Read_UINT8(s, length);
1020 if (tag != 0x80 || length != 0x01)
1022 status = ISO_STATUS_INVALIDCOMMANDDATA;
1023 goto create_response;
1025 Stream_Read_UINT8(s, context->currentSE.algoId);
1028 Stream_Read_UINT8(s, tag);
1029 Stream_Read_UINT8(s, length);
1030 if (tag != 0x84 || length != 0x01)
1032 status = ISO_STATUS_INVALIDCOMMANDDATA;
1033 goto create_response;
1035 Stream_Read_UINT8(s, context->currentSE.keyRef);
1039 if (status != ISO_STATUS_SUCCESS)
1040 memset(&context->currentSE, 0,
sizeof(context->currentSE));
1041 return vgids_create_response(status, resultData, resultDataSize, response, responseSize);
1044static BOOL vgids_perform_digital_signature(vgidsContext* context)
1048 EVP_PKEY_CTX* ctx =
nullptr;
1049 EVP_PKEY* pk = freerdp_key_get_evp_pkey(context->privateKey);
1050 const vgidsDigestInfoMap gidsDigestInfo[VGIDS_MAX_DIGEST_INFO] = {
1051 { g_PKCS1_SHA1,
sizeof(g_PKCS1_SHA1), EVP_sha1() },
1052 { g_PKCS1_SHA224,
sizeof(g_PKCS1_SHA224), EVP_sha224() },
1053 { g_PKCS1_SHA256,
sizeof(g_PKCS1_SHA256), EVP_sha256() },
1054 { g_PKCS1_SHA384,
sizeof(g_PKCS1_SHA384), EVP_sha384() },
1055 { g_PKCS1_SHA512,
sizeof(g_PKCS1_SHA512), EVP_sha512() },
1056#if OPENSSL_VERSION_NUMBER >= 0x10101000L
1057 { g_PKCS1_SHA512_224,
sizeof(g_PKCS1_SHA512_224), EVP_sha512_224() },
1058 { g_PKCS1_SHA512_256,
sizeof(g_PKCS1_SHA512_256), EVP_sha512_256() }
1064 WLog_ERR(TAG,
"Failed to create PKEY");
1068 vgids_reset_context_response(context);
1071 Stream_ResetPosition(context->commandData);
1072 for (
int i = 0; i < VGIDS_MAX_DIGEST_INFO; ++i)
1075 const vgidsDigestInfoMap* digest = &gidsDigestInfo[i];
1076 if (Stream_Length(context->commandData) >= digest->infoSize &&
1077 memcmp(Stream_Buffer(context->commandData), digest->info, digest->infoSize) == 0)
1080 Stream_Seek(context->commandData, digest->infoSize);
1081 if (!Stream_CheckAndLogRequiredLength(TAG, context->commandData, 2))
1083 msgSize = Stream_GetRemainingLength(context->commandData);
1086 ctx = EVP_PKEY_CTX_new(pk,
nullptr);
1089 WLog_ERR(TAG,
"Failed to create signing context");
1093 if (EVP_PKEY_sign_init(ctx) <= 0)
1095 WLog_ERR(TAG,
"Failed to init signing context");
1100 if (context->currentSE.algoId & VGIDS_SE_ALGOID_DST_PAD_PKCS1)
1102 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)
1104 WLog_ERR(TAG,
"Failed to set padding mode");
1109 if (EVP_PKEY_CTX_set_signature_md(ctx, digest->digest) <= 0)
1111 WLog_ERR(TAG,
"Failed to set signing mode");
1116 if (EVP_PKEY_sign(ctx,
nullptr, &sigSize, Stream_Pointer(context->commandData),
1119 WLog_ERR(TAG,
"Failed to determine signature size");
1123 context->responseData = Stream_New(
nullptr, sigSize);
1124 if (!context->responseData)
1126 WLog_ERR(TAG,
"Failed to allocate signing buffer");
1131 if (EVP_PKEY_sign(ctx, Stream_Buffer(context->responseData), &sigSize,
1132 Stream_Pointer(context->commandData), msgSize) <= 0)
1134 WLog_ERR(TAG,
"Failed to create signature");
1138 if (!Stream_SetLength(context->responseData, sigSize))
1141 EVP_PKEY_CTX_free(ctx);
1147 vgids_reset_context_command_data(context);
1151 vgids_reset_context_command_data(context);
1152 vgids_reset_context_response(context);
1153 EVP_PKEY_CTX_free(ctx);
1158static BOOL vgids_perform_decrypt(vgidsContext* context)
1160 EVP_PKEY_CTX* ctx =
nullptr;
1163 int padding = RSA_NO_PADDING;
1165 vgids_reset_context_response(context);
1168 if (context->currentSE.algoId & VGIDS_SE_ALGOID_CT_PAD_PKCS1)
1169 padding = RSA_PKCS1_PADDING;
1170 else if (context->currentSE.algoId & VGIDS_SE_ALGOID_CT_PAD_OAEP)
1171 padding = RSA_PKCS1_OAEP_PADDING;
1174 EVP_PKEY* pkey = freerdp_key_get_evp_pkey(context->privateKey);
1176 goto decrypt_failed;
1177 ctx = EVP_PKEY_CTX_new(pkey,
nullptr);
1179 goto decrypt_failed;
1180 if (EVP_PKEY_decrypt_init(ctx) <= 0)
1181 goto decrypt_failed;
1182 if (EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0)
1183 goto decrypt_failed;
1187 const size_t inlen = Stream_Length(context->commandData);
1189 res = EVP_PKEY_decrypt(ctx,
nullptr, &outlen, Stream_Buffer(context->commandData), inlen);
1192 WLog_ERR(TAG,
"Failed to decrypt data");
1193 goto decrypt_failed;
1197 context->responseData = Stream_New(
nullptr, outlen);
1199 if (!context->responseData)
1201 WLog_ERR(TAG,
"Failed to create decryption buffer");
1202 goto decrypt_failed;
1206 res = EVP_PKEY_decrypt(ctx, Stream_Buffer(context->responseData), &outlen,
1207 Stream_Buffer(context->commandData), inlen);
1211 WLog_ERR(TAG,
"Failed to decrypt data");
1212 goto decrypt_failed;
1215 rc = Stream_SetLength(context->responseData, outlen);
1219 EVP_PKEY_CTX_free(ctx);
1220 EVP_PKEY_free(pkey);
1221 vgids_reset_context_command_data(context);
1223 vgids_reset_context_response(context);
1227static BOOL vgids_ins_perform_security_operation(vgidsContext* context,
wStream* s, BYTE** response,
1228 DWORD* responseSize)
1234 DWORD resultDataSize = 0;
1235 const BYTE* resultData =
nullptr;
1236 UINT16 status = ISO_STATUS_SUCCESS;
1239 if (!vgids_parse_apdu_header(s, &cla,
nullptr, &p1, &p2, &lc,
nullptr))
1244 status = ISO_STATUS_WRONGLC;
1245 goto create_response;
1249 if (context->currentSE.keyRef != VGIDS_DEFAULT_KEY_REF)
1251 status = ISO_STATUS_SECURITYSTATUSNOTSATISFIED;
1252 goto create_response;
1256 if (!context->pinVerified)
1258 status = ISO_STATUS_SECURITYSTATUSNOTSATISFIED;
1259 goto create_response;
1263 if (!context->commandData)
1265 context->commandData = Stream_New(
nullptr, lc);
1266 if (!context->commandData)
1269 else if (!Stream_EnsureRemainingCapacity(context->commandData, lc))
1272 Stream_Write(context->commandData, Stream_Pointer(s), lc);
1273 Stream_SealLength(context->commandData);
1276 switch (context->currentSE.crt)
1278 case VGIDS_SE_CRT_SIGN:
1280 if (p1 != 0x9E || p2 != 0x9A)
1282 status = ISO_STATUS_INVALIDP1P2;
1288 vgids_perform_digital_signature(context);
1291 case VGIDS_SE_CRT_CONF:
1293 if ((p1 != 0x86 || p2 != 0x80) && (p1 != 0x80 || p2 != 0x86))
1295 status = ISO_STATUS_INVALIDP1P2;
1301 vgids_perform_decrypt(context);
1305 status = ISO_STATUS_INVALIDP1P2;
1310 if (status == ISO_STATUS_SUCCESS && context->responseData)
1311 status = vgids_handle_chained_response(context, &resultData, &resultDataSize);
1315 return vgids_create_response(status, resultData, resultDataSize, response, responseSize);
1318static BOOL vgids_ins_getresponse(vgidsContext* context,
wStream* s, BYTE** response,
1319 DWORD* responseSize)
1324 DWORD resultDataSize = 0;
1325 const BYTE* resultData =
nullptr;
1326 DWORD expectedLen = 0;
1327 DWORD remainingSize = 0;
1328 UINT16 status = ISO_STATUS_SUCCESS;
1332 if (!context->responseData || !Stream_CheckAndLogRequiredLength(TAG, context->responseData, 1))
1334 status = ISO_STATUS_COMMANDNOTALLOWED;
1335 goto create_response;
1338 if (!vgids_parse_apdu_header(s,
nullptr,
nullptr, &p1, &p2,
nullptr, &le))
1342 if (p1 != 00 || p2 != 0x00)
1344 status = ISO_STATUS_INVALIDP1P2;
1345 goto create_response;
1350 if (expectedLen == 0)
1354 remainingSize = (DWORD)Stream_GetRemainingLength(context->responseData);
1355 if (remainingSize < expectedLen)
1356 expectedLen = remainingSize;
1358 resultData = Stream_Pointer(context->responseData);
1359 resultDataSize = expectedLen;
1360 Stream_Seek(context->responseData, expectedLen);
1363 remainingSize = (DWORD)Stream_GetRemainingLength(context->responseData);
1364 if (remainingSize > 0)
1366 status = ISO_STATUS_MORE_DATA;
1367 if (remainingSize < 256)
1368 status |= (remainingSize & 0xFF);
1372 return vgids_create_response(status, resultData, resultDataSize, response, responseSize);
1375static BOOL vgids_ins_verify(vgidsContext* context,
wStream* s, BYTE** response,
1376 DWORD* responseSize)
1382 UINT16 status = ISO_STATUS_SUCCESS;
1383 char pin[VGIDS_MAX_PIN_SIZE + 1] = WINPR_C_ARRAY_INIT;
1386 if (!vgids_parse_apdu_header(s,
nullptr, &ins, &p1, &p2,
nullptr,
nullptr))
1390 if (p1 != 00 && p2 != 0x80 && p2 != 0x82)
1392 status = ISO_STATUS_INVALIDP1P2;
1393 goto create_response;
1399 context->pinVerified = FALSE;
1400 goto create_response;
1404 if (context->curRetryCounter == 0)
1406 status = ISO_STATUS_AUTHMETHODBLOCKED;
1407 goto create_response;
1411 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
1413 status = ISO_STATUS_INVALIDLC;
1414 goto create_response;
1417 Stream_Read_UINT8(s, lc);
1418 if (!Stream_CheckAndLogRequiredLength(TAG, s, lc) || (lc > VGIDS_MAX_PIN_SIZE))
1420 status = ISO_STATUS_INVALIDLC;
1421 goto create_response;
1425 Stream_Read(s, pin, lc);
1426 if (strcmp(context->pin, pin) != 0)
1429 --context->curRetryCounter;
1430 context->pinVerified = FALSE;
1431 status = (ISO_STATUS_VERIFYFAILED | (context->curRetryCounter & 0xFF));
1436 context->curRetryCounter = context->retryCounter;
1437 context->pinVerified = TRUE;
1441 return vgids_create_response(status,
nullptr, 0, response, responseSize);
1444vgidsContext* vgids_new(
void)
1447 vgidsContext* ctx = calloc(1,
sizeof(vgidsContext));
1449 ctx->files = ArrayList_New(FALSE);
1452 WLog_ERR(TAG,
"Failed to create files array list");
1456 obj = ArrayList_Object(ctx->files);
1466BOOL vgids_init(vgidsContext* ctx,
const char* cert,
const char* privateKey,
const char* pin)
1469 DWORD keymapSize = 0;
1470 DWORD fsTableSize = 0;
1472 BYTE* kxc =
nullptr;
1473 BYTE* keymap =
nullptr;
1474 BYTE* fsTable =
nullptr;
1475 vgidsEF* masterEF =
nullptr;
1476 vgidsEF* cardidEF =
nullptr;
1477 vgidsEF* commonEF =
nullptr;
1478 BYTE cardid[VGIDS_CARDID_SIZE] = WINPR_C_ARRAY_INIT;
1479 vgidsContainerMapEntry cmrec = { {
'P',
'r',
'i',
'v',
'a',
't',
'e',
' ',
'K',
'e',
'y',
' ',
1481 CONTAINER_MAP_VALID_CONTAINER |
1482 CONTAINER_MAP_DEFAULT_CONTAINER,
1486 vgidsFilesysTableEntry filesys[] = {
1487 {
"mscp",
"", 0, 0, 0, 0xA000, 0 },
1488 {
"",
"cardid", 0, 0xDF20, 0, 0xA012, 0 },
1489 {
"",
"cardapps", 0, 0xDF21, 0, 0xA010, 0 },
1490 {
"",
"cardcf", 0, 0xDF22, 0, 0xA010, 0 },
1491 {
"mscp",
"cmapfile", 0, 0xDF23, 0, 0xA010, 0 },
1492 {
"mscp",
"kxc00", 0, 0xDF24, 0, 0xA010, 0 },
1496 if (!cert || !privateKey || !pin)
1498 WLog_DBG(TAG,
"Passed invalid nullptr argument: cert=%p, privateKey=%p, pin=%p",
1499 WINPR_CXX_COMPAT_CAST(
const void*, cert),
1500 WINPR_CXX_COMPAT_CAST(
const void*, privateKey),
1501 WINPR_CXX_COMPAT_CAST(
const void*, pin));
1506 ctx->certificate = freerdp_certificate_new_from_pem(cert);
1507 if (!ctx->certificate)
1510 ctx->privateKey = freerdp_key_new_from_pem_enc(privateKey,
nullptr);
1511 if (!ctx->privateKey)
1516 masterEF = vgids_ef_new(ctx, VGIDS_EFID_MASTER);
1522 cardidEF = vgids_ef_new(ctx, VGIDS_EFID_CARDID);
1525 if (winpr_RAND(cardid,
sizeof(cardid)) < 0)
1527 if (!vgids_ef_write_do(cardidEF, VGIDS_DO_CARDID, cardid,
sizeof(cardid)))
1532 commonEF = vgids_ef_new(ctx, VGIDS_EFID_COMMON);
1537 if (!vgids_ef_write_do(commonEF, VGIDS_DO_CARDCF, g_CardCFContents,
sizeof(g_CardCFContents)))
1542 const size_t size = get_rsa_key_size(ctx->privateKey);
1543 if ((size == 0) || (size > UINT16_MAX / 8))
1546 cmrec.wKeyExchangeKeySizeBits = (WORD)size * 8;
1548 if (!vgids_ef_write_do(commonEF, VGIDS_DO_CMAPFILE, &cmrec,
sizeof(cmrec)))
1552 if (!vgids_ef_write_do(commonEF, VGIDS_DO_CARDAPPS, g_CardAppsContents,
1553 sizeof(g_CardAppsContents)))
1557 if (!vgids_prepare_certificate(ctx->certificate, &kxc, &kxcSize))
1559 if (!vgids_ef_write_do(commonEF, VGIDS_DO_KXC00, kxc, kxcSize))
1563 if (!vgids_prepare_fstable(filesys, ARRAYSIZE(filesys), &fsTable, &fsTableSize))
1565 if (!vgids_ef_write_do(masterEF, VGIDS_DO_FILESYSTEMTABLE, fsTable, fsTableSize))
1569 if (!vgids_prepare_keymap(ctx, &keymap, &keymapSize))
1571 if (!vgids_ef_write_do(masterEF, VGIDS_DO_KEYMAP, keymap, keymapSize))
1575 ctx->curRetryCounter = ctx->retryCounter = VGIDS_DEFAULT_RETRY_COUNTER;
1576 ctx->pin = _strdup(pin);
1592BOOL vgids_process_apdu(vgidsContext* context,
const BYTE* data, DWORD dataSize, BYTE** response,
1593 DWORD* responseSize)
1599 if (!context || !data || !response || !responseSize)
1601 WLog_ERR(TAG,
"Invalid nullptr pointer passed");
1607 WLog_ERR(TAG,
"APDU buffer is less than 4 bytes: %" PRIu32, dataSize);
1612 Stream_StaticConstInit(&s, data, dataSize);
1617 case ISO_INS_SELECT:
1618 return vgids_ins_select(context, &s, response, responseSize);
1619 case ISO_INS_GETDATA:
1620 return vgids_ins_getdata(context, &s, response, responseSize);
1621 case ISO_INS_GETRESPONSE:
1622 return vgids_ins_getresponse(context, &s, response, responseSize);
1624 return vgids_ins_manage_security_environment(context, &s, response, responseSize);
1626 return vgids_ins_perform_security_operation(context, &s, response, responseSize);
1627 case ISO_INS_VERIFY:
1628 return vgids_ins_verify(context, &s, response, responseSize);
1634 return vgids_create_response(ISO_STATUS_COMMANDNOTALLOWED,
nullptr, 0, response, responseSize);
1637void vgids_free(vgidsContext* context)
1641 freerdp_key_free(context->privateKey);
1642 freerdp_certificate_free(context->certificate);
1643 Stream_Free(context->commandData, TRUE);
1644 Stream_Free(context->responseData, TRUE);
1646 ArrayList_Free(context->files);
This struct contains function pointer to initialize/free objects.
OBJECT_FREE_FN fnObjectFree