diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..a13336e
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "pico-ccid"]
+ path = pico-ccid
+ url = https://github.com/polhenarejos/pico-ccid.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..71a5b17
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,101 @@
+ #
+ # This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ # Copyright (c) 2022 Pol Henarejos.
+ #
+ # This program is free software: you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License as published by
+ # the Free Software Foundation, version 3.
+ #
+ # This program 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
+ # General Public License for more details.
+ #
+ # You should have received a copy of the GNU General Public License
+ # along with this program. If not, see .
+ #
+
+cmake_minimum_required(VERSION 3.13)
+
+include(pico_sdk_import.cmake)
+
+project(pico_openpgp C CXX ASM)
+
+set(CMAKE_C_STANDARD 11)
+set(CMAKE_CXX_STANDARD 17)
+
+pico_sdk_init()
+
+add_executable(pico_openpgp)
+
+if (NOT DEFINED USB_VID)
+ set(USB_VID 0xFEFF)
+endif()
+add_definitions(-DUSB_VID=${USB_VID})
+if (NOT DEFINED USB_PID)
+ set(USB_PID 0xFCFD)
+endif()
+add_definitions(-DUSB_PID=${USB_PID})
+
+target_sources(pico_openpgp PUBLIC
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/ccid2040.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/openpgp.c
+ ${CMAKE_CURRENT_LIST_DIR}/src/openpgp/files.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/usb/usb_descriptors.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/file.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/flash.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs/low_flash.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/rng/random.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/rng/neug.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/crypto_utils.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid/eac.c
+
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/sha256.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/aes.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/sha512.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/rsa.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/bignum.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/platform_util.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/md.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/oid.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/rsa_alt_helpers.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/constant_time.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecdsa.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecp.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecp_curves.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/asn1write.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/hmac_drbg.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/md5.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ripemd160.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/sha1.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ecdh.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/cmac.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/cipher.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/cipher_wrap.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/chachapoly.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/camellia.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/chacha20.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/aria.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/poly1305.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/gcm.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/ccm.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/des.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/nist_kw.c
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library/hkdf.c
+ )
+
+target_include_directories(pico_openpgp PUBLIC
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/fs
+ ${CMAKE_CURRENT_LIST_DIR}/src/openpgp
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/ccid
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/rng
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/src/usb
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/include
+ ${CMAKE_CURRENT_LIST_DIR}/pico-ccid/mbedtls/library
+ )
+
+pico_add_extra_outputs(pico_openpgp)
+
+#target_compile_definitions(pico_openpgp PRIVATE MBEDTLS_ECDSA_DETERMINISTIC=1)
+
+target_link_libraries(pico_openpgp PRIVATE pico_stdlib tinyusb_device tinyusb_board pico_multicore hardware_flash hardware_sync hardware_adc pico_unique_id hardware_rtc)
diff --git a/pico-ccid b/pico-ccid
new file mode 160000
index 0000000..16f23df
--- /dev/null
+++ b/pico-ccid
@@ -0,0 +1 @@
+Subproject commit 16f23dfa6c458e027910d17b0ca0fa35e715cf9b
diff --git a/pico_sdk_import.cmake b/pico_sdk_import.cmake
new file mode 100644
index 0000000..28efe9e
--- /dev/null
+++ b/pico_sdk_import.cmake
@@ -0,0 +1,62 @@
+# This is a copy of /external/pico_sdk_import.cmake
+
+# This can be dropped into an external project to help locate this SDK
+# It should be include()ed prior to project()
+
+if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
+ set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
+ message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
+endif ()
+
+if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
+ set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
+ message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
+endif ()
+
+if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
+ set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
+ message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
+endif ()
+
+set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
+set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
+set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
+
+if (NOT PICO_SDK_PATH)
+ if (PICO_SDK_FETCH_FROM_GIT)
+ include(FetchContent)
+ set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
+ if (PICO_SDK_FETCH_FROM_GIT_PATH)
+ get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
+ endif ()
+ FetchContent_Declare(
+ pico_sdk
+ GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
+ GIT_TAG master
+ )
+ if (NOT pico_sdk)
+ message("Downloading Raspberry Pi Pico SDK")
+ FetchContent_Populate(pico_sdk)
+ set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
+ endif ()
+ set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
+ else ()
+ message(FATAL_ERROR
+ "SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
+ )
+ endif ()
+endif ()
+
+get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
+if (NOT EXISTS ${PICO_SDK_PATH})
+ message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
+endif ()
+
+set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
+if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
+ message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
+endif ()
+
+set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
+
+include(${PICO_SDK_INIT_CMAKE_FILE})
diff --git a/src/openpgp/files.c b/src/openpgp/files.c
new file mode 100644
index 0000000..cef4281
--- /dev/null
+++ b/src/openpgp/files.c
@@ -0,0 +1,29 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "files.h"
+
+extern const uint8_t openpgp_aid[];
+
+file_t file_entries[] = {
+ { .fid = 0x0000, .parent = 0, .name = openpgp_aid, .type = FILE_TYPE_WORKING_EF, .data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = {0} },
+ /* 25 */ { .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL, .ef_structure = 0, .acl = {0} } //end
+};
+
+const file_t *MF = &file_entries[0];
+const file_t *file_openpgp = &file_entries[sizeof(file_entries)/sizeof(file_t)-2];
+const file_t *file_last = &file_entries[sizeof(file_entries)/sizeof(file_t)-1];
\ No newline at end of file
diff --git a/src/openpgp/files.h b/src/openpgp/files.h
new file mode 100644
index 0000000..cd8cd16
--- /dev/null
+++ b/src/openpgp/files.h
@@ -0,0 +1,24 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+
+#ifndef _FILES_H_
+#define _FILES_H_
+
+#include "file.h"
+
+#endif
diff --git a/src/openpgp/openpgp.c b/src/openpgp/openpgp.c
new file mode 100644
index 0000000..a557afe
--- /dev/null
+++ b/src/openpgp/openpgp.c
@@ -0,0 +1,174 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "openpgp.h"
+#include "version.h"
+#include "eac.h"
+
+const uint8_t openpgp_aid[] = {
+ 6,
+ 0xD2,0x76,0x00,0x01,0x24,0x01
+};
+
+char atr_openpgp[] = {
+ 21,
+ 0x3b,0xda,0x18,0xff,0x81,0xb1,0xfe,0x75,0x1f,0x03,0x00,0x31,0xf5,0x73,0xc0,0x01,0x60,0x00,0x90,0x00,0x1c
+};
+
+int openpgp_process_apdu();
+
+void select_file(file_t *pe) {
+ if (!pe)
+ {
+ currentDF = (file_t *)MF;
+ currentEF = NULL;
+ }
+ else if (pe->type & FILE_TYPE_INTERNAL_EF) {
+ currentEF = pe;
+ currentDF = &file_entries[pe->parent];
+ }
+ else {
+ currentDF = pe;
+ }
+ if (currentEF == file_openpgp) {
+ selected_applet = currentEF;
+ //sc_hsm_unload(); //reset auth status
+ }
+}
+
+static int cmd_select() {
+ uint8_t p1 = P1(apdu);
+ uint8_t p2 = P2(apdu);
+ file_t *pe = NULL;
+ uint16_t fid = 0x0;
+
+ // Only "first or only occurence" supported
+ //if ((p2 & 0xF3) != 0x00) {
+ // return SW_INCORRECT_P1P2();
+ //}
+
+ if (apdu.cmd_apdu_data_len >= 2)
+ fid = get_uint16_t(apdu.cmd_apdu_data, 0);
+
+ //if ((fid & 0xff00) == (KEY_PREFIX << 8))
+ // fid = (PRKD_PREFIX << 8) | (fid & 0xff);
+
+ if (!pe) {
+ if (p1 == 0x0) { //Select MF, DF or EF - File identifier or absent
+ if (apdu.cmd_apdu_data_len == 0) {
+ pe = (file_t *)MF;
+ //ac_fini();
+ }
+ else if (apdu.cmd_apdu_data_len == 2) {
+ if (!(pe = search_by_fid(fid, NULL, SPECIFY_ANY))) {
+ return SW_FILE_NOT_FOUND();
+ }
+ }
+ }
+ else if (p1 == 0x01) { //Select child DF - DF identifier
+ if (!(pe = search_by_fid(fid, currentDF, SPECIFY_DF))) {
+ return SW_FILE_NOT_FOUND();
+ }
+ }
+ else if (p1 == 0x02) { //Select EF under the current DF - EF identifier
+ if (!(pe = search_by_fid(fid, currentDF, SPECIFY_EF))) {
+ return SW_FILE_NOT_FOUND();
+ }
+ }
+ else if (p1 == 0x03) { //Select parent DF of the current DF - Absent
+ if (apdu.cmd_apdu_data_len != 0)
+ return SW_FILE_NOT_FOUND();
+ }
+ else if (p1 == 0x04) { //Select by DF name - e.g., [truncated] application identifier
+ if (!(pe = search_by_name(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len))) {
+ return SW_FILE_NOT_FOUND();
+ }
+ if (card_terminated) {
+ return set_res_sw (0x62, 0x85);
+ }
+ }
+ else if (p1 == 0x08) { //Select from the MF - Path without the MF identifier
+ if (!(pe = search_by_path(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, MF))) {
+ return SW_FILE_NOT_FOUND();
+ }
+ }
+ else if (p1 == 0x09) { //Select from the current DF - Path without the current DF identifier
+ if (!(pe = search_by_path(apdu.cmd_apdu_data, apdu.cmd_apdu_data_len, currentDF))) {
+ return SW_FILE_NOT_FOUND();
+ }
+ }
+ }
+ if ((p2 & 0xfc) == 0x00 || (p2 & 0xfc) == 0x04) {
+ process_fci(pe);
+ }
+ else
+ return SW_INCORRECT_P1P2();
+ select_file(pe);
+ return SW_OK ();
+}
+
+void init_openpgp() {
+ isUserAuthenticated = false;
+ cmd_select();
+}
+
+int openpgp_unload() {
+ isUserAuthenticated = false;
+ return CCID_OK;
+}
+
+app_t *openpgp_select_aid(app_t *a) {
+ printf("AIDS \r\n");
+ DEBUG_PAYLOAD(apdu.cmd_apdu_data,apdu.cmd_apdu_data_len);
+ DEBUG_PAYLOAD(openpgp_aid+1,openpgp_aid[0]);
+ if (!memcmp(apdu.cmd_apdu_data, openpgp_aid+1, MIN(apdu.cmd_apdu_data_len,openpgp_aid[0]))) {
+ printf("SELECTING OPENPGP\r\n");
+ a->aid = openpgp_aid;
+ a->process_apdu = openpgp_process_apdu;
+ a->unload = openpgp_unload;
+ init_openpgp();
+ return a;
+ }
+ return NULL;
+}
+
+void __attribute__ ((constructor)) openpgp_ctor() {
+ ccid_atr = atr_openpgp;
+ register_app(openpgp_select_aid);
+}
+
+typedef struct cmd
+{
+ uint8_t ins;
+ int (*cmd_handler)();
+} cmd_t;
+
+static const cmd_t cmds[] = {
+ { 0x00, 0x0}
+};
+
+int openpgp_process_apdu() {
+ int r = sm_unwrap();
+ for (const cmd_t *cmd = cmds; cmd->ins != 0x00; cmd++) {
+ if (cmd->ins == INS(apdu)) {
+ int r = cmd->cmd_handler();
+ sm_wrap();
+ return r;
+ }
+ }
+ return SW_INS_NOT_SUPPORTED();
+}
\ No newline at end of file
diff --git a/src/openpgp/openpgp.h b/src/openpgp/openpgp.h
new file mode 100644
index 0000000..f91cfc5
--- /dev/null
+++ b/src/openpgp/openpgp.h
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef __OPENPGP_H_
+#define __OPENPGP_H_
+
+#include "stdlib.h"
+#include
+
+#include "ccid2040.h"
+
+#endif
+
diff --git a/src/openpgp/version.h b/src/openpgp/version.h
new file mode 100644
index 0000000..ff791f8
--- /dev/null
+++ b/src/openpgp/version.h
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the Pico OpenPGP distribution (https://github.com/polhenarejos/pico-openpgp).
+ * Copyright (c) 2022 Pol Henarejos.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef __VERSION_H_
+#define __VERSION_H_
+
+#define OPGP_VERSION 0x0100
+
+#define OPGP_VERSION_MAJOR ((OPGP_VERSION >> 8) & 0xff)
+#define OPGP_VERSION_MINOR (OPGP_VERSION & 0xff)
+
+#endif
+