[WIP] remove dlfcn interface driver (curl on Windows still require dlfcn)

This commit is contained in:
estkme 2024-03-20 13:51:58 +08:00
parent 4095ab5a15
commit 96f47f2d52
26 changed files with 499 additions and 644 deletions

View file

@ -1,4 +1,5 @@
cmake_minimum_required (VERSION 3.8)
project (lpac
VERSION 1.0.1
HOMEPAGE_URL "https://github.com/estkme-group/lpac"
@ -13,10 +14,6 @@ if (APPLE)
set(CMAKE_OSX_ARCHITECTURES "arm64;x86_64")
endif()
if(CYGWIN)
add_definitions(-DHAVE_TIMEGM=1)
endif()
if(UNIX)
include(GNUInstallDirs)
if(NOT CMAKE_INSTALL_RPATH)
@ -24,6 +21,13 @@ if(UNIX)
endif()
endif()
if(WIN32)
add_subdirectory(dlfcn-win32)
set(DL_LIBRARY dlfcn-win32)
else()
set(DL_LIBRARY dl)
endif()
if(CPACK_GENERATOR)
set(CPACK_PACKAGE_VENDOR "eSTK.me Group")
@ -31,20 +35,13 @@ if(CPACK_GENERATOR)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc")
set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "libcurl, libpcsclite, pcscd")
set(CPACK_RPM_PACKAGE_LICENSE "AGPL-3.0-only AND LGPL-2.0-only AND MIT")
set(CPACK_RPM_PACKAGE_LICENSE "AGPL-3.0-only AND LGPL-2.0-only")
set(CPACK_RPM_PACKAGE_AUTOREQ "yes")
set(CPACK_RPM_PACKAGE_REQUIRES "libcurl, libpcsclite, pcscd")
include(CPack)
endif()
if(MINGW)
add_subdirectory(dlfcn-win32)
set(DL_LIBRARY dlfcn-win32)
else()
set(DL_LIBRARY dl)
endif()
add_subdirectory(cjson)
add_subdirectory(euicc)
add_subdirectory(interface)
add_subdirectory(src)

View file

@ -489,6 +489,5 @@ A: The verification of SM-DP+ servers of telecom operators is diverse. Please ch
- lpac (/src): AGPL-3.0
- libeuicc (/euicc): LGPL-v2
- interfaces (/interface): MIT
Copyright (c) 2023-2024 eSTKme Group

View file

@ -1,12 +1,6 @@
#pragma once
#include <inttypes.h>
#ifdef __MINGW32__
#define EUICC_SHARED_EXPORT __declspec(dllexport) __cdecl
#else
#define EUICC_SHARED_EXPORT
#endif
struct euicc_ctx;
struct euicc_apdu_interface

View file

@ -1,2 +0,0 @@
add_subdirectory(apdu)
add_subdirectory(http)

View file

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2023 estkme-group
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,188 +0,0 @@
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __MINGW32__
#include <dlfcn-win32/dlfcn.h>
#else
#include <dlfcn.h>
#endif
#include <euicc/interface.h>
/* BEGIN MINIMAL CURL DEFINE */
#if defined (_WIN32) || defined (__CYGWIN__)
#define LIBCURL_DEFAULT_PATH "libcurl.dll"
#elif defined(__APPLE__)
#define LIBCURL_DEFAULT_PATH "libcurl.4.dylib"
#else
#define LIBCURL_DEFAULT_PATH "libcurl.so.4"
#endif
#define CURL_GLOBAL_DEFAULT ((1 << 0) | (1 << 1))
#define CURLE_OK 0
#define CURLOPT_URL 10002
#define CURLOPT_WRITEFUNCTION 20011
#define CURLOPT_WRITEDATA 10001
#define CURLOPT_SSL_VERIFYPEER 64
#define CURLOPT_SSL_VERIFYHOST 81
#define CURLOPT_HTTPHEADER 10023
#define CURLOPT_POSTFIELDS 10015
#define CURLOPT_POSTFIELDSIZE 60
#define CURLINFO_RESPONSE_CODE 2097154
typedef void CURL;
typedef int CURLcode;
typedef int CURLoption;
typedef int CURLINFO;
static void *libcurl_interface_dlhandle = NULL;
static struct libcurl_interface
{
CURLcode (*curl_global_init)(long flags);
CURL *(*curl_easy_init)(void);
CURLcode (*curl_easy_setopt)(CURL *curl, CURLoption option, ...);
CURLcode (*curl_easy_perform)(CURL *curl);
CURLcode (*curl_easy_getinfo)(CURL *curl, CURLINFO info, ...);
const char *(*curl_easy_strerror)(CURLcode);
void (*curl_easy_cleanup)(CURL *curl);
struct curl_slist *(*curl_slist_append)(struct curl_slist *list, const char *data);
void (*curl_slist_free_all)(struct curl_slist *list);
} libcurl;
/* END MINIMAL CURL DEFINE */
struct http_trans_response_data
{
uint8_t *data;
size_t size;
};
static size_t http_trans_write_callback(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct http_trans_response_data *mem = (struct http_trans_response_data *)userp;
mem->data = realloc(mem->data, mem->size + realsize + 1);
if (mem->data == NULL)
{
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
memcpy(&(mem->data[mem->size]), contents, realsize);
mem->size += realsize;
mem->data[mem->size] = 0;
return realsize;
}
static int http_interface_transmit(struct euicc_ctx *ctx, const char *url, uint32_t *rcode, uint8_t **rx, uint32_t *rx_len, const uint8_t *tx, uint32_t tx_len, const char **h)
{
int fret = 0;
CURL *curl;
CURLcode res;
struct http_trans_response_data responseData = {0};
struct curl_slist *headers = NULL, *nheaders = NULL;
long response_code;
(*rx) = NULL;
(*rcode) = 0;
curl = libcurl.curl_easy_init();
if (!curl)
{
goto err;
}
libcurl.curl_easy_setopt(curl, CURLOPT_URL, url);
libcurl.curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_trans_write_callback);
libcurl.curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&responseData);
libcurl.curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
libcurl.curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
for (int i = 0; h[i] != NULL; i++)
{
nheaders = libcurl.curl_slist_append(headers, h[i]);
if (nheaders == NULL)
{
goto err;
}
headers = nheaders;
}
libcurl.curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
if (tx != NULL)
{
libcurl.curl_easy_setopt(curl, CURLOPT_POSTFIELDS, tx);
libcurl.curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, tx_len);
}
res = libcurl.curl_easy_perform(curl);
if (res != CURLE_OK)
{
fprintf(stderr, "curl_easy_perform() failed: %s\n", libcurl.curl_easy_strerror(res));
goto err;
}
libcurl.curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
*rcode = response_code;
*rx = responseData.data;
*rx_len = responseData.size;
fret = 0;
goto exit;
err:
fret = -1;
free(responseData.data);
exit:
libcurl.curl_easy_cleanup(curl);
libcurl.curl_slist_free_all(headers);
return fret;
}
EUICC_SHARED_EXPORT int libhttpinterface_init(struct euicc_http_interface *ifstruct)
{
const char *libcurl_path;
memset(ifstruct, 0, sizeof(struct euicc_http_interface));
if (!(libcurl_path = getenv("LIBCURL")))
{
libcurl_path = LIBCURL_DEFAULT_PATH;
}
if (!(libcurl_interface_dlhandle = dlopen(libcurl_path, RTLD_LAZY)))
{
fprintf(stderr, "libcurl env missing, current: LIBCURL=%s err:%s\n", libcurl_path, dlerror());
return -1;
}
libcurl.curl_global_init = dlsym(libcurl_interface_dlhandle, "curl_global_init");
libcurl.curl_easy_init = dlsym(libcurl_interface_dlhandle, "curl_easy_init");
libcurl.curl_easy_setopt = dlsym(libcurl_interface_dlhandle, "curl_easy_setopt");
libcurl.curl_easy_perform = dlsym(libcurl_interface_dlhandle, "curl_easy_perform");
libcurl.curl_easy_getinfo = dlsym(libcurl_interface_dlhandle, "curl_easy_getinfo");
libcurl.curl_easy_strerror = dlsym(libcurl_interface_dlhandle, "curl_easy_strerror");
libcurl.curl_easy_cleanup = dlsym(libcurl_interface_dlhandle, "curl_easy_cleanup");
libcurl.curl_slist_append = dlsym(libcurl_interface_dlhandle, "curl_slist_append");
libcurl.curl_slist_free_all = dlsym(libcurl_interface_dlhandle, "curl_slist_free_all");
if (libcurl.curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK)
{
return -1;
}
ifstruct->transmit = http_interface_transmit;
return 0;
}
EUICC_SHARED_EXPORT int libhttpinterface_main(int argc, char **argv)
{
return 0;
}

View file

@ -5,16 +5,25 @@ else()
endif()
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} DIR_LPAC_SRCS)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/applet DIR_LPAC_SRCS)
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/profile DIR_LPAC_SRCS)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/driver DIR_LPAC_SRCS)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/driver/apdu DIR_LPAC_SRCS)
aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/driver/http DIR_LPAC_SRCS)
find_package(PCSCLite)
find_package(curl)
add_executable(lpac ${DIR_LPAC_SRCS})
set_target_properties(lpac PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/output"
BUILD_RPATH "${RPATH_BINARY_PATH}"
)
target_link_libraries(lpac euicc ${DL_LIBRARY})
target_link_libraries(lpac euicc PCSCLite::PCSCLite curl ${DL_LIBRARY})
target_include_directories(lpac PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
find_package(Git)

View file

@ -1,144 +0,0 @@
#include "dlsym_interface.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#ifdef __MINGW32__
#include <dlfcn-win32/dlfcn.h>
#else
#include <dlfcn.h>
#endif
#if defined (_WIN32) || defined (__CYGWIN__)
#define INTERFACELIB_EXTENSION "dll"
#elif defined(__APPLE__)
#define INTERFACELIB_EXTENSION "dylib"
#else
#define INTERFACELIB_EXTENSION "so"
#endif
static struct applet_entry applet_apdu = {
.name = "apdu",
.main = NULL,
};
static struct applet_entry applet_http = {
.name = "http",
.main = NULL,
};
static const struct applet_entry *applets[] = {
&applet_apdu,
&applet_http,
NULL,
};
static const char *libapduinterface_path = NULL;
static void *apdu_interface_dlhandle = NULL;
struct euicc_apdu_interface dlsym_apdu_interface = {0};
static int (*libapduinterface_init)(struct euicc_apdu_interface *ifstruct) = NULL;
static int (*libapduinterface_main)(int argc, char **argv) = NULL;
static const char *libhttpinterface_path = NULL;
static void *http_interface_dlhandle = NULL;
struct euicc_http_interface dlsym_http_interface = {0};
static int (*libhttpinterface_init)(struct euicc_http_interface *ifstruct) = NULL;
static int (*libhttpinterface_main)(int argc, char **argv) = NULL;
static void dlsym_interfaces_get_path(void)
{
if (!(libapduinterface_path = getenv("APDU_INTERFACE")))
{
libapduinterface_path = "libapduinterface_pcsc." INTERFACELIB_EXTENSION;
}
if (!(libhttpinterface_path = getenv("HTTP_INTERFACE")))
{
libhttpinterface_path = "libhttpinterface_curl." INTERFACELIB_EXTENSION;
}
}
static int dlsym_interface_get_dlhandle(void)
{
if (!(apdu_interface_dlhandle = dlopen(libapduinterface_path, RTLD_LAZY)))
{
apdu_interface_dlhandle = NULL;
fprintf(stderr, "APDU interface env missing, current: APDU_INTERFACE=%s err:%s\n", libapduinterface_path, dlerror());
return -1;
}
if (!(http_interface_dlhandle = dlopen(libhttpinterface_path, RTLD_LAZY)))
{
http_interface_dlhandle = NULL;
fprintf(stderr, "HTTP interface env missing, current: HTTP_INTERFACE=%s err:%s\n", libhttpinterface_path, dlerror());
}
return 0;
}
int dlsym_interface_init()
{
dlsym_interfaces_get_path();
if (dlsym_interface_get_dlhandle())
{
return -1;
}
if (apdu_interface_dlhandle)
{
libapduinterface_init = dlsym(apdu_interface_dlhandle, "libapduinterface_init");
if (!libapduinterface_init)
{
fprintf(stderr, "APDU library broken: missing libapduinterface_init\n");
return -1;
}
if (libapduinterface_init(&dlsym_apdu_interface) < 0)
{
fprintf(stderr, "APDU library init error\n");
return -1;
}
libapduinterface_main = dlsym(apdu_interface_dlhandle, "libapduinterface_main");
if (!libapduinterface_main)
{
fprintf(stderr, "APDU library broken: missing libapduinterface_main\n");
return -1;
}
applet_apdu.main = libapduinterface_main;
}
if (http_interface_dlhandle)
{
libhttpinterface_init = dlsym(http_interface_dlhandle, "libhttpinterface_init");
if (!libhttpinterface_init)
{
fprintf(stderr, "HTTP library broken: missing libhttpinterface_init\n");
return -1;
}
if (libhttpinterface_init(&dlsym_http_interface) < 0)
{
fprintf(stderr, "HTTP library init error\n");
return -1;
}
libhttpinterface_main = dlsym(http_interface_dlhandle, "libhttpinterface_main");
if (!libhttpinterface_main)
{
fprintf(stderr, "HTTP library broken: missing libhttpinterface_main\n");
return -1;
}
applet_http.main = libhttpinterface_main;
}
return 0;
}
static int dlsym_interface_applet_main(int argc, char **argv)
{
return applet_entry(argc, argv, applets);
}
struct applet_entry applet_dlsym_interface = {
.name = "driver",
.main = dlsym_interface_applet_main,
};

View file

@ -1,9 +0,0 @@
#pragma once
#include <euicc/interface.h>
#include <applet.h>
extern struct euicc_apdu_interface dlsym_apdu_interface;
extern struct euicc_http_interface dlsym_http_interface;
extern struct applet_entry applet_dlsym_interface;
int dlsym_interface_init(void);

126
src/driver.c Normal file
View file

@ -0,0 +1,126 @@
#include "driver.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef LPAC_WITH_APDU_GBINDER_HIDL
#include "driver/apdu/gbinder_hidl.h"
#endif
#ifndef LPAC_WITHOUT_APDU_PCSC
#include "driver/apdu/pcsc.h"
#endif
#ifndef LPAC_WITHOUT_APDU_AT
#include "driver/apdu/at.h"
#endif
#ifndef LPAC_WITHOUT_HTTP_CURL
#include "driver/http/curl.h"
#endif
#include "driver/apdu/stdio.h"
#include "driver/http/stdio.h"
static const struct lpac_driver *drivers[] = {
#ifdef LPAC_WITH_APDU_GBINDER_HIDL
&driver_apdu_gbinder_hidl,
#endif
#ifndef LPAC_WITHOUT_APDU_PCSC
&driver_apdu_pcsc,
#endif
#ifndef LPAC_WITHOUT_APDU_AT
&driver_apdu_at,
#endif
#ifndef LPAC_WITHOUT_HTTP_CURL
&driver_http_curl,
#endif
&driver_apdu_stdio,
&driver_http_stdio,
NULL,
};
struct euicc_apdu_interface driver_interface_apdu;
struct euicc_http_interface driver_interface_http;
static struct applet_entry applet_apdu = {
.name = "apdu",
.main = NULL,
};
static struct applet_entry applet_http = {
.name = "http",
.main = NULL,
};
static const struct lpac_driver *_driver_apdu = NULL;
static const struct lpac_driver *_driver_http = NULL;
static const struct lpac_driver *_find_driver(enum lpac_driver_type type, const char *name)
{
for (int i = 0; drivers[i] != NULL; i++)
{
const struct lpac_driver *d = drivers[i];
if (d->type != type)
{
continue;
}
if (name == NULL)
{
return d;
}
if (strcmp(d->name, name) == 0)
{
return d;
}
}
return NULL;
}
int driver_init()
{
_driver_apdu = _find_driver(DRIVER_APDU, getenv("LPAC_APDU"));
if (_driver_apdu == NULL)
{
fprintf(stderr, "No APDU driver found\n");
return -1;
}
_driver_http = _find_driver(DRIVER_HTTP, getenv("LPAC_HTTP"));
if (_driver_http == NULL)
{
fprintf(stderr, "No HTTP driver found\n");
return -1;
}
_driver_apdu->init(&driver_interface_apdu);
_driver_http->init(&driver_interface_http);
applet_apdu.main = _driver_apdu->main;
applet_http.main = _driver_http->main;
return 0;
}
void driver_fini()
{
if (_driver_apdu != NULL)
{
_driver_apdu->fini();
}
if (_driver_http != NULL)
{
_driver_http->fini();
}
}
static int dlsym_interface_applet_main(int argc, char **argv)
{
static const struct applet_entry *applets[] = {
&applet_apdu,
&applet_http,
NULL,
};
return applet_entry(argc, argv, applets);
}
struct applet_entry driver_applet = {
.name = "driver",
.main = dlsym_interface_applet_main,
};

27
src/driver.h Normal file
View file

@ -0,0 +1,27 @@
#pragma once
#include <stddef.h>
#include <inttypes.h>
#include <euicc/interface.h>
#include <applet.h>
enum lpac_driver_type
{
DRIVER_APDU,
DRIVER_HTTP,
};
struct lpac_driver
{
enum lpac_driver_type type;
const char *name;
int (*init)(void *interface);
int (*main)(int argc, char **argv);
void (*fini)(void);
};
extern struct euicc_apdu_interface driver_interface_apdu;
extern struct euicc_http_interface driver_interface_http;
extern struct applet_entry driver_applet;
int driver_init(void);
void driver_fini(void);

View file

@ -10,7 +10,7 @@ if(LPAC_APDU_INTERFACE_PCSC)
install(TARGETS apduinterface_pcsc LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/lpac")
endif()
if(MINGW OR CYGWIN)
if(WIN32)
target_link_libraries(apduinterface_pcsc winscard)
elseif(APPLE)
target_link_libraries(apduinterface_pcsc "-framework PCSC")

View file

@ -1,3 +1,5 @@
#include "at.h"
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
@ -5,70 +7,11 @@
#include <unistd.h>
#include <euicc/interface.h>
#include <euicc/hexutil.h>
static FILE *fuart;
static int logic_channel = 0;
static int hexutil_hex2bin(uint8_t *output, uint32_t output_len, const char *str, uint32_t str_len)
{
uint32_t length;
if (!str || !output || str_len % 2 != 0)
{
return -1;
}
length = str_len / 2;
if (length > output_len)
{
return -1;
}
for (uint32_t i = 0; i < length; ++i)
{
char high = str[2 * i];
char low = str[2 * i + 1];
if (high >= '0' && high <= '9')
{
high -= '0';
}
else if (high >= 'a' && high <= 'f')
{
high = high - 'a' + 10;
}
else if (high >= 'A' && high <= 'F')
{
high = high - 'A' + 10;
}
else
{
return -1;
}
if (low >= '0' && low <= '9')
{
low -= '0';
}
else if (low >= 'a' && low <= 'f')
{
low = low - 'a' + 10;
}
else if (low >= 'A' && low <= 'F')
{
low = low - 'A' + 10;
}
else
{
return -1;
}
output[i] = (high << 4) + low;
}
return length;
}
static int at_expect(char **response, const char *expected)
{
char buffer[1024];
@ -195,7 +138,7 @@ static int apdu_interface_transmit(struct euicc_ctx *ctx, uint8_t **rx, uint32_t
goto err;
}
ret = hexutil_hex2bin(*rx, *rx_len, hexstr, strlen(hexstr));
ret = euicc_hexutil_hex2bin_r(*rx, *rx_len, hexstr, strlen(hexstr));
if (ret < 0)
{
goto err;
@ -257,7 +200,7 @@ static void apdu_interface_logic_channel_close(struct euicc_ctx *ctx, uint8_t ch
at_expect(NULL, NULL);
}
int libapduinterface_init(struct euicc_apdu_interface *ifstruct)
static int libapduinterface_init(struct euicc_apdu_interface *ifstruct)
{
memset(ifstruct, 0, sizeof(struct euicc_apdu_interface));
@ -270,7 +213,19 @@ int libapduinterface_init(struct euicc_apdu_interface *ifstruct)
return 0;
}
int libapduinterface_main(int argc, char **argv)
static int libapduinterface_main(int argc, char **argv)
{
return 0;
}
static void libapduinterface_fini(void)
{
}
const struct lpac_driver driver_apdu_at = {
.type = DRIVER_APDU,
.name = "at",
.init = (int (*)(void *))libapduinterface_init,
.main = libapduinterface_main,
.fini = libapduinterface_fini,
};

4
src/driver/apdu/at.h Normal file
View file

@ -0,0 +1,4 @@
#pragma once
#include <driver.h>
extern const struct lpac_driver driver_apdu_at;

View file

@ -1,4 +1,6 @@
// vim: expandtab sw=4 ts=4:
#include "gbinder_hidl.h"
#include <euicc/euicc.h>
#include <euicc/hexutil.h>
#include <euicc/interface.h>
@ -289,7 +291,7 @@ static int apdu_interface_transmit(struct euicc_ctx *ctx, uint8_t **rx, uint32_t
return 0;
}
EUICC_SHARED_EXPORT int libapduinterface_init(struct euicc_apdu_interface *ifstruct)
static int libapduinterface_init(struct euicc_apdu_interface *ifstruct)
{
ifstruct->connect = apdu_interface_connect;
ifstruct->disconnect = apdu_interface_disconnect;
@ -307,7 +309,19 @@ EUICC_SHARED_EXPORT int libapduinterface_init(struct euicc_apdu_interface *ifstr
return 0;
}
EUICC_SHARED_EXPORT int libapduinterface_main(int argc, char **argv)
static int libapduinterface_main(int argc, char **argv)
{
return 0;
}
static void libapduinterface_fini(void)
{
}
const struct lpac_driver driver_apdu_gbinder_hidl = {
.type = DRIVER_APDU,
.name = "gbinder_hidl",
.init = libapduinterface_init,
.main = libapduinterface_main,
.fini = libapduinterface_fini,
};

View file

@ -0,0 +1,4 @@
#pragma once
#include <driver.h>
extern const struct lpac_driver driver_apdu_gbinder_hidl;

View file

@ -1,21 +1,19 @@
#include "pcsc.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#ifdef __MINGW32__
#ifdef _WIN32
#include <winscard.h>
#elif defined(__CYGWIN__)
#include "/usr/include/w32api/winscard.h"
#include "/usr/include/w32api/wtypes.h"
#else
#include <PCSC/wintypes.h>
#include <PCSC/winscard.h>
#endif
#include <euicc/interface.h>
#include <cjson/cJSON_ex.h>
#include <euicc/interface.h>
#define INTERFACE_SELECT_ENV "DRIVER_IFID"
@ -392,7 +390,7 @@ static int pcsc_list_iter(int index, const char *reader, void *userdata)
return 0;
}
EUICC_SHARED_EXPORT int libapduinterface_init(struct euicc_apdu_interface *ifstruct)
static int libapduinterface_init(struct euicc_apdu_interface *ifstruct)
{
memset(ifstruct, 0, sizeof(struct euicc_apdu_interface));
@ -410,7 +408,7 @@ EUICC_SHARED_EXPORT int libapduinterface_init(struct euicc_apdu_interface *ifstr
return 0;
}
EUICC_SHARED_EXPORT int libapduinterface_main(int argc, char **argv)
static int libapduinterface_main(int argc, char **argv)
{
if (argc < 2)
{
@ -454,3 +452,15 @@ EUICC_SHARED_EXPORT int libapduinterface_main(int argc, char **argv)
return 0;
}
static void libapduinterface_fini(void)
{
}
const struct lpac_driver driver_apdu_pcsc = {
.type = DRIVER_APDU,
.name = "pcsc",
.init = (int (*)(void *))libapduinterface_init,
.main = libapduinterface_main,
.fini = libapduinterface_fini,
};

4
src/driver/apdu/pcsc.h Normal file
View file

@ -0,0 +1,4 @@
#pragma once
#include <driver.h>
extern const struct lpac_driver driver_apdu_pcsc;

View file

@ -1,3 +1,5 @@
#include "stdio.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
@ -5,93 +7,8 @@
#include <unistd.h>
#include <cjson/cJSON_ex.h>
#include <euicc/interface.h>
static int hexutil_bin2hex(char *output, uint32_t output_len, const uint8_t *bin, uint32_t bin_len)
{
const char hexDigits[] = "0123456789abcdef";
if (!bin || !output)
{
return -1;
}
if (output_len < (2 * bin_len + 1))
{
return -1;
}
for (uint32_t i = 0; i < bin_len; ++i)
{
char byte = bin[i];
output[2 * i] = hexDigits[(byte >> 4) & 0x0F];
output[2 * i + 1] = hexDigits[byte & 0x0F];
}
output[2 * bin_len] = '\0';
return 0;
}
static int hexutil_hex2bin(uint8_t *output, uint32_t output_len, const char *str, uint32_t str_len)
{
uint32_t length;
if (!str || !output || str_len % 2 != 0)
{
return -1;
}
length = str_len / 2;
if (length > output_len)
{
return -1;
}
for (uint32_t i = 0; i < length; ++i)
{
char high = str[2 * i];
char low = str[2 * i + 1];
if (high >= '0' && high <= '9')
{
high -= '0';
}
else if (high >= 'a' && high <= 'f')
{
high = high - 'a' + 10;
}
else if (high >= 'A' && high <= 'F')
{
high = high - 'A' + 10;
}
else
{
return -1;
}
if (low >= '0' && low <= '9')
{
low -= '0';
}
else if (low >= 'a' && low <= 'f')
{
low = low - 'a' + 10;
}
else if (low >= 'A' && low <= 'F')
{
low = low - 'A' + 10;
}
else
{
return -1;
}
output[i] = (high << 4) + low;
}
return length;
}
#include <euicc/hexutil.h>
// getline is a GNU extension, Mingw32 macOS and FreeBSD don't have (a working) one
static int afgets(char **obuf, FILE *fp)
@ -197,7 +114,7 @@ static int json_request(const char *func, const uint8_t *param, unsigned param_l
{
goto err;
}
if (hexutil_bin2hex(param_hex, (2 * param_len) + 1, param, param_len) < 0)
if (euicc_hexutil_bin2hex(param_hex, (2 * param_len) + 1, param, param_len) < 0)
{
goto err;
}
@ -306,7 +223,7 @@ static int json_response(int *ecode, uint8_t **data, uint32_t *data_len)
{
goto err;
}
if (hexutil_hex2bin(*data, *data_len, jtmp->valuestring, strlen(jtmp->valuestring)) < 0)
if (euicc_hexutil_hex2bin_r(*data, *data_len, jtmp->valuestring, strlen(jtmp->valuestring)) < 0)
{
goto err;
}
@ -407,7 +324,7 @@ static int apdu_interface_transmit(struct euicc_ctx *ctx, uint8_t **rx, uint32_t
return ecode;
}
EUICC_SHARED_EXPORT int libapduinterface_init(struct euicc_apdu_interface *ifstruct)
static int libapduinterface_init(struct euicc_apdu_interface *ifstruct)
{
ifstruct->connect = apdu_interface_connect;
ifstruct->disconnect = apdu_interface_disconnect;
@ -418,7 +335,19 @@ EUICC_SHARED_EXPORT int libapduinterface_init(struct euicc_apdu_interface *ifstr
return 0;
}
EUICC_SHARED_EXPORT int libapduinterface_main(int argc, char **argv)
static int libapduinterface_main(int argc, char **argv)
{
return 0;
}
static void libapduinterface_fini(void)
{
}
const struct lpac_driver driver_apdu_stdio = {
.type = DRIVER_APDU,
.name = "stdio",
.init = (int (*)(void *))libapduinterface_init,
.main = libapduinterface_main,
.fini = libapduinterface_fini,
};

4
src/driver/apdu/stdio.h Normal file
View file

@ -0,0 +1,4 @@
#pragma once
#include <driver.h>
extern const struct lpac_driver driver_apdu_stdio;

205
src/driver/http/curl.c Normal file
View file

@ -0,0 +1,205 @@
#include "curl.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <euicc/interface.h>
#ifndef _WIN32
#include <curl/curl.h>
#else
#include <dlfcn-win32/dlfcn.h>
#define CURL_GLOBAL_DEFAULT ((1 << 0) | (1 << 1))
#define CURLE_OK 0
#define CURLOPT_URL 10002
#define CURLOPT_WRITEFUNCTION 20011
#define CURLOPT_WRITEDATA 10001
#define CURLOPT_SSL_VERIFYPEER 64
#define CURLOPT_SSL_VERIFYHOST 81
#define CURLOPT_HTTPHEADER 10023
#define CURLOPT_POSTFIELDS 10015
#define CURLOPT_POSTFIELDSIZE 60
#define CURLINFO_RESPONSE_CODE 2097154
typedef void CURL;
typedef int CURLcode;
typedef int CURLoption;
typedef int CURLINFO;
static void *libcurl_interface_dlhandle = NULL;
#endif
struct http_trans_response_data
{
uint8_t *data;
size_t size;
};
static struct libcurl_interface
{
CURLcode (*_curl_global_init)(long flags);
CURL *(*_curl_easy_init)(void);
CURLcode (*_curl_easy_setopt)(CURL *curl, CURLoption option, ...);
CURLcode (*_curl_easy_perform)(CURL *curl);
CURLcode (*_curl_easy_getinfo)(CURL *curl, CURLINFO info, ...);
const char *(*_curl_easy_strerror)(CURLcode);
void (*_curl_easy_cleanup)(CURL *curl);
struct curl_slist *(*_curl_slist_append)(struct curl_slist *list, const char *data);
void (*_curl_slist_free_all)(struct curl_slist *list);
} libcurl;
static size_t http_trans_write_callback(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct http_trans_response_data *mem = (struct http_trans_response_data *)userp;
mem->data = realloc(mem->data, mem->size + realsize + 1);
if (mem->data == NULL)
{
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
memcpy(&(mem->data[mem->size]), contents, realsize);
mem->size += realsize;
mem->data[mem->size] = 0;
return realsize;
}
static int http_interface_transmit(struct euicc_ctx *ctx, const char *url, uint32_t *rcode, uint8_t **rx, uint32_t *rx_len, const uint8_t *tx, uint32_t tx_len, const char **h)
{
int fret = 0;
CURL *curl;
CURLcode res;
struct http_trans_response_data responseData = {0};
struct curl_slist *headers = NULL, *nheaders = NULL;
long response_code;
(*rx) = NULL;
(*rcode) = 0;
curl = libcurl._curl_easy_init();
if (!curl)
{
goto err;
}
libcurl._curl_easy_setopt(curl, CURLOPT_URL, url);
libcurl._curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_trans_write_callback);
libcurl._curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&responseData);
libcurl._curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
libcurl._curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
for (int i = 0; h[i] != NULL; i++)
{
nheaders = libcurl._curl_slist_append(headers, h[i]);
if (nheaders == NULL)
{
goto err;
}
headers = nheaders;
}
libcurl._curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
if (tx != NULL)
{
libcurl._curl_easy_setopt(curl, CURLOPT_POSTFIELDS, tx);
libcurl._curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, tx_len);
}
res = libcurl._curl_easy_perform(curl);
if (res != CURLE_OK)
{
fprintf(stderr, "curl_easy_perform() failed: %s\n", libcurl._curl_easy_strerror(res));
goto err;
}
libcurl._curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
*rcode = response_code;
*rx = responseData.data;
*rx_len = responseData.size;
fret = 0;
goto exit;
err:
fret = -1;
free(responseData.data);
exit:
libcurl._curl_easy_cleanup(curl);
libcurl._curl_slist_free_all(headers);
return fret;
}
static int _init_libcurl(void)
{
#ifdef _WIN32
if (!(libcurl_interface_dlhandle = dlopen("libcurl.dll", RTLD_LAZY)))
{
fprintf(stderr, "libcurl init err: %s\n", dlerror());
return -1;
}
libcurl._curl_global_init = dlsym(libcurl_interface_dlhandle, "curl_global_init");
libcurl._curl_easy_init = dlsym(libcurl_interface_dlhandle, "curl_easy_init");
libcurl._curl_easy_setopt = dlsym(libcurl_interface_dlhandle, "curl_easy_setopt");
libcurl._curl_easy_perform = dlsym(libcurl_interface_dlhandle, "curl_easy_perform");
libcurl._curl_easy_getinfo = dlsym(libcurl_interface_dlhandle, "curl_easy_getinfo");
libcurl._curl_easy_strerror = dlsym(libcurl_interface_dlhandle, "curl_easy_strerror");
libcurl._curl_easy_cleanup = dlsym(libcurl_interface_dlhandle, "curl_easy_cleanup");
libcurl._curl_slist_append = dlsym(libcurl_interface_dlhandle, "curl_slist_append");
libcurl._curl_slist_free_all = dlsym(libcurl_interface_dlhandle, "curl_slist_free_all");
#else
libcurl._curl_global_init = curl_global_init;
libcurl._curl_easy_init = curl_easy_init;
libcurl._curl_easy_setopt = curl_easy_setopt;
libcurl._curl_easy_perform = curl_easy_perform;
libcurl._curl_easy_getinfo = curl_easy_getinfo;
libcurl._curl_easy_strerror = curl_easy_strerror;
libcurl._curl_easy_cleanup = curl_easy_cleanup;
libcurl._curl_slist_append = curl_slist_append;
libcurl._curl_slist_free_all = curl_slist_free_all;
#endif
return 0;
}
static int libhttpinterface_init(struct euicc_http_interface *ifstruct)
{
memset(ifstruct, 0, sizeof(struct euicc_http_interface));
if (_init_libcurl() != 0)
{
return -1;
}
if (libcurl._curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK)
{
return -1;
}
ifstruct->transmit = http_interface_transmit;
return 0;
}
static int libhttpinterface_main(int argc, char **argv)
{
return 0;
}
static void libhttpinterface_fini(void)
{
}
const struct lpac_driver driver_http_curl = {
.type = DRIVER_HTTP,
.name = "curl",
.init = (int (*)(void *))libhttpinterface_init,
.main = libhttpinterface_main,
.fini = libhttpinterface_fini,
};

4
src/driver/http/curl.h Normal file
View file

@ -0,0 +1,4 @@
#pragma once
#include <driver.h>
extern const struct lpac_driver driver_http_curl;

View file

@ -1,3 +1,5 @@
#include "stdio.h"
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
@ -5,93 +7,8 @@
#include <unistd.h>
#include <cjson/cJSON_ex.h>
#include <euicc/interface.h>
static int hexutil_bin2hex(char *output, uint32_t output_len, const uint8_t *bin, uint32_t bin_len)
{
const char hexDigits[] = "0123456789abcdef";
if (!bin || !output)
{
return -1;
}
if (output_len < (2 * bin_len + 1))
{
return -1;
}
for (uint32_t i = 0; i < bin_len; ++i)
{
char byte = bin[i];
output[2 * i] = hexDigits[(byte >> 4) & 0x0F];
output[2 * i + 1] = hexDigits[byte & 0x0F];
}
output[2 * bin_len] = '\0';
return 0;
}
static int hexutil_hex2bin(uint8_t *output, uint32_t output_len, const char *str, uint32_t str_len)
{
uint32_t length;
if (!str || !output || str_len % 2 != 0)
{
return -1;
}
length = str_len / 2;
if (length > output_len)
{
return -1;
}
for (uint32_t i = 0; i < length; ++i)
{
char high = str[2 * i];
char low = str[2 * i + 1];
if (high >= '0' && high <= '9')
{
high -= '0';
}
else if (high >= 'a' && high <= 'f')
{
high = high - 'a' + 10;
}
else if (high >= 'A' && high <= 'F')
{
high = high - 'A' + 10;
}
else
{
return -1;
}
if (low >= '0' && low <= '9')
{
low -= '0';
}
else if (low >= 'a' && low <= 'f')
{
low = low - 'a' + 10;
}
else if (low >= 'A' && low <= 'F')
{
low = low - 'A' + 10;
}
else
{
return -1;
}
output[i] = (high << 4) + low;
}
return length;
}
#include <euicc/hexutil.h>
// getline is a GNU extension, Mingw32 macOS and FreeBSD don't have (a working) one
static int afgets(char **obuf, FILE *fp)
@ -196,7 +113,7 @@ static int json_request(const char *url, const uint8_t *tx, uint32_t tx_len, con
{
goto err;
}
if (hexutil_bin2hex(tx_hex, (2 * tx_len) + 1, tx, tx_len) < 0)
if (euicc_hexutil_bin2hex(tx_hex, (2 * tx_len) + 1, tx, tx_len) < 0)
{
goto err;
}
@ -321,7 +238,7 @@ static int http_interface_transmit(struct euicc_ctx *ctx, const char *url, uint3
{
goto err;
}
if (hexutil_hex2bin(*rx, *rx_len, jtmp->valuestring, strlen(jtmp->valuestring)) < 0)
if (euicc_hexutil_hex2bin_r(*rx, *rx_len, jtmp->valuestring, strlen(jtmp->valuestring)) < 0)
{
goto err;
}
@ -341,7 +258,7 @@ exit:
return fret;
}
EUICC_SHARED_EXPORT int libhttpinterface_init(struct euicc_http_interface *ifstruct)
static int libhttpinterface_init(struct euicc_http_interface *ifstruct)
{
memset(ifstruct, 0, sizeof(struct euicc_http_interface));
@ -350,7 +267,19 @@ EUICC_SHARED_EXPORT int libhttpinterface_init(struct euicc_http_interface *ifstr
return 0;
}
EUICC_SHARED_EXPORT int libhttpinterface_main(int argc, char **argv)
static int libhttpinterface_main(int argc, char **argv)
{
return 0;
}
static void libhttpinterface_fini(void)
{
}
const struct lpac_driver driver_http_stdio = {
.type = DRIVER_HTTP,
.name = "stdio",
.init = (int (*)(void *))libhttpinterface_init,
.main = libhttpinterface_main,
.fini = libhttpinterface_fini,
};

4
src/driver/http/stdio.h Normal file
View file

@ -0,0 +1,4 @@
#pragma once
#include <driver.h>
extern const struct lpac_driver driver_http_stdio;

View file

@ -8,8 +8,7 @@
#include <euicc/interface.h>
#include <euicc/euicc.h>
#include "dlsym_interface.h"
#include "driver.h"
#include "applet.h"
#include "applet/chip.h"
#include "applet/profile.h"
@ -17,7 +16,7 @@
#include "applet/version.h"
static const struct applet_entry *applets[] = {
&applet_dlsym_interface,
&driver_applet,
&applet_chip,
&applet_profile,
&applet_notification,
@ -54,17 +53,19 @@ int main(int argc, char **argv)
memset(&euicc_ctx, 0, sizeof(euicc_ctx));
if (dlsym_interface_init())
if (driver_init())
{
return -1;
}
euicc_ctx.apdu.interface = &dlsym_apdu_interface;
euicc_ctx.http.interface = &dlsym_http_interface;
euicc_ctx.apdu.interface = &driver_interface_apdu;
euicc_ctx.http.interface = &driver_interface_http;
ret = applet_entry(argc, argv, applets);
main_fini_euicc();
driver_fini();
return ret;
}