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(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");
297static 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);
333static BOOL vgids_ef_write_do(vgidsEF* ef, UINT16 doID,
const void* data, DWORD dataSize)
336 return vgids_write_tlv(ef->data, doID, data, dataSize);
339static 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))
414void vgids_ef_free(
void* ptr)
419 Stream_Free(ef->data, TRUE);
424static 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;
449static 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) || (certSize > UINT16_MAX))
466 WLog_ERR(TAG,
"Failed to get certificate size");
470 comprData = malloc(certSize);
473 WLog_ERR(TAG,
"Failed to allocate certificate buffer");
478 destSize = WINPR_ASSERTING_INT_CAST(uint16_t, certSize);
479 if (compress(comprData, &destSize, certData, WINPR_ASSERTING_INT_CAST(uint16_t, certSize)) !=
482 WLog_ERR(TAG,
"Failed to compress certificate data");
487 s = Stream_New(NULL, destSize + 4);
488 Stream_Write_UINT16(s, 0x0001);
489 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, certSize));
490 Stream_Write(s, comprData, destSize);
491 Stream_SealLength(s);
493 *kxc = Stream_Buffer(s);
494 *kxcSize = (DWORD)Stream_Length(s);
496 Stream_Free(s, FALSE);
502 Stream_Free(s, TRUE);
508static size_t get_rsa_key_size(
const rdpPrivateKey* privateKey)
510 WINPR_ASSERT(privateKey);
512 return freerdp_key_get_bits(privateKey) / 8;
515static BYTE vgids_get_algid(vgidsContext* p_Ctx)
519 switch (get_rsa_key_size(p_Ctx->privateKey))
522 return VGIDS_ALGID_RSA_1024;
524 return VGIDS_ALGID_RSA_2048;
526 return VGIDS_ALGID_RSA_3072;
528 return VGIDS_ALGID_RSA_4096;
530 WLog_ERR(TAG,
"Failed to determine algid for private key");
537static BOOL vgids_prepare_keymap(vgidsContext* context, BYTE** outData, DWORD* outDataSize)
544 vgidsKeymapRecord record = {
547 VGIDS_KEY_TYPE_KEYEXCHANGE,
548 (0xB000 | VGIDS_DEFAULT_KEY_REF),
554 BYTE algid = vgids_get_algid(context);
558 data = malloc(
sizeof(record) + 1);
561 WLog_ERR(TAG,
"Failed to allocate filesystem table data blob");
566 record.algid = algid;
567 memcpy(data + 1, &record,
sizeof(record));
570 *outDataSize =
sizeof(record) + 1;
575static BOOL vgids_parse_apdu_header(
wStream* s, BYTE* cla, BYTE* ins, BYTE* p1, BYTE* p2, BYTE* lc,
578 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
583 Stream_Read_UINT8(s, *cla);
587 Stream_Read_UINT8(s, *ins);
591 Stream_Read_UINT8(s, *p1);
595 Stream_Read_UINT8(s, *p2);
602 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
605 Stream_Read_UINT8(s, *lc);
606 if (!Stream_CheckAndLogRequiredLength(TAG, s, *lc))
613 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
615 Stream_Read_UINT8(s, *le);
621static BOOL vgids_create_response(UINT16 status,
const BYTE* answer, DWORD answerSize,
622 BYTE** outData, DWORD* outDataSize)
624 BYTE* out = malloc(answerSize + 2);
627 WLog_ERR(TAG,
"Failed to allocate memory for response data");
634 memcpy(out, answer, answerSize);
638 *out = (BYTE)((status >> 8) & 0xFF);
639 *(out + 1) = (BYTE)(status & 0xFF);
640 *outDataSize = answerSize + 2;
644static BOOL vgids_read_do_fkt(
void* data,
size_t index, va_list ap)
646 BYTE* response = NULL;
647 DWORD responseSize = 0;
648 vgidsEF* file = (vgidsEF*)data;
649 vgidsContext* context = va_arg(ap, vgidsContext*);
650 UINT16 efID = (UINT16)va_arg(ap,
unsigned);
651 UINT16 doID = (UINT16)va_arg(ap,
unsigned);
654 if (efID == 0x3FFF || efID == file->id)
657 if (vgids_ef_read_do(file, doID, &response, &responseSize))
659 context->responseData = Stream_New(response, (
size_t)responseSize);
667static void vgids_read_do(vgidsContext* context, UINT16 efID, UINT16 doID)
669 ArrayList_ForEach(context->files, vgids_read_do_fkt, context, efID, doID);
672static void vgids_reset_context_response(vgidsContext* context)
674 Stream_Free(context->responseData, TRUE);
675 context->responseData = NULL;
678static void vgids_reset_context_command_data(vgidsContext* context)
680 Stream_Free(context->commandData, TRUE);
681 context->commandData = NULL;
684static BOOL vgids_ins_select(vgidsContext* context,
wStream* s, BYTE** response,
690 DWORD resultDataSize = 0;
691 const BYTE* resultData = NULL;
692 UINT16 status = ISO_STATUS_SUCCESS;
696 if (!vgids_parse_apdu_header(s, NULL, NULL, &p1, &p2, &lc, NULL))
706 BYTE aid[ISO_AID_MAX_SIZE] = { 0 };
707 if (lc > ISO_AID_MAX_SIZE)
709 WLog_ERR(TAG,
"The LC byte is greater than the maximum AID length");
710 status = ISO_STATUS_INVALIDLC;
715 Stream_Read(s, aid, lc);
716 if (memcmp(aid, g_MsGidsAID, lc) != 0)
718 status = ISO_STATUS_FILENOTFOUND;
728 resultData = g_GidsAppFCI;
729 resultDataSize =
sizeof(g_GidsAppFCI);
735 resultData = g_GidsAppFCP;
736 resultDataSize =
sizeof(g_GidsAppFCP);
740 status = ISO_STATUS_INVALIDP1P2;
745 context->currentDF = ISO_FID_MF;
755 WLog_ERR(TAG,
"The LC byte for the file ID is greater than 2");
756 status = ISO_STATUS_INVALIDLC;
760 Stream_Read_UINT16_BE(s, fid);
761 if (fid != VGIDS_EFID_CURRENTDF || context->currentDF == 0)
763 status = ISO_STATUS_FILENOTFOUND;
771 status = ISO_STATUS_INVALIDP1P2;
776 return vgids_create_response(status, resultData, resultDataSize, response, responseSize);
779static UINT16 vgids_handle_chained_response(vgidsContext* context,
const BYTE** response,
783 UINT16 status = ISO_STATUS_SUCCESS;
784 DWORD remainingBytes = (DWORD)Stream_Length(context->responseData);
785 if (remainingBytes > 256)
787 status = ISO_STATUS_MORE_DATA;
788 remainingBytes = 256;
791 *response = Stream_Buffer(context->responseData);
792 *responseSize = remainingBytes;
793 Stream_Seek(context->responseData, remainingBytes);
797 remainingBytes = (DWORD)(Stream_Length(context->responseData) - remainingBytes);
798 if (remainingBytes < 256 && remainingBytes != 0)
799 status |= (remainingBytes & 0xFF);
803static BOOL vgids_get_public_key(vgidsContext* context, UINT16 doTag)
809 WINPR_ASSERT(context);
815 char* n = freerdp_certificate_get_param(context->certificate, FREERDP_CERT_RSA_N, &nSize);
816 char* e = freerdp_certificate_get_param(context->certificate, FREERDP_CERT_RSA_E, &eSize);
821 pubKey = Stream_New(NULL, nSize + eSize + 0x10);
824 WLog_ERR(TAG,
"Failed to allocate public key stream");
828 response = Stream_New(NULL, Stream_Capacity(pubKey) + 0x10);
831 WLog_ERR(TAG,
"Failed to allocate response stream");
836 if (!vgids_write_tlv(pubKey, 0x81, n, nSize))
839 if (!vgids_write_tlv(pubKey, 0x82, e, eSize))
843 if (!vgids_write_tlv(response, doTag, Stream_Buffer(pubKey), (DWORD)Stream_Length(pubKey)))
847 Stream_SetPosition(response, 0);
848 context->responseData = response;
855 Stream_Free(pubKey, TRUE);
856 Stream_Free(response, TRUE);
860static BOOL vgids_ins_getdata(vgidsContext* context,
wStream* s, BYTE** response,
868 DWORD resultDataSize = 0;
869 const BYTE* resultData = NULL;
870 UINT16 status = ISO_STATUS_SUCCESS;
876 if (!vgids_parse_apdu_header(s, NULL, NULL, &p1, &p2, &lc, NULL))
880 vgids_reset_context_response(context);
883 fileId = (UINT16)(((UINT16)p1 << 8) | p2);
892 Stream_Read_UINT8(s, tag);
893 Stream_Read_UINT8(s, length);
894 if (tag != 0x5C && length != 0x02)
896 status = ISO_STATUS_INVALIDCOMMANDDATA;
900 Stream_Read_UINT16_BE(s, doId);
901 vgids_read_do(context, fileId, doId);
912 if (p1 != 0x3F && p2 != 0xFF)
914 status = ISO_STATUS_INVALIDP1P2;
919 Stream_Read_UINT8(s, tag);
920 Stream_Read_UINT8(s, length);
921 if (tag != 0x70 || length != 0x08)
923 status = ISO_STATUS_INVALIDCOMMANDDATA;
928 Stream_Read_UINT8(s, tag);
929 Stream_Read_UINT8(s, length);
930 Stream_Read_UINT8(s, keyRef);
931 if (tag != 0x84 || length != 0x01 || keyRef != VGIDS_DEFAULT_KEY_REF)
933 status = ISO_STATUS_INVALIDCOMMANDDATA;
938 Stream_Read_UINT8(s, tag);
939 Stream_Read_UINT8(s, length);
940 if (tag != 0xA5 || length != 0x03)
942 status = ISO_STATUS_INVALIDCOMMANDDATA;
946 Stream_Read_UINT16_BE(s, pubKeyDO);
947 Stream_Read_UINT8(s, length);
948 if (pubKeyDO != 0x7F49 || length != 0x80)
950 status = ISO_STATUS_INVALIDCOMMANDDATA;
954 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
956 status = ISO_STATUS_INVALIDLC;
961 vgids_get_public_key(context, pubKeyDO);
965 status = ISO_STATUS_INVALIDCOMMANDDATA;
970 if (context->responseData)
971 status = vgids_handle_chained_response(context, &resultData, &resultDataSize);
972 else if (status == ISO_STATUS_SUCCESS)
973 status = ISO_STATUS_REFERENCEDATANOTFOUND;
975 return vgids_create_response(status, resultData, resultDataSize, response, responseSize);
978static BOOL vgids_ins_manage_security_environment(vgidsContext* context,
wStream* s,
979 BYTE** response, DWORD* responseSize)
986 DWORD resultDataSize = 0;
987 const BYTE* resultData = NULL;
988 UINT16 status = ISO_STATUS_SUCCESS;
990 vgids_reset_context_command_data(context);
991 vgids_reset_context_response(context);
994 if (!vgids_parse_apdu_header(s, NULL, NULL, &p1, &p2, &lc, NULL))
1000 if (p1 != 0x41 && p2 != 0xB6 && p2 != 0xB8)
1002 status = ISO_STATUS_INVALIDP1P2;
1003 goto create_response;
1008 status = ISO_STATUS_WRONGLC;
1009 goto create_response;
1012 context->currentSE.crt = p2;
1016 Stream_Read_UINT8(s, tag);
1017 Stream_Read_UINT8(s, length);
1018 if (tag != 0x80 || length != 0x01)
1020 status = ISO_STATUS_INVALIDCOMMANDDATA;
1021 goto create_response;
1023 Stream_Read_UINT8(s, context->currentSE.algoId);
1026 Stream_Read_UINT8(s, tag);
1027 Stream_Read_UINT8(s, length);
1028 if (tag != 0x84 || length != 0x01)
1030 status = ISO_STATUS_INVALIDCOMMANDDATA;
1031 goto create_response;
1033 Stream_Read_UINT8(s, context->currentSE.keyRef);
1037 if (status != ISO_STATUS_SUCCESS)
1038 memset(&context->currentSE, 0,
sizeof(context->currentSE));
1039 return vgids_create_response(status, resultData, resultDataSize, response, responseSize);
1042static BOOL vgids_perform_digital_signature(vgidsContext* context)
1046 EVP_PKEY_CTX* ctx = NULL;
1047 EVP_PKEY* pk = freerdp_key_get_evp_pkey(context->privateKey);
1048 const vgidsDigestInfoMap gidsDigestInfo[VGIDS_MAX_DIGEST_INFO] = {
1049 { g_PKCS1_SHA1,
sizeof(g_PKCS1_SHA1), EVP_sha1() },
1050 { g_PKCS1_SHA224,
sizeof(g_PKCS1_SHA224), EVP_sha224() },
1051 { g_PKCS1_SHA256,
sizeof(g_PKCS1_SHA256), EVP_sha256() },
1052 { g_PKCS1_SHA384,
sizeof(g_PKCS1_SHA384), EVP_sha384() },
1053 { g_PKCS1_SHA512,
sizeof(g_PKCS1_SHA512), EVP_sha512() },
1054#if OPENSSL_VERSION_NUMBER >= 0x10101000L
1055 { g_PKCS1_SHA512_224,
sizeof(g_PKCS1_SHA512_224), EVP_sha512_224() },
1056 { g_PKCS1_SHA512_256,
sizeof(g_PKCS1_SHA512_256), EVP_sha512_256() }
1062 WLog_ERR(TAG,
"Failed to create PKEY");
1066 vgids_reset_context_response(context);
1069 Stream_SetPosition(context->commandData, 0);
1070 for (
int i = 0; i < VGIDS_MAX_DIGEST_INFO; ++i)
1073 const vgidsDigestInfoMap* digest = &gidsDigestInfo[i];
1074 if (Stream_Length(context->commandData) >= digest->infoSize &&
1075 memcmp(Stream_Buffer(context->commandData), digest->info, digest->infoSize) == 0)
1078 Stream_Seek(context->commandData, digest->infoSize);
1079 if (!Stream_CheckAndLogRequiredLength(TAG, context->commandData, 2))
1081 msgSize = Stream_GetRemainingLength(context->commandData);
1084 ctx = EVP_PKEY_CTX_new(pk, NULL);
1087 WLog_ERR(TAG,
"Failed to create signing context");
1091 if (EVP_PKEY_sign_init(ctx) <= 0)
1093 WLog_ERR(TAG,
"Failed to init signing context");
1098 if (context->currentSE.algoId & VGIDS_SE_ALGOID_DST_PAD_PKCS1)
1100 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)
1102 WLog_ERR(TAG,
"Failed to set padding mode");
1107 if (EVP_PKEY_CTX_set_signature_md(ctx, digest->digest) <= 0)
1109 WLog_ERR(TAG,
"Failed to set signing mode");
1114 if (EVP_PKEY_sign(ctx, NULL, &sigSize, Stream_Pointer(context->commandData), msgSize) <=
1117 WLog_ERR(TAG,
"Failed to determine signature size");
1121 context->responseData = Stream_New(NULL, sigSize);
1122 if (!context->responseData)
1124 WLog_ERR(TAG,
"Failed to allocate signing buffer");
1129 if (EVP_PKEY_sign(ctx, Stream_Buffer(context->responseData), &sigSize,
1130 Stream_Pointer(context->commandData), msgSize) <= 0)
1132 WLog_ERR(TAG,
"Failed to create signature");
1136 Stream_SetLength(context->responseData, sigSize);
1137 EVP_PKEY_CTX_free(ctx);
1143 vgids_reset_context_command_data(context);
1147 vgids_reset_context_command_data(context);
1148 vgids_reset_context_response(context);
1149 EVP_PKEY_CTX_free(ctx);
1154static BOOL vgids_perform_decrypt(vgidsContext* context)
1156 EVP_PKEY_CTX* ctx = NULL;
1159 int padding = RSA_NO_PADDING;
1161 vgids_reset_context_response(context);
1164 if (context->currentSE.algoId & VGIDS_SE_ALGOID_CT_PAD_PKCS1)
1165 padding = RSA_PKCS1_PADDING;
1166 else if (context->currentSE.algoId & VGIDS_SE_ALGOID_CT_PAD_OAEP)
1167 padding = RSA_PKCS1_OAEP_PADDING;
1170 EVP_PKEY* pkey = freerdp_key_get_evp_pkey(context->privateKey);
1172 goto decrypt_failed;
1173 ctx = EVP_PKEY_CTX_new(pkey, NULL);
1175 goto decrypt_failed;
1176 if (EVP_PKEY_decrypt_init(ctx) <= 0)
1177 goto decrypt_failed;
1178 if (EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0)
1179 goto decrypt_failed;
1182 const size_t inlen = Stream_Length(context->commandData);
1184 res = EVP_PKEY_decrypt(ctx, NULL, &outlen, Stream_Buffer(context->commandData), inlen);
1187 WLog_ERR(TAG,
"Failed to decrypt data");
1188 goto decrypt_failed;
1192 context->responseData = Stream_New(NULL, outlen);
1193 if (!context->responseData)
1195 WLog_ERR(TAG,
"Failed to create decryption buffer");
1196 goto decrypt_failed;
1200 res = EVP_PKEY_decrypt(ctx, Stream_Buffer(context->responseData), &outlen,
1201 Stream_Buffer(context->commandData), inlen);
1205 WLog_ERR(TAG,
"Failed to decrypt data");
1206 goto decrypt_failed;
1209 Stream_SetLength(context->responseData, outlen);
1213 EVP_PKEY_CTX_free(ctx);
1214 EVP_PKEY_free(pkey);
1215 vgids_reset_context_command_data(context);
1217 vgids_reset_context_response(context);
1221static BOOL vgids_ins_perform_security_operation(vgidsContext* context,
wStream* s, BYTE** response,
1222 DWORD* responseSize)
1228 DWORD resultDataSize = 0;
1229 const BYTE* resultData = NULL;
1230 UINT16 status = ISO_STATUS_SUCCESS;
1233 if (!vgids_parse_apdu_header(s, &cla, NULL, &p1, &p2, &lc, NULL))
1238 status = ISO_STATUS_WRONGLC;
1239 goto create_response;
1243 if (context->currentSE.keyRef != VGIDS_DEFAULT_KEY_REF)
1245 status = ISO_STATUS_SECURITYSTATUSNOTSATISFIED;
1246 goto create_response;
1250 if (!context->pinVerified)
1252 status = ISO_STATUS_SECURITYSTATUSNOTSATISFIED;
1253 goto create_response;
1257 if (!context->commandData)
1259 context->commandData = Stream_New(NULL, lc);
1260 if (!context->commandData)
1263 else if (!Stream_EnsureRemainingCapacity(context->commandData, lc))
1266 Stream_Write(context->commandData, Stream_Pointer(s), lc);
1267 Stream_SealLength(context->commandData);
1270 switch (context->currentSE.crt)
1272 case VGIDS_SE_CRT_SIGN:
1274 if (p1 != 0x9E || p2 != 0x9A)
1276 status = ISO_STATUS_INVALIDP1P2;
1282 vgids_perform_digital_signature(context);
1285 case VGIDS_SE_CRT_CONF:
1287 if ((p1 != 0x86 || p2 != 0x80) && (p1 != 0x80 || p2 != 0x86))
1289 status = ISO_STATUS_INVALIDP1P2;
1295 vgids_perform_decrypt(context);
1299 status = ISO_STATUS_INVALIDP1P2;
1304 if (status == ISO_STATUS_SUCCESS && context->responseData)
1305 status = vgids_handle_chained_response(context, &resultData, &resultDataSize);
1309 return vgids_create_response(status, resultData, resultDataSize, response, responseSize);
1312static BOOL vgids_ins_getresponse(vgidsContext* context,
wStream* s, BYTE** response,
1313 DWORD* responseSize)
1318 DWORD resultDataSize = 0;
1319 const BYTE* resultData = NULL;
1320 DWORD expectedLen = 0;
1321 DWORD remainingSize = 0;
1322 UINT16 status = ISO_STATUS_SUCCESS;
1326 if (!context->responseData || !Stream_CheckAndLogRequiredLength(TAG, context->responseData, 1))
1328 status = ISO_STATUS_COMMANDNOTALLOWED;
1329 goto create_response;
1332 if (!vgids_parse_apdu_header(s, NULL, NULL, &p1, &p2, NULL, &le))
1336 if (p1 != 00 || p2 != 0x00)
1338 status = ISO_STATUS_INVALIDP1P2;
1339 goto create_response;
1344 if (expectedLen == 0)
1348 remainingSize = (DWORD)Stream_GetRemainingLength(context->responseData);
1349 if (remainingSize < expectedLen)
1350 expectedLen = remainingSize;
1352 resultData = Stream_Pointer(context->responseData);
1353 resultDataSize = expectedLen;
1354 Stream_Seek(context->responseData, expectedLen);
1357 remainingSize = (DWORD)Stream_GetRemainingLength(context->responseData);
1358 if (remainingSize > 0)
1360 status = ISO_STATUS_MORE_DATA;
1361 if (remainingSize < 256)
1362 status |= (remainingSize & 0xFF);
1366 return vgids_create_response(status, resultData, resultDataSize, response, responseSize);
1369static BOOL vgids_ins_verify(vgidsContext* context,
wStream* s, BYTE** response,
1370 DWORD* responseSize)
1376 UINT16 status = ISO_STATUS_SUCCESS;
1377 char pin[VGIDS_MAX_PIN_SIZE + 1] = { 0 };
1380 if (!vgids_parse_apdu_header(s, NULL, &ins, &p1, &p2, NULL, NULL))
1384 if (p1 != 00 && p2 != 0x80 && p2 != 0x82)
1386 status = ISO_STATUS_INVALIDP1P2;
1387 goto create_response;
1393 context->pinVerified = FALSE;
1394 goto create_response;
1398 if (context->curRetryCounter == 0)
1400 status = ISO_STATUS_AUTHMETHODBLOCKED;
1401 goto create_response;
1405 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
1407 status = ISO_STATUS_INVALIDLC;
1408 goto create_response;
1411 Stream_Read_UINT8(s, lc);
1412 if (!Stream_CheckAndLogRequiredLength(TAG, s, lc) || (lc > VGIDS_MAX_PIN_SIZE))
1414 status = ISO_STATUS_INVALIDLC;
1415 goto create_response;
1419 Stream_Read(s, pin, lc);
1420 if (strcmp(context->pin, pin) != 0)
1423 --context->curRetryCounter;
1424 context->pinVerified = FALSE;
1425 status = (ISO_STATUS_VERIFYFAILED | (context->curRetryCounter & 0xFF));
1430 context->curRetryCounter = context->retryCounter;
1431 context->pinVerified = TRUE;
1435 return vgids_create_response(status, NULL, 0, response, responseSize);
1438vgidsContext* vgids_new(
void)
1441 vgidsContext* ctx = calloc(1,
sizeof(vgidsContext));
1443 ctx->files = ArrayList_New(FALSE);
1446 WLog_ERR(TAG,
"Failed to create files array list");
1450 obj = ArrayList_Object(ctx->files);
1451 obj->fnObjectFree = vgids_ef_free;
1460BOOL vgids_init(vgidsContext* ctx,
const char* cert,
const char* privateKey,
const char* pin)
1463 DWORD keymapSize = 0;
1464 DWORD fsTableSize = 0;
1467 BYTE* keymap = NULL;
1468 BYTE* fsTable = NULL;
1469 vgidsEF* masterEF = NULL;
1470 vgidsEF* cardidEF = NULL;
1471 vgidsEF* commonEF = NULL;
1472 BYTE cardid[VGIDS_CARDID_SIZE] = { 0 };
1473 vgidsContainerMapEntry cmrec = { {
'P',
'r',
'i',
'v',
'a',
't',
'e',
' ',
'K',
'e',
'y',
' ',
1475 CONTAINER_MAP_VALID_CONTAINER |
1476 CONTAINER_MAP_DEFAULT_CONTAINER,
1480 vgidsFilesysTableEntry filesys[] = {
1481 {
"mscp",
"", 0, 0, 0, 0xA000, 0 },
1482 {
"",
"cardid", 0, 0xDF20, 0, 0xA012, 0 },
1483 {
"",
"cardapps", 0, 0xDF21, 0, 0xA010, 0 },
1484 {
"",
"cardcf", 0, 0xDF22, 0, 0xA010, 0 },
1485 {
"mscp",
"cmapfile", 0, 0xDF23, 0, 0xA010, 0 },
1486 {
"mscp",
"kxc00", 0, 0xDF24, 0, 0xA010, 0 },
1490 if (!cert || !privateKey || !pin)
1492 WLog_DBG(TAG,
"Passed invalid NULL argument: cert=%p, privateKey=%p, pin=%p", cert,
1498 ctx->certificate = freerdp_certificate_new_from_pem(cert);
1499 if (!ctx->certificate)
1502 ctx->privateKey = freerdp_key_new_from_pem_enc(privateKey, NULL);
1503 if (!ctx->privateKey)
1508 masterEF = vgids_ef_new(ctx, VGIDS_EFID_MASTER);
1514 cardidEF = vgids_ef_new(ctx, VGIDS_EFID_CARDID);
1517 winpr_RAND(cardid,
sizeof(cardid));
1518 if (!vgids_ef_write_do(cardidEF, VGIDS_DO_CARDID, cardid,
sizeof(cardid)))
1523 commonEF = vgids_ef_new(ctx, VGIDS_EFID_COMMON);
1528 if (!vgids_ef_write_do(commonEF, VGIDS_DO_CARDCF, g_CardCFContents,
sizeof(g_CardCFContents)))
1532 const size_t size = get_rsa_key_size(ctx->privateKey);
1533 if ((size == 0) || (size > UINT16_MAX / 8))
1536 cmrec.wKeyExchangeKeySizeBits = (WORD)size * 8;
1537 if (!vgids_ef_write_do(commonEF, VGIDS_DO_CMAPFILE, &cmrec,
sizeof(cmrec)))
1541 if (!vgids_ef_write_do(commonEF, VGIDS_DO_CARDAPPS, g_CardAppsContents,
1542 sizeof(g_CardAppsContents)))
1546 if (!vgids_prepare_certificate(ctx->certificate, &kxc, &kxcSize))
1548 if (!vgids_ef_write_do(commonEF, VGIDS_DO_KXC00, kxc, kxcSize))
1552 if (!vgids_prepare_fstable(filesys, ARRAYSIZE(filesys), &fsTable, &fsTableSize))
1554 if (!vgids_ef_write_do(masterEF, VGIDS_DO_FILESYSTEMTABLE, fsTable, fsTableSize))
1558 if (!vgids_prepare_keymap(ctx, &keymap, &keymapSize))
1560 if (!vgids_ef_write_do(masterEF, VGIDS_DO_KEYMAP, keymap, keymapSize))
1564 ctx->curRetryCounter = ctx->retryCounter = VGIDS_DEFAULT_RETRY_COUNTER;
1565 ctx->pin = _strdup(pin);
1581BOOL vgids_process_apdu(vgidsContext* context,
const BYTE* data, DWORD dataSize, BYTE** response,
1582 DWORD* responseSize)
1588 if (!context || !data || !response || !responseSize)
1590 WLog_ERR(TAG,
"Invalid NULL pointer passed");
1596 WLog_ERR(TAG,
"APDU buffer is less than 4 bytes: %" PRIu32, dataSize);
1601 Stream_StaticConstInit(&s, data, dataSize);
1606 case ISO_INS_SELECT:
1607 return vgids_ins_select(context, &s, response, responseSize);
1608 case ISO_INS_GETDATA:
1609 return vgids_ins_getdata(context, &s, response, responseSize);
1610 case ISO_INS_GETRESPONSE:
1611 return vgids_ins_getresponse(context, &s, response, responseSize);
1613 return vgids_ins_manage_security_environment(context, &s, response, responseSize);
1615 return vgids_ins_perform_security_operation(context, &s, response, responseSize);
1616 case ISO_INS_VERIFY:
1617 return vgids_ins_verify(context, &s, response, responseSize);
1623 return vgids_create_response(ISO_STATUS_COMMANDNOTALLOWED, NULL, 0, response, responseSize);
1626void vgids_free(vgidsContext* context)
1630 freerdp_key_free(context->privateKey);
1631 freerdp_certificate_free(context->certificate);
1632 Stream_Free(context->commandData, TRUE);
1633 Stream_Free(context->responseData, TRUE);
1635 ArrayList_Free(context->files);
This struct contains function pointer to initialize/free objects.