Skip to content

Commit

Permalink
Implement PC/SC compatibility helpers for non-PCSCLite builds
Browse files Browse the repository at this point in the history
Linux and MacOS are both supported by pcsc-lite, but unfortunately there
is no pcsc-lite package for MSYS2 and Windows does not provide the
reader.h header.
  • Loading branch information
leonlynch committed Apr 20, 2024
1 parent ab3e72f commit 678dd75
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 20 deletions.
31 changes: 11 additions & 20 deletions src/pcsc.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@
#include "pcsc.h"

#include <winscard.h>
#ifdef USE_PCSCLITE
// Only PCSCLite provides reader.h
#include <reader.h>
#endif
// Compatibility helpers must not conflict with winscard.h or reader.h
#include "pcsc_compat.h"

#include <stdbool.h>
#include <stdint.h>
Expand All @@ -37,16 +42,6 @@
#include <winsock.h>
#endif

#ifndef USE_PCSCLITE
// Only PCSCLite provides pcsc_stringify_error()
static const char* pcsc_stringify_error(unsigned int result)
{
static char str[16];
snprintf(str, sizeof(str), "0x%08X", result);
return str;
}
#endif

struct pcsc_t {
SCARDCONTEXT context;

Expand All @@ -60,23 +55,19 @@ struct pcsc_t {

struct pcsc_reader_features_t {
// Populated by SCardControl(CM_IOCTL_GET_FEATURE_REQUEST)
uint8_t buf[MAX_BUFFER_SIZE];
uint8_t buf[PCSC_MAX_BUFFER_SIZE];
DWORD buf_len;

// Populated by SCardControl(IFD_PIN_PROPERTIES)
PIN_PROPERTIES_STRUCTURE pin_properties;
DWORD pin_properties_len;

// Populated by SCardControl(IFD_DISPLAY_PROPERTIES)
struct {
uint16_t wLcdMaxCharacters;
uint16_t wLcdMaxLines;
} __attribute__((packed))
display_properties;
DISPLAY_PROPERTIES_STRUCTURE display_properties;
DWORD display_properties_len;

// Populated by SCardControl(GET_TLV_PROPERTIES)
uint8_t properties[MAX_BUFFER_SIZE];
uint8_t properties[PCSC_MAX_BUFFER_SIZE];
DWORD properties_len;
};

Expand Down Expand Up @@ -248,7 +239,7 @@ static int pcsc_reader_populate_features(struct pcsc_reader_t* reader)
++pcsc_tlv;
}

r = pcsc_reader_get_feature(reader, FEATURE_IFD_PIN_PROPERTIES, &control_code);
r = pcsc_reader_get_feature(reader, PCSC_FEATURE_IFD_PIN_PROPERTIES, &control_code);
if (r < 0) {
r = -6;
goto exit;
Expand Down Expand Up @@ -277,7 +268,7 @@ static int pcsc_reader_populate_features(struct pcsc_reader_t* reader)
}
}

r = pcsc_reader_get_feature(reader, FEATURE_IFD_DISPLAY_PROPERTIES, &control_code);
r = pcsc_reader_get_feature(reader, PCSC_FEATURE_IFD_DISPLAY_PROPERTIES, &control_code);
if (r < 0) {
r = -9;
goto exit;
Expand Down Expand Up @@ -306,7 +297,7 @@ static int pcsc_reader_populate_features(struct pcsc_reader_t* reader)
}
}

r = pcsc_reader_get_feature(reader, FEATURE_GET_TLV_PROPERTIES, &control_code);
r = pcsc_reader_get_feature(reader, PCSC_FEATURE_GET_TLV_PROPERTIES, &control_code);
if (r < 0) {
r = -12;
goto exit;
Expand Down
92 changes: 92 additions & 0 deletions src/pcsc_compat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* @file pcsc_compat.h
* @brief PC/SC compatibility helpers
*
* Copyright (c) 2024 Leon Lynch
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/

#ifndef PCSC_COMPAT_H
#define PCSC_COMPAT_H

#include <sys/cdefs.h>
#include <stdint.h>
#include <stdio.h>

__BEGIN_DECLS

#if !defined(SCARD_CTL_CODE) && defined(CTL_CODE)
// Not all implementations define SCARD_CTL_CODE but it can be derived
// from CTL_CODE when available
#define SCARD_CTL_CODE(code) CTL_CODE(FILE_DEVICE_SMARTCARD, (code), METHOD_BUFFERED, FILE_ANY_ACCESS)
#endif

// See PC/SC Part 10 Rev 2.02.09, 2.2
#ifndef CM_IOCTL_GET_FEATURE_REQUEST
#define CM_IOCTL_GET_FEATURE_REQUEST SCARD_CTL_CODE(3400)
#endif

// See PC/SC Part 10 Rev 2.02.09, 2.3
#define PCSC_FEATURE_IFD_PIN_PROPERTIES (0x0A) ///< Interface Device (IFD) PIN handling properties
#define PCSC_FEATURE_IFD_DISPLAY_PROPERTIES (0x11) ///< Interface Device (IFD) display properties
#define PCSC_FEATURE_GET_TLV_PROPERTIES (0x12) ///< Interface Device (IFD) properties in Tag-Length-Value (TLV) form

#ifdef USE_PCSCLITE

#define PCSC_MAX_BUFFER_SIZE (MAX_BUFFER_SIZE)

#else // !USE_PCSCLITE

#define PCSC_MAX_BUFFER_SIZE (264)

// See PC/SC Part 10 Rev 2.02.09, 2.2
typedef struct
{
uint8_t tag;
uint8_t length;
uint32_t value;
} __attribute__((packed))
PCSC_TLV_STRUCTURE;

// See PC/SC Part 10 Rev 2.02.09, 2.6.8
typedef struct {
uint16_t wLcdLayout;
uint8_t bEntryValidationCondition;
uint8_t bTimeOut2;
} __attribute__((packed))
PIN_PROPERTIES_STRUCTURE;

// Only PCSCLite provides pcsc_stringify_error()
static const char* pcsc_stringify_error(unsigned int result)
{
static char str[16];
snprintf(str, sizeof(str), "0x%08X", result);
return str;
}

#endif // USE_PCSCLITE

// PCSCLite does not provide DISPLAY_PROPERTIES_STRUCTURE
// See PC/SC Part 10 Rev 2.02.09, 2.6.9
typedef struct {
uint16_t wLcdMaxCharacters;
uint16_t wLcdMaxLines;
} __attribute__((packed))
DISPLAY_PROPERTIES_STRUCTURE;

__END_DECLS

#endif

0 comments on commit 678dd75

Please sign in to comment.