From 4a3c04a755d7c50390b3c024a8636b6004ef5862 Mon Sep 17 00:00:00 2001 From: frankmorgner Date: Wed, 7 Jul 2010 10:31:50 +0000 Subject: [PATCH] - added parsing of PACE data - bugfix: PACE output data had to be wrapped again git-svn-id: https://vsmartcard.svn.sourceforge.net/svnroot/vsmartcard@201 96b47cad-a561-4643-ad3b-153ac7d7599c --- ccid/patches/ccid-1.3.11.patch | 99 +++++++++++++-- ccid/patches/ccid-1.3.13.patch | 99 +++++++++++++-- ...r4993.patch => pcsclite_trunk_r5063.patch} | 115 +++++++++++++++--- 3 files changed, 278 insertions(+), 35 deletions(-) rename ccid/patches/{pcsclite_trunk_r4993.patch => pcsclite_trunk_r5063.patch} (74%) diff --git a/ccid/patches/ccid-1.3.11.patch b/ccid/patches/ccid-1.3.11.patch index cb97c03..a63d644 100644 --- a/ccid/patches/ccid-1.3.11.patch +++ b/ccid/patches/ccid-1.3.11.patch @@ -81,7 +81,7 @@ Index: ccid-1.3.11/src/commands.c /***************************************************************************** -@@ -691,7 +697,144 @@ +@@ -691,7 +697,217 @@ return ret; } /* SecurePINModify */ @@ -91,8 +91,10 @@ Index: ccid-1.3.11/src/commands.c +{ + RESPONSECODE return_value; + unsigned char lengthCHAT, lengthPIN; -+ uint16_t lengthCertificateDescription; ++ uint16_t lengthCertificateDescription, lengthEF_CardAccess, length_IDicc; ++ uint8_t lengthCAR, lengthCARprev; + int old_read_timeout; ++ size_t parsed; + _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); + old_read_timeout= ccid_descriptor -> readTimeout; @@ -136,6 +138,74 @@ Index: ccid-1.3.11/src/commands.c + /* bPINOperation: PIN PACE Capabilities */ + return_value = SecurePINPACE(reader_index, TxBuffer, TxLength, RxBuffer, + RxLength, CCID_CLASS_PIN_PACE_EXECUTE); ++ if (IFD_SUCCESS != return_value) ++ goto err; ++ ++ ++ if (6+2 > *RxLength) ++ goto err; ++ DEBUG_INFO3("MSE:Set AT Statusbytes: %02X %02X", ++ RxBuffer[6+0], RxBuffer[6+1]); ++ parsed = 6+2; ++ ++ ++ if (parsed+2 > *RxLength) ++ goto err; ++ lengthEF_CardAccess = w2i(RxBuffer, parsed); ++ if (parsed+2+lengthEF_CardAccess > *RxLength) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return_value = IFD_COMMUNICATION_ERROR; ++ goto err; ++ } ++ if (lengthEF_CardAccess) ++ DEBUG_INFO_XXD("EF.CardAccess:\n", &RxBuffer[parsed+2], lengthEF_CardAccess); ++ parsed += 2 + lengthEF_CardAccess; ++ ++ if (parsed+1 > *RxLength) ++ goto err; ++ lengthCAR = RxBuffer[parsed+1]; ++ if (parsed+1+lengthCAR > *RxLength) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return_value = IFD_COMMUNICATION_ERROR; ++ goto err; ++ } ++ if (lengthCAR) ++ DEBUG_INFO_XXD("Recent Certificate Authority:\n", ++ &RxBuffer[parsed+1], ++ lengthCAR); ++ parsed += 1 + lengthCAR; ++ ++ if (parsed+1 > *RxLength) ++ goto err; ++ lengthCARprev = RxBuffer[parsed+1]; ++ if (parsed+1+lengthCARprev > *RxLength) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return_value = IFD_COMMUNICATION_ERROR; ++ goto err; ++ } ++ if (lengthCARprev) ++ DEBUG_INFO_XXD("Previous Certificate Authority:\n", ++ &RxBuffer[parsed+1], ++ lengthCARprev); ++ parsed += 1 + lengthCARprev; ++ ++ if (parsed+2 > *RxLength) ++ goto err; ++ length_IDicc = w2i(RxBuffer, parsed); ++ if (parsed+2+length_IDicc > *RxLength) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return_value = IFD_COMMUNICATION_ERROR; ++ goto err; ++ } ++ if (length_IDicc) ++ DEBUG_INFO_XXD("IDicc:\n", &RxBuffer[parsed+2], length_IDicc); ++ parsed += 2 + length_IDicc; ++ ++ if (parsed != *RxLength) { ++ DEBUG_CRITICAL2("Overrun by %d bytes", *RxLength - parsed); ++ return_value = IFD_COMMUNICATION_ERROR; ++ goto err; ++ } + +err: + ccid_descriptor -> readTimeout = old_read_timeout; @@ -210,15 +280,17 @@ Index: ccid-1.3.11/src/commands.c + } + + length = dw2i(cmd, 1); -+ if (length <= *RxLength) -+ *RxLength = length; ++ if (length + 6 <= *RxLength) ++ *RxLength = length + 6; + else + { -+ DEBUG_CRITICAL2("overrun by %d bytes", length - *RxLength); -+ length = *RxLength; ++ DEBUG_CRITICAL2("overrun by %d bytes", length + 6 - *RxLength); + return IFD_ERROR_INSUFFICIENT_BUFFER; + } -+ memcpy(RxBuffer, &cmd[10], length); ++ uint32_t s = 0x00000000; ++ memcpy(RxBuffer, &s, 4); /* "Kein Fehler" */ ++ memcpy(RxBuffer+4, &length, 2); /* lengthOutputData */ ++ memcpy(RxBuffer+6, &cmd[10], length); + + return IFD_SUCCESS; +} @@ -227,7 +299,7 @@ Index: ccid-1.3.11/src/commands.c /***************************************************************************** * * Escape -@@ -2081,3 +2224,15 @@ +@@ -2081,3 +2297,15 @@ buffer[3] = (value >> 24) & 0xFF; } /* i2dw */ @@ -262,7 +334,7 @@ Index: ccid-1.3.11/src/commands.h RESPONSECODE CmdEscape(unsigned int reader_index, const unsigned char TxBuffer[], unsigned int TxLength, unsigned char RxBuffer[], unsigned int *RxLength); -Index: src/ccid.h +Index: ccid-1.3.11/src/ccid.h =================================================================== --- ccid-1.3.11/src/ccid.h (Revision 4347) +++ ccid-1.3.11/src/ccid.h (Arbeitskopie) @@ -279,6 +351,15 @@ Index: src/ccid.h /* See CCID specs ch. 4.2.1 */ #define CCID_ICC_PRESENT_ACTIVE 0x00 /* 00 0000 00 */ +@@ -216,6 +218,8 @@ + + /* convert a 4 byte integer in USB format into an int */ + #define dw2i(a, x) (unsigned int)((((((a[x+3] << 8) + a[x+2]) << 8) + a[x+1]) << 8) + a[x]) ++/* convert a 2 byte integer in USB format into an int */ ++#define w2i(a, x) (unsigned int)(((a[x+1]) << 8) + a[x]) + + /* all the data rates specified by ISO 7816-3 Fi/Di tables */ + #define ISO_DATA_RATES 10753, 14337, 15625, 17204, \ Index: ccid-1.3.11/src/ccid_ifdhandler.h =================================================================== --- ccid-1.3.11/src/ccid_ifdhandler.h (Revision 4347) diff --git a/ccid/patches/ccid-1.3.13.patch b/ccid/patches/ccid-1.3.13.patch index 77caf2d..0812988 100644 --- a/ccid/patches/ccid-1.3.13.patch +++ b/ccid/patches/ccid-1.3.13.patch @@ -6,7 +6,7 @@ Index: ccid-1.3.13/src/ifdhandler.c iBytesReturned += sizeof(PCSC_TLV_STRUCTURE); } -+ if (ccid_descriptor -> bPINSupport & CCID_CLASS_PIN_PACE_CAPABILITIES) ++ if (get_ccid_descriptor(reader_index) -> bPINSupport & CCID_CLASS_PIN_PACE_CAPABILITIES) + { + pcsc_tlv -> tag = FEATURE_EXECUTE_PACE; + pcsc_tlv -> length = 0x04; /* always 0x04 */ @@ -81,7 +81,7 @@ Index: ccid-1.3.13/src/commands.c /***************************************************************************** -@@ -712,7 +718,144 @@ +@@ -712,7 +718,217 @@ return ret; } /* SecurePINModify */ @@ -91,8 +91,10 @@ Index: ccid-1.3.13/src/commands.c +{ + RESPONSECODE return_value; + unsigned char lengthCHAT, lengthPIN; -+ uint16_t lengthCertificateDescription; ++ uint16_t lengthCertificateDescription, lengthEF_CardAccess, length_IDicc; ++ uint8_t lengthCAR, lengthCARprev; + int old_read_timeout; ++ size_t parsed; + _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); + old_read_timeout= ccid_descriptor -> readTimeout; @@ -136,6 +138,74 @@ Index: ccid-1.3.13/src/commands.c + /* bPINOperation: PIN PACE Capabilities */ + return_value = SecurePINPACE(reader_index, TxBuffer, TxLength, RxBuffer, + RxLength, CCID_CLASS_PIN_PACE_EXECUTE); ++ if (IFD_SUCCESS != return_value) ++ goto err; ++ ++ ++ if (6+2 > *RxLength) ++ goto err; ++ DEBUG_INFO3("MSE:Set AT Statusbytes: %02X %02X", ++ RxBuffer[6+0], RxBuffer[6+1]); ++ parsed = 6+2; ++ ++ ++ if (parsed+2 > *RxLength) ++ goto err; ++ lengthEF_CardAccess = w2i(RxBuffer, parsed); ++ if (parsed+2+lengthEF_CardAccess > *RxLength) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return_value = IFD_COMMUNICATION_ERROR; ++ goto err; ++ } ++ if (lengthEF_CardAccess) ++ DEBUG_INFO_XXD("EF.CardAccess:\n", &RxBuffer[parsed+2], lengthEF_CardAccess); ++ parsed += 2 + lengthEF_CardAccess; ++ ++ if (parsed+1 > *RxLength) ++ goto err; ++ lengthCAR = RxBuffer[parsed+1]; ++ if (parsed+1+lengthCAR > *RxLength) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return_value = IFD_COMMUNICATION_ERROR; ++ goto err; ++ } ++ if (lengthCAR) ++ DEBUG_INFO_XXD("Recent Certificate Authority:\n", ++ &RxBuffer[parsed+1], ++ lengthCAR); ++ parsed += 1 + lengthCAR; ++ ++ if (parsed+1 > *RxLength) ++ goto err; ++ lengthCARprev = RxBuffer[parsed+1]; ++ if (parsed+1+lengthCARprev > *RxLength) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return_value = IFD_COMMUNICATION_ERROR; ++ goto err; ++ } ++ if (lengthCARprev) ++ DEBUG_INFO_XXD("Previous Certificate Authority:\n", ++ &RxBuffer[parsed+1], ++ lengthCARprev); ++ parsed += 1 + lengthCARprev; ++ ++ if (parsed+2 > *RxLength) ++ goto err; ++ length_IDicc = w2i(RxBuffer, parsed); ++ if (parsed+2+length_IDicc > *RxLength) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return_value = IFD_COMMUNICATION_ERROR; ++ goto err; ++ } ++ if (length_IDicc) ++ DEBUG_INFO_XXD("IDicc:\n", &RxBuffer[parsed+2], length_IDicc); ++ parsed += 2 + length_IDicc; ++ ++ if (parsed != *RxLength) { ++ DEBUG_CRITICAL2("Overrun by %d bytes", *RxLength - parsed); ++ return_value = IFD_COMMUNICATION_ERROR; ++ goto err; ++ } + +err: + ccid_descriptor -> readTimeout = old_read_timeout; @@ -210,15 +280,17 @@ Index: ccid-1.3.13/src/commands.c + } + + length = dw2i(cmd, 1); -+ if (length <= *RxLength) -+ *RxLength = length; ++ if (length + 6 <= *RxLength) ++ *RxLength = length + 6; + else + { -+ DEBUG_CRITICAL2("overrun by %d bytes", length - *RxLength); -+ length = *RxLength; ++ DEBUG_CRITICAL2("overrun by %d bytes", length + 6 - *RxLength); + return IFD_ERROR_INSUFFICIENT_BUFFER; + } -+ memcpy(RxBuffer, &cmd[10], length); ++ uint32_t s = 0x00000000; ++ memcpy(RxBuffer, &s, 4); /* "Kein Fehler" */ ++ memcpy(RxBuffer+4, &length, 2); /* lengthOutputData */ ++ memcpy(RxBuffer+6, &cmd[10], length); + + return IFD_SUCCESS; +} @@ -227,7 +299,7 @@ Index: ccid-1.3.13/src/commands.c /***************************************************************************** * * Escape -@@ -2113,3 +2256,15 @@ +@@ -2113,3 +2329,15 @@ buffer[3] = (value >> 24) & 0xFF; } /* i2dw */ @@ -279,6 +351,15 @@ Index: ccid-1.3.13/src/ccid.h /* See CCID specs ch. 4.2.1 */ #define CCID_ICC_PRESENT_ACTIVE 0x00 /* 00 0000 00 */ +@@ -227,6 +229,8 @@ + + /* convert a 4 byte integer in USB format into an int */ + #define dw2i(a, x) (unsigned int)((((((a[x+3] << 8) + a[x+2]) << 8) + a[x+1]) << 8) + a[x]) ++/* convert a 2 byte integer in USB format into an int */ ++#define w2i(a, x) (unsigned int)(((a[x+1]) << 8) + a[x]) + + /* all the data rates specified by ISO 7816-3 Fi/Di tables */ + #define ISO_DATA_RATES 10753, 14337, 15625, 17204, \ Index: ccid-1.3.13/src/ccid_ifdhandler.h =================================================================== --- ccid-1.3.13/src/ccid_ifdhandler.h (Revision 4979) diff --git a/ccid/patches/pcsclite_trunk_r4993.patch b/ccid/patches/pcsclite_trunk_r5063.patch similarity index 74% rename from ccid/patches/pcsclite_trunk_r4993.patch rename to ccid/patches/pcsclite_trunk_r5063.patch index 83306f7..ba5cfc7 100644 --- a/ccid/patches/pcsclite_trunk_r4993.patch +++ b/ccid/patches/pcsclite_trunk_r5063.patch @@ -1,6 +1,6 @@ Index: PCSC/src/PCSC/reader.h.in =================================================================== ---- PCSC/src/PCSC/reader.h.in (Revision 4993) +--- PCSC/src/PCSC/reader.h.in (Revision 5063) +++ PCSC/src/PCSC/reader.h.in (Arbeitskopie) @@ -121,6 +121,7 @@ #define FEATURE_IFD_DISPLAY_PROPERTIES 0x11 @@ -12,13 +12,13 @@ Index: PCSC/src/PCSC/reader.h.in * "IFDs with Secure Pin Entry Capabilities" */ Index: Drivers/ccid/src/ifdhandler.c =================================================================== ---- Drivers/ccid/src/ifdhandler.c (Revision 4993) +--- Drivers/ccid/src/ifdhandler.c (Revision 5063) +++ Drivers/ccid/src/ifdhandler.c (Arbeitskopie) -@@ -1384,6 +1384,16 @@ +@@ -1417,6 +1417,16 @@ iBytesReturned += sizeof(PCSC_TLV_STRUCTURE); } -+ if (ccid_descriptor -> bPINSupport & CCID_CLASS_PIN_PACE_CAPABILITIES) ++ if (get_ccid_descriptor(reader_index) -> bPINSupport & CCID_CLASS_PIN_PACE_CAPABILITIES) + { + pcsc_tlv -> tag = FEATURE_EXECUTE_PACE; + pcsc_tlv -> length = 0x04; /* always 0x04 */ @@ -31,7 +31,7 @@ Index: Drivers/ccid/src/ifdhandler.c /* We can always forward wLcdLayout */ pcsc_tlv -> tag = FEATURE_IFD_PIN_PROPERTIES; pcsc_tlv -> length = 0x04; /* always 0x04 */ -@@ -1548,6 +1558,43 @@ +@@ -1581,6 +1591,43 @@ } } @@ -77,7 +77,7 @@ Index: Drivers/ccid/src/ifdhandler.c Index: Drivers/ccid/src/commands.c =================================================================== ---- Drivers/ccid/src/commands.c (Revision 4993) +--- Drivers/ccid/src/commands.c (Revision 5063) +++ Drivers/ccid/src/commands.c (Arbeitskopie) @@ -68,7 +68,13 @@ unsigned int tx_length, unsigned char tx_buffer[], unsigned int *rx_length, @@ -93,7 +93,7 @@ Index: Drivers/ccid/src/commands.c /***************************************************************************** -@@ -712,7 +718,144 @@ +@@ -712,7 +718,217 @@ return ret; } /* SecurePINModify */ @@ -103,8 +103,10 @@ Index: Drivers/ccid/src/commands.c +{ + RESPONSECODE return_value; + unsigned char lengthCHAT, lengthPIN; -+ uint16_t lengthCertificateDescription; ++ uint16_t lengthCertificateDescription, lengthEF_CardAccess, length_IDicc; ++ uint8_t lengthCAR, lengthCARprev; + int old_read_timeout; ++ size_t parsed; + _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); + old_read_timeout= ccid_descriptor -> readTimeout; @@ -148,6 +150,74 @@ Index: Drivers/ccid/src/commands.c + /* bPINOperation: PIN PACE Capabilities */ + return_value = SecurePINPACE(reader_index, TxBuffer, TxLength, RxBuffer, + RxLength, CCID_CLASS_PIN_PACE_EXECUTE); ++ if (IFD_SUCCESS != return_value) ++ goto err; ++ ++ ++ if (6+2 > *RxLength) ++ goto err; ++ DEBUG_INFO3("MSE:Set AT Statusbytes: %02X %02X", ++ RxBuffer[6+0], RxBuffer[6+1]); ++ parsed = 6+2; ++ ++ ++ if (parsed+2 > *RxLength) ++ goto err; ++ lengthEF_CardAccess = w2i(RxBuffer, parsed); ++ if (parsed+2+lengthEF_CardAccess > *RxLength) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return_value = IFD_COMMUNICATION_ERROR; ++ goto err; ++ } ++ if (lengthEF_CardAccess) ++ DEBUG_INFO_XXD("EF.CardAccess:\n", &RxBuffer[parsed+2], lengthEF_CardAccess); ++ parsed += 2 + lengthEF_CardAccess; ++ ++ if (parsed+1 > *RxLength) ++ goto err; ++ lengthCAR = RxBuffer[parsed+1]; ++ if (parsed+1+lengthCAR > *RxLength) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return_value = IFD_COMMUNICATION_ERROR; ++ goto err; ++ } ++ if (lengthCAR) ++ DEBUG_INFO_XXD("Recent Certificate Authority:\n", ++ &RxBuffer[parsed+1], ++ lengthCAR); ++ parsed += 1 + lengthCAR; ++ ++ if (parsed+1 > *RxLength) ++ goto err; ++ lengthCARprev = RxBuffer[parsed+1]; ++ if (parsed+1+lengthCARprev > *RxLength) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return_value = IFD_COMMUNICATION_ERROR; ++ goto err; ++ } ++ if (lengthCARprev) ++ DEBUG_INFO_XXD("Previous Certificate Authority:\n", ++ &RxBuffer[parsed+1], ++ lengthCARprev); ++ parsed += 1 + lengthCARprev; ++ ++ if (parsed+2 > *RxLength) ++ goto err; ++ length_IDicc = w2i(RxBuffer, parsed); ++ if (parsed+2+length_IDicc > *RxLength) { ++ DEBUG_CRITICAL("Malformed Establish PACE Channel output data."); ++ return_value = IFD_COMMUNICATION_ERROR; ++ goto err; ++ } ++ if (length_IDicc) ++ DEBUG_INFO_XXD("IDicc:\n", &RxBuffer[parsed+2], length_IDicc); ++ parsed += 2 + length_IDicc; ++ ++ if (parsed != *RxLength) { ++ DEBUG_CRITICAL2("Overrun by %d bytes", *RxLength - parsed); ++ return_value = IFD_COMMUNICATION_ERROR; ++ goto err; ++ } + +err: + ccid_descriptor -> readTimeout = old_read_timeout; @@ -222,15 +292,17 @@ Index: Drivers/ccid/src/commands.c + } + + length = dw2i(cmd, 1); -+ if (length <= *RxLength) -+ *RxLength = length; ++ if (length + 6 <= *RxLength) ++ *RxLength = length + 6; + else + { -+ DEBUG_CRITICAL2("overrun by %d bytes", length - *RxLength); -+ length = *RxLength; ++ DEBUG_CRITICAL2("overrun by %d bytes", length + 6 - *RxLength); + return IFD_ERROR_INSUFFICIENT_BUFFER; + } -+ memcpy(RxBuffer, &cmd[10], length); ++ uint32_t s = 0x00000000; ++ memcpy(RxBuffer, &s, 4); /* "Kein Fehler" */ ++ memcpy(RxBuffer+4, &length, 2); /* lengthOutputData */ ++ memcpy(RxBuffer+6, &cmd[10], length); + + return IFD_SUCCESS; +} @@ -239,7 +311,7 @@ Index: Drivers/ccid/src/commands.c /***************************************************************************** * * Escape -@@ -2113,3 +2256,15 @@ +@@ -2113,3 +2329,15 @@ buffer[3] = (value >> 24) & 0xFF; } /* i2dw */ @@ -257,7 +329,7 @@ Index: Drivers/ccid/src/commands.c + Index: Drivers/ccid/src/commands.h =================================================================== ---- Drivers/ccid/src/commands.h (Revision 4993) +--- Drivers/ccid/src/commands.h (Revision 5063) +++ Drivers/ccid/src/commands.h (Arbeitskopie) @@ -37,6 +37,14 @@ unsigned char TxBuffer[], unsigned int TxLength, @@ -276,7 +348,7 @@ Index: Drivers/ccid/src/commands.h unsigned char RxBuffer[], unsigned int *RxLength); Index: Drivers/ccid/src/ccid.h =================================================================== ---- Drivers/ccid/src/ccid.h (Revision 4993) +--- Drivers/ccid/src/ccid.h (Revision 5063) +++ Drivers/ccid/src/ccid.h (Arbeitskopie) @@ -142,8 +142,10 @@ #define CCID_CLASS_EXCHANGE_MASK 0x00070000 @@ -291,9 +363,18 @@ Index: Drivers/ccid/src/ccid.h /* See CCID specs ch. 4.2.1 */ #define CCID_ICC_PRESENT_ACTIVE 0x00 /* 00 0000 00 */ +@@ -228,6 +230,8 @@ + + /* convert a 4 byte integer in USB format into an int */ + #define dw2i(a, x) (unsigned int)((((((a[x+3] << 8) + a[x+2]) << 8) + a[x+1]) << 8) + a[x]) ++/* convert a 2 byte integer in USB format into an int */ ++#define w2i(a, x) (unsigned int)(((a[x+1]) << 8) + a[x]) + + /* all the data rates specified by ISO 7816-3 Fi/Di tables */ + #define ISO_DATA_RATES 10753, 14337, 15625, 17204, \ Index: Drivers/ccid/src/ccid_ifdhandler.h =================================================================== ---- Drivers/ccid/src/ccid_ifdhandler.h (Revision 4993) +--- Drivers/ccid/src/ccid_ifdhandler.h (Revision 5063) +++ Drivers/ccid/src/ccid_ifdhandler.h (Arbeitskopie) @@ -37,6 +37,8 @@ SCARD_CTL_CODE(FEATURE_IFD_PIN_PROPERTIES + CLASS2_IOCTL_MAGIC)