Compare commits

...

12 commits
v2.3.0 ... main

Author SHA1 Message Date
b0157b5a66
fix(driver): introduce warning and Werror too early (#295)
* fix(driver): miswrite -Werror

* fix(driver): remove broken -Werror
2025-08-19 07:23:21 +08:00
283f081a03
chore(ci): enable -Werror in CI (#294) 2025-08-18 22:26:29 +08:00
f7fa2d912a
chore(treewide): remove -Werror and -pedantic (#293) 2025-08-18 22:22:32 +08:00
af92e5d21f
refactor(euicc): strict euicc (#288) 2025-08-18 17:18:24 +08:00
286f6e7160
refactor(src): enable -Wall -Wextra -pedantic for src/ (#287) 2025-08-18 17:07:02 +08:00
4c03199ddd
fix(driver): main entry (#286) 2025-08-17 17:55:48 +08:00
e81fc0e624
chore(driver): cleanup unused main functions (#285) 2025-08-17 17:08:03 +08:00
f73612e3bb
refactor(win32): force CP_UTF8 to get rid of all wchar use except CommandLineToArgvW (#283)
See https://learn.microsoft.com/en-us/windows/apps/design/globalizing/use-utf8-code-page

But Windows doesn't provide CommandLineToArgvA() because in non-Unicode 
codepage environment, the encoding conversion is lossy and it may case 
security issue, so they said:

> To avoid this problem, use the GetCommandLineW function to receive the 
> Unicode command line, or use an application manifest (on Windows Version 1903 
> or later) to set UTF-8 as the process code page.
> https://learn.microsoft.com/en-us/windows/win32/api/processenv/nf-processenv-getcommandlinea#security-remarks

So Windows seems provide two solutions: one for legacy encoding, another 
for modern Unicode encoding. It's great, right? No!!! Windows actually 
only provide ONE solution! They never provide CommandLineToArgvA() at all. 
So altrought I can get UTF-8 version arguments from GetCommandLineA() but 
I can convert it into argv[] with UTF-8 encoding. I must pass it into 
CommandLineToArgvW() to get UTF-16LE version argv[], and convert it into 
UTF-8 with a annoying loop and WideCharToMultiByte(). It's crazy!!!

Signed-off-by: Coelacanthus <uwu@coelacanthus.name>
2025-08-17 14:36:06 +08:00
467613c3a6
refactor(driver/pcsc): use context instead of global states (#281) 2025-08-17 00:44:32 +08:00
22dcc49329
fix(driver): workaround bool constant true/false is not bool type before C23 (#279) 2025-08-16 21:54:56 +08:00
Shua
5f941dcd88
fix(driver/at_win32): Change CP_ACP to CP_UTF8 (#282) 2025-08-16 20:29:12 +08:00
3f0156a549
chore: tidy env name (#277) 2025-08-16 01:16:07 +08:00
30 changed files with 203 additions and 170 deletions

View file

@ -8,6 +8,9 @@ on:
pull_request: pull_request:
branches: [main] branches: [main]
env:
CFLAGS: "-Werror"
jobs: jobs:
build: build:
name: Build for ${{ matrix.build.name }} name: Build for ${{ matrix.build.name }}

View file

@ -48,7 +48,7 @@ static int at_expect(char **response, const char *expected) {
while (1) { while (1) {
fgets(buffer, AT_BUFFER_SIZE, fuart); fgets(buffer, AT_BUFFER_SIZE, fuart);
buffer[strcspn(buffer, "\r\n")] = 0; buffer[strcspn(buffer, "\r\n")] = 0;
if (getenv_or_default(ENV_AT_DEBUG, false)) if (getenv_or_default(ENV_AT_DEBUG, (bool)false))
printf("AT_DEBUG: %s\n", buffer); printf("AT_DEBUG: %s\n", buffer);
if (strcmp(buffer, "ERROR") == 0) { if (strcmp(buffer, "ERROR") == 0) {
return -1; return -1;
@ -214,7 +214,7 @@ static int libapduinterface_init(struct euicc_apdu_interface *ifstruct) {
return 0; return 0;
} }
static int libapduinterface_main(const int argc, char **argv) { static int libapduinterface_main(const struct euicc_apdu_interface *ifstruct, int argc, char **argv) {
if (argc < 2) { if (argc < 2) {
fprintf(stderr, "Usage: %s <list>\n", argv[0]); fprintf(stderr, "Usage: %s <list>\n", argv[0]);
return -1; return -1;
@ -242,6 +242,6 @@ const struct euicc_driver driver_apdu_at = {
.type = DRIVER_APDU, .type = DRIVER_APDU,
.name = "at", .name = "at",
.init = (int (*)(void *))libapduinterface_init, .init = (int (*)(void *))libapduinterface_init,
.main = libapduinterface_main, .main = (int (*)(void *, int, char **))libapduinterface_main,
.fini = (void (*)(void *))libapduinterface_fini, .fini = (void (*)(void *))libapduinterface_fini,
}; };

View file

@ -35,40 +35,35 @@ static void enumerate_com_ports(cJSON *data) {
SP_DEVINFO_DATA devInfoData; SP_DEVINFO_DATA devInfoData;
DWORD i; DWORD i;
hDevInfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_PORTS, 0, 0, DIGCF_PRESENT); hDevInfo = SetupDiGetClassDevsA(&GUID_DEVCLASS_PORTS, 0, 0, DIGCF_PRESENT);
if (hDevInfo == INVALID_HANDLE_VALUE) if (hDevInfo == INVALID_HANDLE_VALUE)
return; return;
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA); devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &devInfoData); i++) { for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &devInfoData); i++) {
wchar_t portName[256] = {0}; char portName[256] = {0};
wchar_t friendlyName[256] = {0}; char friendlyName[256] = {0};
char portNameMB[256] = {0};
char friendlyNameMB[256] = {0};
DWORD size = sizeof(portName); DWORD size = sizeof(portName);
HKEY hKey = SetupDiOpenDevRegKey(hDevInfo, &devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); HKEY hKey = SetupDiOpenDevRegKey(hDevInfo, &devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
if (hKey != INVALID_HANDLE_VALUE) { if (hKey != INVALID_HANDLE_VALUE) {
DWORD type; DWORD type;
if (RegQueryValueExW(hKey, L"PortName", NULL, &type, (LPBYTE)portName, &size) != ERROR_SUCCESS if (RegQueryValueExA(hKey, "PortName", NULL, &type, (LPBYTE)portName, &size) != ERROR_SUCCESS
|| type != REG_SZ) { || type != REG_SZ) {
portName[0] = L'\0'; portName[0] = L'\0';
} }
} }
if (!SetupDiGetDeviceRegistryPropertyW(hDevInfo, &devInfoData, SPDRP_FRIENDLYNAME, NULL, (PBYTE)friendlyName, if (!SetupDiGetDeviceRegistryPropertyA(hDevInfo, &devInfoData, SPDRP_FRIENDLYNAME, NULL, (PBYTE)friendlyName,
sizeof(friendlyName), NULL)) { sizeof(friendlyName), NULL)) {
friendlyName[0] = L'\0'; friendlyName[0] = L'\0';
} }
WideCharToMultiByte(CP_ACP, 0, portName, -1, portNameMB, sizeof(portNameMB), NULL, NULL); if (starts_with(portName, "COM")) {
WideCharToMultiByte(CP_ACP, 0, friendlyName, -1, friendlyNameMB, sizeof(friendlyNameMB), NULL, NULL);
if (starts_with(portNameMB, "COM")) {
cJSON *item = cJSON_CreateObject(); cJSON *item = cJSON_CreateObject();
if (item) { if (item) {
cJSON_AddStringToObject(item, "env", portNameMB); cJSON_AddStringToObject(item, "env", portName);
cJSON_AddStringToObject(item, "name", friendlyNameMB[0] ? friendlyNameMB : portNameMB); cJSON_AddStringToObject(item, "name", friendlyName[0] ? friendlyName : portName);
cJSON_AddItemToArray(data, item); cJSON_AddItemToArray(data, item);
} else { } else {
cJSON_Delete(item); cJSON_Delete(item);
@ -125,7 +120,7 @@ static int at_expect(char **response, const char *expected) {
continue; continue;
} }
if (getenv_or_default(ENV_AT_DEBUG, false)) if (getenv_or_default(ENV_AT_DEBUG, (bool)false))
fprintf(stderr, "AT_DEBUG_RX: %s\n", line); fprintf(stderr, "AT_DEBUG_RX: %s\n", line);
if (strcmp(line, "ERROR") == 0) { if (strcmp(line, "ERROR") == 0) {
@ -155,7 +150,7 @@ end:
static int at_write_command(const char *cmd) { static int at_write_command(const char *cmd) {
DWORD bytes_written; DWORD bytes_written;
if (getenv_or_default(ENV_AT_DEBUG, false)) if (getenv_or_default(ENV_AT_DEBUG, (bool)false))
fprintf(stderr, "AT_DEBUG_TX: %s", cmd); fprintf(stderr, "AT_DEBUG_TX: %s", cmd);
if (!WriteFile(hComm, cmd, strlen(cmd), &bytes_written, NULL)) { if (!WriteFile(hComm, cmd, strlen(cmd), &bytes_written, NULL)) {
@ -171,16 +166,13 @@ static int apdu_interface_connect(struct euicc_ctx *ctx) {
logic_channel = 0; logic_channel = 0;
char dev_ascii[64]; char devname[64];
snprintf(dev_ascii, sizeof(dev_ascii), "\\\\.\\%s", device); snprintf(devname, sizeof(devname), "\\\\.\\%s", device);
wchar_t devname[64]; hComm = CreateFile(devname, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
mbstowcs(devname, dev_ascii, sizeof(devname) / sizeof(wchar_t));
hComm = CreateFileW(devname, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hComm == INVALID_HANDLE_VALUE) { if (hComm == INVALID_HANDLE_VALUE) {
fprintf(stderr, "Failed to open device: %s, error: %lu\n", dev_ascii, GetLastError()); fprintf(stderr, "Failed to open device: %s, error: %lu\n", devname, GetLastError());
return -1; return -1;
} }
@ -350,7 +342,7 @@ static int libapduinterface_init(struct euicc_apdu_interface *ifstruct) {
return 0; return 0;
} }
static int libapduinterface_main(int argc, char **argv) { static int libapduinterface_main(const struct euicc_apdu_interface *ifstruct, int argc, char **argv) {
if (argc < 2) { if (argc < 2) {
fprintf(stderr, "Usage: %s <list>\n", argv[0]); fprintf(stderr, "Usage: %s <list>\n", argv[0]);
return -1; return -1;
@ -380,6 +372,6 @@ const struct euicc_driver driver_apdu_at_win32 = {
.type = DRIVER_APDU, .type = DRIVER_APDU,
.name = "at", .name = "at",
.init = (int (*)(void *))libapduinterface_init, .init = (int (*)(void *))libapduinterface_init,
.main = libapduinterface_main, .main = (int (*)(void *, int, char **))libapduinterface_main,
.fini = (void (*)(void *))libapduinterface_fini, .fini = (void (*)(void *))libapduinterface_fini,
}; };

View file

@ -224,7 +224,7 @@ static int apdu_interface_transmit(struct euicc_ctx *ctx, uint8_t **rx, uint32_t
uint8_t tx_hex[4096] = {0}; uint8_t tx_hex[4096] = {0};
euicc_hexutil_bin2hex(tx_hex, 4096, &tx[5], tx_len - 5); euicc_hexutil_bin2hex(tx_hex, 4096, &tx[5], tx_len - 5);
if (getenv_or_default(ENV_DEBUG, false)) if (getenv_or_default(ENV_DEBUG, (bool)false))
fprintf(stderr, "APDU req: %s\n", tx_hex); fprintf(stderr, "APDU req: %s\n", tx_hex);
struct sim_apdu apdu = { struct sim_apdu apdu = {
@ -256,7 +256,7 @@ static int apdu_interface_transmit(struct euicc_ctx *ctx, uint8_t **rx, uint32_t
return -lastRadioErr; return -lastRadioErr;
} }
if (getenv_or_default(ENV_DEBUG, false)) if (getenv_or_default(ENV_DEBUG, (bool)false))
fprintf(stderr, "APDU resp: %d%d %d %s\n", lastIccIoResult.sw1, lastIccIoResult.sw2, fprintf(stderr, "APDU resp: %d%d %d %s\n", lastIccIoResult.sw1, lastIccIoResult.sw2,
lastIccIoResult.simResponse.len, lastIccIoResult.simResponse.data.str); lastIccIoResult.simResponse.len, lastIccIoResult.simResponse.data.str);
@ -291,14 +291,12 @@ static int libapduinterface_init(struct euicc_apdu_interface *ifstruct) {
return 0; return 0;
} }
static int libapduinterface_main(int argc, char **argv) { return 0; }
static void libapduinterface_fini(struct euicc_apdu_interface *ifstruct) {} static void libapduinterface_fini(struct euicc_apdu_interface *ifstruct) {}
const struct euicc_driver driver_apdu_gbinder_hidl = { const struct euicc_driver driver_apdu_gbinder_hidl = {
.type = DRIVER_APDU, .type = DRIVER_APDU,
.name = "gbinder_hidl", .name = "gbinder_hidl",
.init = (int (*)(void *))libapduinterface_init, .init = (int (*)(void *))libapduinterface_init,
.main = libapduinterface_main, .main = NULL,
.fini = (void (*)(void *))libapduinterface_fini, .fini = (void (*)(void *))libapduinterface_fini,
}; };

View file

@ -289,7 +289,7 @@ static int libapduinterface_init(struct euicc_apdu_interface *ifstruct) {
} }
mbim_priv->uim_slot = uim_slot; mbim_priv->uim_slot = uim_slot;
mbim_priv->use_proxy = getenv_or_default(ENV_USE_PROXY, false); mbim_priv->use_proxy = getenv_or_default(ENV_USE_PROXY, (bool)false);
mbim_priv->device_path = getenv_or_default(ENV_DEVICE, "/dev/cdc-wdm0"); mbim_priv->device_path = getenv_or_default(ENV_DEVICE, "/dev/cdc-wdm0");
memset(ifstruct, 0, sizeof(struct euicc_apdu_interface)); memset(ifstruct, 0, sizeof(struct euicc_apdu_interface));
@ -303,14 +303,12 @@ static int libapduinterface_init(struct euicc_apdu_interface *ifstruct) {
return 0; return 0;
} }
static int libapduinterface_main(int argc, char **argv) { return 0; }
static void libapduinterface_fini(struct euicc_apdu_interface *ifstruct) { g_free(ifstruct->userdata); } static void libapduinterface_fini(struct euicc_apdu_interface *ifstruct) { g_free(ifstruct->userdata); }
const struct euicc_driver driver_apdu_mbim = { const struct euicc_driver driver_apdu_mbim = {
.type = DRIVER_APDU, .type = DRIVER_APDU,
.name = "mbim", .name = "mbim",
.init = (int (*)(void *))libapduinterface_init, .init = (int (*)(void *))libapduinterface_init,
.main = libapduinterface_main, .main = NULL,
.fini = (void (*)(void *))libapduinterface_fini, .fini = (void (*)(void *))libapduinterface_fini,
}; };

View file

@ -17,6 +17,10 @@
# include <PCSC/wintypes.h> # include <PCSC/wintypes.h>
#endif #endif
#ifdef interface
# undef interface
#endif
#define ENV_DRV_IFID APDU_ENV_NAME(PCSC, DRV_IFID) #define ENV_DRV_IFID APDU_ENV_NAME(PCSC, DRV_IFID)
#define ENV_DRV_NAME APDU_ENV_NAME(PCSC, DRV_NAME) #define ENV_DRV_NAME APDU_ENV_NAME(PCSC, DRV_NAME)
#define ENV_DRV_IGNORE_NAME APDU_ENV_NAME(PCSC, DRV_IGNORE_NAME) #define ENV_DRV_IGNORE_NAME APDU_ENV_NAME(PCSC, DRV_IGNORE_NAME)
@ -29,9 +33,11 @@
#define APDU_CLOSELOGICCHANNEL "\x00\x70\x80\xFF\x00" #define APDU_CLOSELOGICCHANNEL "\x00\x70\x80\xFF\x00"
#define APDU_SELECT_HEADER "\x00\xA4\x04\x00\xFF" #define APDU_SELECT_HEADER "\x00\xA4\x04\x00\xFF"
static SCARDCONTEXT pcsc_ctx; struct pcsc_userdata {
static SCARDHANDLE pcsc_hCard; SCARDCONTEXT ctx;
static LPSTR pcsc_mszReaders; SCARDHANDLE hCard;
LPSTR mszReaders;
};
static void pcsc_error(const char *method, const int32_t code) { static void pcsc_error(const char *method, const int32_t code) {
fprintf(stderr, "%s failed: %08X (%s)\n", method, code, pcsc_stringify_error(code)); fprintf(stderr, "%s failed: %08X (%s)\n", method, code, pcsc_stringify_error(code));
@ -50,15 +56,14 @@ static bool is_ignored_reader_name(const char *reader) {
return false; return false;
} }
static int pcsc_ctx_open(void) { static int pcsc_ctx_open(struct pcsc_userdata *userdata) {
int ret;
DWORD dwReaders; DWORD dwReaders;
pcsc_ctx = 0; userdata->ctx = 0;
pcsc_hCard = 0; userdata->hCard = 0;
pcsc_mszReaders = NULL; userdata->mszReaders = NULL;
ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &pcsc_ctx); int ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &userdata->ctx);
if (ret != SCARD_S_SUCCESS) { if (ret != SCARD_S_SUCCESS) {
pcsc_error("SCardEstablishContext()", ret); pcsc_error("SCardEstablishContext()", ret);
return -1; return -1;
@ -66,21 +71,21 @@ static int pcsc_ctx_open(void) {
#ifdef SCARD_AUTOALLOCATE #ifdef SCARD_AUTOALLOCATE
dwReaders = SCARD_AUTOALLOCATE; dwReaders = SCARD_AUTOALLOCATE;
ret = SCardListReaders(pcsc_ctx, NULL, (LPSTR)&pcsc_mszReaders, &dwReaders); ret = SCardListReaders(userdata->ctx, NULL, (LPSTR)&userdata->mszReaders, &dwReaders);
#else #else
// macOS does not support SCARD_AUTOALLOCATE, so we need to call SCardListReaders twice. // macOS does not support SCARD_AUTOALLOCATE, so we need to call SCardListReaders twice.
// First call to get the size of the buffer, second call to get the actual data. // First call to get the size of the buffer, second call to get the actual data.
ret = SCardListReaders(pcsc_ctx, NULL, NULL, &dwReaders); ret = SCardListReaders(userdata->ctx, NULL, NULL, &dwReaders);
if (ret != SCARD_S_SUCCESS) { if (ret != SCARD_S_SUCCESS) {
pcsc_error("SCardListReaders()", ret); pcsc_error("SCardListReaders()", ret);
return -1; return -1;
} }
pcsc_mszReaders = malloc(sizeof(char) * dwReaders); userdata->mszReaders = malloc(sizeof(char) * dwReaders);
if (pcsc_mszReaders == NULL) { if (userdata->mszReaders == NULL) {
fprintf(stderr, "malloc: not enough memory\n"); fprintf(stderr, "malloc: not enough memory\n");
return -1; return -1;
} }
ret = SCardListReaders(pcsc_ctx, NULL, pcsc_mszReaders, &dwReaders); ret = SCardListReaders(userdata->ctx, NULL, userdata->mszReaders, &dwReaders);
#endif #endif
if (ret != SCARD_S_SUCCESS) { if (ret != SCARD_S_SUCCESS) {
pcsc_error("SCardListReaders()", ret); pcsc_error("SCardListReaders()", ret);
@ -90,30 +95,25 @@ static int pcsc_ctx_open(void) {
return 0; return 0;
} }
static int pcsc_iter_reader(int (*callback)(int index, const char *reader, void *userdata), void *userdata) { static int pcsc_iter_reader(struct pcsc_userdata *userdata,
int ret; int (*callback)(struct pcsc_userdata *userdata, int index, const char *reader,
LPSTR psReader; void *context),
void *context) {
psReader = pcsc_mszReaders; int index = 0;
for (int i = 0, n = 0;; i++) { LPSTR pReader = userdata->mszReaders;
char *p = pcsc_mszReaders + i; while (*pReader != '\0') {
if (*p == '\0') { const int ret = callback(userdata, index, pReader, context);
ret = callback(n, psReader, userdata);
if (ret < 0) if (ret < 0)
return -1; return -1;
if (ret > 0) if (ret > 0)
return 0; return 0;
if (*(p + 1) == '\0') { pReader += strlen(pReader) + 1;
break; index++;
}
psReader = p + 1;
n++;
}
} }
return -1; return -1;
} }
static int pcsc_open_hCard_iter(int index, const char *reader, void *userdata) { static int pcsc_open_hCard_iter(struct pcsc_userdata *userdata, const int index, const char *reader, void *context) {
DWORD dwActiveProtocol; DWORD dwActiveProtocol;
const int id = getenv_or_default(ENV_DRV_IFID, (int)-1); const int id = getenv_or_default(ENV_DRV_IFID, (int)-1);
@ -128,8 +128,8 @@ static int pcsc_open_hCard_iter(int index, const char *reader, void *userdata) {
return 0; // skip ignored reader names return 0; // skip ignored reader names
} }
const int ret = const int ret = SCardConnect(userdata->ctx, reader, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0, &userdata->hCard,
SCardConnect(pcsc_ctx, reader, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0, &pcsc_hCard, &dwActiveProtocol); &dwActiveProtocol);
if (ret != SCARD_S_SUCCESS) { if (ret != SCARD_S_SUCCESS) {
pcsc_error("SCardConnect()", ret); pcsc_error("SCardConnect()", ret);
// see <https://blog.apdu.fr/posts/2024/12/gnupg-and-pcsc-conflicts-episode-3/> // see <https://blog.apdu.fr/posts/2024/12/gnupg-and-pcsc-conflicts-episode-3/>
@ -141,36 +141,36 @@ static int pcsc_open_hCard_iter(int index, const char *reader, void *userdata) {
return 1; return 1;
} }
static int pcsc_open_hCard(void) { return pcsc_iter_reader(pcsc_open_hCard_iter, NULL); } static int pcsc_open_hCard(struct pcsc_userdata *userdata) {
return pcsc_iter_reader(userdata, pcsc_open_hCard_iter, NULL);
}
static void pcsc_close(void) { static void pcsc_close(const struct pcsc_userdata *userdata) {
if (pcsc_mszReaders) { if (userdata->mszReaders != NULL) {
// macOS does not support SCARD_AUTOALLOCATE, so we need to free the buffer manually. // macOS does not support SCARD_AUTOALLOCATE, so we need to free the buffer manually.
#ifdef SCARD_AUTOALLOCATE #ifdef SCARD_AUTOALLOCATE
SCardFreeMemory(pcsc_ctx, pcsc_mszReaders); SCardFreeMemory(userdata->ctx, userdata->mszReaders);
#else #else
// on macOS, pcsc_mszReaders is allocated by malloc() // on macOS, mszReaders is allocated by malloc()
free(pcsc_mszReaders); free(userdata->mszReaders);
#endif #endif
} }
if (pcsc_hCard) { if (userdata->hCard) {
SCardDisconnect(pcsc_hCard, SCARD_UNPOWER_CARD); SCardDisconnect(userdata->hCard, SCARD_UNPOWER_CARD);
} }
if (pcsc_ctx) { if (userdata->ctx) {
SCardReleaseContext(pcsc_ctx); SCardReleaseContext(userdata->ctx);
} }
pcsc_ctx = 0;
pcsc_hCard = 0;
pcsc_mszReaders = NULL;
} }
static int pcsc_transmit_lowlevel(uint8_t *rx, uint32_t *rx_len, const uint8_t *tx, const uint8_t tx_len) { static int pcsc_transmit_lowlevel(const struct pcsc_userdata *userdata, uint8_t *rx, uint32_t *rx_len,
const uint8_t *tx, const uint8_t tx_len) {
int ret; int ret;
DWORD rx_len_merged; DWORD rx_len_merged;
rx_len_merged = *rx_len; rx_len_merged = *rx_len;
ret = SCardTransmit(pcsc_hCard, SCARD_PCI_T0, tx, tx_len, NULL, rx, &rx_len_merged); ret = SCardTransmit(userdata->hCard, SCARD_PCI_T0, tx, tx_len, NULL, rx, &rx_len_merged);
if (ret != SCARD_S_SUCCESS) { if (ret != SCARD_S_SUCCESS) {
pcsc_error("SCardTransmit()", ret); pcsc_error("SCardTransmit()", ret);
return -1; return -1;
@ -180,7 +180,7 @@ static int pcsc_transmit_lowlevel(uint8_t *rx, uint32_t *rx_len, const uint8_t *
return 0; return 0;
} }
static void pcsc_logic_channel_close(uint8_t channel) { static void pcsc_logic_channel_close(const struct pcsc_userdata *userdata, const uint8_t channel) {
uint8_t tx[sizeof(APDU_CLOSELOGICCHANNEL) - 1]; uint8_t tx[sizeof(APDU_CLOSELOGICCHANNEL) - 1];
uint8_t rx[EUICC_INTERFACE_BUFSZ]; uint8_t rx[EUICC_INTERFACE_BUFSZ];
uint32_t rx_len; uint32_t rx_len;
@ -190,10 +190,10 @@ static void pcsc_logic_channel_close(uint8_t channel) {
rx_len = sizeof(rx); rx_len = sizeof(rx);
pcsc_transmit_lowlevel(rx, &rx_len, tx, sizeof(tx)); pcsc_transmit_lowlevel(userdata, rx, &rx_len, tx, sizeof(tx));
} }
static int pcsc_logic_channel_open(const uint8_t *aid, uint8_t aid_len) { static int pcsc_logic_channel_open(const struct pcsc_userdata *userdata, const uint8_t *aid, uint8_t aid_len) {
int channel = 0; int channel = 0;
uint8_t tx[EUICC_INTERFACE_BUFSZ]; uint8_t tx[EUICC_INTERFACE_BUFSZ];
uint8_t *tx_wptr; uint8_t *tx_wptr;
@ -205,7 +205,8 @@ static int pcsc_logic_channel_open(const uint8_t *aid, uint8_t aid_len) {
} }
rx_len = sizeof(rx); rx_len = sizeof(rx);
if (pcsc_transmit_lowlevel(rx, &rx_len, (const uint8_t *)APDU_OPENLOGICCHANNEL, sizeof(APDU_OPENLOGICCHANNEL) - 1) if (pcsc_transmit_lowlevel(userdata, rx, &rx_len, (const uint8_t *)APDU_OPENLOGICCHANNEL,
sizeof(APDU_OPENLOGICCHANNEL) - 1)
< 0) { < 0) {
goto err; goto err;
} }
@ -230,7 +231,7 @@ static int pcsc_logic_channel_open(const uint8_t *aid, uint8_t aid_len) {
tx[4] = aid_len; tx[4] = aid_len;
rx_len = sizeof(rx); rx_len = sizeof(rx);
if (pcsc_transmit_lowlevel(rx, &rx_len, tx, tx_wptr - tx) < 0) { if (pcsc_transmit_lowlevel(userdata, rx, &rx_len, tx, tx_wptr - tx) < 0) {
goto err; goto err;
} }
@ -248,31 +249,37 @@ static int pcsc_logic_channel_open(const uint8_t *aid, uint8_t aid_len) {
err: err:
if (channel) { if (channel) {
pcsc_logic_channel_close(channel); pcsc_logic_channel_close(userdata, channel);
} }
return -1; return -1;
} }
static int apdu_interface_connect(struct euicc_ctx *ctx) { static int apdu_interface_connect(struct euicc_ctx *ctx) {
struct pcsc_userdata *userdata = ctx->apdu.interface->userdata;
uint8_t rx[EUICC_INTERFACE_BUFSZ]; uint8_t rx[EUICC_INTERFACE_BUFSZ];
uint32_t rx_len; uint32_t rx_len;
if (pcsc_open_hCard() < 0) { if (pcsc_open_hCard(userdata) < 0) {
return -1; return -1;
} }
rx_len = sizeof(rx); rx_len = sizeof(rx);
pcsc_transmit_lowlevel(rx, &rx_len, (const uint8_t *)APDU_TERMINAL_CAPABILITIES, pcsc_transmit_lowlevel(userdata, rx, &rx_len, (const uint8_t *)APDU_TERMINAL_CAPABILITIES,
sizeof(APDU_TERMINAL_CAPABILITIES) - 1); sizeof(APDU_TERMINAL_CAPABILITIES) - 1);
return 0; return 0;
} }
static void apdu_interface_disconnect(struct euicc_ctx *ctx) { pcsc_close(); } static void apdu_interface_disconnect(struct euicc_ctx *ctx) {
const struct pcsc_userdata *userdata = ctx->apdu.interface->userdata;
pcsc_close(userdata);
}
static int apdu_interface_transmit(struct euicc_ctx *ctx, uint8_t **rx, uint32_t *rx_len, const uint8_t *tx, static int apdu_interface_transmit(struct euicc_ctx *ctx, uint8_t **rx, uint32_t *rx_len, const uint8_t *tx,
uint32_t tx_len) { uint32_t tx_len) {
const struct pcsc_userdata *userdata = ctx->apdu.interface->userdata;
*rx = malloc(EUICC_INTERFACE_BUFSZ); *rx = malloc(EUICC_INTERFACE_BUFSZ);
if (!*rx) { if (!*rx) {
fprintf(stderr, "SCardTransmit() RX buffer alloc failed\n"); fprintf(stderr, "SCardTransmit() RX buffer alloc failed\n");
@ -280,7 +287,7 @@ static int apdu_interface_transmit(struct euicc_ctx *ctx, uint8_t **rx, uint32_t
} }
*rx_len = EUICC_INTERFACE_BUFSZ; *rx_len = EUICC_INTERFACE_BUFSZ;
if (pcsc_transmit_lowlevel(*rx, rx_len, tx, tx_len) < 0) { if (pcsc_transmit_lowlevel(userdata, *rx, rx_len, tx, tx_len) < 0) {
free(*rx); free(*rx);
*rx_len = 0; *rx_len = 0;
return -1; return -1;
@ -290,21 +297,22 @@ static int apdu_interface_transmit(struct euicc_ctx *ctx, uint8_t **rx, uint32_t
} }
static int apdu_interface_logic_channel_open(struct euicc_ctx *ctx, const uint8_t *aid, uint8_t aid_len) { static int apdu_interface_logic_channel_open(struct euicc_ctx *ctx, const uint8_t *aid, uint8_t aid_len) {
return pcsc_logic_channel_open(aid, aid_len); const struct pcsc_userdata *userdata = ctx->apdu.interface->userdata;
return pcsc_logic_channel_open(userdata, aid, aid_len);
} }
static void apdu_interface_logic_channel_close(struct euicc_ctx *ctx, uint8_t channel) { static void apdu_interface_logic_channel_close(struct euicc_ctx *ctx, uint8_t channel) {
pcsc_logic_channel_close(channel); const struct pcsc_userdata *userdata = ctx->apdu.interface->userdata;
pcsc_logic_channel_close(userdata, channel);
} }
static int pcsc_list_iter(int index, const char *reader, void *userdata) { static int pcsc_list_iter(struct pcsc_userdata *userdata, const int index, const char *reader, void *context) {
cJSON *json = userdata; cJSON *json = context;
cJSON *jreader;
char index_str[16]; char index_str[16];
snprintf(index_str, sizeof(index_str), "%d", index); snprintf(index_str, sizeof(index_str), "%d", index);
jreader = cJSON_CreateObject(); cJSON *jreader = cJSON_CreateObject();
if (!jreader) { if (!jreader) {
return -1; return -1;
} }
@ -328,9 +336,14 @@ static int libapduinterface_init(struct euicc_apdu_interface *ifstruct) {
set_deprecated_env_name(ENV_DRV_IFID, "DRIVER_IFID"); set_deprecated_env_name(ENV_DRV_IFID, "DRIVER_IFID");
set_deprecated_env_name(ENV_DRV_NAME, "DRIVER_NAME"); set_deprecated_env_name(ENV_DRV_NAME, "DRIVER_NAME");
struct pcsc_userdata *userdata = malloc(sizeof(struct pcsc_userdata));
if (userdata == NULL)
return -1;
memset(userdata, 0, sizeof(struct pcsc_userdata));
memset(ifstruct, 0, sizeof(struct euicc_apdu_interface)); memset(ifstruct, 0, sizeof(struct euicc_apdu_interface));
if (pcsc_ctx_open() < 0) { if (pcsc_ctx_open(userdata) < 0) {
return -1; return -1;
} }
@ -339,21 +352,26 @@ static int libapduinterface_init(struct euicc_apdu_interface *ifstruct) {
ifstruct->logic_channel_open = apdu_interface_logic_channel_open; ifstruct->logic_channel_open = apdu_interface_logic_channel_open;
ifstruct->logic_channel_close = apdu_interface_logic_channel_close; ifstruct->logic_channel_close = apdu_interface_logic_channel_close;
ifstruct->transmit = apdu_interface_transmit; ifstruct->transmit = apdu_interface_transmit;
ifstruct->userdata = userdata;
return 0; return 0;
} }
static int libapduinterface_main(int argc, char **argv) { static int libapduinterface_main(const struct euicc_apdu_interface *ifstruct, int argc, char **argv) {
struct pcsc_userdata *userdata = ifstruct->userdata;
if (userdata == NULL) {
fprintf(stderr, "No userdata set\n");
return -1;
}
if (argc < 2) { if (argc < 2) {
fprintf(stderr, "Usage: %s <list>\n", argv[0]); fprintf(stderr, "Usage: %s <list>\n", argv[0]);
return -1; return -1;
} }
if (strcmp(argv[1], "list") == 0) { if (strcmp(argv[1], "list") == 0) {
cJSON *payload; cJSON *payload = cJSON_CreateObject();
cJSON *data;
payload = cJSON_CreateObject();
if (!payload) { if (!payload) {
return -1; return -1;
} }
@ -362,12 +380,12 @@ static int libapduinterface_main(int argc, char **argv) {
return -1; return -1;
} }
data = cJSON_CreateArray(); cJSON *data = cJSON_CreateArray();
if (!data) { if (!data) {
return -1; return -1;
} }
pcsc_iter_reader(pcsc_list_iter, data); pcsc_iter_reader(userdata, pcsc_list_iter, data);
if (!cJSON_AddItemToObject(payload, "data", data)) { if (!cJSON_AddItemToObject(payload, "data", data)) {
return -1; return -1;
@ -381,12 +399,15 @@ static int libapduinterface_main(int argc, char **argv) {
return 0; return 0;
} }
static void libapduinterface_fini(struct euicc_apdu_interface *ifstruct) {} static void libapduinterface_fini(const struct euicc_apdu_interface *ifstruct) {
struct pcsc_userdata *userdata = ifstruct->userdata;
free(userdata);
}
const struct euicc_driver driver_apdu_pcsc = { const struct euicc_driver driver_apdu_pcsc = {
.type = DRIVER_APDU, .type = DRIVER_APDU,
.name = "pcsc", .name = "pcsc",
.init = (int (*)(void *))libapduinterface_init, .init = (int (*)(void *))libapduinterface_init,
.main = libapduinterface_main, .main = (int (*)(void *, int, char **))libapduinterface_main,
.fini = (void (*)(void *))libapduinterface_fini, .fini = (void (*)(void *))libapduinterface_fini,
}; };

View file

@ -235,8 +235,6 @@ static int libapduinterface_init(struct euicc_apdu_interface *ifstruct) {
return 0; return 0;
} }
static int libapduinterface_main(int argc, char **argv) { return 0; }
static void libapduinterface_fini(struct euicc_apdu_interface *ifstruct) { static void libapduinterface_fini(struct euicc_apdu_interface *ifstruct) {
struct qmi_data *qmi_priv = ifstruct->userdata; struct qmi_data *qmi_priv = ifstruct->userdata;
@ -249,6 +247,6 @@ const struct euicc_driver driver_apdu_qmi = {
.type = DRIVER_APDU, .type = DRIVER_APDU,
.name = "qmi", .name = "qmi",
.init = (int (*)(void *))libapduinterface_init, .init = (int (*)(void *))libapduinterface_init,
.main = libapduinterface_main, .main = NULL,
.fini = (void (*)(void *))libapduinterface_fini, .fini = (void (*)(void *))libapduinterface_fini,
}; };

View file

@ -101,8 +101,6 @@ static int libapduinterface_init(struct euicc_apdu_interface *ifstruct) {
return 0; return 0;
} }
static int libapduinterface_main(int argc, char **argv) { return 0; }
static void libapduinterface_fini(struct euicc_apdu_interface *ifstruct) { static void libapduinterface_fini(struct euicc_apdu_interface *ifstruct) {
struct qmi_data *qmi_priv = ifstruct->userdata; struct qmi_data *qmi_priv = ifstruct->userdata;
@ -115,6 +113,6 @@ const struct euicc_driver driver_apdu_qmi_qrtr = {
.type = DRIVER_APDU, .type = DRIVER_APDU,
.name = "qmi_qrtr", .name = "qmi_qrtr",
.init = (int (*)(void *))libapduinterface_init, .init = (int (*)(void *))libapduinterface_init,
.main = libapduinterface_main, .main = NULL,
.fini = (void (*)(void *))libapduinterface_fini, .fini = (void (*)(void *))libapduinterface_fini,
}; };

View file

@ -230,14 +230,12 @@ static int libapduinterface_init(struct euicc_apdu_interface *ifstruct) {
return 0; return 0;
} }
static int libapduinterface_main(int argc, char **argv) { return 0; }
static void libapduinterface_fini(struct euicc_apdu_interface *ifstruct) {} static void libapduinterface_fini(struct euicc_apdu_interface *ifstruct) {}
const struct euicc_driver driver_apdu_stdio = { const struct euicc_driver driver_apdu_stdio = {
.type = DRIVER_APDU, .type = DRIVER_APDU,
.name = "stdio", .name = "stdio",
.init = (int (*)(void *))libapduinterface_init, .init = (int (*)(void *))libapduinterface_init,
.main = libapduinterface_main, .main = NULL,
.fini = (void (*)(void *))libapduinterface_fini, .fini = (void (*)(void *))libapduinterface_fini,
}; };

View file

@ -70,8 +70,6 @@ static const struct euicc_driver *_driver_http = NULL;
struct euicc_apdu_interface euicc_driver_interface_apdu; struct euicc_apdu_interface euicc_driver_interface_apdu;
struct euicc_http_interface euicc_driver_interface_http; struct euicc_http_interface euicc_driver_interface_http;
int (*euicc_driver_main_apdu)(int argc, char **argv) = NULL;
int (*euicc_driver_main_http)(int argc, char **argv) = NULL;
static const struct euicc_driver *find_driver(const enum euicc_driver_type type, const char *name) { static const struct euicc_driver *find_driver(const enum euicc_driver_type type, const char *name) {
for (int i = 0; drivers[i] != NULL; i++) { for (int i = 0; drivers[i] != NULL; i++) {
@ -111,8 +109,8 @@ int euicc_driver_list(int argc, char **argv) {
cJSON_AddItemToArray(http_drivers, driver_name); cJSON_AddItemToArray(http_drivers, driver_name);
} }
} }
cJSON_AddItemToObject(payload, "LPAC_APDU", apdu_drivers); cJSON_AddItemToObject(payload, ENV_APDU_DRIVER, apdu_drivers);
cJSON_AddItemToObject(payload, "LPAC_HTTP", http_drivers); cJSON_AddItemToObject(payload, ENV_HTTP_DRIVER, http_drivers);
json_print("driver", payload); json_print("driver", payload);
return 0; return 0;
@ -141,9 +139,6 @@ int euicc_driver_init(const char *apdu_driver_name, const char *http_driver_name
return -1; return -1;
} }
euicc_driver_main_apdu = _driver_apdu->main;
euicc_driver_main_http = _driver_http->main;
return 0; return 0;
} }
@ -155,3 +150,27 @@ void euicc_driver_fini() {
_driver_http->fini(&euicc_driver_interface_http); _driver_http->fini(&euicc_driver_interface_http);
} }
} }
int euicc_driver_main_apdu(const int argc, char **argv) {
if (_driver_apdu == NULL) {
fprintf(stderr, "No APDU driver found\n");
return -1;
}
if (_driver_apdu->main == NULL) {
fprintf(stderr, "The APDU driver '%s' does not support main function\n", _driver_apdu->name);
return -1;
}
return _driver_apdu->main(&euicc_driver_interface_apdu, argc, argv);
}
int euicc_driver_main_http(const int argc, char **argv) {
if (_driver_http == NULL) {
fprintf(stderr, "No HTTP driver found\n");
return -1;
}
if (_driver_http->main == NULL) {
fprintf(stderr, "The HTTP driver '%s' does not support main function\n", _driver_http->name);
return -1;
}
return _driver_http->main(&euicc_driver_interface_http, argc, argv);
}

View file

@ -7,9 +7,10 @@
extern struct euicc_apdu_interface euicc_driver_interface_apdu; extern struct euicc_apdu_interface euicc_driver_interface_apdu;
extern struct euicc_http_interface euicc_driver_interface_http; extern struct euicc_http_interface euicc_driver_interface_http;
extern int (*euicc_driver_main_apdu)(int argc, char **argv);
extern int (*euicc_driver_main_http)(int argc, char **argv);
int euicc_driver_list(int argc, char **argv); int euicc_driver_list(int argc, char **argv);
int euicc_driver_init(const char *apdu_driver_name, const char *http_driver_name); int euicc_driver_init(const char *apdu_driver_name, const char *http_driver_name);
void euicc_driver_fini(void); void euicc_driver_fini(void);
extern int euicc_driver_main_apdu(int argc, char **argv);
extern int euicc_driver_main_http(int argc, char **argv);

View file

@ -9,6 +9,6 @@ struct euicc_driver {
enum euicc_driver_type type; enum euicc_driver_type type;
const char *name; const char *name;
int (*init)(void *interface); int (*init)(void *interface);
int (*main)(int argc, char **argv); int (*main)(void *interface, int argc, char **argv);
void (*fini)(void *interface); void (*fini)(void *interface);
}; };

View file

@ -174,14 +174,12 @@ static int libhttpinterface_init(struct euicc_http_interface *ifstruct) {
return 0; return 0;
} }
static int libhttpinterface_main(int argc, char **argv) { return 0; }
static void libhttpinterface_fini(struct euicc_http_interface *ifstruct) {} static void libhttpinterface_fini(struct euicc_http_interface *ifstruct) {}
const struct euicc_driver driver_http_curl = { const struct euicc_driver driver_http_curl = {
.type = DRIVER_HTTP, .type = DRIVER_HTTP,
.name = "curl", .name = "curl",
.init = (int (*)(void *))libhttpinterface_init, .init = (int (*)(void *))libhttpinterface_init,
.main = libhttpinterface_main, .main = NULL,
.fini = (void (*)(void *))libhttpinterface_fini, .fini = (void (*)(void *))libhttpinterface_fini,
}; };

View file

@ -175,14 +175,12 @@ static int libhttpinterface_init(struct euicc_http_interface *ifstruct) {
return 0; return 0;
} }
static int libhttpinterface_main(int argc, char **argv) { return 0; }
static void libhttpinterface_fini(struct euicc_http_interface *ifstruct) {} static void libhttpinterface_fini(struct euicc_http_interface *ifstruct) {}
const struct euicc_driver driver_http_stdio = { const struct euicc_driver driver_http_stdio = {
.type = DRIVER_HTTP, .type = DRIVER_HTTP,
.name = "stdio", .name = "stdio",
.init = (int (*)(void *))libhttpinterface_init, .init = (int (*)(void *))libhttpinterface_init,
.main = libhttpinterface_main, .main = NULL,
.fini = (void (*)(void *))libhttpinterface_fini, .fini = (void (*)(void *))libhttpinterface_fini,
}; };

View file

@ -7,6 +7,7 @@ else()
endif() endif()
target_link_libraries(euicc cjson-static) target_link_libraries(euicc cjson-static)
target_include_directories(euicc PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>) target_include_directories(euicc PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
target_compile_options(euicc PRIVATE -Wall -Wextra)
if(LPAC_DYNAMIC_LIBEUICC) if(LPAC_DYNAMIC_LIBEUICC)
# Install headers # Install headers
file(GLOB ALL_HEADERS "*.h") file(GLOB ALL_HEADERS "*.h")

View file

@ -255,7 +255,7 @@ long euicc_derutil_convert_bin2long(const uint8_t *buffer, uint32_t buffer_len)
int euicc_derutil_convert_long2bin(uint8_t *buffer, uint32_t *buffer_len, long value) { int euicc_derutil_convert_long2bin(uint8_t *buffer, uint32_t *buffer_len, long value) {
uint8_t required_len = 1; uint8_t required_len = 1;
for (int i = 1; i < sizeof(value); i++) { for (size_t i = 1; i < sizeof(value); i++) {
if ((value >> (i * 8))) { if ((value >> (i * 8))) {
required_len++; required_len++;
} else { } else {

View file

@ -256,7 +256,7 @@ int es9p_initiate_authentication_r(struct euicc_ctx *ctx, char **transaction_id,
struct es10b_authenticate_server_param *resp, const char *server_address, struct es10b_authenticate_server_param *resp, const char *server_address,
const char *b64_euicc_challenge, const char *b64_euicc_info_1) { const char *b64_euicc_challenge, const char *b64_euicc_info_1) {
const char *ikey[] = {"smdpAddress", "euiccChallenge", "euiccInfo1", NULL}; const char *ikey[] = {"smdpAddress", "euiccChallenge", "euiccInfo1", NULL};
const char *idata[] = {ctx->http.server_address, b64_euicc_challenge, b64_euicc_info_1, NULL}; const char *idata[] = {server_address, b64_euicc_challenge, b64_euicc_info_1, NULL};
const char *okey[] = {"transactionId", "serverSigned1", "serverSignature1", const char *okey[] = {"transactionId", "serverSigned1", "serverSignature1",
"euiccCiPKIdToBeUsed", "serverCertificate", NULL}; "euiccCiPKIdToBeUsed", "serverCertificate", NULL};
const char oobj[] = {0, 0, 0, 0, 0}; const char oobj[] = {0, 0, 0, 0, 0};
@ -267,8 +267,8 @@ int es9p_initiate_authentication_r(struct euicc_ctx *ctx, char **transaction_id,
(void **)&resp->b64_serverCertificate, (void **)&resp->b64_serverCertificate,
NULL}; NULL};
if (es9p_trans_json(ctx, ctx->http.server_address, "/gsma/rsp2/es9plus/initiateAuthentication", ikey, idata, okey, if (es9p_trans_json(ctx, server_address, "/gsma/rsp2/es9plus/initiateAuthentication", ikey, idata, okey, oobj,
oobj, optr)) { optr)) {
return -1; return -1;
} }
@ -289,8 +289,8 @@ int es9p_get_bound_profile_package_r(struct euicc_ctx *ctx, char **b64_bound_pro
const char oobj[] = {0}; const char oobj[] = {0};
void **optr[] = {(void **)b64_bound_profile_package, NULL}; void **optr[] = {(void **)b64_bound_profile_package, NULL};
if (es9p_trans_json(ctx, ctx->http.server_address, "/gsma/rsp2/es9plus/getBoundProfilePackage", ikey, idata, okey, if (es9p_trans_json(ctx, server_address, "/gsma/rsp2/es9plus/getBoundProfilePackage", ikey, idata, okey, oobj,
oobj, optr)) { optr)) {
return -1; return -1;
} }
@ -309,8 +309,7 @@ int es9p_authenticate_client_r(struct euicc_ctx *ctx, struct es10b_prepare_downl
void **optr[] = {(void **)&resp->b64_profileMetadata, (void **)&resp->b64_smdpSigned2, void **optr[] = {(void **)&resp->b64_profileMetadata, (void **)&resp->b64_smdpSigned2,
(void **)&resp->b64_smdpSignature2, (void **)&resp->b64_smdpCertificate, NULL}; (void **)&resp->b64_smdpSignature2, (void **)&resp->b64_smdpCertificate, NULL};
if (es9p_trans_json(ctx, ctx->http.server_address, "/gsma/rsp2/es9plus/authenticateClient", ikey, idata, okey, oobj, if (es9p_trans_json(ctx, server_address, "/gsma/rsp2/es9plus/authenticateClient", ikey, idata, okey, oobj, optr)) {
optr)) {
return -1; return -1;
} }
@ -327,8 +326,7 @@ int es9p_cancel_session_r(struct euicc_ctx *ctx, const char *server_address, con
const char *ikey[] = {"transactionId", "cancelSessionResponse", NULL}; const char *ikey[] = {"transactionId", "cancelSessionResponse", NULL};
const char *idata[] = {transaction_id, b64_cancel_session_response, NULL}; const char *idata[] = {transaction_id, b64_cancel_session_response, NULL};
if (es9p_trans_json(ctx, ctx->http.server_address, "/gsma/rsp2/es9plus/cancelSession", ikey, idata, NULL, NULL, if (es9p_trans_json(ctx, server_address, "/gsma/rsp2/es9plus/cancelSession", ikey, idata, NULL, NULL, NULL)) {
NULL)) {
return -1; return -1;
} }
@ -346,8 +344,7 @@ int es11_authenticate_client_r(struct euicc_ctx *ctx, char ***smdp_list, const c
const char oobj[] = {1}; const char oobj[] = {1};
void **optr[] = {(void **)&j_eventEntries, NULL}; void **optr[] = {(void **)&j_eventEntries, NULL};
if (es9p_trans_json(ctx, ctx->http.server_address, "/gsma/rsp2/es9plus/authenticateClient", ikey, idata, okey, oobj, if (es9p_trans_json(ctx, server_address, "/gsma/rsp2/es9plus/authenticateClient", ikey, idata, okey, oobj, optr)) {
optr)) {
return -1; return -1;
} }

View file

@ -59,7 +59,7 @@ static const struct es9p_error es9p_errors[] = {
const char *es9p_error_message(const char *subject_code, const char *reason_code) { const char *es9p_error_message(const char *subject_code, const char *reason_code) {
struct es9p_error error; struct es9p_error error;
for (int i = 0; i < sizeof(es9p_errors) / sizeof(es9p_errors[0]); i++) { for (size_t i = 0; i < sizeof(es9p_errors) / sizeof(es9p_errors[0]); i++) {
error = es9p_errors[i]; error = es9p_errors[i];
if (strcmp(error.subject_code, subject_code) == 0 && strcmp(error.reason_code, reason_code) == 0) { if (strcmp(error.subject_code, subject_code) == 0 && strcmp(error.reason_code, reason_code) == 0) {
return error.description; return error.description;

View file

@ -125,13 +125,13 @@ int euicc_hexutil_bin2gsmbcd(char *output, uint32_t output_len, const uint8_t *b
} }
length = strlen(output); length = strlen(output);
for (int i = 0; i < length - 1; i += 2) { for (size_t i = 0; i < length - 1; i += 2) {
char temp = output[i]; char temp = output[i];
output[i] = output[i + 1]; output[i] = output[i + 1];
output[i + 1] = temp; output[i + 1] = temp;
} }
for (int i = length - 1; i >= 0; i--) { for (uint32_t i = length - 1; i > 0; i--) {
if (output[i] != 'f') { if (output[i] != 'f') {
break; break;
} }

View file

@ -11,9 +11,10 @@ aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/applet/chip DIR_LPAC_SRCS)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/applet/notification DIR_LPAC_SRCS) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/applet/notification DIR_LPAC_SRCS)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/applet/profile DIR_LPAC_SRCS) aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/applet/profile DIR_LPAC_SRCS)
add_executable(lpac ${DIR_LPAC_SRCS}) add_executable(lpac ${DIR_LPAC_SRCS} lpac.manifest)
target_link_libraries(lpac euicc-drivers lpac-utils) target_link_libraries(lpac euicc-drivers lpac-utils)
target_include_directories(lpac PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>) target_include_directories(lpac PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
target_compile_options(lpac PRIVATE -Wall -Wextra)
find_package(Git) find_package(Git)
add_custom_target(version add_custom_target(version

View file

@ -12,7 +12,7 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
static int applet_main(int argc, char **argv) { static int applet_main(__attribute__((unused)) int argc, __attribute__((unused)) char **argv) {
_cleanup_free_ char *eid = NULL; _cleanup_free_ char *eid = NULL;
_cleanup_(es10a_euicc_configured_addresses_free) struct es10a_euicc_configured_addresses addresses; _cleanup_(es10a_euicc_configured_addresses_free) struct es10a_euicc_configured_addresses addresses;
_cleanup_es10b_rat_list_ struct es10b_rat *ratList; _cleanup_es10b_rat_list_ struct es10b_rat *ratList;

View file

@ -10,7 +10,7 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
static int applet_main(int argc, char **argv) { static int applet_main(__attribute__((unused)) int argc, __attribute__((unused)) char **argv) {
_cleanup_es10b_notification_metadata_list_ struct es10b_notification_metadata_list *notifications, *rptr; _cleanup_es10b_notification_metadata_list_ struct es10b_notification_metadata_list *notifications, *rptr;
cJSON *jdata = NULL; cJSON *jdata = NULL;

View file

@ -75,7 +75,7 @@ static int handle_notification(const uint32_t seqNumber, const struct es10b_pend
return 0; return 0;
} }
static int applet_main(const int argc, char **argv) { static int applet_main(__attribute__((unused)) const int argc, __attribute__((unused)) char **argv) {
if (isatty(fileno(stdin))) { if (isatty(fileno(stdin))) {
jprint_error("This applet must be run with input redirection from a file or pipe.", NULL); jprint_error("This applet must be run with input redirection from a file or pipe.", NULL);
return -1; return -1;

View file

@ -43,7 +43,7 @@ char *strsep(char **stringp, const char *__delim) {
static bool is_strict_matching_id(const char *token) { static bool is_strict_matching_id(const char *token) {
const size_t n = strlen(token); const size_t n = strlen(token);
for (int i = 0; i < n; i++) { for (size_t i = 0; i < n; i++) {
if (isalnum(token[i]) || token[i] == '-') if (isalnum(token[i]) || token[i] == '-')
continue; continue;
return false; return false;
@ -51,7 +51,7 @@ static bool is_strict_matching_id(const char *token) {
return true; return true;
} }
static void sigint_handler(int x) { cancelled = 1; } static void sigint_handler(__attribute__((unused)) int x) { cancelled = 1; }
static cJSON *build_download_result_json(const struct es10b_load_bound_profile_package_result *result) { static cJSON *build_download_result_json(const struct es10b_load_bound_profile_package_result *result) {
cJSON *jdata = cJSON_CreateObject(); cJSON *jdata = cJSON_CreateObject();

View file

@ -10,7 +10,7 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
static int applet_main(int argc, char **argv) { static int applet_main(__attribute__((unused)) int argc, __attribute__((unused)) char **argv) {
_cleanup_es10c_profile_info_list_ struct es10c_profile_info_list *profiles; _cleanup_es10c_profile_info_list_ struct es10c_profile_info_list *profiles;
struct es10c_profile_info_list *rptr; struct es10c_profile_info_list *rptr;
cJSON *jdata = NULL; cJSON *jdata = NULL;

View file

@ -5,7 +5,7 @@
# define LPAC_VERSION "v0.0.0-unknown" # define LPAC_VERSION "v0.0.0-unknown"
#endif #endif
static int applet_main(int argc, char **argv) { static int applet_main(__attribute__((unused)) int argc, __attribute__((unused)) char **argv) {
jprint_success(cJSON_CreateString(LPAC_VERSION)); jprint_success(cJSON_CreateString(LPAC_VERSION));
return 0; return 0;
} }

9
src/lpac.manifest Normal file
View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity type="win32" name="me.estk.lpac" version="6.0.0.0"/>
<application>
<windowsSettings>
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
</windowsSettings>
</application>
</assembly>

View file

@ -15,6 +15,7 @@
#include <driver.h> #include <driver.h>
#include <euicc/euicc.h> #include <euicc/euicc.h>
#include <euicc/hexutil.h> #include <euicc/hexutil.h>
#include <lpac/utils.h>
#ifdef WIN32 #ifdef WIN32
# include <windef.h> # include <windef.h>
@ -25,16 +26,13 @@
# include <stringapiset.h> # include <stringapiset.h>
#endif #endif
#define ENV_ISD_R_AID "LPAC_CUSTOM_ISD_R_AID" #define ENV_ISD_R_AID CUSTOM_ENV_NAME(ISD_R_AID)
#define ISD_R_AID_MAX_LENGTH 16 #define ISD_R_AID_MAX_LENGTH 16
#define ENV_ES10X_MSS "LPAC_CUSTOM_ES10X_MSS" #define ENV_ES10X_MSS CUSTOM_ENV_NAME(ES10X_MSS)
#define ES10X_MSS_MIN_VALUE 6 #define ES10X_MSS_MIN_VALUE 6
#define ES10X_MSS_MAX_VALUE 255 #define ES10X_MSS_MAX_VALUE 255
#define ENV_APDU_DRIVER "LPAC_APDU"
#define ENV_HTTP_DRIVER "LPAC_HTTP"
static int driver_applet_main(const int argc, char **argv) { static int driver_applet_main(const int argc, char **argv) {
const struct applet_entry *applets[] = { const struct applet_entry *applets[] = {
&(struct applet_entry){ &(struct applet_entry){
@ -103,7 +101,7 @@ static int setup_mss(uint8_t *mss) {
return 0; return 0;
} }
int main_init_euicc() { int main_init_euicc(void) {
if (setup_aid(&euicc_ctx.aid, &euicc_ctx.aid_len)) { if (setup_aid(&euicc_ctx.aid, &euicc_ctx.aid_len)) {
jprint_error("euicc_init", "invalid custom ISD-R applet id given"); jprint_error("euicc_init", "invalid custom ISD-R applet id given");
return -1; return -1;
@ -120,7 +118,7 @@ int main_init_euicc() {
return 0; return 0;
} }
void main_fini_euicc() { void main_fini_euicc(void) {
if (!euicc_ctx_inited) { if (!euicc_ctx_inited) {
return; return;
} }

View file

@ -1,3 +1,4 @@
add_library(lpac-utils OBJECT lpac/utils.c) add_library(lpac-utils OBJECT lpac/utils.c)
target_include_directories(lpac-utils PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) target_include_directories(lpac-utils PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(lpac-utils PRIVATE cjson-static euicc) target_link_libraries(lpac-utils PRIVATE cjson-static euicc)
target_compile_options(lpac-utils PRIVATE -Wall -Wextra)

View file

@ -8,8 +8,12 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
#define HTTP_ENV_NAME(DRIVER, NAME) "LPAC_HTTP_" #DRIVER "_" #NAME #define ENV_HTTP_DRIVER "LPAC_HTTP"
#define APDU_ENV_NAME(DRIVER, NAME) "LPAC_APDU_" #DRIVER "_" #NAME #define ENV_APDU_DRIVER "LPAC_APDU"
#define HTTP_ENV_NAME(DRIVER, NAME) ENV_HTTP_DRIVER "_" #DRIVER "_" #NAME
#define APDU_ENV_NAME(DRIVER, NAME) ENV_APDU_DRIVER "_" #DRIVER "_" #NAME
#define CUSTOM_ENV_NAME(NAME) "LPAC_CUSTOM_" #NAME
#define _cleanup_(x) __attribute__((cleanup(x))) #define _cleanup_(x) __attribute__((cleanup(x)))