├── .gitignore ├── example ├── README ├── ChangeLog ├── java │ ├── pkcs11.cfg │ └── README ├── .cvsignore ├── run_tests.in ├── ref │ ├── pkcs11u.h │ └── pkcs11.h ├── soft-token.rc ├── configure.ac ├── data │ ├── test.crt │ ├── ca.key │ ├── test.key │ └── ca.crt ├── Makefile.am ├── config.h.in ├── locl.h ├── release.sh ├── test_soft_pkcs11.c ├── install-sh ├── missing └── Makefile.in ├── docs └── pkcs-11v2-20.pdf ├── .soft-token.rc ├── scripts └── sshpass ├── pkcs11 ├── pkcs11u.h └── pkcs11.h ├── exceptions.h ├── log.h ├── types.h ├── log.cpp ├── CMakeLists.txt ├── tools.h ├── object.h ├── keys └── ssh-private.key ├── soft_token.h ├── storage.h ├── attribute.cpp ├── attribute.h ├── function_wrap.h ├── spec └── fs_spec.rb ├── README.md ├── tools.cpp ├── object.cpp ├── storage.cpp ├── soft_token.cpp └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /example/README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinnalru/soft-pkcs11/HEAD/example/README -------------------------------------------------------------------------------- /example/ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinnalru/soft-pkcs11/HEAD/example/ChangeLog -------------------------------------------------------------------------------- /docs/pkcs-11v2-20.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kinnalru/soft-pkcs11/HEAD/docs/pkcs-11v2-20.pdf -------------------------------------------------------------------------------- /.soft-token.rc: -------------------------------------------------------------------------------- 1 | 2 | [ssh] 3 | driver=fs 4 | #path=/home/jerry/devel/jerry/pscs/soft-pkcs/keys2 5 | path=/home/jerry/devel/soft-pkcs/keys 6 | -------------------------------------------------------------------------------- /example/java/pkcs11.cfg: -------------------------------------------------------------------------------- 1 | # $Id: pkcs11.cfg,v 1.1 2006/01/11 12:06:20 lha Exp $ 2 | name = SoftToken 3 | library = /tmp/pkcs11/lib/soft-pkcs11.so 4 | -------------------------------------------------------------------------------- /example/.cvsignore: -------------------------------------------------------------------------------- 1 | Makefile.in 2 | aclocal.m4 3 | autom4te.cache 4 | config.guess 5 | config.h.in 6 | config.sub 7 | configure 8 | install-sh 9 | ltmain.sh 10 | missing 11 | -------------------------------------------------------------------------------- /scripts/sshpass: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [ -n "$SSH_ASKPASS_PASSWORD" ]; then 4 | echo "$SSH_ASKPASS_PASSWORD" 5 | else 6 | export SSH_ASKPASS_PASSWORD="123123123" 7 | export SSH_ASKPASS=$0 8 | 9 | [ "$DISPLAY" ] || export DISPLAY=dummydisplay:0 10 | 11 | exec setsid ssh "$@" 12 | fi 13 | -------------------------------------------------------------------------------- /example/run_tests.in: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # $Id: run_tests.in,v 1.2 2006/01/11 00:48:14 lha Exp $ 3 | 4 | srcdir="@srcdir@" 5 | 6 | cat > test-rc-file.rc < 5 | 6 | #include "pkcs11/pkcs11t.h" 7 | 8 | struct pkcs11_exception_t : std::runtime_error { 9 | explicit pkcs11_exception_t(CK_RV r, const std::string& msg) 10 | : std::runtime_error(msg) 11 | , rv(rv) 12 | {} 13 | 14 | CK_RV rv; 15 | }; 16 | 17 | struct system_exception_t : std::runtime_error { 18 | explicit system_exception_t(const std::string& msg) 19 | : std::runtime_error(msg) 20 | {} 21 | }; 22 | #endif 23 | 24 | -------------------------------------------------------------------------------- /example/soft-token.rc: -------------------------------------------------------------------------------- 1 | # Separator is \t 2 | # fields are id, label, cert file[, optional keyfile] 3 | # "anchor" (only one per configuration file) special id will be using 4 | # a special id to mark is as an x509 anchor. 5 | # 6 | # $Id: soft-token.rc,v 1.1 2004/05/02 16:22:47 lha Exp $ 7 | # 8 | 9 | test Testlabel /home/jerry/devel/soft-pkcs/example/data/ca.crt /home/jerry/devel/soft-pkcs/example/data/ca.key 10 | 11 | #lha Love's certificate /secure/lha/su/CA/lha.crt /secure/lha/su/CA/lha-nopw.key 12 | #su Stockholm university's CA /secure/lha/su/CA/su-ca.crt 13 | #anchor SWUPKI policy CA root /secure/lha/su/CA/swupki-pca.crt 14 | 15 | path=/home/jerry/devel/soft-pkcs/keys 16 | -------------------------------------------------------------------------------- /example/configure.ac: -------------------------------------------------------------------------------- 1 | dnl Process this file with autoconf to produce a configure script. 2 | AC_REVISION($Revision: 1.12 $) 3 | AC_PREREQ(2.59) 4 | test -z "$CFLAGS" && CFLAGS="-g" 5 | AC_INIT([soft-pkcs11], 1.8, [lha@it.su.se]) 6 | AC_CONFIG_SRCDIR([main.c]) 7 | AM_CONFIG_HEADER(config.h) 8 | 9 | AM_INIT_AUTOMAKE([foreign no-dependencies 1.9]) 10 | AM_MAINTAINER_MODE 11 | 12 | dnl Checks for programs. 13 | AC_PROG_CC 14 | AC_PROG_CPP 15 | AC_PROG_CC_STDC 16 | 17 | AC_PROG_LIBTOOL 18 | 19 | AC_CONFIG_FILES(Makefile) 20 | 21 | AH_TOP([#ifndef RCSID 22 | #define RCSID(msg) \ 23 | static /**/const char *const rcsid[] = { (const char *)rcsid, "@(#)" msg } 24 | #endif]) 25 | 26 | AC_OUTPUT 27 | 28 | -------------------------------------------------------------------------------- /log.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef ST_LOG_H 3 | #define ST_LOG_H 4 | 5 | 6 | struct logger_t { 7 | static logger_t& instance(); 8 | 9 | logger_t& operator()(const std::string& msg); 10 | logger_t& operator()(const char* fmt, ...); 11 | 12 | struct scopped_t { 13 | scopped_t(); 14 | ~scopped_t(); 15 | }; 16 | 17 | private: 18 | void print_tab(); 19 | }; 20 | 21 | 22 | 23 | #define LOG(msg, ...) logger_t::instance()(msg "\n", ##__VA_ARGS__); 24 | #define LOG_F(msg, ...) logger_t::instance()(__FUNCTION__ msg "\n", ##__VA_ARGS__); 25 | 26 | #define LOG_G(msg, ...) logger_t::instance()(msg "\n", ##__VA_ARGS__); logger_t::scopped_t s__; 27 | 28 | 29 | #endif -------------------------------------------------------------------------------- /types.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef ST_TYPES_H 3 | #define ST_TYPES_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "attribute.h" 11 | 12 | typedef std::vector Bytes; 13 | typedef std::vector Handles; 14 | typedef std::function handle_iterator_t; 15 | 16 | typedef std::map Attributes; 17 | typedef std::map Objects; 18 | 19 | // typedef std::map MetaAttributes; 20 | // typedef std::map MetaAttributesList; 21 | 22 | struct descriptor_t; 23 | typedef std::shared_ptr descriptor_p; 24 | 25 | #endif -------------------------------------------------------------------------------- /example/data/test.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIB4zCCAUygAwIBAgIJAIkHl5ihSqlsMA0GCSqGSIb3DQEBBAUAMCoxGzAZBgNV 3 | BAMMEmh4NTA5IFRlc3QgUm9vdCBDQTELMAkGA1UEBhMCU0UwHhcNMDYwMTEwMjMy 4 | MzQ3WhcNMTYwMTA4MjMyMzQ3WjAhMRIwEAYDVQQDDAlUZXN0IGNlcnQxCzAJBgNV 5 | BAYTAlNFMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5vE1OzLS09JJqULhl 6 | SGBTXdBSRGTXUmt5R0Wqh5weOaWKvBXKpaMwwHf7AOpjQHmDhNY00RecqGCABUGa 7 | kx1YkmMTbCti2ZfSsW6NdlQcaIHOm68zWtq35+xUB1uK+Uj2KDKbyKijw1HRYDO0 8 | 2yokFQVC4jP6vTjQMVfKqPpf7wIDAQABoxowGDAJBgNVHRMEAjAAMAsGA1UdDwQE 9 | AwIF4DANBgkqhkiG9w0BAQQFAAOBgQAhqHeag2jLry8hSsKQGiZ2IWXw1quxd/kE 10 | DN0DKozfqZ+8WqqU9xSTUN0Hzv795q1w8L0AKAhhkaaLDe3fX0vXTyPvPkmu0vYJ 11 | On3L3E1EwbhOI4uZgh1W+cD8f+MGGqNwVo3q3PqmMbovDK3oANoCTfNPiCAo/GDV 12 | l8GgQ22zAQ== 13 | -----END CERTIFICATE----- 14 | -------------------------------------------------------------------------------- /example/Makefile.am: -------------------------------------------------------------------------------- 1 | # $Id: Makefile.am,v 1.4 2006/01/11 11:50:24 lha Exp $ 2 | 3 | lib_LTLIBRARIES = soft-pkcs11.la 4 | 5 | INCLUDES = -I$(srcdir)/ref 6 | 7 | soft_pkcs11_la_SOURCES = \ 8 | main.c 9 | 10 | soft_pkcs11_la_LDFLAGS = -module 11 | soft_pkcs11_la_LIBADD = -lcrypto 12 | 13 | TESTS = run_tests 14 | 15 | check_PROGRAMS = run_tests test_soft_pkcs11 16 | 17 | test_main.c: main.c 18 | cp $(srcdir)/main.c test_main.c 19 | 20 | test_soft_pkcs11_SOURCES = test_soft_pkcs11.c test_main.c 21 | test_soft_pkcs11_LDADD = -lcrypto 22 | 23 | do_subst = sed -e 's,[@]srcdir[@],$(srcdir),g' 24 | 25 | run_tests: run_tests.in Makefile 26 | $(do_subst) < $(srcdir)/run_tests.in > run_tests.tmp 27 | chmod +x run_tests.tmp 28 | mv run_tests.tmp run_tests 29 | 30 | CLEANFILES = test-rc-file.rc test_main.c 31 | 32 | -------------------------------------------------------------------------------- /example/data/ca.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXAIBAAKBgQDQFUi5OLnCG9Zo+jaYIRv0Qn1PUB56IZYPNDrOPYj6P/023AxO 3 | oKkb/Ax/u+JSh3KrnrgUiskkTe7w4CGZK/n7rT30O46GGyFRgeJiHplp8QE8lrE5 4 | n150sUUWP2TGKeB7tG1f8FL7DtxnIHyTZz8sQKswosWxzE1N8XUanWUtzwIDAQAB 5 | AoGAHiGW4EtYisUhLR5eXXUd6SbfomaFo0XNxvHXOhorBaHSdukyVwhotIaxAKYi 6 | RbUbY8KeAUt/iORIH1U1SErX7djsNEiLbCHdxc//I6yJhNld9Fpr34mzE7A/aViH 7 | 8XXc/Eh8DnRB269vaIon0ub9El+qe2/yrGuOAu1tOsqFrAECQQDu9Y++omI5EJGB 8 | K5R+YA32ung6xrFZl0ctW+YDFlDUT+iPu7XcGeoIJPo1BZp3ghBY2gUp1ciXRMnj 9 | q3x9fxLPAkEA3uwMhtuBPQe/r2/5SAj7N/mthwRuHhtporACwYgvy8KxGclgskrf 10 | P396eS+DFZ0GabWSIWy+r+xXEs0CwDr1AQJAEMpmcFG+rx3P65ChXYPoV0bg/dhK 11 | S+5KTRChB+SAh3qZ78eTzsRvYmUew60CHpWgCm4/YKIp9x8ZRIsfMz5DlwJAAyO5 12 | 7XBL+qsQRQ1DqoMN3rTyf7NNRblHHJZ0A3vCiJEeY2mVpg0t5bwK4ogLxZMnkveO 13 | rk/Uw6+FbmtavZBXAQJBAJIDVcOJ+yCDYRKBOmOZsf+zyg64m97AhCOfScoVqOcs 14 | PjOY0wgS1s/u3nqMyO9j57jKJKS5us/lp/uBON+7QYg= 15 | -----END RSA PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /example/data/test.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXgIBAAKBgQC5vE1OzLS09JJqULhlSGBTXdBSRGTXUmt5R0Wqh5weOaWKvBXK 3 | paMwwHf7AOpjQHmDhNY00RecqGCABUGakx1YkmMTbCti2ZfSsW6NdlQcaIHOm68z 4 | Wtq35+xUB1uK+Uj2KDKbyKijw1HRYDO02yokFQVC4jP6vTjQMVfKqPpf7wIDAQAB 5 | AoGAR5RrUsgPiIGM/84WEmp/PQG1rE7Rci5AXx/5mEvk/b0HsFzmJRAKwVoboy9q 6 | JVAOxIHoL7i5WdWGQzBDZTf3IacNL4Sg6oBBdL2s/8mgOloFjV8LXmtV8doiQqC2 7 | AJa3cMyCwbXRbsmUirg7SuN5xm7R9n+0859I/++v99rb8tECQQD2XQZcYzKGVSvo 8 | jxfNVI+UrKZAODl+Uhq7iD231T6ialMwhmfLSnlPwxz4yp2eXiLwihG++Sun2fUV 9 | 9vaCYIFnAkEAwQAtNtx6tc0TgpVu4hKi1GvnSh1pTsAV1t/BqrXFcdxr+Jl64kNk 10 | Go02Mfl0LM5WLQWNdTazWXoReoOMaUvwOQJBAMPHv1NSHYe1TbR9aovpJEUhQukM 11 | BVyGgOoA5hMeKq1FU6DfXsKmB2vEgVSRJ9r/skJ3ZozeVLwKMINpBBMuAAcCQQCO 12 | Y7H3+rwxqsZNHjB7bCJjs+QlAwPxjLfQGq8IYij0cxnZhGpryiptiGdGgXMbp3Ne 13 | re0KYDv7tJp2l90cxmDJAkEAo6TI1/OoDUojGsF8vSnLbF6wp7C41uIJjzspzZ6j 14 | uJwXktaGNZBWWt0rc0F1T81fiWre2zyUaAQG3XUOiAq/7g== 15 | -----END RSA PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /example/data/ca.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICbDCCAdWgAwIBAgIJAN+VzffJ7S/TMA0GCSqGSIb3DQEBBAUAMCoxGzAZBgNV 3 | BAMMEmh4NTA5IFRlc3QgUm9vdCBDQTELMAkGA1UEBhMCU0UwHhcNMDYwMTEwMjMy 4 | MzQ2WhcNMTYwMTA4MjMyMzQ2WjAqMRswGQYDVQQDDBJoeDUwOSBUZXN0IFJvb3Qg 5 | Q0ExCzAJBgNVBAYTAlNFMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQFUi5 6 | OLnCG9Zo+jaYIRv0Qn1PUB56IZYPNDrOPYj6P/023AxOoKkb/Ax/u+JSh3KrnrgU 7 | iskkTe7w4CGZK/n7rT30O46GGyFRgeJiHplp8QE8lrE5n150sUUWP2TGKeB7tG1f 8 | 8FL7DtxnIHyTZz8sQKswosWxzE1N8XUanWUtzwIDAQABo4GZMIGWMB0GA1UdDgQW 9 | BBQZfJWD/+zYQzjWkSGeBh2yCS/SvDBaBgNVHSMEUzBRgBQZfJWD/+zYQzjWkSGe 10 | Bh2yCS/SvKEupCwwKjEbMBkGA1UEAwwSaHg1MDkgVGVzdCBSb290IENBMQswCQYD 11 | VQQGEwJTRYIJAN+VzffJ7S/TMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMA0G 12 | CSqGSIb3DQEBBAUAA4GBAGP/PQZlOq5qs6dCOgKlnRTKLjD2tpX2yC2IpVJhAMOV 13 | kM0muEdG6v6r01pbnK0kezB1ayf60QAB1iKAEys37gM3lIl8epNFalYJ4obDBK9U 14 | DAHkL8ur2AylR40PmXe/9Lt1V1yoxO1rh49Fj4ff4vPStcJwJAkJXEPNTNj06+pr 15 | -----END CERTIFICATE----- 16 | -------------------------------------------------------------------------------- /log.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include "tools.h" 5 | #include "log.h" 6 | 7 | 8 | static logger_t* logger = 0; 9 | static int tab = 0; 10 | 11 | logger_t& logger_t::instance() 12 | { 13 | if (!logger) { 14 | logger = new logger_t(); 15 | } 16 | 17 | return *logger; 18 | } 19 | 20 | logger_t& logger_t::operator()(const std::string& msg) 21 | { 22 | print_tab(); 23 | st_logf(msg.c_str()); 24 | return *this; 25 | } 26 | 27 | logger_t& logger_t::operator()(const char* fmt, ...) 28 | { 29 | print_tab(); 30 | 31 | va_list ap; 32 | va_start(ap, fmt); 33 | st_logf(fmt, ap); 34 | va_end(ap); 35 | return *this; 36 | } 37 | 38 | void logger_t::print_tab() 39 | { 40 | if (tab > 0) { 41 | st_logf(std::string(tab * 3, ' ').c_str()); 42 | } 43 | } 44 | 45 | 46 | logger_t::scopped_t::scopped_t() 47 | { 48 | ++tab; 49 | } 50 | 51 | logger_t::scopped_t::~scopped_t() 52 | { 53 | --tab; 54 | } 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(TARGET soft-pkcs) 2 | project(${TARGET}) 3 | 4 | cmake_minimum_required(VERSION 2.4) 5 | if(COMMAND cmake_policy) 6 | cmake_policy(SET CMP0003 NEW) 7 | endif(COMMAND cmake_policy) 8 | 9 | if(CMAKE_BUILD_TYPE STREQUAL Debug) 10 | add_definitions(-DDEBUG) 11 | endif() 12 | add_definitions(-DDEBUG) 13 | 14 | add_definitions("-std=c++0x -std=c++11") 15 | 16 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 17 | 18 | find_package(Boost REQUIRED COMPONENTS 19 | system 20 | filesystem 21 | ) 22 | include_directories(${Boost_INCLUDE_DIRS}) 23 | 24 | #add_subdirectory(3rdparty//qtwebdav) 25 | 26 | set(HEADERS 27 | types.h 28 | object.h 29 | soft_token.h 30 | storage.h 31 | tools.h 32 | log.h 33 | attribute.h 34 | ) 35 | 36 | set(SOURCES 37 | main.cpp 38 | tools.cpp 39 | storage.cpp 40 | soft_token.cpp 41 | object.cpp 42 | log.cpp 43 | attribute.cpp 44 | ) 45 | 46 | 47 | set(DEPS 48 | ${Boost_LIBRARIES} 49 | ) 50 | 51 | add_library(${TARGET} SHARED ${HEADERS} ${SOURCES}) 52 | target_link_libraries(${TARGET} ${DEPS}) 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /tools.h: -------------------------------------------------------------------------------- 1 | #ifndef ST_TOOLS_H 2 | #define ST_TOOLS_H 3 | 4 | #include "pkcs11/pkcs11u.h" 5 | #include "pkcs11/pkcs11.h" 6 | 7 | #include "types.h" 8 | #include "attribute.h" 9 | 10 | void st_logf(const char *fmt, ...); 11 | void st_logf(const char *fmt, va_list args); 12 | 13 | void print_attributes(const CK_ATTRIBUTE *attributes, CK_ULONG num_attributes); 14 | void print_attributes(const Attributes& attributes); 15 | 16 | std::pair> read_bignum(void* ssl_bignum); 17 | 18 | template 19 | inline std::pair create_object(CK_ATTRIBUTE_TYPE type, const T& object) { 20 | return std::make_pair(type, attribute_t(type, object)); 21 | } 22 | 23 | std::vector read_all(std::shared_ptr file); 24 | 25 | std::shared_ptr read_mem(const std::vector& data); 26 | 27 | std::shared_ptr write_mem(char **buf, size_t *size); 28 | 29 | 30 | std::string read_password(); 31 | 32 | std::string ask_password(); 33 | 34 | int ask_password_cb(char *buf, int size, int rwflag, void *userdata); 35 | 36 | std::vector piped(const std::string& cmd, const std::vector& input = std::vector()); 37 | 38 | int start(const std::string& cmd, const std::vector& input = std::vector()); 39 | 40 | 41 | #endif 42 | 43 | -------------------------------------------------------------------------------- /object.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef ST_OBJECT_H 3 | #define ST_OBJECT_H 4 | 5 | #include "types.h" 6 | 7 | 8 | struct object_t { 9 | virtual ~object_t(){} 10 | 11 | virtual Attributes operator()(descriptor_p desc, const Attributes& attributes) const = 0; 12 | }; 13 | 14 | struct data_object_t: public object_t { 15 | Attributes operator()(descriptor_p desc, const Attributes& attributes) const; 16 | }; 17 | 18 | 19 | struct public_key_t: public data_object_t { 20 | Attributes operator()(descriptor_p desc, const Attributes& attributes) const; 21 | }; 22 | 23 | struct rsa_public_key_t: public public_key_t { 24 | Attributes operator()(descriptor_p desc, const Attributes& attributes) const; 25 | }; 26 | 27 | struct ssh_public_key_t: public rsa_public_key_t { 28 | Attributes operator()(descriptor_p desc, const Attributes& attributes) const; 29 | }; 30 | 31 | 32 | struct private_key_t: public data_object_t { 33 | Attributes operator()(descriptor_p desc, const Attributes& attributes) const; 34 | }; 35 | 36 | // struct rsa_private_key_t: public private_key_t { 37 | // Attributes operator()(descriptor_p desc, const Attributes& attributes) const; 38 | // }; 39 | 40 | 41 | struct secrete_key_t: public data_object_t { 42 | Attributes operator()(descriptor_p desc, const Attributes& attributes) const; 43 | }; 44 | 45 | 46 | #endif 47 | 48 | 49 | -------------------------------------------------------------------------------- /example/java/README: -------------------------------------------------------------------------------- 1 | 2 | Java 1.5 support 3 | ================ 4 | 5 | soft-pkcs11 is now tested with the Java 1.5 pkcs11 module. To use a 6 | pkcs11 module as a keystore you have to write a configuration file. A 7 | sample one for soft-pkcs11 is includede in this directory. 8 | 9 | To use it, update the configuration file where the PKCS11 module is 10 | installed and run the command below in this directory (or use absolute 11 | path to the configuration file). 12 | 13 | keytool \ 14 | -keystore NONE \ 15 | -storetype PKCS11 \ 16 | -providerClass sun.security.pkcs11.SunPKCS11 \ 17 | -providerArg pkcs11.cfg \ 18 | -list 19 | 20 | If you get a "load failed" IOException, your configuration file might 21 | be wrong. To get a known good configuration file, run make check in 22 | the object tree and and the sample program will create a sample file 23 | called test-rc-file.rc that points out sample certificates that are 24 | included in with the distribution. You can use it with this command. 25 | 26 | Example output: 27 | 28 | $ env SOFTPKCS11RC=../test-rc-file.rc keytool -keystore NONE -storetype PKCS11 -providerClass sun.security.pkcs11.SunPKCS11 -providerArg pkcs11.cfg -list 29 | Enter keystore password: 30 | 31 | Keystore type: PKCS11 32 | Keystore provider: SunPKCS11-SoftToken 33 | 34 | Your keystore contains 2 entries 35 | 36 | User certificate, keyEntry, 37 | Certificate fingerprint (MD5): 34:54:37:E1:EF:03:6F:61:32:79:83:47:8C:ED:9A:55 38 | CA certificate, trustedCertEntry, 39 | Certificate fingerprint (MD5): E1:34:AF:32:19:47:A3:F4:37:F0:03:C1:3E:23:16:E7 40 | 41 | -------------------------------------------------------------------------------- /keys/ssh-private.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpgIBAAKCAQEAvjgnifsKFfoFC6CwUlmQSm9IZ2OgP9NhROWKG7zkuznmF6Sg 3 | a1ktj+Jk5l53BAVw00X/DPsGdw7o+HkuAueD27HVHE1CLTqj2l8QeGvM61xDK9/M 4 | VyF1fMNx622YEGv+7BfXGSrOG6tB2cZmxYNQjLD5SSd5J0ukbJMkF/AskC3nVJNa 5 | 8nFhpWn7LR1J7blzJ1hXYYbB4NxayEUTdBmgyhEjMC9mX/KByFXIPKAIH7x4a5bs 6 | IxkySPFlt98d7TiYbkLqSwAM4zSHdbkZZgDwlFbWJ4rhAts1toLS8CBtQYw1cAfu 7 | rCVebNy7+WeQUqdN4h90Z7InU+sEv26u+5TDvQIDAQABAoIBAQC4OQxZ/q4a8KRY 8 | SYzahHFRFYuqzfrSNbb7kc765CsmBIIKHd9bd+e/dQRBc/WSCG7nvt+vw6HURrVs 9 | h3f/ShcS+5yop05THXq5L950sfqpaxaG9F0jeX0eku7Okrp2FRGzt7cTYbhxZaAF 10 | +LdpzK6DQ5Z6uecFHqYknTCUmn+eNZlwoJtJWvIfSbEM7RTdbz5Esvi7K7wsNbMo 11 | BwvN7zODvH1daYYpazDpsbovj2Xcl+hHIezFx3RVGEfGPNKBheHUaROooVugx5dv 12 | hwCbQ1rnqOu2l+xeCAmocugDj59JHmG8wGY/2qxn/1oupGOLVM9j9r9BydakvHyx 13 | 8iJiqqnBAoGBAPLgcv8kp7Fyd541xVs1yF9d3vIbUxJQqIVSDOodBLZff9mup00Q 14 | 6JkSAkuTbI+4St3R6iGENrKEnMjFI4ybyLLB1z3okZL6I3ok32iVQrhIosbDxQ9p 15 | 1chRZdHv1u23RolRXOZV8oijIY5FkKm270CbbbDUrX8Q/wCz73gB7lsxAoGBAMh/ 16 | VLEHSDpx3Ad5Gn9eOky50unvJgLqnkrVQZBaCLmiIHIuvmjThCyfOoh+XFF6dj4l 17 | 4IPxDhdI/RL0F/LBDNMp0UTTYIYbTxurhJ1tE0xn57i9TVz+fouyCvwxBf0iogIU 18 | 8GsHBkL62JnbQk3HNYGEksRRe+/99JKjRrLCVzZNAoGBANLvaDB7T0Dnn0fCf3Ll 19 | 1O4ugrBWVuFzN8kCJ8E0DqGtc0ZFT3u5EanPYDrvALwZXLwl0WfmgfKtBdXAkU1P 20 | BxFpFFzqHXQ+1o0AdR9JcrbGLsjdwcnPKyJcv0eDO3EdWZ9tEHfjcU6GD2CWvjsH 21 | a+b6llubekr/IdkkbPgXBUIhAoGBAIeMZiKE7NTuczXuLvbbKokCvFABqW4hVkD7 22 | aicAZ5Oww0TOy1YtYdeVEsqCu0EujNA5ZU9uYftmEgqFUceBsnz0cZGZYlFoFxR6 23 | 4d5YhsqKGMPx32K2f7FL/lc/gXAAwQytQVjqV9Zipptl+65/tnHIwjzNZf/7biTR 24 | FBP4hWOlAoGBAIrrLQuEDixsWRH39loD094qAy8m7+noXxLN5X6kBWCty0W3oHei 25 | 24scVliHDcZt0I1/frWJ+wJoNiu5s7x+hDGO+RgEvAwRjRGPpUFBfE+o74G4imnC 26 | BEn4vzc5Jo3A77dbRLdDVBGs6f6RN9IBo8dmOUO7TgSgtX/UHfV2FiaF 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /example/config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | #ifndef RCSID 4 | #define RCSID(msg) \ 5 | static /**/const char *const rcsid[] = { (const char *)rcsid, "@(#)" msg } 6 | #endif 7 | 8 | /* Define to 1 if you have the header file. */ 9 | #undef HAVE_DLFCN_H 10 | 11 | /* Define to 1 if you have the header file. */ 12 | #undef HAVE_INTTYPES_H 13 | 14 | /* Define to 1 if you have the header file. */ 15 | #undef HAVE_MEMORY_H 16 | 17 | /* Define to 1 if you have the header file. */ 18 | #undef HAVE_STDINT_H 19 | 20 | /* Define to 1 if you have the header file. */ 21 | #undef HAVE_STDLIB_H 22 | 23 | /* Define to 1 if you have the header file. */ 24 | #undef HAVE_STRINGS_H 25 | 26 | /* Define to 1 if you have the header file. */ 27 | #undef HAVE_STRING_H 28 | 29 | /* Define to 1 if you have the header file. */ 30 | #undef HAVE_SYS_STAT_H 31 | 32 | /* Define to 1 if you have the header file. */ 33 | #undef HAVE_SYS_TYPES_H 34 | 35 | /* Define to 1 if you have the header file. */ 36 | #undef HAVE_UNISTD_H 37 | 38 | /* Name of package */ 39 | #undef PACKAGE 40 | 41 | /* Define to the address where bug reports for this package should be sent. */ 42 | #undef PACKAGE_BUGREPORT 43 | 44 | /* Define to the full name of this package. */ 45 | #undef PACKAGE_NAME 46 | 47 | /* Define to the full name and version of this package. */ 48 | #undef PACKAGE_STRING 49 | 50 | /* Define to the one symbol short name of this package. */ 51 | #undef PACKAGE_TARNAME 52 | 53 | /* Define to the version of this package. */ 54 | #undef PACKAGE_VERSION 55 | 56 | /* Define to 1 if you have the ANSI C header files. */ 57 | #undef STDC_HEADERS 58 | 59 | /* Version number of package */ 60 | #undef VERSION 61 | -------------------------------------------------------------------------------- /soft_token.h: -------------------------------------------------------------------------------- 1 | #ifndef ST_SOFT_TOKEN_H 2 | #define ST_SOFT_TOKEN_H 3 | 4 | #include "types.h" 5 | #include 6 | 7 | 8 | 9 | typedef std::vector Handles; 10 | typedef std::function handle_iterator_t; 11 | 12 | typedef std::map Attributes; 13 | typedef std::map Objects; 14 | 15 | typedef std::function ObjectsPred; 16 | typedef boost::filter_iterator ObjectsIterator; 17 | 18 | 19 | class soft_token_t { 20 | public: 21 | 22 | soft_token_t(const std::string& rcfile); 23 | ~soft_token_t(); 24 | 25 | 26 | bool ssh_agent() const; 27 | 28 | bool ready() const; 29 | bool logged() const; 30 | bool login(const std::string& pin); 31 | void logout(); 32 | 33 | std::string full_name() const; 34 | 35 | Handles handles() const; 36 | 37 | ObjectsIterator begin(); 38 | ObjectsIterator begin(Attributes attrs); 39 | ObjectsIterator end(); 40 | static CK_OBJECT_HANDLE handle_invalid(); 41 | 42 | Attributes attributes(CK_OBJECT_HANDLE id) const; 43 | bool has_object(CK_OBJECT_HANDLE id) const; 44 | bool check(CK_OBJECT_HANDLE id, const Attributes& attrs) const; 45 | 46 | std::string read(CK_OBJECT_HANDLE id); 47 | CK_OBJECT_HANDLE write(const std::string& filename, const std::vector& data, const Attributes& attrs = Attributes()); 48 | 49 | 50 | std::vector sign(CK_OBJECT_HANDLE id, CK_MECHANISM_TYPE type, CK_BYTE_PTR pData, CK_ULONG ulDataLen); 51 | 52 | std::vector create_key(CK_OBJECT_CLASS klass, const Attributes& attrs) const; 53 | 54 | 55 | private: 56 | 57 | void check_storage(); 58 | void reset(); 59 | 60 | struct Pimpl; 61 | std::auto_ptr p_; 62 | }; 63 | 64 | 65 | 66 | #endif 67 | 68 | -------------------------------------------------------------------------------- /storage.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef ST_STORAGE_H 3 | #define ST_STORAGE_H 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include "types.h" 12 | #include "tools.h" 13 | 14 | struct item_t { 15 | item_t(const std::string& fn, const std::vector& d, const Attributes& a = Attributes()) 16 | : filename(fn) 17 | , data(d) 18 | , attributes(a) 19 | {} 20 | 21 | const std::string filename; 22 | const std::vector data; 23 | Attributes attributes; 24 | }; 25 | 26 | struct storage_t { 27 | 28 | virtual ~storage_t(){}; 29 | 30 | static std::shared_ptr create(const boost::property_tree::ptree& config, const std::string& pin = std::string()); 31 | 32 | virtual std::list items() = 0; 33 | virtual item_t read(const std::string& fn) = 0; 34 | virtual item_t write(const item_t& item) = 0; 35 | 36 | virtual bool present() const = 0; 37 | virtual void set_pin(const std::string& pin) = 0; 38 | 39 | std::string full_name() const { 40 | if (prev) { 41 | return name() + "|" + prev->full_name(); 42 | } 43 | else { 44 | return name(); 45 | } 46 | } 47 | 48 | 49 | protected: 50 | storage_t(const std::string& n, const boost::property_tree::ptree& c, std::shared_ptr s = std::shared_ptr()) 51 | : name_(n), prev(s), config_(c){}; 52 | storage_t(const storage_t& other) = delete; 53 | storage_t& operator=(const storage_t& other) = delete; 54 | 55 | const std::string& name() const {return name_;}; 56 | 57 | std::string name_; 58 | std::shared_ptr prev; 59 | boost::property_tree::ptree config_; 60 | std::string path_; 61 | }; 62 | 63 | struct descriptor_t { 64 | 65 | descriptor_t(const item_t& it); 66 | ~descriptor_t() {} 67 | 68 | const item_t item; 69 | std::string first_line; 70 | CK_OBJECT_HANDLE id; 71 | std::shared_ptr file; 72 | }; 73 | 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /attribute.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include "attribute.h" 6 | 7 | attribute_t::attribute_t(const CK_ATTRIBUTE& other) { 8 | this->operator=(other); 9 | } 10 | 11 | // attribute_t::attribute_t(CK_ATTRIBUTE_TYPE type, CK_ULONG size) { 12 | // attr_.type = type; 13 | // attr_.pValue = NULL_PTR; 14 | // attr_.ulValueLen = size; 15 | // } 16 | 17 | attribute_t::attribute_t(CK_ATTRIBUTE_TYPE type, CK_VOID_PTR value, CK_ULONG size) { 18 | CK_ATTRIBUTE other; 19 | other.type = type; 20 | other.pValue = value; 21 | other.ulValueLen = size; 22 | 23 | this->operator=(other); 24 | } 25 | 26 | attribute_t::attribute_t(CK_ATTRIBUTE_TYPE type, const std::string& string) { 27 | CK_ATTRIBUTE other; 28 | other.type = type; 29 | other.pValue = const_cast(string.c_str()); 30 | other.ulValueLen = string.size(); 31 | 32 | this->operator=(other); 33 | } 34 | 35 | attribute_t::attribute_t(CK_ATTRIBUTE_TYPE type, const std::vector& bytes) 36 | { 37 | CK_ATTRIBUTE other; 38 | other.type = type; 39 | other.pValue = const_cast(bytes.data()); 40 | other.ulValueLen = bytes.size(); 41 | 42 | this->operator=(other); 43 | } 44 | 45 | #include "tools.h" 46 | 47 | bool attribute_t::operator==(const attribute_t& other) const 48 | { 49 | if (other.attr_.type != attr_.type) return false; 50 | if (other.attr_.ulValueLen != attr_.ulValueLen) return false; 51 | if (other.attr_.pValue == NULL_PTR && attr_.pValue == NULL_PTR) return true; 52 | 53 | return memcmp(other.ptr_.get(), ptr_.get(), attr_.ulValueLen) == 0; 54 | } 55 | 56 | bool attribute_t::operator!=(const attribute_t& other) const 57 | { 58 | return !(*this == other); 59 | } 60 | 61 | attribute_t& attribute_t::operator=(const CK_ATTRIBUTE& other) { 62 | 63 | if (other.ulValueLen != -1 && other.pValue != 0) { 64 | ptr_.reset(malloc(other.ulValueLen), free); 65 | if (!ptr_.get()) throw std::bad_alloc(); 66 | memcpy(ptr_.get(), other.pValue, other.ulValueLen); 67 | } 68 | 69 | attr_.type = other.type; 70 | attr_.pValue = ptr_.get(); 71 | attr_.ulValueLen = other.ulValueLen; 72 | return *this; 73 | } 74 | 75 | void attribute_t::apply(CK_ATTRIBUTE& dst) const { 76 | assert(dst.type == attr_.type); 77 | 78 | if (dst.pValue != NULL_PTR && attr_.pValue != NULL_PTR && dst.ulValueLen >= attr_.ulValueLen) 79 | { 80 | memcpy(dst.pValue, attr_.pValue, attr_.ulValueLen); 81 | } 82 | 83 | dst.ulValueLen = attr_.ulValueLen; 84 | } 85 | -------------------------------------------------------------------------------- /attribute.h: -------------------------------------------------------------------------------- 1 | #ifndef ST_ATTRIBUTE_H 2 | #define ST_ATTRIBUTE_H 3 | 4 | #include 5 | #include 6 | 7 | #include "pkcs11/pkcs11u.h" 8 | #include "pkcs11/pkcs11.h" 9 | 10 | struct attribute_t { 11 | 12 | attribute_t() : attr_({0,0,0}) {} 13 | attribute_t(const CK_ATTRIBUTE& other); 14 | 15 | attribute_t(CK_ATTRIBUTE_TYPE type, CK_VOID_PTR value, CK_ULONG size); 16 | 17 | attribute_t(CK_ATTRIBUTE_TYPE type, const std::string& string); 18 | attribute_t(CK_ATTRIBUTE_TYPE type, const std::vector& bytes); 19 | 20 | template 21 | attribute_t(CK_ATTRIBUTE_TYPE type, const T& object) { 22 | CK_ATTRIBUTE other; 23 | other.type = type; 24 | other.pValue = const_cast(&object); 25 | other.ulValueLen = sizeof(object); 26 | 27 | this->operator=(other); 28 | } 29 | 30 | bool operator==(const attribute_t& other) const; 31 | bool operator!=(const attribute_t& other) const; 32 | 33 | attribute_t& operator=(const CK_ATTRIBUTE& other); 34 | 35 | void apply(CK_ATTRIBUTE& dst) const; 36 | 37 | const CK_ATTRIBUTE* operator->() const { 38 | return &attr_; 39 | } 40 | 41 | template 42 | inline T value() const { 43 | return reinterpret_cast(attr_.pValue); 44 | } 45 | 46 | template 47 | inline T to_value() const { 48 | return (attr_.pValue) 49 | ? *(reinterpret_cast(attr_.pValue)) 50 | : 0; 51 | } 52 | 53 | inline CK_OBJECT_HANDLE to_handle() const { 54 | return to_value(); 55 | } 56 | 57 | inline CK_ULONG to_id() const { 58 | return to_value(); 59 | } 60 | 61 | inline const std::string to_object_id() const { 62 | return to_string(); 63 | } 64 | 65 | inline const std::string to_string() const { 66 | return (attr_.pValue) 67 | ? std::string(reinterpret_cast(attr_.pValue), attr_.ulValueLen) 68 | : std::string(""); 69 | } 70 | 71 | inline const std::vector to_bytes() const { 72 | return std::vector(reinterpret_cast(attr_.pValue), reinterpret_cast(attr_.pValue) + attr_.ulValueLen); 73 | } 74 | 75 | inline bool to_bool() const { 76 | return attr_.pValue && *(reinterpret_cast(attr_.pValue)) == CK_TRUE; 77 | } 78 | 79 | inline CK_OBJECT_CLASS to_class() const { 80 | if (attr_.ulValueLen != sizeof(CK_OBJECT_CLASS)) { 81 | throw std::runtime_error("can't cast to CK_OBJECT_CLASS: invalid value length"); 82 | } 83 | return to_value(); 84 | } 85 | 86 | private: 87 | CK_ATTRIBUTE attr_; 88 | std::shared_ptr ptr_; 89 | }; 90 | 91 | 92 | #endif 93 | 94 | -------------------------------------------------------------------------------- /example/locl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2004, Stockholms universitet 3 | * (Stockholm University, Stockholm Sweden) 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * 3. Neither the name of the university nor the names of its contributors 18 | * may be used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 25 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | * POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | 34 | /* $Id: locl.h,v 1.5 2005/08/28 15:30:31 lha Exp $ */ 35 | 36 | #ifdef HAVE_CONFIG_H 37 | #include 38 | #endif 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | 55 | #include 56 | #include 57 | 58 | #define OPENSSL_ASN1_MALLOC_ENCODE(T, B, BL, S, R) \ 59 | { \ 60 | unsigned char *p; \ 61 | (BL) = i2d_##T((S), NULL); \ 62 | if ((BL) <= 0) { \ 63 | (R) = EINVAL; \ 64 | } else { \ 65 | (B) = malloc((BL)); \ 66 | if ((B) == NULL) { \ 67 | (R) = ENOMEM; \ 68 | } else { \ 69 | p = (B); \ 70 | (R) = 0; \ 71 | (BL) = i2d_##T((S), &p); \ 72 | if ((BL) <= 0) { \ 73 | free((B)); \ 74 | (R) = EINVAL; \ 75 | } \ 76 | } \ 77 | } \ 78 | } 79 | -------------------------------------------------------------------------------- /example/release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # $Id: release.sh,v 1.2 2005/08/28 15:36:00 lha Exp $ 3 | # 4 | 5 | package=soft-pkcs11 6 | ftp=/afs/su.se/home/l/h/lha/Public/soft-pkcs11 7 | checkversion=YES 8 | name=`basename $0` 9 | root=vr.l.nxs.se:/cvsroot 10 | 11 | if [ X"$#" = X0 ]; then 12 | echo "$name [-tag branch] version" 13 | exit 1 14 | fi 15 | 16 | while true ; do 17 | case "$1" in 18 | -tag) 19 | shift 20 | if [ X"$#" = X0 ] ; then 21 | echo "missing tagname"; exit 1; 22 | fi 23 | tag_name="$1" 24 | ;; 25 | -h*) 26 | echo $name [-tag branch] version 27 | echo $name -tag tupp-0-35-branch 0.35.3pre1 28 | echo $name -tag HEAD 0.36pre1 29 | echo $name 0.36 30 | exit 1 31 | ;; 32 | -*) 33 | echo "$name: unknown option $1" 34 | exit 1 35 | ;; 36 | *) 37 | break 38 | ;; 39 | esac 40 | shift 41 | done 42 | 43 | if [ X$# != X1 ]; then 44 | echo "$name: missing version" 45 | exit 1 46 | fi 47 | 48 | version="$1" 49 | 50 | if expr "$version" : ${package} > /dev/null ; then 51 | echo "version number should not contain \"${package}\"" 52 | exit 1 53 | fi 54 | 55 | 56 | if [ X"${tag_name}" = "X" ]; then 57 | tag_name=${package}-`echo "${version}" | sed 's,\.,-,g'` 58 | fi 59 | 60 | echo preparing "${package}-${version}" from tag ${tag_name} 61 | 62 | exportfile=${package}-export-log.$$ 63 | 64 | echo exporting tree... 65 | cvs -d $root \ 66 | export -d "${package}-${version}" -r "${tag_name}" ${package} > $exportfile 67 | res=$? 68 | if [ X"$res" != X0 ]; then 69 | echo "cvs export failed, check $exportfile" 70 | exit 1 71 | fi 72 | rm $exportfile 73 | 74 | ac="notfound" 75 | [ -f "${package}-${version}/configure.in" ] && ac="configure.in" 76 | [ -f "${package}-${version}/configure.ac" ] && ac="configure.ac" 77 | if [ "$ac" = notfound ] ; then 78 | echo "could not find configure, confused" 79 | exit 1 80 | fi 81 | 82 | if [ X"$checkversion" = XYES ]; then 83 | echo checking version 84 | chkver=`grep -e '^VERSION=' "${package}-${version}/$ac" | sed 's,[^=]*=,,'` 85 | if [ "X$chkver" = X ]; then 86 | chkver=`grep -e '^AC_INIT(' "${package}-${version}/$ac" | sed 's/[^,]*,[ ]*//;s/[ ]*,.*//'` 87 | fi 88 | 89 | if [ "X${chkver}" != "X${version}" ]; then 90 | echo "version mismatch ${chkver} != ${version}" 91 | exit 1 92 | fi 93 | fi 94 | 95 | echo "autofooing" 96 | res=0 97 | done=0 98 | if [ -d "${package}-${version}" ] ; then 99 | cd "${package}-${version}" 100 | if [ -f HACKING ]; then 101 | sh HACKING 102 | res=$? 103 | done=1 104 | fi 105 | if [ -f regen.sh ]; then 106 | sh regen.sh 107 | res=$? 108 | done=1 109 | fi 110 | if [ "X$done" = X0 ] ; then 111 | autoreconf -f -i 112 | fi 113 | cd .. 114 | fi 115 | if [ X"$res" != X0 ]; then 116 | echo "autofooing failed" 117 | exit 1 118 | fi 119 | 120 | echo "removing autom4te cache" 121 | amc="${package}-${version}/autom4te*.cache" 122 | if [ -d ${amc} ] ; then 123 | rm -r ${amc} 124 | fi 125 | 126 | if [ -f "${package}-${version}/doc/${package}.texi" ] ; then 127 | echo "generate info documenation" 128 | (cd "${package}-${version}/doc" && makeinfo "${package}.texi") 129 | fi 130 | 131 | echo "rolling tar-ball" 132 | tar cf - "${package}-${version}" | gzip -9 > "${package}-${version}.tar.gz" 133 | res=$? 134 | if [ X"$res" != X0 ]; then 135 | echo "creation of tar-ball failed" 136 | exit 1 137 | fi 138 | 139 | if [ -d $HOME/.gnupg ] ; then 140 | gpg -b -a ${package}-${version}.tar.gz 141 | fi 142 | 143 | echo Done! 144 | echo Dont forget to copy the "${package}-${version}.tar.gz" file to the ftp-site. 145 | test X"$ftp" != X && echo "cp ${package}-${version}.tar.gz* $ftp" 146 | exit 0 147 | -------------------------------------------------------------------------------- /function_wrap.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define FUSION_MAX_MAP_SIZE 30 9 | #define FUSION_MAX_VECTOR_SIZE 30 10 | 11 | #include 12 | #include 13 | 14 | #include "pkcs11/pkcs11u.h" 15 | #include "pkcs11/pkcs11.h" 16 | 17 | unsigned int constexpr const_hash(char const *input) { 18 | return *input 19 | ? static_cast(*input) + 33 * const_hash(input + 1) 20 | : 5381; 21 | } 22 | 23 | template 24 | struct tag_s { 25 | enum {value = T}; 26 | }; 27 | 28 | template 29 | Function rvcast(Function f) {return f;} 30 | 31 | #define __ADD_TAG(r, data, elem) (tag_s) 32 | #define __ADD_RVCAST(r, data, elem) (rvcast(elem)) 33 | 34 | #define IMPLEMENTED_FUNCTIONS (\ 35 | C_Initialize, C_Finalize,\ 36 | C_GetInfo, C_GetFunctionList, C_GetSlotList, C_GetSlotInfo, C_GetTokenInfo,\ 37 | C_GetMechanismList, C_GetMechanismInfo,\ 38 | C_InitToken, C_InitPIN,\ 39 | C_OpenSession, C_CloseSession,\ 40 | C_GetSessionInfo,\ 41 | C_Login, C_Logout,\ 42 | C_CreateObject,\ 43 | C_GetAttributeValue,\ 44 | C_FindObjectsInit, C_FindObjects, C_FindObjectsFinal,\ 45 | C_SignInit, C_Sign, C_SignUpdate, C_SignFinal\ 46 | ) 47 | 48 | #define __TUPLE_SEQ BOOST_PP_TUPLE_TO_SEQ(IMPLEMENTED_FUNCTIONS) 49 | 50 | #define __SEQ_WITH_CK BOOST_PP_SEQ_FOR_EACH(__ADD_TAG, 0, __TUPLE_SEQ) 51 | #define __SEQ_WITH_RVCAST BOOST_PP_SEQ_FOR_EACH(__ADD_RVCAST, 0, __TUPLE_SEQ) 52 | 53 | #define __TUPLE_WITH_CK BOOST_PP_SEQ_TO_TUPLE(__SEQ_WITH_CK) 54 | #define __TUPLE_WITH_RVCAST BOOST_PP_SEQ_TO_TUPLE(__SEQ_WITH_RVCAST) 55 | 56 | 57 | #define FUNCTION_TYPES BOOST_PP_TUPLE_REM_CTOR(BOOST_PP_TUPLE_SIZE(__TUPLE_WITH_CK), __TUPLE_WITH_CK) 58 | #define FUNCTION_CASTS BOOST_PP_TUPLE_REM_CTOR(BOOST_PP_TUPLE_SIZE(__TUPLE_WITH_RVCAST), __TUPLE_WITH_RVCAST) 59 | 60 | const auto functions_c = boost::fusion::make_map(FUNCTION_CASTS); 61 | 62 | template 63 | struct function_name_holder { 64 | 65 | function_name_holder(){}; 66 | function_name_holder(const std::string& fn) {set_value(fn);} 67 | void set_value(const std::string& fn) {instance()->value_ = fn;} 68 | 69 | static const std::string& value() {return instance()->value_;} 70 | 71 | private: 72 | static function_name_holder* instance() { 73 | if (!p_) p_ = new function_name_holder(); 74 | return p_; 75 | }; 76 | 77 | std::string value_; 78 | static function_name_holder* p_; 79 | }; 80 | 81 | template 82 | function_name_holder* function_name_holder::p_ = 0; 83 | 84 | 85 | template 86 | CK_RV wrap_function_impl(Args... args) { 87 | return Handler::handle(boost::fusion::at_key(functions_c), args...); 88 | } 89 | 90 | template 91 | Function wrap_exceptions() 92 | { 93 | return static_cast(wrap_function_impl); 94 | } 95 | 96 | template 97 | CK_RV wrap_not_implemented_impl(Args... args) { 98 | LOG("%s - not implemeted!", function_name_holder::value().c_str()); 99 | return CKR_FUNCTION_NOT_SUPPORTED; 100 | } 101 | 102 | template 103 | Function wrap_not_implemented(const std::string& fn) 104 | { 105 | function_name_holder().set_value(fn); 106 | return static_cast(wrap_not_implemented_impl); 107 | } 108 | 109 | #define WRAP_FUNCTION(function_type, handler) wrap_exceptions, handler>() 110 | 111 | #define WRAP_NOT_IMPLEMENTED(function_type) wrap_not_implemented>(#function_type) 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /example/test_soft_pkcs11.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2006, Stockholms universitet 3 | * (Stockholm University, Stockholm Sweden) 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions 8 | * are met: 9 | * 10 | * 1. Redistributions of source code must retain the above copyright 11 | * notice, this list of conditions and the following disclaimer. 12 | * 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * 3. Neither the name of the university nor the names of its contributors 18 | * may be used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 25 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | * POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | 34 | /* $Id: test_soft_pkcs11.c,v 1.5 2006/01/11 12:41:18 lha Exp $ */ 35 | 36 | #include "locl.h" 37 | 38 | static CK_RV 39 | find_object(CK_SESSION_HANDLE session, 40 | char *id, 41 | CK_OBJECT_CLASS key_class, 42 | CK_OBJECT_HANDLE_PTR object) 43 | { 44 | CK_ULONG object_count; 45 | CK_RV ret; 46 | CK_ATTRIBUTE search_data[] = { 47 | {CKA_ID, id, 0 }, 48 | {CKA_CLASS, &key_class, sizeof(key_class)} 49 | }; 50 | CK_ULONG num_search_data = sizeof(search_data)/sizeof(search_data[0]); 51 | 52 | search_data[0].ulValueLen = strlen(id); 53 | 54 | ret = C_FindObjectsInit(session, search_data, num_search_data); 55 | if (ret != CKR_OK) 56 | return ret; 57 | 58 | ret = C_FindObjects(session, object, 1, &object_count); 59 | if (ret != CKR_OK) 60 | return ret; 61 | if (object_count == 0) { 62 | printf("found no object\n"); 63 | return 1; 64 | } 65 | 66 | ret = C_FindObjectsFinal(session); 67 | if (ret != CKR_OK) 68 | return ret; 69 | 70 | return CKR_OK; 71 | } 72 | 73 | static char *sighash = "hej"; 74 | static char signature[1024]; 75 | static char outdata[1024]; 76 | 77 | 78 | int 79 | main(int argc, char **argv) 80 | { 81 | CK_SLOT_ID_PTR slot_ids; 82 | CK_SLOT_ID slot; 83 | CK_ULONG num_slots; 84 | CK_RV ret; 85 | CK_SLOT_INFO slot_info; 86 | CK_TOKEN_INFO token_info; 87 | CK_SESSION_HANDLE session; 88 | CK_OBJECT_HANDLE public, private; 89 | 90 | C_Initialize(NULL_PTR); 91 | 92 | ret = C_GetSlotList(FALSE, NULL, &num_slots); 93 | if (ret) 94 | return 1; 95 | 96 | if (num_slots == 0) 97 | return 1; 98 | 99 | if ((slot_ids = calloc(1, num_slots * sizeof(*slot_ids))) == NULL) 100 | return 1; 101 | 102 | ret = C_GetSlotList(FALSE, slot_ids, &num_slots); 103 | if (ret) 104 | return 1; 105 | 106 | slot = slot_ids[0]; 107 | free(slot_ids); 108 | 109 | ret = C_GetSlotInfo(slot, &slot_info); 110 | if (ret) 111 | return 1; 112 | 113 | if ((slot_info.flags & CKF_TOKEN_PRESENT) == 0) 114 | return 1; 115 | 116 | ret = C_GetTokenInfo(slot, &token_info); 117 | if (ret) 118 | return 1; 119 | 120 | if (token_info.flags & CKF_LOGIN_REQUIRED) { 121 | printf("login required, no C_Login support yet"); 122 | return 1; 123 | } 124 | 125 | ret = C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL, &session); 126 | if (ret != CKR_OK) 127 | return 1; 128 | 129 | ret = find_object(session, "cert", CKO_PUBLIC_KEY, &public); 130 | if (ret) 131 | return 1; 132 | ret = find_object(session, "cert", CKO_PRIVATE_KEY, &private); 133 | if (ret) 134 | return 1; 135 | 136 | { 137 | CK_ULONG ck_sigsize; 138 | CK_MECHANISM mechanism; 139 | 140 | memset(&mechanism, 0, sizeof(mechanism)); 141 | mechanism.mechanism = CKM_RSA_PKCS; 142 | 143 | ret = C_SignInit(session, &mechanism, private); 144 | if (ret != CKR_OK) 145 | return 1; 146 | 147 | ck_sigsize = sizeof(signature); 148 | ret = C_Sign(session, (CK_BYTE *)sighash, strlen(sighash), 149 | (CK_BYTE *)signature, &ck_sigsize); 150 | if (ret != CKR_OK) { 151 | printf("message: %d\n", ret); 152 | return 1; 153 | } 154 | 155 | ret = C_VerifyInit(session, &mechanism, public); 156 | if (ret != CKR_OK) 157 | return 1; 158 | 159 | ret = C_Verify(session, (CK_BYTE *)signature, ck_sigsize, 160 | (CK_BYTE *)sighash, strlen(sighash)); 161 | if (ret != CKR_OK) { 162 | printf("message: %d\n", ret); 163 | return 1; 164 | } 165 | } 166 | 167 | { 168 | CK_ULONG ck_sigsize, outsize; 169 | CK_MECHANISM mechanism; 170 | 171 | memset(&mechanism, 0, sizeof(mechanism)); 172 | mechanism.mechanism = CKM_RSA_PKCS; 173 | 174 | ret = C_EncryptInit(session, &mechanism, public); 175 | if (ret != CKR_OK) 176 | return 1; 177 | 178 | ck_sigsize = sizeof(signature); 179 | ret = C_Encrypt(session, (CK_BYTE *)sighash, strlen(sighash), 180 | (CK_BYTE *)signature, &ck_sigsize); 181 | if (ret != CKR_OK) { 182 | printf("message: %d\n", ret); 183 | return 1; 184 | } 185 | 186 | ret = C_DecryptInit(session, &mechanism, private); 187 | if (ret != CKR_OK) 188 | return 1; 189 | 190 | outsize = sizeof(outdata); 191 | ret = C_Decrypt(session, (CK_BYTE *)signature, ck_sigsize, 192 | (CK_BYTE *)outdata, &outsize); 193 | if (ret != CKR_OK) { 194 | printf("message: %d\n", ret); 195 | return 1; 196 | } 197 | 198 | if (memcmp(sighash, outdata, strlen(sighash)) != 0) 199 | return 1; 200 | } 201 | 202 | ret = C_CloseSession(session); 203 | if (ret != CKR_OK) 204 | return 1; 205 | 206 | C_Finalize(NULL_PTR); 207 | 208 | return 0; 209 | } 210 | -------------------------------------------------------------------------------- /spec/fs_spec.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'rspec' 3 | 4 | RSpec.configure do |config| 5 | config.color = true 6 | config.tty = true 7 | config.formatter = :documentation 8 | end 9 | 10 | 11 | shared_context "Initialize folder", need_values: 'dirs' do 12 | before(:all) do 13 | %x(mkdir -p /tmp/st/) 14 | @tmpdir=%x(mktemp -d -p /tmp/st).strip 15 | @keydir="#{@tmpdir}/keys" 16 | @keydir2="#{@tmpdir}/keys/tmp" 17 | %x(mkdir -p #{@keydir}) 18 | %x(mkdir -p #{@keydir2}) 19 | @cfgfile="#{@tmpdir}/.soft-token.rc" 20 | @module="#{ENV['MODULE']}/libsoft-pkcs.so" 21 | 22 | ENV['SOFTPKCS11RC'] = @cfgfile 23 | 24 | puts "export SOFTPKCS11RC=\"#{@cfgfile}\"" 25 | end 26 | 27 | before(:each) do 28 | end 29 | 30 | after(:all) do 31 | if @tmpdir['/tmp/st'] && File.exists?(@tmpdir) 32 | # FileUtils.rm_rf(@tmpdir) 33 | end 34 | end 35 | 36 | end 37 | 38 | shared_examples "simple keypair" do 39 | it "should deal with simple keypair" do 40 | output = %x(ssh-keygen -f #{@keydir}/test -N "") 41 | result = ($? == 0) 42 | expect(result).to eq true 43 | 44 | output = %x(pkcs11-tool --module #{@module} -O -l -p 123123123) 45 | result = ($? == 0) 46 | expect(result).to eq true 47 | expect(output.strip.split("\n").count).to eq 13 48 | end 49 | 50 | context "should read" do 51 | 52 | it "SSH public key" do 53 | sshpub = %x(pkcs11-tool --module #{@module} -l -p 123123123 -r -y pubkey -a "SSH test.pub") 54 | result = ($? == 0) 55 | expect(result).to eq true 56 | expect(File.read("#{@keydir}/test.pub").strip).to eq sshpub.strip 57 | end 58 | 59 | it "SSH private key" do 60 | sshpriv = %x(pkcs11-tool --module #{@module} -l -p 123123123 -r -y privkey -a "test") 61 | result = ($? == 0) 62 | expect(result).to eq true 63 | expect(File.read("#{@keydir}/test").strip).to eq sshpriv.strip 64 | end 65 | 66 | it "SSH public key in openssl format" do 67 | rsapub = %x(pkcs11-tool --module #{@module} -l -p 123123123 -r -y pubkey -a "test.pub") 68 | result = ($? == 0) 69 | rsapub2 = %x(ssh-keygen -f #{@keydir}/test.pub -e -m PKCS8) 70 | result2 = ($? == 0) 71 | 72 | expect(result).to eq true 73 | expect(result2).to eq true 74 | expect(rsapub.strip).to eq rsapub2.strip 75 | end 76 | 77 | end 78 | 79 | end 80 | 81 | shared_examples "store keypair" do 82 | it "generate another keypair" do 83 | output = %x(ssh-keygen -f #{@keydir2}/newkey -N "") 84 | result = ($? == 0) 85 | expect(result).to eq true 86 | 87 | output = %x(pkcs11-tool --module #{@module} -O -l -p 123123123 | grep newkey) 88 | result = ($? == 0) 89 | expect(result).to eq false 90 | expect(output.strip.split("\n").count).to eq 0 91 | end 92 | 93 | 94 | context "add keys to container" do 95 | it "private key" do 96 | output = %x(pkcs11-tool --module #{@module} -l -p 123123123 -w #{@keydir2}/newkey --label newkey.key --type data) 97 | result = ($? == 0) 98 | 99 | output = %x(pkcs11-tool --module #{@module} -O -l -p 123123123 | grep newkey) 100 | result = ($? == 0) 101 | expect(result).to eq true 102 | expect(output.strip.split("\n").count).to eq 1 103 | 104 | end 105 | 106 | it "public key" do 107 | output = %x(pkcs11-tool --module #{@module} -l -p 123123123 -w #{@keydir2}/newkey.pub --label newkey.pub --type data) 108 | result = ($? == 0) 109 | 110 | output = %x(pkcs11-tool --module #{@module} -O -l -p 123123123 | grep newkey) 111 | result = ($? == 0) 112 | expect(result).to eq true 113 | expect(output.strip.split("\n").count).to eq 3 114 | end 115 | 116 | 117 | it "compare keys" do 118 | output = %x(pkcs11-tool --module #{@module} -l -p 123123123 -r --label newkey.key -y privkey) 119 | result = ($? == 0) 120 | expect(output.strip).to eq File.read("#{@keydir2}/newkey").strip 121 | 122 | output = %x(pkcs11-tool --module #{@module} -l -p 123123123 -r --label "SSH newkey.pub" -y pubkey) 123 | result = ($? == 0) 124 | expect(output.strip).to eq File.read("#{@keydir2}/newkey.pub").strip 125 | end 126 | 127 | it "sign data with module and openssl" do 128 | output = %x(echo "Data to SIGN" | pkcs11-tool --module #{@module} -l -p 123123123 -m RSA-PKCS -s -a newkey.key -o #{@keydir2}/token_sign) 129 | result = ($? == 0) 130 | expect(result).to eq true 131 | 132 | output = %x(echo "Data to SIGN" | openssl rsautl -sign -inkey #{@keydir2}/newkey -out #{@keydir2}/openssl_sign) 133 | result = ($? == 0) 134 | expect(result).to eq true 135 | 136 | expect(File.read("#{@keydir2}/token_sign")).to eq File.read("#{@keydir2}/openssl_sign") 137 | 138 | output = %x(openssl rsautl -verify -in #{@keydir2}/token_sign -inkey #{@keydir2}/newkey -raw -hexdump) 139 | result = ($? == 0) 140 | expect(result).to eq true 141 | end 142 | end 143 | 144 | 145 | end 146 | 147 | 148 | 149 | describe "local FS driver", need_values: 'dirs' do 150 | 151 | it "must list empty keys folder" do 152 | 153 | config = %{ 154 | [local fs for test] 155 | driver=fs 156 | path=#{@keydir} 157 | }.strip 158 | 159 | File.write(@cfgfile, config) 160 | expect(File.read(@cfgfile).strip).to eq config 161 | 162 | output = %x(pkcs11-tool --module #{@module} -O -l -p 123123123) 163 | result = ($? == 0) 164 | expect(result).to eq true 165 | expect(output.strip.split("\n").count).to eq 0 166 | 167 | end 168 | 169 | include_examples "simple keypair" 170 | include_examples "store keypair" 171 | 172 | end 173 | 174 | 175 | describe "local crypto driver", need_values: 'dirs' do 176 | 177 | it "must list empty keys folder" do 178 | 179 | config = %{ 180 | [local fs for test] 181 | driver=fs 182 | path=#{@keydir} 183 | 184 | [openssl encryption] 185 | driver=crypt 186 | decrypt=/usr/bin/openssl enc -d -base64 -aes-256-cbc -k '%PIN%' 187 | encrypt=/usr/bin/openssl enc -base64 -aes-256-cbc -k '%PIN%' 188 | }.strip 189 | 190 | File.write(@cfgfile, config) 191 | expect(File.read(@cfgfile).strip).to eq config 192 | 193 | output = %x(pkcs11-tool --module #{@module} -O -l -p 123123123) 194 | result = ($? == 0) 195 | expect(result).to eq true 196 | expect(output.strip.split("\n").count).to eq 0 197 | 198 | end 199 | 200 | include_examples "store keypair" 201 | 202 | end -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # soft-pkcs11 2 | 3 | soft-pkcs11 is a software only pkcs11 implementation. The main idea is to be able to turn your phone into secure keychain. But you can use this module as you wish. 4 | 5 | It is inspired by soft-pkcs11(http://people.su.se/~lha/soft-pkcs11/README) implementation by Love Hörnquist Åstrand(http://people.su.se/~lha/) and includes it as an example. 6 | 7 | It only handles RSA, this is because I use it for ssh-agent. 8 | 9 | It is not production-ready yet but I'am using it every day. 10 | 11 | 12 | ## Features 13 | 14 | * Can working with simple folder with keys 15 | * Can work with remote folder assesbile through fuse(sshfs for ex.) 16 | * Can bind together private and public keys by public modulus or filename convention(.pub after private key name) 17 | * Ssh to openssl pubkey convertion 18 | * Can use encfs to transparently encrypt/decrypt keys 19 | * Can use openssl to transparently encrypt/decrypt keys 20 | * Can use ANY script to transparently encrypt/decrypt keys 21 | * Can use many transport/encryption layers: openssl over encfs over sshfs.... 22 | * No data stored in memory or copied to computer 23 | * easy(but on C++) to extend transport protocol to be able to use with HTTP or FTP or any other 24 | 25 | 26 | ## PKCS11 Features 27 | 28 | * Create object(type determined byt content so 'data' must be used on creation) 29 | * Read object(pubkey, privkey and data) 30 | * Sign(used by ssh to establish connection) 31 | 32 | 33 | ## Usage 34 | I'am using it with my android phone to make it my keychain. All keys stored on my phone in encrypted form(openssl/enfs/md-crypt). 35 | They are mounted to local folder with fuse sshfs. And they are accessible only for my user(even root can't access mounted fs). 36 | After mouting encrypted keys they mounts through another fuse module encfs to another folder and makes unencrypted. 37 | But you still must use RSA private key encryption. So I can use my phone with ssh or ssh-agent. 38 | 39 | This is very easy: 40 | ```Shell 41 | eval `ssh-agent` 42 | ssh-add -s `pwd`/./libsoft-pkcs.so 43 | 44 | #use ssh-agent forwarding 45 | ssh -A jerry@somedomain 46 | ssh user@anotherdomain 47 | ```` 48 | Well done. 49 | 50 | 51 | ## Config Examples 52 | 53 | SOFTPKCS11RC enviroment variable or $HOME/.soft-token.rc used to configure module. 54 | All drivers are stacked in order as they appeared in config. 55 | 56 | 57 | ### Local folder with encrypted keys 58 | ```INI 59 | [fs any label] 60 | #simple filesystem driver so you already can use soft-pkcs11 to expose keys is folder 61 | driver=fs 62 | path=/home/jerry/devel/soft-pkcs/keys 63 | 64 | [openssl encryption] 65 | driver=crypt 66 | #%PIN% substituted when token logged in with pin 67 | decrypt=/usr/bin/openssl enc -d -base64 -aes-256-cbc -k '%PIN%' 68 | encrypt=/usr/bin/openssl enc -base64 -aes-256-cbc -k '%PIN%' 69 | ``` 70 | 71 | 72 | With this config key files stored in `/home/jerry/devel/soft-pkcs/keys` encrypted as specified in `[openssl encryption]` block. Pin used as password for encryption. 73 | 74 | ### Remote Android FS with encfs 75 | 76 | ```INI 77 | [android fs] 78 | driver=fuse 79 | #this is simple password to access my phone through ssh. It is simple because SFTP server is not always run. 80 | mount=echo "123123123" | sshfs -o password_stdin root@android:/mnt/sdcard/keys /home/jerry/.soft-pkcs11/sshfs &> /dev/null 81 | umount=fusermount -u /home/jerry/.soft-pkcs11/sshfs &> /dev/null 82 | #if you don't want to use encryption you can use module already. 83 | path=/home/jerry/.soft-pkcs11/sshfs 84 | 85 | [encryption layer] 86 | driver=fuse 87 | #password(pin) ALWAYS written to stdin with 'fuse' driver 88 | #setting up encfs(.encfs6.xml) is made by hand 89 | mount=encfs -S /home/jerry/.soft-pkcs11/sshfs /home/jerry/.soft-pkcs11/keys &> /dev/null 90 | umount=fusermount -u /home/jerry/.soft-pkcs11/keys &> /dev/null 91 | path=/home/jerry/.soft-pkcs11/keys 92 | ``` 93 | 94 | You can combine driver layers. 95 | 96 | 97 | # Usage 98 | 99 | To manage keys through soft-pkcs11 module you can use `pkcs11-tool` from `opensc` package: 100 | ```Shell 101 | jerry@jerry ~/devel/soft-pkcs/build $ pkcs11-tool --module ./libsoft-pkcs.so -O -l -p 123123123 102 | Using slot 0 with a present token (0x1) 103 | Public Key Object; RSA 0 bits 104 | label: SSH ssh-private.key.pub 105 | ID: 32303834333137323432393530393938333731 106 | Usage: encrypt, verify 107 | Private Key Object; RSA 108 | label: ssh-private.key 109 | ID: 3130383437353832373236323639373335323836 110 | Usage: decrypt, sign, unwrap 111 | Access: always authenticate 112 | Private Key Object; RSA 113 | label: ssl-private.key 114 | ID: 3133313438313534303736313735313537333832 115 | Usage: decrypt, sign, unwrap 116 | Access: always authenticate 117 | Public Key Object; RSA 0 bits 118 | label: ssh-private.key.pub 119 | ID: 3130383437353832373236323639373335323836 120 | Usage: encrypt, verify 121 | 122 | # get contents of private key 123 | pkcs11-tool --module ./libsoft-pkcs.so -l -p 123123123 -r -y privkey -a ssh-private.key 124 | 125 | # add private key to container 126 | pkcs11-tool --module ./libsoft-pkcs.so -O -l -p 123123123 -w ../keys/ssh-private.key --label ssh-private.key --type data 127 | 128 | # add public key to container 129 | pkcs11-tool --module ./libsoft-pkcs.so -O -l -p 123123123 -w ../keys/ssh-private.key.pub --label ssh-private.key.pub --type data 130 | 131 | ``` 132 | 133 | To use it with ssh: 134 | 135 | ```Shell 136 | jerry@jerry ~/devel/soft-pkcs/build $ eval `ssh-agent` 137 | Agent pid 12930 138 | jerry@jerry ~/devel/soft-pkcs/build $ ssh-add -s `pwd`/libsoft-pkcs.so 139 | Enter passphrase for PKCS#11: <123123123> 140 | Card added: /home/jerry/devel/soft-pkcs/build/./libsoft-pkcs.so 141 | jerry@jerry ~/devel/soft-pkcs/build $ ssh jerry@localhost 142 | jerry@jerry ~ SSH 143 | ``` 144 | 145 | 146 | 147 | ## Security 148 | 149 | * There is no data stored in module memory except pin. But data can be stored in underlying fs cache or something else. Data transmitted to the module in initialization and only public metadata stored(label, size, public modulus...). Another data transmittion happens when you `read` key/data contents or use `sign/encrypt` which are implemeted through OpenSsl. 150 | * You can use any underlying crypto-tools like dm-crypt, sshfs, encfs, gpg-crypt and other, so they are responsible for whole security. 151 | * If you loose your phone - all keys on it stay encrypted(if you using encryption) by selected software(openssl/encfs) and also by generic RSA-encrypted private internals. 152 | * It is strongly recommended to use RSA-encrycted private keys. 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /example/install-sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # install - install a program, script, or datafile 3 | 4 | scriptversion=2005-05-14.22 5 | 6 | # This originates from X11R5 (mit/util/scripts/install.sh), which was 7 | # later released in X11R6 (xc/config/util/install.sh) with the 8 | # following copyright and license. 9 | # 10 | # Copyright (C) 1994 X Consortium 11 | # 12 | # Permission is hereby granted, free of charge, to any person obtaining a copy 13 | # of this software and associated documentation files (the "Software"), to 14 | # deal in the Software without restriction, including without limitation the 15 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 16 | # sell copies of the Software, and to permit persons to whom the Software is 17 | # furnished to do so, subject to the following conditions: 18 | # 19 | # The above copyright notice and this permission notice shall be included in 20 | # all copies or substantial portions of the Software. 21 | # 22 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- 27 | # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | # 29 | # Except as contained in this notice, the name of the X Consortium shall not 30 | # be used in advertising or otherwise to promote the sale, use or other deal- 31 | # ings in this Software without prior written authorization from the X Consor- 32 | # tium. 33 | # 34 | # 35 | # FSF changes to this file are in the public domain. 36 | # 37 | # Calling this script install-sh is preferred over install.sh, to prevent 38 | # `make' implicit rules from creating a file called install from it 39 | # when there is no Makefile. 40 | # 41 | # This script is compatible with the BSD install script, but was written 42 | # from scratch. It can only install one file at a time, a restriction 43 | # shared with many OS's install programs. 44 | 45 | # set DOITPROG to echo to test this script 46 | 47 | # Don't use :- since 4.3BSD and earlier shells don't like it. 48 | doit="${DOITPROG-}" 49 | 50 | # put in absolute paths if you don't have them in your path; or use env. vars. 51 | 52 | mvprog="${MVPROG-mv}" 53 | cpprog="${CPPROG-cp}" 54 | chmodprog="${CHMODPROG-chmod}" 55 | chownprog="${CHOWNPROG-chown}" 56 | chgrpprog="${CHGRPPROG-chgrp}" 57 | stripprog="${STRIPPROG-strip}" 58 | rmprog="${RMPROG-rm}" 59 | mkdirprog="${MKDIRPROG-mkdir}" 60 | 61 | chmodcmd="$chmodprog 0755" 62 | chowncmd= 63 | chgrpcmd= 64 | stripcmd= 65 | rmcmd="$rmprog -f" 66 | mvcmd="$mvprog" 67 | src= 68 | dst= 69 | dir_arg= 70 | dstarg= 71 | no_target_directory= 72 | 73 | usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE 74 | or: $0 [OPTION]... SRCFILES... DIRECTORY 75 | or: $0 [OPTION]... -t DIRECTORY SRCFILES... 76 | or: $0 [OPTION]... -d DIRECTORIES... 77 | 78 | In the 1st form, copy SRCFILE to DSTFILE. 79 | In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. 80 | In the 4th, create DIRECTORIES. 81 | 82 | Options: 83 | -c (ignored) 84 | -d create directories instead of installing files. 85 | -g GROUP $chgrpprog installed files to GROUP. 86 | -m MODE $chmodprog installed files to MODE. 87 | -o USER $chownprog installed files to USER. 88 | -s $stripprog installed files. 89 | -t DIRECTORY install into DIRECTORY. 90 | -T report an error if DSTFILE is a directory. 91 | --help display this help and exit. 92 | --version display version info and exit. 93 | 94 | Environment variables override the default commands: 95 | CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG 96 | " 97 | 98 | while test -n "$1"; do 99 | case $1 in 100 | -c) shift 101 | continue;; 102 | 103 | -d) dir_arg=true 104 | shift 105 | continue;; 106 | 107 | -g) chgrpcmd="$chgrpprog $2" 108 | shift 109 | shift 110 | continue;; 111 | 112 | --help) echo "$usage"; exit $?;; 113 | 114 | -m) chmodcmd="$chmodprog $2" 115 | shift 116 | shift 117 | continue;; 118 | 119 | -o) chowncmd="$chownprog $2" 120 | shift 121 | shift 122 | continue;; 123 | 124 | -s) stripcmd=$stripprog 125 | shift 126 | continue;; 127 | 128 | -t) dstarg=$2 129 | shift 130 | shift 131 | continue;; 132 | 133 | -T) no_target_directory=true 134 | shift 135 | continue;; 136 | 137 | --version) echo "$0 $scriptversion"; exit $?;; 138 | 139 | *) # When -d is used, all remaining arguments are directories to create. 140 | # When -t is used, the destination is already specified. 141 | test -n "$dir_arg$dstarg" && break 142 | # Otherwise, the last argument is the destination. Remove it from $@. 143 | for arg 144 | do 145 | if test -n "$dstarg"; then 146 | # $@ is not empty: it contains at least $arg. 147 | set fnord "$@" "$dstarg" 148 | shift # fnord 149 | fi 150 | shift # arg 151 | dstarg=$arg 152 | done 153 | break;; 154 | esac 155 | done 156 | 157 | if test -z "$1"; then 158 | if test -z "$dir_arg"; then 159 | echo "$0: no input file specified." >&2 160 | exit 1 161 | fi 162 | # It's OK to call `install-sh -d' without argument. 163 | # This can happen when creating conditional directories. 164 | exit 0 165 | fi 166 | 167 | for src 168 | do 169 | # Protect names starting with `-'. 170 | case $src in 171 | -*) src=./$src ;; 172 | esac 173 | 174 | if test -n "$dir_arg"; then 175 | dst=$src 176 | src= 177 | 178 | if test -d "$dst"; then 179 | mkdircmd=: 180 | chmodcmd= 181 | else 182 | mkdircmd=$mkdirprog 183 | fi 184 | else 185 | # Waiting for this to be detected by the "$cpprog $src $dsttmp" command 186 | # might cause directories to be created, which would be especially bad 187 | # if $src (and thus $dsttmp) contains '*'. 188 | if test ! -f "$src" && test ! -d "$src"; then 189 | echo "$0: $src does not exist." >&2 190 | exit 1 191 | fi 192 | 193 | if test -z "$dstarg"; then 194 | echo "$0: no destination specified." >&2 195 | exit 1 196 | fi 197 | 198 | dst=$dstarg 199 | # Protect names starting with `-'. 200 | case $dst in 201 | -*) dst=./$dst ;; 202 | esac 203 | 204 | # If destination is a directory, append the input filename; won't work 205 | # if double slashes aren't ignored. 206 | if test -d "$dst"; then 207 | if test -n "$no_target_directory"; then 208 | echo "$0: $dstarg: Is a directory" >&2 209 | exit 1 210 | fi 211 | dst=$dst/`basename "$src"` 212 | fi 213 | fi 214 | 215 | # This sed command emulates the dirname command. 216 | dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'` 217 | 218 | # Make sure that the destination directory exists. 219 | 220 | # Skip lots of stat calls in the usual case. 221 | if test ! -d "$dstdir"; then 222 | defaultIFS=' 223 | ' 224 | IFS="${IFS-$defaultIFS}" 225 | 226 | oIFS=$IFS 227 | # Some sh's can't handle IFS=/ for some reason. 228 | IFS='%' 229 | set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` 230 | shift 231 | IFS=$oIFS 232 | 233 | pathcomp= 234 | 235 | while test $# -ne 0 ; do 236 | pathcomp=$pathcomp$1 237 | shift 238 | if test ! -d "$pathcomp"; then 239 | $mkdirprog "$pathcomp" 240 | # mkdir can fail with a `File exist' error in case several 241 | # install-sh are creating the directory concurrently. This 242 | # is OK. 243 | test -d "$pathcomp" || exit 244 | fi 245 | pathcomp=$pathcomp/ 246 | done 247 | fi 248 | 249 | if test -n "$dir_arg"; then 250 | $doit $mkdircmd "$dst" \ 251 | && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ 252 | && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ 253 | && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ 254 | && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } 255 | 256 | else 257 | dstfile=`basename "$dst"` 258 | 259 | # Make a couple of temp file names in the proper directory. 260 | dsttmp=$dstdir/_inst.$$_ 261 | rmtmp=$dstdir/_rm.$$_ 262 | 263 | # Trap to clean up those temp files at exit. 264 | trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 265 | trap '(exit $?); exit' 1 2 13 15 266 | 267 | # Copy the file name to the temp name. 268 | $doit $cpprog "$src" "$dsttmp" && 269 | 270 | # and set any options; do chmod last to preserve setuid bits. 271 | # 272 | # If any of these fail, we abort the whole thing. If we want to 273 | # ignore errors from any of these, just make sure not to ignore 274 | # errors from the above "$doit $cpprog $src $dsttmp" command. 275 | # 276 | { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ 277 | && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ 278 | && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ 279 | && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && 280 | 281 | # Now rename the file to the real destination. 282 | { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ 283 | || { 284 | # The rename failed, perhaps because mv can't rename something else 285 | # to itself, or perhaps because mv is so ancient that it does not 286 | # support -f. 287 | 288 | # Now remove or move aside any old file at destination location. 289 | # We try this two ways since rm can't unlink itself on some 290 | # systems and the destination file might be busy for other 291 | # reasons. In this case, the final cleanup might fail but the new 292 | # file should still install successfully. 293 | { 294 | if test -f "$dstdir/$dstfile"; then 295 | $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ 296 | || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ 297 | || { 298 | echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 299 | (exit 1); exit 1 300 | } 301 | else 302 | : 303 | fi 304 | } && 305 | 306 | # Now rename the file to the real destination. 307 | $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" 308 | } 309 | } 310 | fi || { (exit 1); exit 1; } 311 | done 312 | 313 | # The final little trick to "correctly" pass the exit status to the exit trap. 314 | { 315 | (exit 0); exit 0 316 | } 317 | 318 | # Local variables: 319 | # eval: (add-hook 'write-file-hooks 'time-stamp) 320 | # time-stamp-start: "scriptversion=" 321 | # time-stamp-format: "%:y-%02m-%02d.%02H" 322 | # time-stamp-end: "$" 323 | # End: 324 | -------------------------------------------------------------------------------- /tools.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | #include 22 | 23 | #include "tools.h" 24 | #include "log.h" 25 | #include "exceptions.h" 26 | 27 | int log_fd = 0; 28 | 29 | 30 | void st_logf(const char* fmt, ...) 31 | { 32 | va_list ap; 33 | va_start(ap, fmt); 34 | // vdprintf(STDOUT_FILENO, fmt, ap); 35 | st_logf(fmt, ap); 36 | va_end(ap); 37 | 38 | } 39 | 40 | void st_logf(const char* fmt, va_list args) 41 | { 42 | if (log_fd == 0) { 43 | log_fd = ::open("/tmp/soft-token.log", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 44 | } 45 | 46 | vdprintf(log_fd, fmt, args); 47 | } 48 | 49 | 50 | void print_attributes(const CK_ATTRIBUTE *attributes, CK_ULONG num_attributes) 51 | { 52 | Attributes attrs; 53 | for (CK_ULONG i = 0; i < num_attributes; i++) { 54 | attrs[attributes[i].type] = attributes[i]; 55 | } 56 | print_attributes(attrs); 57 | } 58 | 59 | void print_attributes(const Attributes& attributes) 60 | { 61 | CK_ULONG i; 62 | 63 | LOG_G("Print attributes: %lu", attributes.size()); 64 | 65 | for (auto it = attributes.begin(); it != attributes.end(); ++it) { 66 | const attribute_t& attr = it->second; 67 | 68 | switch (it->first) { 69 | case CKA_TOKEN: { 70 | LOG(" A type: size: <%d> value: <%s>", attr->ulValueLen, (attr.to_bool()) ? "TRUE" : "FALSE"); 71 | break; 72 | } 73 | case CKA_KEY_TYPE: { 74 | LOG(" A type: size: <%d> value: <%lu>", attr->ulValueLen, attr.to_value()); 75 | break; 76 | } 77 | case CKA_CLASS: { 78 | CK_OBJECT_CLASS klass = attr.to_class(); 79 | switch (klass) { 80 | case CKO_CERTIFICATE: 81 | LOG(" A type: size: <%d> value: <%s>", attr->ulValueLen, "certificate"); 82 | break; 83 | case CKO_PUBLIC_KEY: 84 | LOG(" A type: size: <%d> value: <%s>", attr->ulValueLen, "public key"); 85 | break; 86 | case CKO_PRIVATE_KEY: 87 | LOG(" A type: size: <%d> value: <%s>", attr->ulValueLen, "private key"); 88 | break; 89 | case CKO_SECRET_KEY: 90 | LOG(" A type: size: <%d> value: <%s>", attr->ulValueLen, "secret key"); 91 | break; 92 | case CKO_DOMAIN_PARAMETERS: 93 | LOG(" A type: size: <%d> value: <%s>", attr->ulValueLen, "domain parameters"); 94 | break; 95 | default: 96 | LOG(" A type: size: <%d> value: [class 0x%08lx]", attr->ulValueLen, klass); 97 | break; 98 | } 99 | break; 100 | } 101 | case CKA_PRIVATE: 102 | LOG(" A type: size: <%d>", attr->ulValueLen); 103 | break; 104 | case CKA_LABEL: 105 | LOG(" A type: size: <%d> value: <%s>", attr->ulValueLen, attr.to_string().c_str()); 106 | break; 107 | case CKA_APPLICATION: 108 | LOG(" A type: size: <%d> value: <%s>", attr->ulValueLen, attr.to_string().c_str()); 109 | break; 110 | case CKA_VALUE: 111 | LOG(" A type: size: <%d>", attr->ulValueLen); 112 | break; 113 | case CKA_ID: 114 | LOG(" A type: size: <%d> value: <%lu>", attr->ulValueLen, attr.to_id()); 115 | break; 116 | case CKA_OBJECT_ID: 117 | LOG(" A type: size: <%d> value: <%s>", attr->ulValueLen, attr.to_object_id().c_str()); 118 | 119 | break; 120 | default: 121 | LOG(" A type: size: <%d> type: [0x%08lx]", attr->ulValueLen, attr->type); 122 | break; 123 | } 124 | } 125 | } 126 | 127 | std::pair> read_bignum(void* ssl_bignum) 128 | { 129 | BIGNUM *b = reinterpret_cast(ssl_bignum); 130 | 131 | int size = BN_num_bytes(b); 132 | assert(size > 0); 133 | 134 | std::shared_ptr buff(static_cast(malloc(size)), free); 135 | assert(buff.get() != NULL); 136 | 137 | int rc = BN_bn2bin(b, buff.get()); 138 | assert(size == rc); 139 | return std::make_pair(size, buff); 140 | } 141 | 142 | std::vector read_all(std::shared_ptr file) 143 | { 144 | std::vector data; 145 | 146 | if (file) { 147 | std::vector portion(4096); 148 | while(!::feof(file.get())) { 149 | portion.resize(4096); 150 | portion.resize(::fread(portion.data(), 1, portion.size(), file.get())); 151 | data.insert(data.end(), portion.begin(), portion.end()); 152 | } 153 | } 154 | return data; 155 | } 156 | 157 | std::shared_ptr read_mem(const std::vector< char >& data) 158 | { 159 | return std::shared_ptr( 160 | ::fmemopen(const_cast(data.data()), data.size(), "r"), 161 | ::fclose 162 | ); 163 | } 164 | 165 | std::shared_ptr write_mem(char **buf, size_t *size) 166 | { 167 | return std::shared_ptr( 168 | ::open_memstream(buf, size), 169 | ::fclose 170 | ); 171 | } 172 | 173 | 174 | void set_stdin_echo(bool enable) 175 | { 176 | struct termios tty; 177 | tcgetattr(STDIN_FILENO, &tty); 178 | if( !enable ) 179 | tty.c_lflag &= ~ECHO; 180 | else 181 | tty.c_lflag |= ECHO; 182 | 183 | (void) tcsetattr(STDIN_FILENO, TCSANOW, &tty); 184 | } 185 | 186 | std::string read_password() 187 | { 188 | std::cout << "Please enter PIN to login to SoftToken:" << std::endl; 189 | set_stdin_echo(false); 190 | std::string pass; 191 | std::cin >> pass; 192 | set_stdin_echo(true); 193 | return pass; 194 | } 195 | 196 | std::string ask_password() 197 | { 198 | if (isatty(fileno(stdin))) { 199 | return read_password(); 200 | } 201 | else { 202 | try { 203 | const auto data = piped("if which kdialog &> /dev/null; then kdialog --password 'Please enter PIN' --title 'Logging to SoftToken'; elif which x11-ssh-askpass &> /dev/null; then x11-ssh-askpass 'Please enter PIN to login to SoftToken'; else exit 1; fi"); 204 | std::string pass(data.begin(), data.end()); 205 | boost::algorithm::trim(pass); 206 | return pass; 207 | } 208 | catch(...) { 209 | } 210 | } 211 | 212 | return std::string(); 213 | } 214 | 215 | 216 | int ask_password_cb(char* buf, int size, int rwflag, void* userdata) 217 | { 218 | std::string password = ask_password(); 219 | 220 | if (password.empty()) { 221 | return 0; 222 | } 223 | 224 | const size_t len = std::min(size_t(size), password.size()); 225 | memcpy(buf, password.c_str(), len); 226 | return len; 227 | } 228 | 229 | 230 | std::vector piped(const std::string& cmd, const std::vector& input) { 231 | std::vector result; 232 | 233 | int fd1[2]; 234 | int fd2[2]; 235 | int fd3[2]; 236 | pid_t pid; 237 | 238 | if ( (pipe(fd1) < 0) || (pipe(fd2) < 0) || (pipe(fd3) < 0) ) 239 | { 240 | throw std::system_error(errno, std::system_category(), "Can't create pipe to subprocess"); 241 | } 242 | 243 | if ( (pid = fork()) < 0 ) 244 | { 245 | throw std::system_error(errno, std::system_category(), "Can't create fork subprocess"); 246 | } 247 | else if (pid == 0) // CHILD PROCESS 248 | { 249 | close(fd1[1]); 250 | close(fd2[0]); 251 | close(fd3[0]); 252 | 253 | if (fd1[0] != STDIN_FILENO) 254 | { 255 | if (dup2(fd1[0], STDIN_FILENO) != STDIN_FILENO) 256 | { 257 | exit(EXIT_FAILURE); 258 | } 259 | close(fd1[0]); 260 | } 261 | 262 | if (fd2[1] != STDOUT_FILENO) 263 | { 264 | if (dup2(fd2[1], STDOUT_FILENO) != STDOUT_FILENO) 265 | { 266 | exit(EXIT_FAILURE); 267 | } 268 | close(fd2[1]); 269 | } 270 | 271 | if (fd3[1] != STDERR_FILENO) 272 | { 273 | if (dup2(fd3[1], STDERR_FILENO) != STDERR_FILENO) 274 | { 275 | exit(EXIT_FAILURE); 276 | } 277 | close(fd3[1]); 278 | } 279 | 280 | execlp("sh", "sh", "-c", cmd.c_str(), 0); 281 | exit(EXIT_FAILURE); 282 | } 283 | else 284 | { 285 | int rv; 286 | close(fd1[0]); 287 | close(fd2[1]); 288 | close(fd3[1]); 289 | 290 | if (input.size()) { 291 | if (write(fd1[1], input.data(), input.size()) != input.size()) 292 | { 293 | throw std::system_error(errno, std::system_category(), "can't write to subprocess"); 294 | } 295 | } 296 | 297 | close(fd1[1]); 298 | 299 | std::vector portion(4096); 300 | 301 | while (true) { 302 | auto size = read(fd2[0], portion.data(), portion.size()); 303 | if (size == -1) { 304 | throw std::system_error(errno, std::system_category(), "can't read from subprocess"); 305 | } else if (size > 0) { 306 | portion.resize(size); 307 | result.insert(result.end(), portion.begin(), portion.end()); 308 | } else { 309 | break; 310 | } 311 | } 312 | 313 | int exitcode; 314 | waitpid(pid, &exitcode, 0); 315 | if (WEXITSTATUS(exitcode) != 0) { 316 | throw std::runtime_error("process failed: " + cmd); 317 | } 318 | } 319 | 320 | return result; 321 | } 322 | 323 | int start(const std::string& cmd, const std::vector& input) { 324 | FILE* file = NULL; 325 | try { 326 | file = ::popen(cmd.c_str(), "w"); 327 | 328 | if (!file) { 329 | return -1; 330 | } 331 | 332 | if (input.size()) { 333 | if (::fwrite(input.data(), 1, input.size(), file) != input.size()) { 334 | pclose(file); 335 | return -1; 336 | } 337 | } 338 | return pclose(file); 339 | } 340 | catch(...) { 341 | pclose(file); 342 | return -1; 343 | } 344 | } 345 | 346 | 347 | 348 | 349 | -------------------------------------------------------------------------------- /pkcs11/pkcs11.h: -------------------------------------------------------------------------------- 1 | /* pkcs11.h include file for PKCS #11. */ 2 | /* $Revision: 1.1.1.1 $ */ 3 | 4 | /* License to copy and use this software is granted provided that it is 5 | * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface 6 | * (Cryptoki)" in all material mentioning or referencing this software. 7 | 8 | * License is also granted to make and use derivative works provided that 9 | * such works are identified as "derived from the RSA Security Inc. PKCS #11 10 | * Cryptographic Token Interface (Cryptoki)" in all material mentioning or 11 | * referencing the derived work. 12 | 13 | * RSA Security Inc. makes no representations concerning either the 14 | * merchantability of this software or the suitability of this software for 15 | * any particular purpose. It is provided "as is" without express or implied 16 | * warranty of any kind. 17 | */ 18 | 19 | #ifndef _PKCS11_H_ 20 | #define _PKCS11_H_ 1 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | /* Before including this file (pkcs11.h) (or pkcs11t.h by 27 | * itself), 6 platform-specific macros must be defined. These 28 | * macros are described below, and typical definitions for them 29 | * are also given. Be advised that these definitions can depend 30 | * on both the platform and the compiler used (and possibly also 31 | * on whether a Cryptoki library is linked statically or 32 | * dynamically). 33 | * 34 | * In addition to defining these 6 macros, the packing convention 35 | * for Cryptoki structures should be set. The Cryptoki 36 | * convention on packing is that structures should be 1-byte 37 | * aligned. 38 | * 39 | * If you're using Microsoft Developer Studio 5.0 to produce 40 | * Win32 stuff, this might be done by using the following 41 | * preprocessor directive before including pkcs11.h or pkcs11t.h: 42 | * 43 | * #pragma pack(push, cryptoki, 1) 44 | * 45 | * and using the following preprocessor directive after including 46 | * pkcs11.h or pkcs11t.h: 47 | * 48 | * #pragma pack(pop, cryptoki) 49 | * 50 | * If you're using an earlier version of Microsoft Developer 51 | * Studio to produce Win16 stuff, this might be done by using 52 | * the following preprocessor directive before including 53 | * pkcs11.h or pkcs11t.h: 54 | * 55 | * #pragma pack(1) 56 | * 57 | * In a UNIX environment, you're on your own for this. You might 58 | * not need to do (or be able to do!) anything. 59 | * 60 | * 61 | * Now for the macros: 62 | * 63 | * 64 | * 1. CK_PTR: The indirection string for making a pointer to an 65 | * object. It can be used like this: 66 | * 67 | * typedef CK_BYTE CK_PTR CK_BYTE_PTR; 68 | * 69 | * If you're using Microsoft Developer Studio 5.0 to produce 70 | * Win32 stuff, it might be defined by: 71 | * 72 | * #define CK_PTR * 73 | * 74 | * If you're using an earlier version of Microsoft Developer 75 | * Studio to produce Win16 stuff, it might be defined by: 76 | * 77 | * #define CK_PTR far * 78 | * 79 | * In a typical UNIX environment, it might be defined by: 80 | * 81 | * #define CK_PTR * 82 | * 83 | * 84 | * 2. CK_DEFINE_FUNCTION(returnType, name): A macro which makes 85 | * an exportable Cryptoki library function definition out of a 86 | * return type and a function name. It should be used in the 87 | * following fashion to define the exposed Cryptoki functions in 88 | * a Cryptoki library: 89 | * 90 | * CK_DEFINE_FUNCTION(CK_RV, C_Initialize)( 91 | * CK_VOID_PTR pReserved 92 | * ) 93 | * { 94 | * ... 95 | * } 96 | * 97 | * If you're using Microsoft Developer Studio 5.0 to define a 98 | * function in a Win32 Cryptoki .dll, it might be defined by: 99 | * 100 | * #define CK_DEFINE_FUNCTION(returnType, name) \ 101 | * returnType __declspec(dllexport) name 102 | * 103 | * If you're using an earlier version of Microsoft Developer 104 | * Studio to define a function in a Win16 Cryptoki .dll, it 105 | * might be defined by: 106 | * 107 | * #define CK_DEFINE_FUNCTION(returnType, name) \ 108 | * returnType __export _far _pascal name 109 | * 110 | * In a UNIX environment, it might be defined by: 111 | * 112 | * #define CK_DEFINE_FUNCTION(returnType, name) \ 113 | * returnType name 114 | * 115 | * 116 | * 3. CK_DECLARE_FUNCTION(returnType, name): A macro which makes 117 | * an importable Cryptoki library function declaration out of a 118 | * return type and a function name. It should be used in the 119 | * following fashion: 120 | * 121 | * extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)( 122 | * CK_VOID_PTR pReserved 123 | * ); 124 | * 125 | * If you're using Microsoft Developer Studio 5.0 to declare a 126 | * function in a Win32 Cryptoki .dll, it might be defined by: 127 | * 128 | * #define CK_DECLARE_FUNCTION(returnType, name) \ 129 | * returnType __declspec(dllimport) name 130 | * 131 | * If you're using an earlier version of Microsoft Developer 132 | * Studio to declare a function in a Win16 Cryptoki .dll, it 133 | * might be defined by: 134 | * 135 | * #define CK_DECLARE_FUNCTION(returnType, name) \ 136 | * returnType __export _far _pascal name 137 | * 138 | * In a UNIX environment, it might be defined by: 139 | * 140 | * #define CK_DECLARE_FUNCTION(returnType, name) \ 141 | * returnType name 142 | * 143 | * 144 | * 4. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro 145 | * which makes a Cryptoki API function pointer declaration or 146 | * function pointer type declaration out of a return type and a 147 | * function name. It should be used in the following fashion: 148 | * 149 | * // Define funcPtr to be a pointer to a Cryptoki API function 150 | * // taking arguments args and returning CK_RV. 151 | * CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args); 152 | * 153 | * or 154 | * 155 | * // Define funcPtrType to be the type of a pointer to a 156 | * // Cryptoki API function taking arguments args and returning 157 | * // CK_RV, and then define funcPtr to be a variable of type 158 | * // funcPtrType. 159 | * typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args); 160 | * funcPtrType funcPtr; 161 | * 162 | * If you're using Microsoft Developer Studio 5.0 to access 163 | * functions in a Win32 Cryptoki .dll, in might be defined by: 164 | * 165 | * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ 166 | * returnType __declspec(dllimport) (* name) 167 | * 168 | * If you're using an earlier version of Microsoft Developer 169 | * Studio to access functions in a Win16 Cryptoki .dll, it might 170 | * be defined by: 171 | * 172 | * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ 173 | * returnType __export _far _pascal (* name) 174 | * 175 | * In a UNIX environment, it might be defined by: 176 | * 177 | * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ 178 | * returnType (* name) 179 | * 180 | * 181 | * 5. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes 182 | * a function pointer type for an application callback out of 183 | * a return type for the callback and a name for the callback. 184 | * It should be used in the following fashion: 185 | * 186 | * CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args); 187 | * 188 | * to declare a function pointer, myCallback, to a callback 189 | * which takes arguments args and returns a CK_RV. It can also 190 | * be used like this: 191 | * 192 | * typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args); 193 | * myCallbackType myCallback; 194 | * 195 | * If you're using Microsoft Developer Studio 5.0 to do Win32 196 | * Cryptoki development, it might be defined by: 197 | * 198 | * #define CK_CALLBACK_FUNCTION(returnType, name) \ 199 | * returnType (* name) 200 | * 201 | * If you're using an earlier version of Microsoft Developer 202 | * Studio to do Win16 development, it might be defined by: 203 | * 204 | * #define CK_CALLBACK_FUNCTION(returnType, name) \ 205 | * returnType _far _pascal (* name) 206 | * 207 | * In a UNIX environment, it might be defined by: 208 | * 209 | * #define CK_CALLBACK_FUNCTION(returnType, name) \ 210 | * returnType (* name) 211 | * 212 | * 213 | * 6. NULL_PTR: This macro is the value of a NULL pointer. 214 | * 215 | * In any ANSI/ISO C environment (and in many others as well), 216 | * this should best be defined by 217 | * 218 | * #ifndef NULL_PTR 219 | * #define NULL_PTR 0 220 | * #endif 221 | */ 222 | 223 | 224 | /* All the various Cryptoki types and #define'd values are in the 225 | * file pkcs11t.h. */ 226 | #include "pkcs11t.h" 227 | 228 | #define __PASTE(x,y) x##y 229 | 230 | 231 | /* ============================================================== 232 | * Define the "extern" form of all the entry points. 233 | * ============================================================== 234 | */ 235 | 236 | #define CK_NEED_ARG_LIST 1 237 | #define CK_PKCS11_FUNCTION_INFO(name) \ 238 | extern CK_DECLARE_FUNCTION(CK_RV, name) 239 | 240 | /* pkcs11f.h has all the information about the Cryptoki 241 | * function prototypes. */ 242 | #include "pkcs11f.h" 243 | 244 | #undef CK_NEED_ARG_LIST 245 | #undef CK_PKCS11_FUNCTION_INFO 246 | 247 | 248 | /* ============================================================== 249 | * Define the typedef form of all the entry points. That is, for 250 | * each Cryptoki function C_XXX, define a type CK_C_XXX which is 251 | * a pointer to that kind of function. 252 | * ============================================================== 253 | */ 254 | 255 | #define CK_NEED_ARG_LIST 1 256 | #define CK_PKCS11_FUNCTION_INFO(name) \ 257 | typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name)) 258 | 259 | /* pkcs11f.h has all the information about the Cryptoki 260 | * function prototypes. */ 261 | #include "pkcs11f.h" 262 | 263 | #undef CK_NEED_ARG_LIST 264 | #undef CK_PKCS11_FUNCTION_INFO 265 | 266 | 267 | /* ============================================================== 268 | * Define structed vector of entry points. A CK_FUNCTION_LIST 269 | * contains a CK_VERSION indicating a library's Cryptoki version 270 | * and then a whole slew of function pointers to the routines in 271 | * the library. This type was declared, but not defined, in 272 | * pkcs11t.h. 273 | * ============================================================== 274 | */ 275 | 276 | #define CK_PKCS11_FUNCTION_INFO(name) \ 277 | __PASTE(CK_,name) name; 278 | 279 | struct CK_FUNCTION_LIST { 280 | 281 | CK_VERSION version; /* Cryptoki version */ 282 | 283 | /* Pile all the function pointers into the CK_FUNCTION_LIST. */ 284 | /* pkcs11f.h has all the information about the Cryptoki 285 | * function prototypes. */ 286 | #include "pkcs11f.h" 287 | 288 | }; 289 | 290 | #undef CK_PKCS11_FUNCTION_INFO 291 | 292 | 293 | #undef __PASTE 294 | 295 | #ifdef __cplusplus 296 | } 297 | #endif 298 | 299 | #endif 300 | -------------------------------------------------------------------------------- /example/ref/pkcs11.h: -------------------------------------------------------------------------------- 1 | /* pkcs11.h include file for PKCS #11. */ 2 | /* $Revision: 1.1.1.1 $ */ 3 | 4 | /* License to copy and use this software is granted provided that it is 5 | * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface 6 | * (Cryptoki)" in all material mentioning or referencing this software. 7 | 8 | * License is also granted to make and use derivative works provided that 9 | * such works are identified as "derived from the RSA Security Inc. PKCS #11 10 | * Cryptographic Token Interface (Cryptoki)" in all material mentioning or 11 | * referencing the derived work. 12 | 13 | * RSA Security Inc. makes no representations concerning either the 14 | * merchantability of this software or the suitability of this software for 15 | * any particular purpose. It is provided "as is" without express or implied 16 | * warranty of any kind. 17 | */ 18 | 19 | #ifndef _PKCS11_H_ 20 | #define _PKCS11_H_ 1 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | 26 | /* Before including this file (pkcs11.h) (or pkcs11t.h by 27 | * itself), 6 platform-specific macros must be defined. These 28 | * macros are described below, and typical definitions for them 29 | * are also given. Be advised that these definitions can depend 30 | * on both the platform and the compiler used (and possibly also 31 | * on whether a Cryptoki library is linked statically or 32 | * dynamically). 33 | * 34 | * In addition to defining these 6 macros, the packing convention 35 | * for Cryptoki structures should be set. The Cryptoki 36 | * convention on packing is that structures should be 1-byte 37 | * aligned. 38 | * 39 | * If you're using Microsoft Developer Studio 5.0 to produce 40 | * Win32 stuff, this might be done by using the following 41 | * preprocessor directive before including pkcs11.h or pkcs11t.h: 42 | * 43 | * #pragma pack(push, cryptoki, 1) 44 | * 45 | * and using the following preprocessor directive after including 46 | * pkcs11.h or pkcs11t.h: 47 | * 48 | * #pragma pack(pop, cryptoki) 49 | * 50 | * If you're using an earlier version of Microsoft Developer 51 | * Studio to produce Win16 stuff, this might be done by using 52 | * the following preprocessor directive before including 53 | * pkcs11.h or pkcs11t.h: 54 | * 55 | * #pragma pack(1) 56 | * 57 | * In a UNIX environment, you're on your own for this. You might 58 | * not need to do (or be able to do!) anything. 59 | * 60 | * 61 | * Now for the macros: 62 | * 63 | * 64 | * 1. CK_PTR: The indirection string for making a pointer to an 65 | * object. It can be used like this: 66 | * 67 | * typedef CK_BYTE CK_PTR CK_BYTE_PTR; 68 | * 69 | * If you're using Microsoft Developer Studio 5.0 to produce 70 | * Win32 stuff, it might be defined by: 71 | * 72 | * #define CK_PTR * 73 | * 74 | * If you're using an earlier version of Microsoft Developer 75 | * Studio to produce Win16 stuff, it might be defined by: 76 | * 77 | * #define CK_PTR far * 78 | * 79 | * In a typical UNIX environment, it might be defined by: 80 | * 81 | * #define CK_PTR * 82 | * 83 | * 84 | * 2. CK_DEFINE_FUNCTION(returnType, name): A macro which makes 85 | * an exportable Cryptoki library function definition out of a 86 | * return type and a function name. It should be used in the 87 | * following fashion to define the exposed Cryptoki functions in 88 | * a Cryptoki library: 89 | * 90 | * CK_DEFINE_FUNCTION(CK_RV, C_Initialize)( 91 | * CK_VOID_PTR pReserved 92 | * ) 93 | * { 94 | * ... 95 | * } 96 | * 97 | * If you're using Microsoft Developer Studio 5.0 to define a 98 | * function in a Win32 Cryptoki .dll, it might be defined by: 99 | * 100 | * #define CK_DEFINE_FUNCTION(returnType, name) \ 101 | * returnType __declspec(dllexport) name 102 | * 103 | * If you're using an earlier version of Microsoft Developer 104 | * Studio to define a function in a Win16 Cryptoki .dll, it 105 | * might be defined by: 106 | * 107 | * #define CK_DEFINE_FUNCTION(returnType, name) \ 108 | * returnType __export _far _pascal name 109 | * 110 | * In a UNIX environment, it might be defined by: 111 | * 112 | * #define CK_DEFINE_FUNCTION(returnType, name) \ 113 | * returnType name 114 | * 115 | * 116 | * 3. CK_DECLARE_FUNCTION(returnType, name): A macro which makes 117 | * an importable Cryptoki library function declaration out of a 118 | * return type and a function name. It should be used in the 119 | * following fashion: 120 | * 121 | * extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)( 122 | * CK_VOID_PTR pReserved 123 | * ); 124 | * 125 | * If you're using Microsoft Developer Studio 5.0 to declare a 126 | * function in a Win32 Cryptoki .dll, it might be defined by: 127 | * 128 | * #define CK_DECLARE_FUNCTION(returnType, name) \ 129 | * returnType __declspec(dllimport) name 130 | * 131 | * If you're using an earlier version of Microsoft Developer 132 | * Studio to declare a function in a Win16 Cryptoki .dll, it 133 | * might be defined by: 134 | * 135 | * #define CK_DECLARE_FUNCTION(returnType, name) \ 136 | * returnType __export _far _pascal name 137 | * 138 | * In a UNIX environment, it might be defined by: 139 | * 140 | * #define CK_DECLARE_FUNCTION(returnType, name) \ 141 | * returnType name 142 | * 143 | * 144 | * 4. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro 145 | * which makes a Cryptoki API function pointer declaration or 146 | * function pointer type declaration out of a return type and a 147 | * function name. It should be used in the following fashion: 148 | * 149 | * // Define funcPtr to be a pointer to a Cryptoki API function 150 | * // taking arguments args and returning CK_RV. 151 | * CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args); 152 | * 153 | * or 154 | * 155 | * // Define funcPtrType to be the type of a pointer to a 156 | * // Cryptoki API function taking arguments args and returning 157 | * // CK_RV, and then define funcPtr to be a variable of type 158 | * // funcPtrType. 159 | * typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args); 160 | * funcPtrType funcPtr; 161 | * 162 | * If you're using Microsoft Developer Studio 5.0 to access 163 | * functions in a Win32 Cryptoki .dll, in might be defined by: 164 | * 165 | * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ 166 | * returnType __declspec(dllimport) (* name) 167 | * 168 | * If you're using an earlier version of Microsoft Developer 169 | * Studio to access functions in a Win16 Cryptoki .dll, it might 170 | * be defined by: 171 | * 172 | * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ 173 | * returnType __export _far _pascal (* name) 174 | * 175 | * In a UNIX environment, it might be defined by: 176 | * 177 | * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ 178 | * returnType (* name) 179 | * 180 | * 181 | * 5. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes 182 | * a function pointer type for an application callback out of 183 | * a return type for the callback and a name for the callback. 184 | * It should be used in the following fashion: 185 | * 186 | * CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args); 187 | * 188 | * to declare a function pointer, myCallback, to a callback 189 | * which takes arguments args and returns a CK_RV. It can also 190 | * be used like this: 191 | * 192 | * typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args); 193 | * myCallbackType myCallback; 194 | * 195 | * If you're using Microsoft Developer Studio 5.0 to do Win32 196 | * Cryptoki development, it might be defined by: 197 | * 198 | * #define CK_CALLBACK_FUNCTION(returnType, name) \ 199 | * returnType (* name) 200 | * 201 | * If you're using an earlier version of Microsoft Developer 202 | * Studio to do Win16 development, it might be defined by: 203 | * 204 | * #define CK_CALLBACK_FUNCTION(returnType, name) \ 205 | * returnType _far _pascal (* name) 206 | * 207 | * In a UNIX environment, it might be defined by: 208 | * 209 | * #define CK_CALLBACK_FUNCTION(returnType, name) \ 210 | * returnType (* name) 211 | * 212 | * 213 | * 6. NULL_PTR: This macro is the value of a NULL pointer. 214 | * 215 | * In any ANSI/ISO C environment (and in many others as well), 216 | * this should best be defined by 217 | * 218 | * #ifndef NULL_PTR 219 | * #define NULL_PTR 0 220 | * #endif 221 | */ 222 | 223 | 224 | /* All the various Cryptoki types and #define'd values are in the 225 | * file pkcs11t.h. */ 226 | #include "pkcs11t.h" 227 | 228 | #define __PASTE(x,y) x##y 229 | 230 | 231 | /* ============================================================== 232 | * Define the "extern" form of all the entry points. 233 | * ============================================================== 234 | */ 235 | 236 | #define CK_NEED_ARG_LIST 1 237 | #define CK_PKCS11_FUNCTION_INFO(name) \ 238 | extern CK_DECLARE_FUNCTION(CK_RV, name) 239 | 240 | /* pkcs11f.h has all the information about the Cryptoki 241 | * function prototypes. */ 242 | #include "pkcs11f.h" 243 | 244 | #undef CK_NEED_ARG_LIST 245 | #undef CK_PKCS11_FUNCTION_INFO 246 | 247 | 248 | /* ============================================================== 249 | * Define the typedef form of all the entry points. That is, for 250 | * each Cryptoki function C_XXX, define a type CK_C_XXX which is 251 | * a pointer to that kind of function. 252 | * ============================================================== 253 | */ 254 | 255 | #define CK_NEED_ARG_LIST 1 256 | #define CK_PKCS11_FUNCTION_INFO(name) \ 257 | typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name)) 258 | 259 | /* pkcs11f.h has all the information about the Cryptoki 260 | * function prototypes. */ 261 | #include "pkcs11f.h" 262 | 263 | #undef CK_NEED_ARG_LIST 264 | #undef CK_PKCS11_FUNCTION_INFO 265 | 266 | 267 | /* ============================================================== 268 | * Define structed vector of entry points. A CK_FUNCTION_LIST 269 | * contains a CK_VERSION indicating a library's Cryptoki version 270 | * and then a whole slew of function pointers to the routines in 271 | * the library. This type was declared, but not defined, in 272 | * pkcs11t.h. 273 | * ============================================================== 274 | */ 275 | 276 | #define CK_PKCS11_FUNCTION_INFO(name) \ 277 | __PASTE(CK_,name) name; 278 | 279 | struct CK_FUNCTION_LIST { 280 | 281 | CK_VERSION version; /* Cryptoki version */ 282 | 283 | /* Pile all the function pointers into the CK_FUNCTION_LIST. */ 284 | /* pkcs11f.h has all the information about the Cryptoki 285 | * function prototypes. */ 286 | #include "pkcs11f.h" 287 | 288 | }; 289 | 290 | #undef CK_PKCS11_FUNCTION_INFO 291 | 292 | 293 | #undef __PASTE 294 | 295 | #ifdef __cplusplus 296 | } 297 | #endif 298 | 299 | #endif 300 | -------------------------------------------------------------------------------- /object.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | #include "tools.h" 12 | #include "storage.h" 13 | #include "object.h" 14 | 15 | 16 | const CK_BBOOL bool_true = CK_TRUE; 17 | const CK_BBOOL bool_false = CK_FALSE; 18 | 19 | Attributes data_object_t::operator()(descriptor_p desc, const Attributes& attributes) const 20 | { 21 | const CK_OBJECT_CLASS klass = CKO_DATA; 22 | const CK_FLAGS flags = 0; 23 | 24 | Attributes attrs = { 25 | create_object(CKA_CLASS, klass), 26 | 27 | //Common Storage Object Attributes 28 | create_object(CKA_TOKEN, bool_true), 29 | create_object(CKA_PRIVATE, bool_true), 30 | create_object(CKA_MODIFIABLE,bool_false), 31 | create_object(CKA_LABEL, desc->item.filename), 32 | 33 | //Data Object Attributes 34 | //create_object(CKA_APPLICATION, desc->id), 35 | create_object(CKA_OBJECT_ID, boost::lexical_cast(desc->id)), 36 | //create_object(CKA_VALUE, desc->id), //read when needed 37 | }; 38 | 39 | //keys in attrs takes precedence with attributes 40 | attrs.insert(attributes.begin(), attributes.end()); 41 | 42 | return attrs; 43 | } 44 | 45 | Attributes public_key_t::operator()(descriptor_p desc, const Attributes& attributes) const 46 | { 47 | const Attributes base_attrs = data_object_t::operator()(desc, attributes); 48 | 49 | const CK_OBJECT_CLASS klass = CKO_PUBLIC_KEY; 50 | const CK_MECHANISM_TYPE mech_type = CKM_RSA_X_509; 51 | 52 | CK_ULONG id = desc->id; 53 | 54 | Attributes attrs = { 55 | create_object(CKA_CLASS, klass), 56 | 57 | //Common Storage Object Attributes 58 | create_object(CKA_TOKEN, bool_true), 59 | create_object(CKA_PRIVATE, bool_false), 60 | create_object(CKA_MODIFIABLE,bool_false), 61 | create_object(CKA_LABEL, desc->item.filename), 62 | 63 | //Common Key Attributes 64 | //create_object(CKA_KEY_TYPE, type), 65 | create_object(CKA_ID, id), 66 | //create_object(CKA_START_DATE, id), 67 | //create_object(CKA_END_DATE, id), 68 | create_object(CKA_DERIVE, bool_false), 69 | create_object(CKA_LOCAL, bool_false), 70 | create_object(CKA_KEY_GEN_MECHANISM, mech_type), 71 | 72 | //Common Public Key Attributes 73 | //create_object(CKA_SUBJECT, bool_true), 74 | create_object(CKA_ENCRYPT, bool_true), 75 | create_object(CKA_VERIFY, bool_true), 76 | //create_object(CKA_VERIFY_RECOVER, bool_false), 77 | //create_object(CKA_TRUSTED10, bool_true), 78 | //create_object(CKA_WRAP_TEMPLATE , bool_true), 79 | 80 | ///////////// 81 | 82 | }; 83 | 84 | //keys in attrs takes precedence with attributes 85 | attrs.insert(base_attrs.begin(), base_attrs.end()); 86 | 87 | return attrs; 88 | } 89 | 90 | Attributes rsa_public_key_t::operator()(descriptor_p desc, const Attributes& attributes) const 91 | { 92 | const Attributes base_attrs = public_key_t::operator()(desc, attributes); 93 | 94 | const CK_KEY_TYPE type = CKK_RSA; 95 | 96 | Attributes attrs = { 97 | create_object(CKA_KEY_TYPE, type), 98 | }; 99 | 100 | if (EVP_PKEY *pkey = PEM_read_PUBKEY(desc->file.get(), NULL, NULL, NULL)) { 101 | int size = 0; 102 | std::shared_ptr buf; 103 | 104 | std::tie(size, buf) = read_bignum(pkey->pkey.rsa->n); 105 | attrs.insert(std::make_pair(CKA_MODULUS, attribute_t(CKA_MODULUS, buf.get(), size))); 106 | attrs.insert(create_object(CKA_MODULUS_BITS, size * 8)); 107 | 108 | std::tie(size, buf) = read_bignum(pkey->pkey.rsa->e); 109 | attrs.insert(std::make_pair(CKA_PUBLIC_EXPONENT, attribute_t(CKA_PUBLIC_EXPONENT, buf.get(), size))); 110 | 111 | EVP_PKEY_free(pkey); 112 | } 113 | 114 | //keys in attrs takes precedence with attributes 115 | attrs.insert(base_attrs.begin(), base_attrs.end()); 116 | 117 | return attrs; 118 | } 119 | 120 | 121 | Attributes ssh_public_key_t::operator()(descriptor_p desc, const Attributes& attributes) const 122 | { 123 | Attributes attrs; 124 | const auto data = piped("cat > /tmp/.soft-pkcs.tmp && ssh-keygen -e -m PKCS8 -f /tmp/.soft-pkcs.tmp && rm /tmp/.soft-pkcs.tmp", desc->item.data); 125 | 126 | assert(data.size()); 127 | 128 | if (!data.empty()) { 129 | std::shared_ptr reserve = desc->file; 130 | desc->file =read_mem(data); 131 | attrs = rsa_public_key_t::operator()(desc, attributes); 132 | desc->file = reserve; 133 | 134 | attrs.insert(create_object(CKA_VALUE, data)); 135 | } 136 | 137 | return attrs; 138 | } 139 | 140 | Attributes private_key_t::operator()(descriptor_p desc, const Attributes& attributes) const 141 | { 142 | const Attributes base_attrs = data_object_t::operator()(desc, attributes); 143 | 144 | const CK_OBJECT_CLASS klass = CKO_PRIVATE_KEY; 145 | const CK_MECHANISM_TYPE mech_type = CKM_RSA_X_509; 146 | const CK_KEY_TYPE type = CKK_GENERIC_SECRET; 147 | 148 | 149 | CK_ULONG id = desc->id; 150 | 151 | Attributes attrs = { 152 | create_object(CKA_CLASS, klass), 153 | 154 | // std::make_pair(CKA_VALUE, attribute_t(CKA_VALUE, data.size())), // SPECIAL CASE FOR VALUE 155 | 156 | //Common Storage Object Attributes 157 | create_object(CKA_TOKEN, bool_true), 158 | create_object(CKA_PRIVATE, bool_true), 159 | create_object(CKA_MODIFIABLE,bool_false), 160 | create_object(CKA_LABEL, desc->item.filename), 161 | 162 | //Common Key Attributes 163 | create_object(CKA_KEY_TYPE, type), 164 | create_object(CKA_ID, id), 165 | //create_object(CKA_START_DATE, id), 166 | //create_object(CKA_END_DATE, id), 167 | create_object(CKA_DERIVE, bool_false), 168 | create_object(CKA_LOCAL, bool_false), 169 | create_object(CKA_KEY_GEN_MECHANISM, mech_type), 170 | 171 | //Common Private Key Attributes 172 | //create_object(CKA_SUBJECT, bool_true), 173 | create_object(CKA_SENSITIVE, bool_true), 174 | create_object(CKA_DECRYPT, bool_true), 175 | create_object(CKA_SIGN, bool_true), 176 | create_object(CKA_SIGN_RECOVER, bool_false), 177 | create_object(CKA_UNWRAP, bool_true), 178 | create_object(CKA_EXTRACTABLE, bool_true), 179 | //create_object(CKA_ALWAYS_SENSITIVE, bool_true), 180 | create_object(CKA_NEVER_EXTRACTABLE, bool_false), 181 | //create_object(CKA_WRAP_WITH_TRUSTED1, bool_false), 182 | //create_object(CKA_UNWRAP_TEMPLATE, bool_false), 183 | create_object(CKA_ALWAYS_AUTHENTICATE, bool_true), 184 | 185 | ///////////// 186 | 187 | }; 188 | 189 | if (EVP_PKEY *pkey = PEM_read_PrivateKey(desc->file.get(), NULL, NULL, const_cast(""))) { 190 | int size = 0; 191 | std::shared_ptr buf; 192 | 193 | std::tie(size, buf) = read_bignum(pkey->pkey.rsa->n); 194 | attrs.insert(std::make_pair(CKA_MODULUS, attribute_t(CKA_MODULUS, buf.get(), size))); 195 | 196 | std::tie(size, buf) = read_bignum(pkey->pkey.rsa->e); 197 | attrs.insert(std::make_pair(CKA_PUBLIC_EXPONENT, attribute_t(CKA_PUBLIC_EXPONENT, buf.get(), size))); 198 | 199 | switch (EVP_PKEY_type(pkey->type)) { 200 | case EVP_PKEY_RSA: 201 | attrs[CKA_KEY_TYPE] = attribute_t(CKA_KEY_TYPE, (CK_KEY_TYPE)CKK_RSA); 202 | break; 203 | case EVP_PKEY_DSA: 204 | attrs[CKA_KEY_TYPE] = attribute_t(CKA_KEY_TYPE, (CK_KEY_TYPE)CKK_DSA); 205 | break; 206 | case EVP_PKEY_DH: 207 | attrs[CKA_KEY_TYPE] = attribute_t(CKA_KEY_TYPE, (CK_KEY_TYPE)CKK_DH); 208 | break; 209 | case EVP_PKEY_EC: 210 | attrs[CKA_KEY_TYPE] = attribute_t(CKA_KEY_TYPE, (CK_KEY_TYPE)CKK_EC); 211 | break; 212 | }; 213 | 214 | EVP_PKEY_free(pkey); 215 | } 216 | 217 | 218 | 219 | 220 | //keys in attrs takes precedence with attributes 221 | attrs.insert(base_attrs.begin(), base_attrs.end()); 222 | 223 | return attrs; 224 | } 225 | 226 | // Attributes rsa_private_key_t::operator()(descriptor_p desc, const Attributes& attributes) const 227 | // { 228 | // const Attributes base_attrs = private_key_t::operator()(desc, attributes); 229 | // 230 | // const CK_KEY_TYPE type = CKK_RSA; 231 | // 232 | // Attributes attrs = { 233 | // create_object(CKA_KEY_TYPE, type), 234 | // }; 235 | // 236 | // if (EVP_PKEY *pkey = PEM_read_PrivateKey(desc->file.get(), NULL, NULL, const_cast(""))) { 237 | // int size = 0; 238 | // std::shared_ptr buf; 239 | // 240 | // std::tie(size, buf) = read_bignum(pkey->pkey.rsa->n); 241 | // attrs.insert(std::make_pair(CKA_MODULUS, attribute_t(CKA_MODULUS, buf.get(), size))); 242 | // 243 | // st_logf(" ..... CKA_MODULUS: %lu\n", attrs[CKA_MODULUS].to_handle()); 244 | // 245 | // std::tie(size, buf) = read_bignum(pkey->pkey.rsa->e); 246 | // attrs.insert(std::make_pair(CKA_PUBLIC_EXPONENT, attribute_t(CKA_PUBLIC_EXPONENT, buf.get(), size))); 247 | // 248 | // EVP_PKEY_free(pkey); 249 | // } 250 | // 251 | // //keys in attrs takes precedence with attributes 252 | // attrs.insert(base_attrs.begin(), base_attrs.end()); 253 | // 254 | // return attrs; 255 | // } 256 | 257 | Attributes secrete_key_t::operator()(descriptor_p desc, const Attributes& attributes) const 258 | { 259 | const Attributes base_attrs = data_object_t::operator()(desc, attributes); 260 | 261 | const CK_OBJECT_CLASS klass = CKO_SECRET_KEY; 262 | const CK_MECHANISM_TYPE mech_type = CKM_RSA_X_509; 263 | 264 | //ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-11/v2-20/pkcs-11v2-20.pdf 265 | Attributes attrs = { 266 | create_object(CKA_CLASS, klass), 267 | 268 | // std::make_pair(CKA_VALUE, attribute_t(CKA_VALUE, data.size())), // SPECIAL CASE FOR VALUE 269 | 270 | //Common Storage Object Attributes 271 | create_object(CKA_TOKEN, bool_true), 272 | create_object(CKA_PRIVATE, bool_true), 273 | create_object(CKA_MODIFIABLE,bool_false), 274 | create_object(CKA_LABEL, desc->item.filename), 275 | 276 | //Common Key Attributes 277 | //create_object(CKA_KEY_TYPE, id), 278 | create_object(CKA_ID, desc->id), 279 | //create_object(CKA_START_DATE, id), 280 | //create_object(CKA_END_DATE, id), 281 | create_object(CKA_DERIVE, bool_false), 282 | create_object(CKA_LOCAL, bool_false), 283 | create_object(CKA_KEY_GEN_MECHANISM, mech_type), 284 | 285 | //Common Secret Key Attributes 286 | create_object(CKA_SENSITIVE, bool_true), //bool_false 287 | create_object(CKA_ENCRYPT, bool_true), 288 | create_object(CKA_DECRYPT, bool_true), 289 | create_object(CKA_SIGN, bool_true), 290 | create_object(CKA_VERIFY, bool_false), 291 | create_object(CKA_WRAP, bool_false), 292 | create_object(CKA_UNWRAP, bool_false), 293 | create_object(CKA_EXTRACTABLE, bool_true), 294 | //create_object(CKA_ALWAYS_SENSITIVE, bool_true), 295 | create_object(CKA_NEVER_EXTRACTABLE, bool_false), 296 | //create_object(CKA_CHECK_VALUE, bool_false), 297 | //create_object(CKA_WRAP_WITH_TRUSTED, bool_false), 298 | //create_object(CKA_TRUSTED, bool_false), 299 | //create_object(CKA_WRAP_TEMPLATE, bool_false), 300 | //create_object(CKA_UNWRAP_TEMPLATE, bool_false), 301 | create_object(CKA_ALWAYS_AUTHENTICATE, bool_true), 302 | 303 | ///////////// 304 | 305 | }; 306 | 307 | //keys in attrs takes precedence with attributes 308 | attrs.insert(attributes.begin(), attributes.end()); 309 | 310 | return attrs; 311 | } 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | -------------------------------------------------------------------------------- /example/missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common stub for a few missing GNU programs while installing. 3 | 4 | scriptversion=2005-06-08.21 5 | 6 | # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005 7 | # Free Software Foundation, Inc. 8 | # Originally by Fran,cois Pinard , 1996. 9 | 10 | # This program is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation; either version 2, or (at your option) 13 | # any later version. 14 | 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 23 | # 02110-1301, USA. 24 | 25 | # As a special exception to the GNU General Public License, if you 26 | # distribute this file as part of a program that contains a 27 | # configuration script generated by Autoconf, you may include it under 28 | # the same distribution terms that you use for the rest of that program. 29 | 30 | if test $# -eq 0; then 31 | echo 1>&2 "Try \`$0 --help' for more information" 32 | exit 1 33 | fi 34 | 35 | run=: 36 | 37 | # In the cases where this matters, `missing' is being run in the 38 | # srcdir already. 39 | if test -f configure.ac; then 40 | configure_ac=configure.ac 41 | else 42 | configure_ac=configure.in 43 | fi 44 | 45 | msg="missing on your system" 46 | 47 | case "$1" in 48 | --run) 49 | # Try to run requested program, and just exit if it succeeds. 50 | run= 51 | shift 52 | "$@" && exit 0 53 | # Exit code 63 means version mismatch. This often happens 54 | # when the user try to use an ancient version of a tool on 55 | # a file that requires a minimum version. In this case we 56 | # we should proceed has if the program had been absent, or 57 | # if --run hadn't been passed. 58 | if test $? = 63; then 59 | run=: 60 | msg="probably too old" 61 | fi 62 | ;; 63 | 64 | -h|--h|--he|--hel|--help) 65 | echo "\ 66 | $0 [OPTION]... PROGRAM [ARGUMENT]... 67 | 68 | Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an 69 | error status if there is no known handling for PROGRAM. 70 | 71 | Options: 72 | -h, --help display this help and exit 73 | -v, --version output version information and exit 74 | --run try to run the given command, and emulate it if it fails 75 | 76 | Supported PROGRAM values: 77 | aclocal touch file \`aclocal.m4' 78 | autoconf touch file \`configure' 79 | autoheader touch file \`config.h.in' 80 | automake touch all \`Makefile.in' files 81 | bison create \`y.tab.[ch]', if possible, from existing .[ch] 82 | flex create \`lex.yy.c', if possible, from existing .c 83 | help2man touch the output file 84 | lex create \`lex.yy.c', if possible, from existing .c 85 | makeinfo touch the output file 86 | tar try tar, gnutar, gtar, then tar without non-portable flags 87 | yacc create \`y.tab.[ch]', if possible, from existing .[ch] 88 | 89 | Send bug reports to ." 90 | exit $? 91 | ;; 92 | 93 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 94 | echo "missing $scriptversion (GNU Automake)" 95 | exit $? 96 | ;; 97 | 98 | -*) 99 | echo 1>&2 "$0: Unknown \`$1' option" 100 | echo 1>&2 "Try \`$0 --help' for more information" 101 | exit 1 102 | ;; 103 | 104 | esac 105 | 106 | # Now exit if we have it, but it failed. Also exit now if we 107 | # don't have it and --version was passed (most likely to detect 108 | # the program). 109 | case "$1" in 110 | lex|yacc) 111 | # Not GNU programs, they don't have --version. 112 | ;; 113 | 114 | tar) 115 | if test -n "$run"; then 116 | echo 1>&2 "ERROR: \`tar' requires --run" 117 | exit 1 118 | elif test "x$2" = "x--version" || test "x$2" = "x--help"; then 119 | exit 1 120 | fi 121 | ;; 122 | 123 | *) 124 | if test -z "$run" && ($1 --version) > /dev/null 2>&1; then 125 | # We have it, but it failed. 126 | exit 1 127 | elif test "x$2" = "x--version" || test "x$2" = "x--help"; then 128 | # Could not run --version or --help. This is probably someone 129 | # running `$TOOL --version' or `$TOOL --help' to check whether 130 | # $TOOL exists and not knowing $TOOL uses missing. 131 | exit 1 132 | fi 133 | ;; 134 | esac 135 | 136 | # If it does not exist, or fails to run (possibly an outdated version), 137 | # try to emulate it. 138 | case "$1" in 139 | aclocal*) 140 | echo 1>&2 "\ 141 | WARNING: \`$1' is $msg. You should only need it if 142 | you modified \`acinclude.m4' or \`${configure_ac}'. You might want 143 | to install the \`Automake' and \`Perl' packages. Grab them from 144 | any GNU archive site." 145 | touch aclocal.m4 146 | ;; 147 | 148 | autoconf) 149 | echo 1>&2 "\ 150 | WARNING: \`$1' is $msg. You should only need it if 151 | you modified \`${configure_ac}'. You might want to install the 152 | \`Autoconf' and \`GNU m4' packages. Grab them from any GNU 153 | archive site." 154 | touch configure 155 | ;; 156 | 157 | autoheader) 158 | echo 1>&2 "\ 159 | WARNING: \`$1' is $msg. You should only need it if 160 | you modified \`acconfig.h' or \`${configure_ac}'. You might want 161 | to install the \`Autoconf' and \`GNU m4' packages. Grab them 162 | from any GNU archive site." 163 | files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` 164 | test -z "$files" && files="config.h" 165 | touch_files= 166 | for f in $files; do 167 | case "$f" in 168 | *:*) touch_files="$touch_files "`echo "$f" | 169 | sed -e 's/^[^:]*://' -e 's/:.*//'`;; 170 | *) touch_files="$touch_files $f.in";; 171 | esac 172 | done 173 | touch $touch_files 174 | ;; 175 | 176 | automake*) 177 | echo 1>&2 "\ 178 | WARNING: \`$1' is $msg. You should only need it if 179 | you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. 180 | You might want to install the \`Automake' and \`Perl' packages. 181 | Grab them from any GNU archive site." 182 | find . -type f -name Makefile.am -print | 183 | sed 's/\.am$/.in/' | 184 | while read f; do touch "$f"; done 185 | ;; 186 | 187 | autom4te) 188 | echo 1>&2 "\ 189 | WARNING: \`$1' is needed, but is $msg. 190 | You might have modified some files without having the 191 | proper tools for further handling them. 192 | You can get \`$1' as part of \`Autoconf' from any GNU 193 | archive site." 194 | 195 | file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` 196 | test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` 197 | if test -f "$file"; then 198 | touch $file 199 | else 200 | test -z "$file" || exec >$file 201 | echo "#! /bin/sh" 202 | echo "# Created by GNU Automake missing as a replacement of" 203 | echo "# $ $@" 204 | echo "exit 0" 205 | chmod +x $file 206 | exit 1 207 | fi 208 | ;; 209 | 210 | bison|yacc) 211 | echo 1>&2 "\ 212 | WARNING: \`$1' $msg. You should only need it if 213 | you modified a \`.y' file. You may need the \`Bison' package 214 | in order for those modifications to take effect. You can get 215 | \`Bison' from any GNU archive site." 216 | rm -f y.tab.c y.tab.h 217 | if [ $# -ne 1 ]; then 218 | eval LASTARG="\${$#}" 219 | case "$LASTARG" in 220 | *.y) 221 | SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` 222 | if [ -f "$SRCFILE" ]; then 223 | cp "$SRCFILE" y.tab.c 224 | fi 225 | SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` 226 | if [ -f "$SRCFILE" ]; then 227 | cp "$SRCFILE" y.tab.h 228 | fi 229 | ;; 230 | esac 231 | fi 232 | if [ ! -f y.tab.h ]; then 233 | echo >y.tab.h 234 | fi 235 | if [ ! -f y.tab.c ]; then 236 | echo 'main() { return 0; }' >y.tab.c 237 | fi 238 | ;; 239 | 240 | lex|flex) 241 | echo 1>&2 "\ 242 | WARNING: \`$1' is $msg. You should only need it if 243 | you modified a \`.l' file. You may need the \`Flex' package 244 | in order for those modifications to take effect. You can get 245 | \`Flex' from any GNU archive site." 246 | rm -f lex.yy.c 247 | if [ $# -ne 1 ]; then 248 | eval LASTARG="\${$#}" 249 | case "$LASTARG" in 250 | *.l) 251 | SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` 252 | if [ -f "$SRCFILE" ]; then 253 | cp "$SRCFILE" lex.yy.c 254 | fi 255 | ;; 256 | esac 257 | fi 258 | if [ ! -f lex.yy.c ]; then 259 | echo 'main() { return 0; }' >lex.yy.c 260 | fi 261 | ;; 262 | 263 | help2man) 264 | echo 1>&2 "\ 265 | WARNING: \`$1' is $msg. You should only need it if 266 | you modified a dependency of a manual page. You may need the 267 | \`Help2man' package in order for those modifications to take 268 | effect. You can get \`Help2man' from any GNU archive site." 269 | 270 | file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` 271 | if test -z "$file"; then 272 | file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` 273 | fi 274 | if [ -f "$file" ]; then 275 | touch $file 276 | else 277 | test -z "$file" || exec >$file 278 | echo ".ab help2man is required to generate this page" 279 | exit 1 280 | fi 281 | ;; 282 | 283 | makeinfo) 284 | echo 1>&2 "\ 285 | WARNING: \`$1' is $msg. You should only need it if 286 | you modified a \`.texi' or \`.texinfo' file, or any other file 287 | indirectly affecting the aspect of the manual. The spurious 288 | call might also be the consequence of using a buggy \`make' (AIX, 289 | DU, IRIX). You might want to install the \`Texinfo' package or 290 | the \`GNU make' package. Grab either from any GNU archive site." 291 | # The file to touch is that specified with -o ... 292 | file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` 293 | if test -z "$file"; then 294 | # ... or it is the one specified with @setfilename ... 295 | infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` 296 | file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile` 297 | # ... or it is derived from the source name (dir/f.texi becomes f.info) 298 | test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info 299 | fi 300 | # If the file does not exist, the user really needs makeinfo; 301 | # let's fail without touching anything. 302 | test -f $file || exit 1 303 | touch $file 304 | ;; 305 | 306 | tar) 307 | shift 308 | 309 | # We have already tried tar in the generic part. 310 | # Look for gnutar/gtar before invocation to avoid ugly error 311 | # messages. 312 | if (gnutar --version > /dev/null 2>&1); then 313 | gnutar "$@" && exit 0 314 | fi 315 | if (gtar --version > /dev/null 2>&1); then 316 | gtar "$@" && exit 0 317 | fi 318 | firstarg="$1" 319 | if shift; then 320 | case "$firstarg" in 321 | *o*) 322 | firstarg=`echo "$firstarg" | sed s/o//` 323 | tar "$firstarg" "$@" && exit 0 324 | ;; 325 | esac 326 | case "$firstarg" in 327 | *h*) 328 | firstarg=`echo "$firstarg" | sed s/h//` 329 | tar "$firstarg" "$@" && exit 0 330 | ;; 331 | esac 332 | fi 333 | 334 | echo 1>&2 "\ 335 | WARNING: I can't seem to be able to run \`tar' with the given arguments. 336 | You may want to install GNU tar or Free paxutils, or check the 337 | command line arguments." 338 | exit 1 339 | ;; 340 | 341 | *) 342 | echo 1>&2 "\ 343 | WARNING: \`$1' is needed, and is $msg. 344 | You might have modified some files without having the 345 | proper tools for further handling them. Check the \`README' file, 346 | it often tells you about the needed prerequisites for installing 347 | this package. You may also peek at any GNU archive site, in case 348 | some other package would contain this missing \`$1' program." 349 | exit 1 350 | ;; 351 | esac 352 | 353 | exit 0 354 | 355 | # Local variables: 356 | # eval: (add-hook 'write-file-hooks 'time-stamp) 357 | # time-stamp-start: "scriptversion=" 358 | # time-stamp-format: "%:y-%02m-%02d.%02H" 359 | # time-stamp-end: "$" 360 | # End: 361 | -------------------------------------------------------------------------------- /storage.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | 14 | #include "storage.h" 15 | #include "tools.h" 16 | #include "exceptions.h" 17 | 18 | namespace fs = boost::filesystem; 19 | typedef boost::property_tree::ptree config_t; 20 | typedef boost::filter_iterator, fs::directory_iterator> files_iterator; 21 | 22 | const std::string fs_driver_c = "fs"; 23 | const std::string fuse_driver_c = "fuse"; 24 | const std::string shell_driver_c = "shell"; 25 | const std::string crypt_driver_c = "crypt"; 26 | 27 | const std::string meta_c = ".soft-pkcs.meta"; 28 | 29 | std::string metaname(const std::string& file) { 30 | return "." + file + ".meta"; 31 | }; 32 | 33 | const std::map > load_attribute = { 34 | {"id", [](const std::string& val){return attribute_t(CKA_ID, boost::lexical_cast(val));}} 35 | }; 36 | 37 | const std::map > dump_attribute = { 38 | {CKA_ID, [](const attribute_t& attr){return std::make_pair("id", boost::property_tree::ptree(boost::lexical_cast(attr.to_id())));}} 39 | }; 40 | 41 | Attributes parse_meta(const Bytes& bytes) { 42 | Attributes attributes; 43 | boost::property_tree::ptree ini; 44 | 45 | boost::interprocess::basic_vectorstream stream(bytes); 46 | boost::property_tree::ini_parser::read_ini(stream, ini); 47 | 48 | BOOST_FOREACH(auto attr, ini) { 49 | auto it = load_attribute.find(attr.first); 50 | if (it != load_attribute.end()) { 51 | auto a = it->second(attr.second.data()); 52 | attributes[a->type] = a; 53 | } 54 | } 55 | 56 | return attributes; 57 | } 58 | 59 | Bytes write_meta(const Attributes& attributes) { 60 | boost::property_tree::ptree ini; 61 | 62 | BOOST_FOREACH(auto& attr, attributes) { 63 | auto it = dump_attribute.find(attr.first); 64 | if (it != dump_attribute.end()) { 65 | ini.push_back(it->second(attr.second)); 66 | } 67 | } 68 | 69 | boost::interprocess::basic_vectorstream stream; 70 | boost::property_tree::ini_parser::write_ini(stream, ini); 71 | 72 | return stream.vector(); 73 | } 74 | /* 75 | std::list storage_t::items() 76 | { 77 | std::list items = do_items(); 78 | 79 | // try { 80 | // MetaAttributesList metalist = parse_meta(do_read(meta_c).data); 81 | // BOOST_FOREACH(item_t& item, items) { 82 | // item.meta = metalist[item.filename]; 83 | // } 84 | // } 85 | // catch (...) {}; 86 | return items; 87 | } 88 | 89 | item_t storage_t::read(const std::string& fn) 90 | { 91 | item_t item = do_read(fn); 92 | // try { 93 | // MetaAttributesList metalist = parse_meta(do_read(meta_c).data); 94 | // item.meta = metalist[item.filename]; 95 | // } 96 | // catch(...){} 97 | return item; 98 | } 99 | 100 | item_t storage_t::write(const item_t& item) 101 | { 102 | // try { 103 | // MetaAttributesList metalist = parse_meta(do_read(meta_c).data); 104 | // metalist[item.filename] = item.meta; 105 | // auto data = write_meta(metalist); 106 | // do_write(item_t(meta_c, data)); 107 | // } 108 | // catch(...) {} 109 | return do_write(item); 110 | }*/ 111 | 112 | 113 | 114 | struct fs_storage_t : storage_t { 115 | fs_storage_t(const config_t& c, const std::string& pin, std::shared_ptr s) 116 | : storage_t(fs_driver_c, c, s) 117 | { 118 | set_pin(pin); 119 | path = config_.get("path"); 120 | st_logf("Path : %s\n", path.c_str()); 121 | } 122 | 123 | files_iterator files_begin() { 124 | if (fs::exists(path) && fs::is_directory(path)) { 125 | return files_iterator( 126 | [](const fs::directory_entry& d){return fs::is_regular_file(d.status());}, 127 | fs::directory_iterator(path) 128 | ); 129 | } 130 | return files_end(); 131 | } 132 | 133 | files_iterator files_end() const { 134 | return files_iterator(fs::directory_iterator()); 135 | } 136 | 137 | virtual void set_pin(const std::string& pin) { 138 | if (prev) prev->set_pin(pin); 139 | } 140 | 141 | virtual bool present() const { 142 | return fs::exists(path) && fs::is_directory(path); 143 | } 144 | 145 | virtual std::list items() { 146 | std::list result; 147 | 148 | for(auto it = files_begin(); it != files_end(); ++it) { 149 | std::ifstream stream(it->path().string()); 150 | 151 | if (!boost::algorithm::ends_with(it->path().filename().string(), ".meta")) { 152 | const std::string fn = it->path().filename().string(); 153 | result.push_back( 154 | item_t( 155 | fn, 156 | read_file((fs::directory_entry(path).path() / fn).string()), 157 | parse_meta(read_file((fs::directory_entry(path).path() / metaname(fn)).string())) 158 | ) 159 | ); 160 | } 161 | } 162 | 163 | return result; 164 | }; 165 | 166 | virtual item_t read(const std::string& fn) { 167 | return item_t( 168 | fn, 169 | read_file((fs::directory_entry(path).path() / fn).string()), 170 | parse_meta(read_file((fs::directory_entry(path).path() / metaname(fn)).string())) 171 | ); 172 | throw std::runtime_error("such file not found"); 173 | }; 174 | 175 | virtual item_t write(const item_t& item) { 176 | write_file((fs::directory_entry(path).path() / (item.filename)).string(), item.data); 177 | write_file((fs::directory_entry(path).path() / metaname(item.filename)).string(), write_meta(item.attributes)); 178 | 179 | return read(item.filename); 180 | } 181 | 182 | Bytes read_file(const std::string& filepath) { 183 | try { 184 | std::ifstream stream(filepath); 185 | return Bytes((std::istreambuf_iterator(stream)), std::istreambuf_iterator()); 186 | } 187 | catch(...) { 188 | return Bytes(); 189 | } 190 | } 191 | 192 | void write_file(const std::string& filepath, const Bytes& data) { 193 | std::shared_ptr file( 194 | ::fopen(filepath.c_str(), "w+"), 195 | ::fclose 196 | ); 197 | 198 | if (!file.get()) { 199 | throw std::runtime_error("can't open file for writing"); 200 | } 201 | 202 | int res = ::fwrite(data.data(), 1, data.size(), file.get()); 203 | if (res != data.size()) { 204 | throw std::runtime_error("can't write file"); 205 | } 206 | 207 | file.reset(); 208 | } 209 | 210 | std::string path; 211 | }; 212 | 213 | struct mount_t { 214 | mount_t(const std::string& m, const std::string& u, const std::string& pass) 215 | : umount(u) 216 | { 217 | system(umount.c_str()); 218 | if (start(m.c_str(), std::vector(pass.begin(), pass.end())) != 0) { 219 | throw std::runtime_error("Can't mount: " + m); 220 | } 221 | } 222 | 223 | ~mount_t() { 224 | st_logf("Umounting: %s\n", umount.c_str()); 225 | system(umount.c_str()); 226 | } 227 | 228 | std::string umount; 229 | }; 230 | 231 | struct fuse_storage_t : fs_storage_t { 232 | fuse_storage_t(const config_t& c, const std::string& pin, std::shared_ptr s = std::shared_ptr()) 233 | : fs_storage_t(c, pin, s) 234 | { 235 | name_ = fuse_driver_c; 236 | set_pin(pin); 237 | } 238 | 239 | virtual void set_pin(const std::string& pin) { 240 | const std::string mount = config_.get("mount"); 241 | const std::string umount = config_.get("umount"); 242 | 243 | st_logf("Mount: %s, Umount: %s\n", mount.c_str(), umount.c_str()); 244 | m_.reset(new mount_t(mount, umount, pin)); 245 | 246 | if (prev) prev->set_pin(pin); 247 | } 248 | 249 | std::shared_ptr m_; 250 | }; 251 | 252 | struct shell_storage_t : storage_t { 253 | shell_storage_t(const config_t& c, const std::string& pin, std::shared_ptr s = std::shared_ptr()) 254 | : storage_t(shell_driver_c, c, s) 255 | , timestamp_(0), last_present_(false) 256 | { 257 | present_ = c.get("present"); 258 | list_ = c.get("list"); 259 | read_ = c.get("read"); 260 | write_ = c.get("write"); 261 | 262 | set_pin(pin); 263 | } 264 | 265 | virtual void set_pin(const std::string& pin) { 266 | if (prev) prev->set_pin(pin); 267 | } 268 | 269 | virtual bool present() const { 270 | 271 | time_t current = ::time(NULL); 272 | if (current - timestamp_ < 3) { 273 | if (last_present_) return true; 274 | } 275 | 276 | last_present_ = (start(present_) == 0); 277 | st_logf("Shell storage present: %d\n", last_present_); 278 | timestamp_ = ::time(NULL); 279 | return last_present_; 280 | } 281 | 282 | virtual std::list items() { 283 | std::list result; 284 | 285 | std::vector files; 286 | 287 | try { 288 | auto data = piped(list_); 289 | boost::split(files, data, boost::is_any_of("\n")); 290 | } 291 | catch (const std::exception& e) { 292 | timestamp_ = 0; 293 | if (present()) { 294 | throw pkcs11_exception_t(CKR_DEVICE_ERROR, std::string("failed to list files: ") + e.what()); 295 | } else { 296 | throw pkcs11_exception_t(CKR_DEVICE_REMOVED, "device removed"); 297 | } 298 | } 299 | 300 | for(auto file: files) { 301 | if (file.empty() or file == meta_c) continue; 302 | 303 | const item_t item = read(file); 304 | assert(!item.data.empty()); 305 | result.push_back(item); 306 | } 307 | 308 | return result; 309 | } 310 | 311 | virtual item_t read(const std::string& fn) { 312 | std::string read = read_; 313 | boost::replace_all(read, "%FILE%", fn); 314 | std::string read_meta = read_; 315 | boost::replace_all(read_meta, "%FILE%", metaname(fn)); 316 | try { 317 | return item_t { 318 | fn, 319 | piped(read), 320 | parse_meta(piped(read_meta)) 321 | }; 322 | } 323 | catch(const std::exception& e) { 324 | timestamp_ = 0; 325 | if (present()) { 326 | throw pkcs11_exception_t(CKR_DEVICE_ERROR, std::string("failed to read file: ") + e.what()); 327 | } else { 328 | throw pkcs11_exception_t(CKR_DEVICE_REMOVED, "device removed"); 329 | } 330 | } 331 | } 332 | 333 | virtual item_t write(const item_t& item) { 334 | std::string write_cmd, write_meta_cmd = write_; 335 | boost::replace_all(write_cmd, "%FILE%", item.filename); 336 | boost::replace_all(write_meta_cmd, "%FILE%", metaname(item.filename)); 337 | 338 | try { 339 | piped(write_cmd, item.data); 340 | piped(write_meta_cmd, write_meta(item.attributes)); 341 | } 342 | catch(const std::exception& e) { 343 | timestamp_ = 0; 344 | if (present()) { 345 | throw pkcs11_exception_t(CKR_DEVICE_ERROR, std::string("failed to write file: ") + e.what()); 346 | } else { 347 | throw pkcs11_exception_t(CKR_DEVICE_REMOVED, "device removed"); 348 | } 349 | } 350 | return read(item.filename); 351 | } 352 | 353 | std::string present_; 354 | std::string list_; 355 | std::string read_; 356 | std::string write_; 357 | 358 | mutable time_t timestamp_; 359 | mutable bool last_present_; 360 | }; 361 | 362 | struct crypt_storage_t : storage_t { 363 | crypt_storage_t(const config_t& c, const std::string& pin, std::shared_ptr s) 364 | : storage_t(crypt_driver_c, c, s) 365 | { 366 | set_pin(pin); 367 | } 368 | 369 | virtual ~crypt_storage_t() { 370 | } 371 | 372 | virtual void set_pin(const std::string& pin) { 373 | encrypt_ = config_.get("encrypt"); 374 | decrypt_ = config_.get("decrypt"); 375 | 376 | boost::replace_all(encrypt_, "%PIN%", pin); 377 | boost::replace_all(decrypt_, "%PIN%", pin); 378 | 379 | if (prev) prev->set_pin(pin); 380 | } 381 | 382 | virtual bool present() const { 383 | return prev->present(); 384 | } 385 | 386 | virtual std::list items() { 387 | std::list result; 388 | for(auto item: prev->items()) { 389 | try { 390 | const item_t d = decrypt(item); 391 | if (!d.data.empty()) { 392 | result.push_back(d); 393 | } 394 | } catch (std::exception& e) { 395 | st_logf("Can't decrypt file %s: %s\n", item.filename.c_str(), e.what()); 396 | } 397 | } 398 | 399 | return result; 400 | } 401 | 402 | virtual item_t read(const std::string& fn) { 403 | return decrypt(prev->read(fn)); 404 | } 405 | 406 | virtual item_t write(const item_t& item) { 407 | return decrypt(prev->write(encrypt(item))); 408 | } 409 | 410 | item_t decrypt(const item_t& item) const { 411 | try { 412 | return item_t { 413 | item.filename, 414 | piped(decrypt_, item.data), 415 | item.attributes 416 | }; 417 | } catch(const std::exception& e) { 418 | throw pkcs11_exception_t(CKR_DEVICE_ERROR, std::string("failed to decrypt file: ") + e.what()); 419 | } 420 | } 421 | 422 | item_t encrypt(const item_t& item) const { 423 | try { 424 | return item_t { 425 | item.filename, 426 | piped(encrypt_, item.data), 427 | item.attributes 428 | }; 429 | } catch(const std::exception& e) { 430 | throw pkcs11_exception_t(CKR_DEVICE_ERROR, std::string("failed to decrypt file: ") + e.what()); 431 | } 432 | } 433 | 434 | std::string decrypt_; 435 | std::string encrypt_; 436 | }; 437 | 438 | 439 | std::shared_ptr storage_t::create(const config_t& config, const std::string& pin) 440 | { 441 | std::shared_ptr storage; 442 | BOOST_FOREACH(auto p, config) { 443 | if (p.second.size() > 0) { 444 | if (p.second.get("driver") == fs_driver_c) { 445 | storage.reset(new fs_storage_t(p.second, pin, storage)); 446 | } 447 | else if (p.second.get("driver") == fuse_driver_c) { 448 | storage.reset(new fuse_storage_t(p.second, pin, storage)); 449 | } 450 | else if (p.second.get("driver") == crypt_driver_c) { 451 | storage.reset(new crypt_storage_t(p.second, pin, storage)); 452 | } 453 | else if (p.second.get("driver") == shell_driver_c) { 454 | storage.reset(new shell_storage_t(p.second, pin, storage)); 455 | } 456 | } 457 | } 458 | 459 | return storage; 460 | } 461 | 462 | 463 | struct to_object_id : std::unary_function { 464 | CK_OBJECT_HANDLE operator() (const fs::directory_entry& d) const { 465 | return static_cast(hash(d.path().filename().c_str())); 466 | } 467 | CK_OBJECT_HANDLE operator() (const std::string& filename) const { 468 | return static_cast(hash(filename)); 469 | } 470 | private: 471 | std::hash hash; 472 | }; 473 | 474 | descriptor_t::descriptor_t(const item_t& it) 475 | : item(it) 476 | { 477 | if (item.data.empty()) { 478 | throw std::runtime_error("There is no data in item"); 479 | } 480 | 481 | const std::string str(item.data.begin(), item.data.end()); 482 | std::stringstream stream(str); 483 | 484 | std::getline(stream, first_line, '\n'); 485 | stream.seekg (0, stream.beg); 486 | 487 | id = to_object_id()(item.filename); 488 | 489 | void* src = const_cast(item.data.data()); 490 | file.reset( 491 | ::fmemopen(src, item.data.size(), "r"), 492 | ::fclose 493 | ); 494 | 495 | if (!file.get()) { 496 | throw std::runtime_error("Can't memopen data"); 497 | } 498 | }; 499 | 500 | 501 | -------------------------------------------------------------------------------- /soft_token.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "tools.h" 27 | #include "storage.h" 28 | #include "soft_token.h" 29 | #include "exceptions.h" 30 | #include "object.h" 31 | #include "log.h" 32 | 33 | enum Attribute : CK_ATTRIBUTE_TYPE { 34 | AttrFilename = CKA_VENDOR_DEFINED + 1, 35 | AttrSshPublic, 36 | AttrSshUnpacked, 37 | }; 38 | 39 | const CK_BBOOL bool_true = CK_TRUE; 40 | const CK_BBOOL bool_false = CK_FALSE; 41 | 42 | namespace fs = boost::filesystem; 43 | using namespace boost::adaptors; 44 | 45 | struct is_public_key : std::unary_function { 46 | bool operator() (descriptor_p desc) { 47 | return desc->first_line.find("ssh-rsa") == 0 48 | || desc->first_line == "-----BEGIN PUBLIC KEY-----" 49 | || desc->first_line == "-----BEGIN RSA PUBLIC KEY-----"; 50 | } 51 | }; 52 | 53 | struct is_rsa_public_key : std::unary_function { 54 | bool operator() (descriptor_p desc) { 55 | return desc->first_line == "-----BEGIN PUBLIC KEY-----" 56 | || desc->first_line == "-----BEGIN RSA PUBLIC KEY-----"; 57 | } 58 | }; 59 | 60 | struct is_ssh_public_key : std::unary_function { 61 | bool operator() (descriptor_p desc) { 62 | return desc->first_line.find("ssh-rsa") == 0; 63 | } 64 | }; 65 | 66 | struct is_private_key : std::unary_function { 67 | bool operator() (descriptor_p desc) { 68 | return desc->first_line == "-----BEGIN RSA PRIVATE KEY-----" 69 | || desc->first_line == "-----BEGIN PRIVATE KEY-----"; 70 | } 71 | }; 72 | 73 | // struct is_rsa_private_key : std::unary_function { 74 | // bool operator() (descriptor_p desc) { 75 | // return desc->first_line == "-----BEGIN RSA PRIVATE KEY-----"; 76 | // } 77 | // }; 78 | 79 | struct to_attributes : std::unary_function { 80 | 81 | Objects& objects; 82 | to_attributes(Objects& o): objects(o) { 83 | 84 | } 85 | 86 | Objects::value_type operator() (const item_t& item) { 87 | 88 | descriptor_p desc(new descriptor_t(item)); 89 | 90 | Attributes attrs = { 91 | create_object(AttrFilename, desc->item.filename), 92 | }; 93 | 94 | // attrs = data_object_attrs(desc, attrs); 95 | 96 | if (is_rsa_public_key()(desc)) { 97 | rsa_public_key_t o = rsa_public_key_t(); 98 | attrs = o(desc, attrs); 99 | } 100 | else if (is_ssh_public_key()(desc)) { 101 | ssh_public_key_t o = ssh_public_key_t(); 102 | attrs = o(desc, attrs); 103 | 104 | { 105 | //create additional unpacked key 106 | attrs[AttrSshUnpacked] = attribute_t(AttrSshUnpacked, bool_true); 107 | objects.insert(std::make_pair(desc->id - 1, attrs)).first->first; 108 | }; 109 | 110 | attrs.erase(AttrSshUnpacked); 111 | attrs.erase(CKA_VALUE); 112 | attrs[CKA_ID] = attribute_t(CKA_ID, desc->id); 113 | attrs[CKA_LABEL] = attribute_t(CKA_LABEL, "SSH " + attrs[CKA_LABEL].to_string()); 114 | attrs[AttrSshPublic] = attribute_t(AttrSshPublic, bool_true); 115 | } 116 | // else if (is_rsa_private_key()(desc)) { 117 | // rsa_private_key_t o = rsa_private_key_t(); 118 | // attrs = o(desc, attrs); 119 | // } 120 | else if (is_private_key()(desc)) { 121 | private_key_t o = private_key_t(); 122 | attrs = o(desc, attrs); 123 | } 124 | else { 125 | data_object_t o = data_object_t(); 126 | attrs = o(desc, attrs); 127 | } 128 | 129 | BOOST_FOREACH(auto& attr, item.attributes) { 130 | attrs[attr.first] = attr.second; 131 | } 132 | 133 | return std::make_pair(desc->id, attrs); 134 | } 135 | }; 136 | 137 | struct by_attrs : std::unary_function { 138 | by_attrs(const Attributes& a) : attrs(a) {} 139 | 140 | bool operator()(const Objects::value_type& object_pair) const { 141 | 142 | CK_OBJECT_HANDLE h = object_pair.second.at(CKA_OBJECT_ID).to_handle(); 143 | 144 | LOG(" * SCAN object: %s [%lu] [%lu]\n", object_pair.second.at(CKA_LABEL).to_string().c_str(), object_pair.first, h); 145 | 146 | for (auto it = attrs.begin(); it != attrs.end(); ++it) { 147 | const Attributes& object_attrs = object_pair.second; 148 | 149 | LOG(" - compare attr type:: [0x%08lx]\n", it->first); 150 | 151 | auto fnd = object_attrs.find(it->first); 152 | if (fnd != object_attrs.end()) { 153 | if (fnd->second != it->second) { 154 | LOG(" - attr type [0x%08lx] NOT equal %lu -- %lu\n", it->first, *((CK_ULONG*)it->second->pValue), *((CK_ULONG*)fnd->second->pValue)); 155 | return false; 156 | } else { 157 | LOG(" - attr type [0x%08lx] EQUAL %lu -- %lu\n", it->first, it->second.to_handle(), fnd->second.to_handle()); 158 | } 159 | } 160 | else { 161 | LOG(" - attr type [0x%08lx] NOT FOUND\n", it->first); 162 | return false; 163 | } 164 | } 165 | 166 | LOG(" * object MATCH\n"); 167 | return true; 168 | }; 169 | 170 | private: 171 | const Attributes attrs; 172 | }; 173 | 174 | 175 | 176 | struct not1 : std::unary_function { 177 | 178 | not1(ObjectsPred p) : pred(p) {} 179 | 180 | bool operator()(const Objects::value_type& object_attrs) const { 181 | return !pred(object_attrs); 182 | } 183 | 184 | private: 185 | ObjectsPred pred; 186 | }; 187 | 188 | struct soft_token_t::Pimpl { 189 | 190 | Pimpl() {} 191 | 192 | /// Find in objects by predicate 193 | Objects::const_iterator find(std::function pred) const { 194 | return std::find_if(objects.begin(), objects.end(), [&pred] (const Objects::value_type& v) { 195 | return pred(v.second); 196 | }); 197 | } 198 | 199 | /// Find in objects by predicate 200 | Objects::iterator find(std::function pred) { 201 | return std::find_if(objects.begin(), objects.end(), [&pred] (const Objects::value_type& v) { 202 | return pred(v.second); 203 | }); 204 | } 205 | 206 | 207 | /// Filter objects by predicate 208 | template 209 | boost::filter_iterator filter_iterator(ObjectsPred pred, It b = It(), It e = It()) { 210 | if (b == It()) {b = objects.begin();} 211 | if (e == It()) {e = objects.end();} 212 | 213 | return boost::filter_iterator(pred, b, e); 214 | } 215 | 216 | /// Filter objects by attributes 217 | template 218 | boost::filter_iterator filter_iterator(const Attributes& attrs, It b = It(), It e = It()) { 219 | if (b == It()) {b = objects.begin();} 220 | if (e == It()) {e = objects.end();} 221 | 222 | return boost::filter_iterator(by_attrs(attrs), b, e); 223 | } 224 | 225 | 226 | /// Filter end iterator 227 | template 228 | boost::filter_iterator filter_end(It e = It()) { 229 | if (e == It()) {e = objects.end();} 230 | 231 | return boost::filter_iterator(ObjectsPred(), e, e); 232 | } 233 | 234 | /// Iterate over transformed(through trans-function) collection 235 | template 236 | boost::transform_iterator trans_iterator(Trans trans, It b) const { 237 | return boost::transform_iterator(b, trans); 238 | } 239 | 240 | /// Transformed end-iterator 241 | template 242 | boost::transform_iterator trans_end(Trans trans, It e) const { 243 | return boost::transform_iterator(e, trans); 244 | } 245 | 246 | boost::property_tree::ptree config; 247 | Objects objects; 248 | 249 | std::shared_ptr storage; 250 | std::string pin; 251 | }; 252 | 253 | int read_password(char *buf, int size, int rwflag, void *userdata) { 254 | std::string p; 255 | std::cin >> p; 256 | std::copy_n(p.begin(), std::min(size, static_cast(p.size())), buf); 257 | return p.size(); 258 | } 259 | 260 | 261 | template 262 | bool is_equal(CK_ATTRIBUTE_TYPE type, const A& a1, const A& a2) { 263 | auto it1 = a1.second.find(type); 264 | if (it1 != a1.second.end()) { 265 | auto it2 = a2.second.find(type); 266 | if (it2 != a2.second.end()) { 267 | return it1->second == it2->second; 268 | } 269 | } 270 | return false; 271 | } 272 | 273 | soft_token_t::soft_token_t(const std::string& rcfile) 274 | : p_(new Pimpl()) 275 | { 276 | 277 | try { 278 | boost::property_tree::ini_parser::read_ini(rcfile, p_->config); 279 | } 280 | catch (const std::exception& e) { 281 | LOG("Error reading config file %s: %s\n", rcfile.c_str(), e.what()); 282 | exit(-1); 283 | } 284 | 285 | LOG("Config file: %s\n", rcfile.c_str()); 286 | } 287 | 288 | bool soft_token_t::ssh_agent() const 289 | { 290 | return p_->config.get("ssh-agent", false); 291 | } 292 | 293 | soft_token_t::~soft_token_t() 294 | { 295 | p_.reset(); 296 | } 297 | 298 | bool soft_token_t::ready() const 299 | { 300 | try { 301 | if (!p_->storage) { 302 | p_->storage = storage_t::create(p_->config); 303 | } 304 | 305 | return p_->storage->present(); 306 | } 307 | catch(...) { 308 | return false; 309 | } 310 | } 311 | 312 | bool soft_token_t::logged() const 313 | { 314 | return p_->storage.get() && !p_->pin.empty(); 315 | } 316 | 317 | bool soft_token_t::login(const std::string& pin) 318 | { 319 | try { 320 | LOG(" log 1\n"); 321 | p_->pin = pin; 322 | LOG(" log 2\n"); 323 | check_storage(); 324 | LOG(" log 3\n"); 325 | reset(); 326 | LOG(" log 4\n"); 327 | } 328 | catch(const std::exception& e) { 329 | LOG("Exception: %s\n", e.what()); 330 | return false; 331 | } 332 | 333 | return true; 334 | } 335 | 336 | void soft_token_t::logout() 337 | { 338 | p_->pin.clear(); 339 | p_->objects.clear(); 340 | p_->storage.reset(); 341 | } 342 | 343 | std::string soft_token_t::full_name() const 344 | { 345 | return (p_->storage) ? p_->storage->full_name() : "no storage"; 346 | } 347 | 348 | Handles soft_token_t::handles() const 349 | { 350 | return Handles( 351 | p_->trans_iterator(boost::bind(&Objects::value_type::first,_1), p_->objects.begin()), 352 | p_->trans_end(boost::bind(&Objects::value_type::first,_1), p_->objects.end()) 353 | ); 354 | } 355 | 356 | ObjectsIterator soft_token_t::begin() 357 | { 358 | try { 359 | check_storage(); 360 | } 361 | catch(...) { 362 | 363 | } 364 | // const auto objects = p_->objects | transformed(boost::bind(&Objects::value_type::first,_1)); 365 | // 366 | // auto it = boost::begin(objects); 367 | // auto end = boost::end(objects); 368 | // 369 | // return handle_iterator_t([it, end] () mutable { 370 | // if (it != end) { 371 | // return *(it++); 372 | // } 373 | // else { 374 | // return soft_token_t::handle_invalid(); 375 | // } 376 | // }); 377 | 378 | return p_->filter_iterator([](const Objects::value_type&){return true;}); 379 | } 380 | 381 | ObjectsIterator soft_token_t::begin(Attributes attrs) 382 | { 383 | try { 384 | check_storage(); 385 | } 386 | catch(...) { 387 | 388 | } 389 | 390 | // const auto objects = p_->objects | filtered(by_attrs(attrs)) | transformed(boost::bind(&Objects::value_type::first,_1)); 391 | // 392 | // auto it = boost::begin(objects); 393 | // auto end = boost::end(objects); 394 | // 395 | // return handle_iterator_t([it, end] () mutable { 396 | // if (it != end) { 397 | // return *(it++); 398 | // } 399 | // else { 400 | // return soft_token_t::handle_invalid(); 401 | // } 402 | // }); 403 | 404 | return p_->filter_iterator(attrs); 405 | } 406 | 407 | ObjectsIterator soft_token_t::end() 408 | { 409 | return p_->filter_end(); 410 | } 411 | 412 | 413 | CK_OBJECT_HANDLE soft_token_t::handle_invalid() 414 | { 415 | return static_cast(-1); 416 | } 417 | 418 | 419 | Attributes soft_token_t::attributes(CK_OBJECT_HANDLE id) const 420 | { 421 | auto it = p_->objects.find(id); 422 | 423 | if (it != p_->objects.end()) { 424 | return it->second; 425 | } 426 | 427 | return Attributes(); 428 | } 429 | 430 | bool soft_token_t::has_object(CK_OBJECT_HANDLE id) const 431 | { 432 | return p_->objects.find(id) != p_->objects.end(); 433 | } 434 | 435 | bool soft_token_t::check(CK_OBJECT_HANDLE id, const Attributes& attrs) const 436 | { 437 | auto it = p_->objects.find(id); 438 | return (it != p_->objects.end()) && by_attrs(attrs)(*it); 439 | } 440 | 441 | std::string soft_token_t::read(CK_OBJECT_HANDLE id) 442 | { 443 | auto it = p_->objects.find(id); 444 | 445 | if (it != p_->objects.end()) { 446 | if (it->second[AttrSshUnpacked].to_bool()) { 447 | return it->second[CKA_VALUE].to_string(); 448 | } 449 | 450 | check_storage(); 451 | const item_t item = p_->storage->read(it->second[AttrFilename].to_string()); 452 | return std::string(item.data.begin(), item.data.end()); 453 | } 454 | 455 | return std::string(); 456 | } 457 | 458 | CK_OBJECT_HANDLE soft_token_t::write(const std::string& filename, const std::vector& data, const Attributes& attrs) 459 | { 460 | auto it = std::find_if(p_->objects.begin(), p_->objects.end(), 461 | by_attrs({create_object(AttrFilename, filename)})); 462 | 463 | if (it != p_->objects.end()) { 464 | return soft_token_t::handle_invalid(); 465 | } 466 | 467 | const item_t item({ 468 | filename, 469 | Bytes(data.begin(), data.end()), 470 | attrs 471 | }); 472 | 473 | check_storage(); 474 | const item_t item2 = p_->storage->write(item); 475 | const auto a = p_->objects.insert(to_attributes(p_->objects)(item2)).first; 476 | return a->first; 477 | } 478 | 479 | std::vector soft_token_t::sign(CK_OBJECT_HANDLE id, CK_MECHANISM_TYPE type, CK_BYTE_PTR pData, CK_ULONG ulDataLen) 480 | { 481 | if (p_->objects.find(id) == p_->objects.end()) { 482 | throw pkcs11_exception_t(CKR_KEY_HANDLE_INVALID, "Object handle invalid"); 483 | } 484 | 485 | const auto str = read(id); 486 | std::vector data(str.begin(), str.end()); 487 | 488 | std::shared_ptr file( 489 | ::fmemopen(data.data(), data.size(), "r"), 490 | ::fclose 491 | ); 492 | 493 | pem_password_cb cc; 494 | 495 | 496 | if (EVP_PKEY *pkey = PEM_read_PrivateKey(file.get(), NULL, ask_password_cb, NULL)) { 497 | if (pkey->pkey.rsa == NULL) { 498 | throw pkcs11_exception_t(CKR_FUNCTION_FAILED, "Can't read private key"); 499 | } 500 | std::vector buffer(RSA_size(pkey->pkey.rsa)); 501 | int padding, padding_len; 502 | 503 | switch(type) { 504 | case CKM_RSA_PKCS: 505 | padding = RSA_PKCS1_PADDING; 506 | padding_len = RSA_PKCS1_PADDING_SIZE; 507 | break; 508 | case CKM_RSA_X_509: 509 | padding = RSA_NO_PADDING; 510 | padding_len = 0; 511 | break; 512 | default: 513 | throw pkcs11_exception_t(CKR_MECHANISM_INVALID, "Mechanism not supported"); 514 | } 515 | 516 | 517 | if (pData == NULL_PTR) { 518 | throw pkcs11_exception_t(CKR_ARGUMENTS_BAD, "Data is empty"); 519 | } 520 | 521 | auto len = RSA_private_encrypt(ulDataLen, pData, buffer.data(), pkey->pkey.rsa, padding); 522 | 523 | LOG("private encrypt done\n"); 524 | if (len <= 0) { 525 | throw pkcs11_exception_t(CKR_FUNCTION_FAILED, "error in RSA_private_encrypt"); 526 | } 527 | if (len > buffer.size()) { 528 | throw pkcs11_exception_t(CKR_FUNCTION_FAILED, "internal buffer too small"); 529 | } 530 | 531 | return buffer; 532 | } 533 | 534 | return std::vector(); 535 | } 536 | 537 | std::unique_ptr parse_bignum(CK_ATTRIBUTE_TYPE key, const Attributes& attrs) { 538 | if (attrs.find(key) != attrs.end()) { 539 | return std::unique_ptr( 540 | BN_bin2bn(attrs.at(key).value(), attrs.at(key)->ulValueLen, NULL), 541 | BN_free 542 | ); 543 | } else { 544 | return std::unique_ptr(NULL, BN_free); 545 | } 546 | } 547 | 548 | 549 | std::vector soft_token_t::create_key(CK_OBJECT_CLASS klass, const Attributes& attrs) const 550 | { 551 | std::unique_ptr pubkey(RSA_new(), RSA_free); 552 | 553 | std::unique_ptr modul = parse_bignum(CKA_MODULUS, attrs); 554 | std::unique_ptr expon = parse_bignum(CKA_PUBLIC_EXPONENT, attrs); 555 | 556 | std::unique_ptr priv_expon = parse_bignum(CKA_PRIVATE_EXPONENT, attrs); 557 | std::unique_ptr priv_p1 = parse_bignum(CKA_PRIME_1, attrs); 558 | std::unique_ptr priv_p2 = parse_bignum(CKA_PRIME_2, attrs); 559 | std::unique_ptr priv_e1 = parse_bignum(CKA_EXPONENT_1, attrs); 560 | std::unique_ptr priv_e2 = parse_bignum(CKA_EXPONENT_2, attrs); 561 | std::unique_ptr priv_c = parse_bignum(CKA_COEFFICIENT, attrs); 562 | 563 | pubkey->e = expon.release(); 564 | pubkey->n = modul.release(); 565 | 566 | pubkey->d = priv_expon.release(); 567 | pubkey->p = priv_p1.release(); 568 | pubkey->q = priv_p2.release(); 569 | pubkey->dmp1 = priv_e1.release(); 570 | pubkey->dmq1 = priv_e2.release(); 571 | pubkey->iqmp = priv_c.release(); 572 | 573 | std::shared_ptr pRsaKey( 574 | EVP_PKEY_new(), 575 | EVP_PKEY_free 576 | ); 577 | 578 | if (1 != EVP_PKEY_assign_RSA(pRsaKey.get(), pubkey.release())) { 579 | throw std::runtime_error("Can't assign rsa key"); 580 | } 581 | 582 | char *dst_buf; 583 | size_t size; 584 | 585 | try { 586 | auto file = write_mem(&dst_buf, &size); 587 | 588 | if (klass == CKO_PUBLIC_KEY) { 589 | if (PEM_write_PUBKEY(file.get(), pRsaKey.get()) != 1) { 590 | LOG("PEM_write_PUBKEY error\n"); 591 | throw std::runtime_error("Can't create rsa key from modulus"); 592 | } 593 | LOG("PEM_write_PUBKEY OK\n"); 594 | } else if (klass == CKO_PRIVATE_KEY) { 595 | if (PEM_write_PrivateKey(file.get(), pRsaKey.get(), NULL, 0, 0, NULL, NULL) != 1) { 596 | LOG("PEM_write_PrivateKey error\n"); 597 | throw std::runtime_error("Can't create rsa key from modulus"); 598 | } 599 | LOG("PEM_write_PrivateKey OK\n"); 600 | } 601 | } catch(...) { 602 | } 603 | 604 | std::vector ret(dst_buf, dst_buf + size); 605 | free(dst_buf); 606 | return ret; 607 | } 608 | 609 | 610 | void soft_token_t::check_storage() 611 | { 612 | if (p_->storage && p_->storage->present()) { 613 | p_->storage->set_pin(p_->pin); 614 | LOG("storage is ok\n"); 615 | return; 616 | } 617 | 618 | if (p_->storage && !p_->storage->present()) { 619 | p_->objects.clear(); 620 | p_->storage.reset(); 621 | throw pkcs11_exception_t(CKR_DEVICE_REMOVED, "token removed"); 622 | } 623 | 624 | if (!p_->storage) { 625 | 626 | // if (p_->pin.empty()) { 627 | // throw pkcs11_exception_t(CKR_USER_NOT_LOGGED_IN, "no pin provided"); 628 | // } 629 | 630 | LOG("creating storage...\n"); 631 | p_->storage = storage_t::create(p_->config, p_->pin); 632 | reset(); 633 | } 634 | } 635 | 636 | void soft_token_t::reset() 637 | { 638 | p_->objects.clear(); 639 | 640 | LOG(" * RESET cheking...\n"); 641 | check_storage(); 642 | 643 | LOG(" cheking...\n"); 644 | to_attributes convert(p_->objects); 645 | for(auto item: p_->storage->items()) { 646 | LOG(" Finded object: %s\n", item.filename.c_str()); 647 | const auto a = p_->objects.insert(convert(item)).first; 648 | LOG(" object: %lu\n", a->first); 649 | } 650 | 651 | const CK_OBJECT_CLASS public_key_c = CKO_PUBLIC_KEY; 652 | const CK_OBJECT_CLASS private_key_c = CKO_PRIVATE_KEY; 653 | 654 | 655 | for(auto& private_key: p_->objects | filtered(by_attrs({create_object(CKA_CLASS, private_key_c)}))) { 656 | auto public_range = p_->objects 657 | | filtered(by_attrs({create_object(CKA_CLASS, public_key_c)})) 658 | // | filtered(by_attrs({create_object(AttrSshPublic, bool_true)})) 659 | | filtered([&private_key] (const Objects::value_type& pub_key) { 660 | return is_equal(CKA_MODULUS, pub_key, private_key) 661 | || pub_key.second.at(CKA_LABEL).to_string() == (private_key.second.at(CKA_LABEL).to_string() + ".pub"); 662 | }); 663 | 664 | for (auto& public_key : public_range) { 665 | public_key.second[CKA_ID] = private_key.second[CKA_ID]; 666 | public_key.second[CKA_OBJECT_ID] = private_key.second[CKA_OBJECT_ID]; 667 | } 668 | } 669 | 670 | LOG("2\n"); 671 | 672 | for(auto it = p_->objects.begin(); it != p_->objects.end(); ++it ) { 673 | //LOG(" *** Final obejct: %s %s - %lu\n", it->second.at(CKA_LABEL).to_string().c_str(), std::to_string(it->first).c_str(), it->second.at(CKA_ID).to_id()); 674 | print_attributes(it->second); 675 | } 676 | } 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | -------------------------------------------------------------------------------- /example/Makefile.in: -------------------------------------------------------------------------------- 1 | # Makefile.in generated by automake 1.9.6 from Makefile.am. 2 | # @configure_input@ 3 | 4 | # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 5 | # 2003, 2004, 2005 Free Software Foundation, Inc. 6 | # This Makefile.in is free software; the Free Software Foundation 7 | # gives unlimited permission to copy and/or distribute it, 8 | # with or without modifications, as long as this notice is preserved. 9 | 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY, to the extent permitted by law; without 12 | # even the implied warranty of MERCHANTABILITY or FITNESS FOR A 13 | # PARTICULAR PURPOSE. 14 | 15 | @SET_MAKE@ 16 | 17 | # $Id: Makefile.am,v 1.4 2006/01/11 11:50:24 lha Exp $ 18 | 19 | srcdir = @srcdir@ 20 | top_srcdir = @top_srcdir@ 21 | VPATH = @srcdir@ 22 | pkgdatadir = $(datadir)/@PACKAGE@ 23 | pkglibdir = $(libdir)/@PACKAGE@ 24 | pkgincludedir = $(includedir)/@PACKAGE@ 25 | top_builddir = . 26 | am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd 27 | INSTALL = @INSTALL@ 28 | install_sh_DATA = $(install_sh) -c -m 644 29 | install_sh_PROGRAM = $(install_sh) -c 30 | install_sh_SCRIPT = $(install_sh) -c 31 | INSTALL_HEADER = $(INSTALL_DATA) 32 | transform = $(program_transform_name) 33 | NORMAL_INSTALL = : 34 | PRE_INSTALL = : 35 | POST_INSTALL = : 36 | NORMAL_UNINSTALL = : 37 | PRE_UNINSTALL = : 38 | POST_UNINSTALL = : 39 | build_triplet = @build@ 40 | host_triplet = @host@ 41 | check_PROGRAMS = run_tests$(EXEEXT) test_soft_pkcs11$(EXEEXT) 42 | DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ 43 | $(srcdir)/Makefile.in $(srcdir)/config.h.in \ 44 | $(top_srcdir)/configure ChangeLog config.guess config.sub \ 45 | install-sh ltmain.sh missing 46 | subdir = . 47 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 48 | am__aclocal_m4_deps = $(top_srcdir)/configure.ac 49 | am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ 50 | $(ACLOCAL_M4) 51 | am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ 52 | configure.lineno configure.status.lineno 53 | mkinstalldirs = $(install_sh) -d 54 | CONFIG_HEADER = config.h 55 | CONFIG_CLEAN_FILES = 56 | am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; 57 | am__vpath_adj = case $$p in \ 58 | $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ 59 | *) f=$$p;; \ 60 | esac; 61 | am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; 62 | am__installdirs = "$(DESTDIR)$(libdir)" 63 | libLTLIBRARIES_INSTALL = $(INSTALL) 64 | LTLIBRARIES = $(lib_LTLIBRARIES) 65 | soft_pkcs11_la_DEPENDENCIES = 66 | am_soft_pkcs11_la_OBJECTS = main.lo 67 | soft_pkcs11_la_OBJECTS = $(am_soft_pkcs11_la_OBJECTS) 68 | run_tests_SOURCES = run_tests.c 69 | run_tests_OBJECTS = run_tests.$(OBJEXT) 70 | run_tests_LDADD = $(LDADD) 71 | am_test_soft_pkcs11_OBJECTS = test_soft_pkcs11.$(OBJEXT) \ 72 | test_main.$(OBJEXT) 73 | test_soft_pkcs11_OBJECTS = $(am_test_soft_pkcs11_OBJECTS) 74 | test_soft_pkcs11_DEPENDENCIES = 75 | DEFAULT_INCLUDES = -I. -I$(srcdir) -I. 76 | depcomp = 77 | am__depfiles_maybe = 78 | COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ 79 | $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) 80 | LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \ 81 | $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ 82 | $(AM_CFLAGS) $(CFLAGS) 83 | CCLD = $(CC) 84 | LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ 85 | $(AM_LDFLAGS) $(LDFLAGS) -o $@ 86 | SOURCES = $(soft_pkcs11_la_SOURCES) run_tests.c \ 87 | $(test_soft_pkcs11_SOURCES) 88 | DIST_SOURCES = $(soft_pkcs11_la_SOURCES) run_tests.c \ 89 | $(test_soft_pkcs11_SOURCES) 90 | ETAGS = etags 91 | CTAGS = ctags 92 | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 93 | distdir = $(PACKAGE)-$(VERSION) 94 | top_distdir = $(distdir) 95 | am__remove_distdir = \ 96 | { test ! -d $(distdir) \ 97 | || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ 98 | && rm -fr $(distdir); }; } 99 | DIST_ARCHIVES = $(distdir).tar.gz 100 | GZIP_ENV = --best 101 | distuninstallcheck_listfiles = find . -type f -print 102 | distcleancheck_listfiles = find . -type f -print 103 | ACLOCAL = @ACLOCAL@ 104 | AMTAR = @AMTAR@ 105 | AR = @AR@ 106 | AUTOCONF = @AUTOCONF@ 107 | AUTOHEADER = @AUTOHEADER@ 108 | AUTOMAKE = @AUTOMAKE@ 109 | AWK = @AWK@ 110 | CC = @CC@ 111 | CFLAGS = @CFLAGS@ 112 | CPP = @CPP@ 113 | CPPFLAGS = @CPPFLAGS@ 114 | CXX = @CXX@ 115 | CXXCPP = @CXXCPP@ 116 | CXXFLAGS = @CXXFLAGS@ 117 | CYGPATH_W = @CYGPATH_W@ 118 | DEFS = @DEFS@ 119 | ECHO = @ECHO@ 120 | ECHO_C = @ECHO_C@ 121 | ECHO_N = @ECHO_N@ 122 | ECHO_T = @ECHO_T@ 123 | EGREP = @EGREP@ 124 | EXEEXT = @EXEEXT@ 125 | F77 = @F77@ 126 | FFLAGS = @FFLAGS@ 127 | INSTALL_DATA = @INSTALL_DATA@ 128 | INSTALL_PROGRAM = @INSTALL_PROGRAM@ 129 | INSTALL_SCRIPT = @INSTALL_SCRIPT@ 130 | INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ 131 | LDFLAGS = @LDFLAGS@ 132 | LIBOBJS = @LIBOBJS@ 133 | LIBS = @LIBS@ 134 | LIBTOOL = @LIBTOOL@ 135 | LN_S = @LN_S@ 136 | LTLIBOBJS = @LTLIBOBJS@ 137 | MAINT = @MAINT@ 138 | MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ 139 | MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ 140 | MAKEINFO = @MAKEINFO@ 141 | OBJEXT = @OBJEXT@ 142 | PACKAGE = @PACKAGE@ 143 | PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ 144 | PACKAGE_NAME = @PACKAGE_NAME@ 145 | PACKAGE_STRING = @PACKAGE_STRING@ 146 | PACKAGE_TARNAME = @PACKAGE_TARNAME@ 147 | PACKAGE_VERSION = @PACKAGE_VERSION@ 148 | PATH_SEPARATOR = @PATH_SEPARATOR@ 149 | RANLIB = @RANLIB@ 150 | SET_MAKE = @SET_MAKE@ 151 | SHELL = @SHELL@ 152 | STRIP = @STRIP@ 153 | VERSION = @VERSION@ 154 | ac_ct_AR = @ac_ct_AR@ 155 | ac_ct_CC = @ac_ct_CC@ 156 | ac_ct_CXX = @ac_ct_CXX@ 157 | ac_ct_F77 = @ac_ct_F77@ 158 | ac_ct_RANLIB = @ac_ct_RANLIB@ 159 | ac_ct_STRIP = @ac_ct_STRIP@ 160 | am__leading_dot = @am__leading_dot@ 161 | am__tar = @am__tar@ 162 | am__untar = @am__untar@ 163 | bindir = @bindir@ 164 | build = @build@ 165 | build_alias = @build_alias@ 166 | build_cpu = @build_cpu@ 167 | build_os = @build_os@ 168 | build_vendor = @build_vendor@ 169 | datadir = @datadir@ 170 | exec_prefix = @exec_prefix@ 171 | host = @host@ 172 | host_alias = @host_alias@ 173 | host_cpu = @host_cpu@ 174 | host_os = @host_os@ 175 | host_vendor = @host_vendor@ 176 | includedir = @includedir@ 177 | infodir = @infodir@ 178 | install_sh = @install_sh@ 179 | libdir = @libdir@ 180 | libexecdir = @libexecdir@ 181 | localstatedir = @localstatedir@ 182 | mandir = @mandir@ 183 | mkdir_p = @mkdir_p@ 184 | oldincludedir = @oldincludedir@ 185 | prefix = @prefix@ 186 | program_transform_name = @program_transform_name@ 187 | sbindir = @sbindir@ 188 | sharedstatedir = @sharedstatedir@ 189 | sysconfdir = @sysconfdir@ 190 | target_alias = @target_alias@ 191 | lib_LTLIBRARIES = soft-pkcs11.la 192 | INCLUDES = -I$(srcdir)/ref 193 | soft_pkcs11_la_SOURCES = \ 194 | main.c 195 | 196 | soft_pkcs11_la_LDFLAGS = -module 197 | soft_pkcs11_la_LIBADD = -lcrypto 198 | TESTS = run_tests 199 | test_soft_pkcs11_SOURCES = test_soft_pkcs11.c test_main.c 200 | test_soft_pkcs11_LDADD = -lcrypto 201 | do_subst = sed -e 's,[@]srcdir[@],$(srcdir),g' 202 | CLEANFILES = test-rc-file.rc test_main.c 203 | all: config.h 204 | $(MAKE) $(AM_MAKEFLAGS) all-am 205 | 206 | .SUFFIXES: 207 | .SUFFIXES: .c .lo .o .obj 208 | am--refresh: 209 | @: 210 | $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) 211 | @for dep in $?; do \ 212 | case '$(am__configure_deps)' in \ 213 | *$$dep*) \ 214 | echo ' cd $(srcdir) && $(AUTOMAKE) --foreign --ignore-deps'; \ 215 | cd $(srcdir) && $(AUTOMAKE) --foreign --ignore-deps \ 216 | && exit 0; \ 217 | exit 1;; \ 218 | esac; \ 219 | done; \ 220 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps Makefile'; \ 221 | cd $(top_srcdir) && \ 222 | $(AUTOMAKE) --foreign --ignore-deps Makefile 223 | .PRECIOUS: Makefile 224 | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status 225 | @case '$?' in \ 226 | *config.status*) \ 227 | echo ' $(SHELL) ./config.status'; \ 228 | $(SHELL) ./config.status;; \ 229 | *) \ 230 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ 231 | cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ 232 | esac; 233 | 234 | $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) 235 | $(SHELL) ./config.status --recheck 236 | 237 | $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) 238 | cd $(srcdir) && $(AUTOCONF) 239 | $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) 240 | cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) 241 | 242 | config.h: stamp-h1 243 | @if test ! -f $@; then \ 244 | rm -f stamp-h1; \ 245 | $(MAKE) stamp-h1; \ 246 | else :; fi 247 | 248 | stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status 249 | @rm -f stamp-h1 250 | cd $(top_builddir) && $(SHELL) ./config.status config.h 251 | $(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) 252 | cd $(top_srcdir) && $(AUTOHEADER) 253 | rm -f stamp-h1 254 | touch $@ 255 | 256 | distclean-hdr: 257 | -rm -f config.h stamp-h1 258 | install-libLTLIBRARIES: $(lib_LTLIBRARIES) 259 | @$(NORMAL_INSTALL) 260 | test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)" 261 | @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ 262 | if test -f $$p; then \ 263 | f=$(am__strip_dir) \ 264 | echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \ 265 | $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \ 266 | else :; fi; \ 267 | done 268 | 269 | uninstall-libLTLIBRARIES: 270 | @$(NORMAL_UNINSTALL) 271 | @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \ 272 | p=$(am__strip_dir) \ 273 | echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \ 274 | $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \ 275 | done 276 | 277 | clean-libLTLIBRARIES: 278 | -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) 279 | @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ 280 | dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ 281 | test "$$dir" != "$$p" || dir=.; \ 282 | echo "rm -f \"$${dir}/so_locations\""; \ 283 | rm -f "$${dir}/so_locations"; \ 284 | done 285 | soft-pkcs11.la: $(soft_pkcs11_la_OBJECTS) $(soft_pkcs11_la_DEPENDENCIES) 286 | $(LINK) -rpath $(libdir) $(soft_pkcs11_la_LDFLAGS) $(soft_pkcs11_la_OBJECTS) $(soft_pkcs11_la_LIBADD) $(LIBS) 287 | 288 | clean-checkPROGRAMS: 289 | @list='$(check_PROGRAMS)'; for p in $$list; do \ 290 | f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ 291 | echo " rm -f $$p $$f"; \ 292 | rm -f $$p $$f ; \ 293 | done 294 | test_soft_pkcs11$(EXEEXT): $(test_soft_pkcs11_OBJECTS) $(test_soft_pkcs11_DEPENDENCIES) 295 | @rm -f test_soft_pkcs11$(EXEEXT) 296 | $(LINK) $(test_soft_pkcs11_LDFLAGS) $(test_soft_pkcs11_OBJECTS) $(test_soft_pkcs11_LDADD) $(LIBS) 297 | 298 | mostlyclean-compile: 299 | -rm -f *.$(OBJEXT) 300 | 301 | distclean-compile: 302 | -rm -f *.tab.c 303 | 304 | .c.o: 305 | $(COMPILE) -c $< 306 | 307 | .c.obj: 308 | $(COMPILE) -c `$(CYGPATH_W) '$<'` 309 | 310 | .c.lo: 311 | $(LTCOMPILE) -c -o $@ $< 312 | 313 | mostlyclean-libtool: 314 | -rm -f *.lo 315 | 316 | clean-libtool: 317 | -rm -rf .libs _libs 318 | 319 | distclean-libtool: 320 | -rm -f libtool 321 | uninstall-info-am: 322 | 323 | ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) 324 | list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ 325 | unique=`for i in $$list; do \ 326 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ 327 | done | \ 328 | $(AWK) ' { files[$$0] = 1; } \ 329 | END { for (i in files) print i; }'`; \ 330 | mkid -fID $$unique 331 | tags: TAGS 332 | 333 | TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ 334 | $(TAGS_FILES) $(LISP) 335 | tags=; \ 336 | here=`pwd`; \ 337 | list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ 338 | unique=`for i in $$list; do \ 339 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ 340 | done | \ 341 | $(AWK) ' { files[$$0] = 1; } \ 342 | END { for (i in files) print i; }'`; \ 343 | if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ 344 | test -n "$$unique" || unique=$$empty_fix; \ 345 | $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ 346 | $$tags $$unique; \ 347 | fi 348 | ctags: CTAGS 349 | CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ 350 | $(TAGS_FILES) $(LISP) 351 | tags=; \ 352 | here=`pwd`; \ 353 | list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ 354 | unique=`for i in $$list; do \ 355 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ 356 | done | \ 357 | $(AWK) ' { files[$$0] = 1; } \ 358 | END { for (i in files) print i; }'`; \ 359 | test -z "$(CTAGS_ARGS)$$tags$$unique" \ 360 | || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ 361 | $$tags $$unique 362 | 363 | GTAGS: 364 | here=`$(am__cd) $(top_builddir) && pwd` \ 365 | && cd $(top_srcdir) \ 366 | && gtags -i $(GTAGS_ARGS) $$here 367 | 368 | distclean-tags: 369 | -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags 370 | 371 | check-TESTS: $(TESTS) 372 | @failed=0; all=0; xfail=0; xpass=0; skip=0; \ 373 | srcdir=$(srcdir); export srcdir; \ 374 | list='$(TESTS)'; \ 375 | if test -n "$$list"; then \ 376 | for tst in $$list; do \ 377 | if test -f ./$$tst; then dir=./; \ 378 | elif test -f $$tst; then dir=; \ 379 | else dir="$(srcdir)/"; fi; \ 380 | if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ 381 | all=`expr $$all + 1`; \ 382 | case " $(XFAIL_TESTS) " in \ 383 | *" $$tst "*) \ 384 | xpass=`expr $$xpass + 1`; \ 385 | failed=`expr $$failed + 1`; \ 386 | echo "XPASS: $$tst"; \ 387 | ;; \ 388 | *) \ 389 | echo "PASS: $$tst"; \ 390 | ;; \ 391 | esac; \ 392 | elif test $$? -ne 77; then \ 393 | all=`expr $$all + 1`; \ 394 | case " $(XFAIL_TESTS) " in \ 395 | *" $$tst "*) \ 396 | xfail=`expr $$xfail + 1`; \ 397 | echo "XFAIL: $$tst"; \ 398 | ;; \ 399 | *) \ 400 | failed=`expr $$failed + 1`; \ 401 | echo "FAIL: $$tst"; \ 402 | ;; \ 403 | esac; \ 404 | else \ 405 | skip=`expr $$skip + 1`; \ 406 | echo "SKIP: $$tst"; \ 407 | fi; \ 408 | done; \ 409 | if test "$$failed" -eq 0; then \ 410 | if test "$$xfail" -eq 0; then \ 411 | banner="All $$all tests passed"; \ 412 | else \ 413 | banner="All $$all tests behaved as expected ($$xfail expected failures)"; \ 414 | fi; \ 415 | else \ 416 | if test "$$xpass" -eq 0; then \ 417 | banner="$$failed of $$all tests failed"; \ 418 | else \ 419 | banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \ 420 | fi; \ 421 | fi; \ 422 | dashes="$$banner"; \ 423 | skipped=""; \ 424 | if test "$$skip" -ne 0; then \ 425 | skipped="($$skip tests were not run)"; \ 426 | test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ 427 | dashes="$$skipped"; \ 428 | fi; \ 429 | report=""; \ 430 | if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ 431 | report="Please report to $(PACKAGE_BUGREPORT)"; \ 432 | test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ 433 | dashes="$$report"; \ 434 | fi; \ 435 | dashes=`echo "$$dashes" | sed s/./=/g`; \ 436 | echo "$$dashes"; \ 437 | echo "$$banner"; \ 438 | test -z "$$skipped" || echo "$$skipped"; \ 439 | test -z "$$report" || echo "$$report"; \ 440 | echo "$$dashes"; \ 441 | test "$$failed" -eq 0; \ 442 | else :; fi 443 | 444 | distdir: $(DISTFILES) 445 | $(am__remove_distdir) 446 | mkdir $(distdir) 447 | @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ 448 | topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ 449 | list='$(DISTFILES)'; for file in $$list; do \ 450 | case $$file in \ 451 | $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ 452 | $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ 453 | esac; \ 454 | if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ 455 | dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ 456 | if test "$$dir" != "$$file" && test "$$dir" != "."; then \ 457 | dir="/$$dir"; \ 458 | $(mkdir_p) "$(distdir)$$dir"; \ 459 | else \ 460 | dir=''; \ 461 | fi; \ 462 | if test -d $$d/$$file; then \ 463 | if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ 464 | cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ 465 | fi; \ 466 | cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ 467 | else \ 468 | test -f $(distdir)/$$file \ 469 | || cp -p $$d/$$file $(distdir)/$$file \ 470 | || exit 1; \ 471 | fi; \ 472 | done 473 | -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ 474 | ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ 475 | ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ 476 | ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ 477 | || chmod -R a+r $(distdir) 478 | dist-gzip: distdir 479 | tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz 480 | $(am__remove_distdir) 481 | 482 | dist-bzip2: distdir 483 | tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 484 | $(am__remove_distdir) 485 | 486 | dist-tarZ: distdir 487 | tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z 488 | $(am__remove_distdir) 489 | 490 | dist-shar: distdir 491 | shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz 492 | $(am__remove_distdir) 493 | 494 | dist-zip: distdir 495 | -rm -f $(distdir).zip 496 | zip -rq $(distdir).zip $(distdir) 497 | $(am__remove_distdir) 498 | 499 | dist dist-all: distdir 500 | tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz 501 | $(am__remove_distdir) 502 | 503 | # This target untars the dist file and tries a VPATH configuration. Then 504 | # it guarantees that the distribution is self-contained by making another 505 | # tarfile. 506 | distcheck: dist 507 | case '$(DIST_ARCHIVES)' in \ 508 | *.tar.gz*) \ 509 | GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ 510 | *.tar.bz2*) \ 511 | bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ 512 | *.tar.Z*) \ 513 | uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ 514 | *.shar.gz*) \ 515 | GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ 516 | *.zip*) \ 517 | unzip $(distdir).zip ;;\ 518 | esac 519 | chmod -R a-w $(distdir); chmod a+w $(distdir) 520 | mkdir $(distdir)/_build 521 | mkdir $(distdir)/_inst 522 | chmod a-w $(distdir) 523 | dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ 524 | && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ 525 | && cd $(distdir)/_build \ 526 | && ../configure --srcdir=.. --prefix="$$dc_install_base" \ 527 | $(DISTCHECK_CONFIGURE_FLAGS) \ 528 | && $(MAKE) $(AM_MAKEFLAGS) \ 529 | && $(MAKE) $(AM_MAKEFLAGS) dvi \ 530 | && $(MAKE) $(AM_MAKEFLAGS) check \ 531 | && $(MAKE) $(AM_MAKEFLAGS) install \ 532 | && $(MAKE) $(AM_MAKEFLAGS) installcheck \ 533 | && $(MAKE) $(AM_MAKEFLAGS) uninstall \ 534 | && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ 535 | distuninstallcheck \ 536 | && chmod -R a-w "$$dc_install_base" \ 537 | && ({ \ 538 | (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ 539 | && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ 540 | && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ 541 | && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ 542 | distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ 543 | } || { rm -rf "$$dc_destdir"; exit 1; }) \ 544 | && rm -rf "$$dc_destdir" \ 545 | && $(MAKE) $(AM_MAKEFLAGS) dist \ 546 | && rm -rf $(DIST_ARCHIVES) \ 547 | && $(MAKE) $(AM_MAKEFLAGS) distcleancheck 548 | $(am__remove_distdir) 549 | @(echo "$(distdir) archives ready for distribution: "; \ 550 | list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ 551 | sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}' 552 | distuninstallcheck: 553 | @cd $(distuninstallcheck_dir) \ 554 | && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ 555 | || { echo "ERROR: files left after uninstall:" ; \ 556 | if test -n "$(DESTDIR)"; then \ 557 | echo " (check DESTDIR support)"; \ 558 | fi ; \ 559 | $(distuninstallcheck_listfiles) ; \ 560 | exit 1; } >&2 561 | distcleancheck: distclean 562 | @if test '$(srcdir)' = . ; then \ 563 | echo "ERROR: distcleancheck can only run from a VPATH build" ; \ 564 | exit 1 ; \ 565 | fi 566 | @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ 567 | || { echo "ERROR: files left in build directory after distclean:" ; \ 568 | $(distcleancheck_listfiles) ; \ 569 | exit 1; } >&2 570 | check-am: all-am 571 | $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) 572 | $(MAKE) $(AM_MAKEFLAGS) check-TESTS 573 | check: check-am 574 | all-am: Makefile $(LTLIBRARIES) config.h 575 | installdirs: 576 | for dir in "$(DESTDIR)$(libdir)"; do \ 577 | test -z "$$dir" || $(mkdir_p) "$$dir"; \ 578 | done 579 | install: install-am 580 | install-exec: install-exec-am 581 | install-data: install-data-am 582 | uninstall: uninstall-am 583 | 584 | install-am: all-am 585 | @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am 586 | 587 | installcheck: installcheck-am 588 | install-strip: 589 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ 590 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ 591 | `test -z '$(STRIP)' || \ 592 | echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install 593 | mostlyclean-generic: 594 | 595 | clean-generic: 596 | -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) 597 | 598 | distclean-generic: 599 | -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) 600 | 601 | maintainer-clean-generic: 602 | @echo "This command is intended for maintainers to use" 603 | @echo "it deletes files that may require special tools to rebuild." 604 | clean: clean-am 605 | 606 | clean-am: clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ 607 | clean-libtool mostlyclean-am 608 | 609 | distclean: distclean-am 610 | -rm -f $(am__CONFIG_DISTCLEAN_FILES) 611 | -rm -f Makefile 612 | distclean-am: clean-am distclean-compile distclean-generic \ 613 | distclean-hdr distclean-libtool distclean-tags 614 | 615 | dvi: dvi-am 616 | 617 | dvi-am: 618 | 619 | html: html-am 620 | 621 | info: info-am 622 | 623 | info-am: 624 | 625 | install-data-am: 626 | 627 | install-exec-am: install-libLTLIBRARIES 628 | 629 | install-info: install-info-am 630 | 631 | install-man: 632 | 633 | installcheck-am: 634 | 635 | maintainer-clean: maintainer-clean-am 636 | -rm -f $(am__CONFIG_DISTCLEAN_FILES) 637 | -rm -rf $(top_srcdir)/autom4te.cache 638 | -rm -f Makefile 639 | maintainer-clean-am: distclean-am maintainer-clean-generic 640 | 641 | mostlyclean: mostlyclean-am 642 | 643 | mostlyclean-am: mostlyclean-compile mostlyclean-generic \ 644 | mostlyclean-libtool 645 | 646 | pdf: pdf-am 647 | 648 | pdf-am: 649 | 650 | ps: ps-am 651 | 652 | ps-am: 653 | 654 | uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES 655 | 656 | .PHONY: CTAGS GTAGS all all-am am--refresh check check-TESTS check-am \ 657 | clean clean-checkPROGRAMS clean-generic clean-libLTLIBRARIES \ 658 | clean-libtool ctags dist dist-all dist-bzip2 dist-gzip \ 659 | dist-shar dist-tarZ dist-zip distcheck distclean \ 660 | distclean-compile distclean-generic distclean-hdr \ 661 | distclean-libtool distclean-tags distcleancheck distdir \ 662 | distuninstallcheck dvi dvi-am html html-am info info-am \ 663 | install install-am install-data install-data-am install-exec \ 664 | install-exec-am install-info install-info-am \ 665 | install-libLTLIBRARIES install-man install-strip installcheck \ 666 | installcheck-am installdirs maintainer-clean \ 667 | maintainer-clean-generic mostlyclean mostlyclean-compile \ 668 | mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ 669 | tags uninstall uninstall-am uninstall-info-am \ 670 | uninstall-libLTLIBRARIES 671 | 672 | 673 | test_main.c: main.c 674 | cp $(srcdir)/main.c test_main.c 675 | 676 | run_tests: run_tests.in Makefile 677 | $(do_subst) < $(srcdir)/run_tests.in > run_tests.tmp 678 | chmod +x run_tests.tmp 679 | mv run_tests.tmp run_tests 680 | # Tell versions [3.59,3.63) of GNU make to not export all variables. 681 | # Otherwise a system limit (for SysV at least) may be exceeded. 682 | .NOEXPORT: 683 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | #include "pkcs11/pkcs11u.h" 22 | #include "pkcs11/pkcs11.h" 23 | 24 | #include "tools.h" 25 | #include "soft_token.h" 26 | #include "exceptions.h" 27 | #include "log.h" 28 | 29 | #include "function_wrap.h" 30 | 31 | #define ASSERT_PTR(ptr)\ 32 | if (ptr == NULL_PTR) throw pkcs11_exception_t(CKR_ARGUMENTS_BAD, "Pointer " #ptr " must present."); 33 | 34 | #define ASSERT_NOT_PTR(ptr)\ 35 | if (ptr != NULL_PTR) throw pkcs11_exception_t(CKR_ARGUMENTS_BAD, "Pointer " #ptr " must present."); 36 | 37 | std::auto_ptr soft_token; 38 | 39 | template 40 | struct func_t { 41 | static CK_RV not_supported() { 42 | st_logf("function %d not supported\n", ID); 43 | return CKR_FUNCTION_NOT_SUPPORTED; 44 | } 45 | }; 46 | 47 | struct exception_handler { 48 | template 49 | static CK_RV handle(Function f, Args... args) { 50 | try { 51 | return f(args...); 52 | } 53 | catch (pkcs11_exception_t& e) { 54 | LOG("PKCS Error: %s", e.what()); 55 | return e.rv; 56 | } 57 | catch (std::exception& e) { 58 | LOG("Error: %s", e.what()); 59 | return CKR_FUNCTION_FAILED; 60 | } 61 | catch (...) { 62 | LOG("Unexpected Error"); 63 | return CKR_GENERAL_ERROR; 64 | } 65 | } 66 | }; 67 | 68 | struct session_t { 69 | 70 | static std::list::iterator create() { 71 | return _sessions.insert(_sessions.end(), session_t(++_id)); 72 | }; 73 | 74 | static void destroy(CK_SESSION_HANDLE id) { 75 | auto it = find(id); 76 | if (it != _sessions.end()) { 77 | _sessions.erase(it); 78 | } 79 | } 80 | 81 | static std::list::iterator find(CK_SESSION_HANDLE id) { 82 | return std::find(_sessions.begin(), _sessions.end(), id); 83 | }; 84 | 85 | static std::list::iterator end() { 86 | return _sessions.end(); 87 | } 88 | 89 | static void clear() { 90 | return _sessions.clear(); 91 | } 92 | 93 | static std::list::size_type count() {return _sessions.size();} 94 | 95 | operator CK_SESSION_HANDLE() const {return id;} 96 | 97 | 98 | const CK_SESSION_HANDLE id; 99 | ObjectsIterator objects_iterator; 100 | CK_OBJECT_HANDLE sign_key; 101 | CK_MECHANISM sign_mechanism; 102 | 103 | private: 104 | session_t(CK_SESSION_HANDLE id) : id(id) {} 105 | 106 | private: 107 | static CK_SESSION_HANDLE _id; 108 | static std::list _sessions; 109 | }; 110 | 111 | 112 | CK_SESSION_HANDLE session_t::_id = 0; 113 | std::list session_t::_sessions = std::list(); 114 | 115 | 116 | extern "C" { 117 | 118 | CK_RV C_Initialize(CK_VOID_PTR a) 119 | { 120 | LOG_G("%s",__FUNCTION__); 121 | 122 | if (CK_C_INITIALIZE_ARGS_PTR args = reinterpret_cast(a)) { 123 | return CKR_CANT_LOCK; 124 | } 125 | 126 | std::string rcfile; 127 | try { 128 | rcfile = std::string(std::getenv("SOFTPKCS11RC")); 129 | } 130 | catch(...) { 131 | const std::string home = std::string(std::getenv("HOME")); 132 | rcfile = home + "/.soft-token.rc"; 133 | } 134 | 135 | if (soft_token.get()) return CKR_CRYPTOKI_ALREADY_INITIALIZED; 136 | 137 | soft_token.reset(new soft_token_t(rcfile)); 138 | 139 | return CKR_OK; 140 | } 141 | 142 | CK_RV C_Finalize(CK_VOID_PTR a) 143 | { 144 | LOG_G("%s",__FUNCTION__); 145 | ASSERT_NOT_PTR(a); 146 | 147 | session_t::clear(); 148 | soft_token.reset(); 149 | 150 | return CKR_OK; 151 | } 152 | 153 | static void snprintf_fill(char *str, size_t size, char fillchar, const char *fmt, ...) 154 | { 155 | int len; 156 | va_list ap; 157 | len = vsnprintf(str, size, fmt, ap); 158 | va_end(ap); 159 | if (len < 0 || len > size) 160 | return; 161 | while(len < size) 162 | str[len++] = fillchar; 163 | } 164 | 165 | CK_RV C_GetInfo(CK_INFO_PTR info) 166 | { 167 | LOG_G("%s",__FUNCTION__); 168 | ASSERT_PTR(info); 169 | 170 | if (!soft_token.get()) return CKR_CRYPTOKI_NOT_INITIALIZED; 171 | 172 | memset(info, 17, sizeof(*info)); 173 | info->cryptokiVersion.major = 1; 174 | info->cryptokiVersion.minor = 10; 175 | snprintf_fill((char *)info->manufacturerID, 176 | sizeof(info->manufacturerID), 177 | ' ', 178 | "SoftToken"); 179 | snprintf_fill((char *)info->libraryDescription, 180 | sizeof(info->libraryDescription), ' ', 181 | "SoftToken"); 182 | info->libraryVersion.major = 0; 183 | info->libraryVersion.minor = 1; 184 | 185 | return CKR_OK; 186 | } 187 | 188 | CK_RV C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount) 189 | { 190 | LOG_G("%s",__FUNCTION__); 191 | 192 | if (!soft_token.get()) return CKR_CRYPTOKI_NOT_INITIALIZED; 193 | 194 | try { 195 | if (soft_token->ready()) { 196 | if (pSlotList) { 197 | pSlotList[0] = 1; 198 | } 199 | 200 | *pulCount = 1; 201 | } 202 | else { 203 | *pulCount = (tokenPresent) ? 0 : 1; 204 | } 205 | } 206 | catch(...) { 207 | return CKR_FUNCTION_FAILED; 208 | } 209 | 210 | return CKR_OK; 211 | } 212 | 213 | CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) 214 | { 215 | LOG_G("%s",__FUNCTION__); 216 | ASSERT_PTR(pInfo); 217 | 218 | if (!soft_token.get()) return CKR_CRYPTOKI_NOT_INITIALIZED; 219 | if (slotID != 1) return CKR_SLOT_ID_INVALID; 220 | 221 | memset(pInfo, 18, sizeof(*pInfo)); 222 | 223 | snprintf_fill((char *)pInfo->slotDescription, 224 | sizeof(pInfo->slotDescription), 225 | ' ', 226 | "SoftToken (slot)"); 227 | snprintf_fill((char *)pInfo->manufacturerID, 228 | sizeof(pInfo->manufacturerID), 229 | ' ', 230 | "SoftToken (slot)"); 231 | 232 | pInfo->flags = CKF_REMOVABLE_DEVICE; 233 | if (soft_token->ready()) pInfo->flags |= CKF_TOKEN_PRESENT; 234 | 235 | pInfo->hardwareVersion.major = 1; 236 | pInfo->hardwareVersion.minor = 0; 237 | pInfo->firmwareVersion.major = 1; 238 | pInfo->firmwareVersion.minor = 0; 239 | 240 | return CKR_OK; 241 | } 242 | 243 | CK_RV C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) 244 | { 245 | LOG_G("%s",__FUNCTION__); 246 | ASSERT_PTR(pInfo); 247 | 248 | if (slotID != 1) return CKR_SLOT_ID_INVALID; 249 | if (!soft_token.get()) return CKR_CRYPTOKI_NOT_INITIALIZED; 250 | if (!soft_token->ready()) return CKR_TOKEN_NOT_PRESENT; 251 | 252 | memset(pInfo, 19, sizeof(*pInfo)); 253 | 254 | snprintf_fill((char *)pInfo->label, 255 | sizeof(pInfo->label), 256 | ' ', 257 | "SoftToken (token)"); 258 | snprintf_fill((char *)pInfo->manufacturerID, 259 | sizeof(pInfo->manufacturerID), 260 | ' ', 261 | "SoftToken (token)"); 262 | snprintf_fill((char *)pInfo->model, 263 | sizeof(pInfo->model), 264 | ' ', 265 | soft_token->full_name().c_str()); 266 | snprintf_fill((char *)pInfo->serialNumber, 267 | sizeof(pInfo->serialNumber), 268 | ' ', 269 | "391137"); 270 | pInfo->flags = CKF_TOKEN_INITIALIZED | CKF_USER_PIN_INITIALIZED | CKF_LOGIN_REQUIRED | CKF_PROTECTED_AUTHENTICATION_PATH; 271 | 272 | pInfo->ulMaxSessionCount = 5; 273 | pInfo->ulSessionCount = session_t::count(); 274 | pInfo->ulMaxRwSessionCount = 5; 275 | pInfo->ulRwSessionCount = session_t::count(); 276 | pInfo->ulMaxPinLen = 1024; 277 | pInfo->ulMinPinLen = 0; 278 | pInfo->ulTotalPublicMemory = 47120; 279 | pInfo->ulFreePublicMemory = 47110; 280 | pInfo->ulTotalPrivateMemory = 47140; 281 | pInfo->ulFreePrivateMemory = 47130; 282 | pInfo->hardwareVersion.major = 2; 283 | pInfo->hardwareVersion.minor = 0; 284 | pInfo->firmwareVersion.major = 2; 285 | pInfo->firmwareVersion.minor = 0; 286 | 287 | return CKR_OK; 288 | } 289 | 290 | CK_RV C_GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount) 291 | { 292 | LOG_G("%s",__FUNCTION__); 293 | 294 | if (slotID != 1) return CKR_SLOT_ID_INVALID; 295 | if (!soft_token.get()) return CKR_CRYPTOKI_NOT_INITIALIZED; 296 | if (!soft_token->ready()) return CKR_TOKEN_NOT_PRESENT; 297 | 298 | if (pMechanismList == NULL_PTR) { 299 | *pulCount = 2; 300 | return CKR_OK; 301 | } 302 | 303 | if (*pulCount >= 2) { 304 | pMechanismList[0] = CKM_RSA_X_509; 305 | pMechanismList[1] = CKM_RSA_PKCS; 306 | } 307 | 308 | return CKR_OK; 309 | } 310 | 311 | CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo) 312 | { 313 | LOG_G("%s slot:%d type:%d", __FUNCTION__, slotID, type); 314 | 315 | return CKR_FUNCTION_NOT_SUPPORTED; 316 | } 317 | 318 | CK_RV C_InitToken(CK_SLOT_ID slotID, 319 | CK_UTF8CHAR_PTR pPin, 320 | CK_ULONG ulPinLen, 321 | CK_UTF8CHAR_PTR pLabel) 322 | { 323 | LOG_G("%s slot:%d", __FUNCTION__, slotID); 324 | return CKR_FUNCTION_NOT_SUPPORTED; 325 | } 326 | 327 | CK_RV C_OpenSession(CK_SLOT_ID slotID, 328 | CK_FLAGS flags, 329 | CK_VOID_PTR pApplication, 330 | CK_NOTIFY Notify, 331 | CK_SESSION_HANDLE_PTR phSession) 332 | { 333 | LOG_G("%s slot:%d", __FUNCTION__, slotID); 334 | 335 | if (slotID != 1) return CKR_SLOT_ID_INVALID; 336 | if (!soft_token.get()) return CKR_CRYPTOKI_NOT_INITIALIZED; 337 | if (!soft_token->ready()) return CKR_TOKEN_NOT_PRESENT; 338 | 339 | *phSession = *session_t::create(); 340 | 341 | return CKR_OK; 342 | } 343 | 344 | CK_RV C_CloseSession(CK_SESSION_HANDLE hSession) 345 | { 346 | LOG_G("%s session:%d", __FUNCTION__, hSession); 347 | 348 | LOG("s1") 349 | if (session_t::find(hSession) == session_t::end()) return CKR_SESSION_HANDLE_INVALID; 350 | 351 | LOG("s2") 352 | session_t::destroy(hSession); 353 | LOG("s3") 354 | return CKR_OK; 355 | } 356 | 357 | CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) 358 | { 359 | LOG_G("%s session:%d", __FUNCTION__, hSession); 360 | ASSERT_PTR(pInfo); 361 | 362 | if (!soft_token.get()) return CKR_CRYPTOKI_NOT_INITIALIZED; 363 | if (session_t::find(hSession) == session_t::end()) return CKR_SESSION_HANDLE_INVALID; 364 | if (!soft_token->ready()) return CKR_DEVICE_REMOVED; 365 | 366 | memset(pInfo, 20, sizeof(*pInfo)); 367 | 368 | pInfo->slotID = 1; 369 | pInfo->state = (soft_token->logged()) 370 | ? CKS_RW_USER_FUNCTIONS 371 | : CKS_RO_PUBLIC_SESSION; 372 | 373 | pInfo->flags = CKF_SERIAL_SESSION; 374 | if (soft_token->logged()) pInfo->flags |= CKF_SERIAL_SESSION; 375 | pInfo->ulDeviceError = 0; 376 | 377 | return CKR_OK; 378 | } 379 | 380 | const std::set public_attributes = { 381 | CKA_CLASS, CKA_LABEL, CKA_APPLICATION, CKA_OBJECT_ID, CKA_MODIFIABLE, 382 | CKA_PRIVATE, CKA_TOKEN, CKA_DERIVE, CKA_LOCAL, CKA_KEY_GEN_MECHANISM, 383 | CKA_ENCRYPT, CKA_VERIFY, CKA_KEY_TYPE, CKA_MODULUS, CKA_MODULUS_BITS, 384 | CKA_PUBLIC_EXPONENT, CKA_SENSITIVE, CKA_DECRYPT, CKA_SIGN, 385 | CKA_SIGN_RECOVER, CKA_UNWRAP, CKA_EXTRACTABLE, CKA_NEVER_EXTRACTABLE, 386 | CKA_ALWAYS_AUTHENTICATE, CKA_ID, CKA_WRAP, CKA_CERTIFICATE_TYPE 387 | }; 388 | 389 | CK_RV C_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) 390 | { 391 | LOG_G("%s session:%d ulCount%d", __FUNCTION__, hSession, ulCount); 392 | 393 | if (!soft_token.get()) return CKR_CRYPTOKI_NOT_INITIALIZED; 394 | if (session_t::find(hSession) == session_t::end()) return CKR_SESSION_HANDLE_INVALID; 395 | if (!soft_token->ready()) return CKR_DEVICE_REMOVED; 396 | 397 | if (!soft_token->logged()) { 398 | if (!soft_token->login(ask_password())) { 399 | return CKR_USER_NOT_LOGGED_IN; 400 | } 401 | } 402 | 403 | auto session = session_t::find(hSession); 404 | 405 | if (ulCount) { 406 | 407 | Attributes attrs; 408 | 409 | print_attributes(pTemplate, ulCount); 410 | 411 | for (CK_ULONG i = 0; i < ulCount; i++) { 412 | attrs[pTemplate[i].type] = pTemplate[i]; 413 | } 414 | 415 | session->objects_iterator = soft_token->begin(attrs); 416 | LOG("Find initialized"); 417 | } else { 418 | LOG("Find ALL initialized"); 419 | session->objects_iterator = soft_token->begin(); 420 | } 421 | 422 | return CKR_OK; 423 | } 424 | 425 | CK_RV C_FindObjects(CK_SESSION_HANDLE hSession, 426 | CK_OBJECT_HANDLE_PTR phObject, 427 | CK_ULONG ulMaxObjectCount, 428 | CK_ULONG_PTR pulObjectCount) 429 | { 430 | LOG_G("%s session:%d ulMaxObjectCount%d", __FUNCTION__, hSession, ulMaxObjectCount); 431 | 432 | if (!soft_token.get()) return CKR_CRYPTOKI_NOT_INITIALIZED; 433 | if (session_t::find(hSession) == session_t::end()) return CKR_SESSION_HANDLE_INVALID; 434 | if (!soft_token->ready()) return CKR_DEVICE_REMOVED; 435 | 436 | if (ulMaxObjectCount == 0) { 437 | return CKR_ARGUMENTS_BAD; 438 | } 439 | 440 | auto session = session_t::find(hSession); 441 | 442 | *pulObjectCount = 0; 443 | 444 | auto& it = session->objects_iterator; 445 | 446 | while(it != soft_token->end()) { 447 | LOG("Found id %lu", it->first); 448 | 449 | *phObject++ = it->first; 450 | (*pulObjectCount)++; 451 | ulMaxObjectCount--; 452 | ++it; 453 | 454 | if (ulMaxObjectCount == 0) break; 455 | } 456 | 457 | LOG("Return %lu objects", *pulObjectCount); 458 | return CKR_OK; 459 | } 460 | 461 | CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE hSession) 462 | { 463 | LOG("F1 %d", hSession); 464 | LOG("F2 %d", hSession); 465 | 466 | LOG_G("%s session:%d", __FUNCTION__, hSession); 467 | 468 | if (!soft_token.get()) return CKR_CRYPTOKI_NOT_INITIALIZED; 469 | 470 | LOG("F3 %d", hSession); 471 | 472 | if (session_t::find(hSession) == session_t::end()) return CKR_SESSION_HANDLE_INVALID; 473 | 474 | LOG("F4 %d", hSession); 475 | if (!soft_token->ready()) return CKR_DEVICE_REMOVED; 476 | 477 | LOG("F5 %d", hSession); 478 | 479 | session_t::find(hSession)->objects_iterator = soft_token->end(); 480 | 481 | LOG("F6 %d", hSession); 482 | 483 | return CKR_OK; 484 | } 485 | 486 | CK_RV C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) 487 | { 488 | LOG_G("%s session:%d handle:%lu %s ulCount:%d", __FUNCTION__, hSession, hObject, soft_token->attributes(hObject)[CKA_LABEL].to_string().c_str(), ulCount); 489 | 490 | if (!soft_token.get()) return CKR_CRYPTOKI_NOT_INITIALIZED; 491 | if (session_t::find(hSession) == session_t::end()) return CKR_SESSION_HANDLE_INVALID; 492 | if (!soft_token->ready()) return CKR_DEVICE_REMOVED; 493 | if (!soft_token->has_object(hObject)) return CKR_OBJECT_HANDLE_INVALID; 494 | 495 | { 496 | LOG_G("Input"); 497 | print_attributes(pTemplate, ulCount); 498 | } 499 | 500 | auto session = session_t::find(hSession); 501 | auto attrs = soft_token->attributes(hObject); 502 | 503 | //TODO handle CKR_BUFFER_TOO_SMALL 504 | 505 | for (int i = 0; i < ulCount; i++) { 506 | if (public_attributes.find(pTemplate[i].type) == public_attributes.end()) { 507 | if (!soft_token->logged()) { 508 | if (!soft_token->login(ask_password())) { 509 | return CKR_USER_NOT_LOGGED_IN; 510 | } 511 | } 512 | } 513 | 514 | auto it = attrs.find(pTemplate[i].type); 515 | 516 | if (it != attrs.end()) 517 | { 518 | it->second.apply(pTemplate[i]); 519 | } 520 | 521 | if (pTemplate[i].type == CKA_VALUE) { 522 | const auto data = soft_token->read(hObject); 523 | if (pTemplate[i].pValue != NULL_PTR) { 524 | memcpy(pTemplate[i].pValue, data.c_str(), data.size()); 525 | } 526 | pTemplate[i].ulValueLen = data.size(); 527 | } 528 | else if (it == attrs.end()) { 529 | pTemplate[i].ulValueLen = (CK_ULONG)-1; 530 | } 531 | } 532 | 533 | { 534 | LOG_G("Output"); 535 | print_attributes(pTemplate, ulCount); 536 | } 537 | return CKR_OK; 538 | } 539 | 540 | CK_RV C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) 541 | { 542 | LOG_G("%s session:%d", __FUNCTION__, hSession); 543 | 544 | if (!soft_token.get()) return CKR_CRYPTOKI_NOT_INITIALIZED; 545 | if (session_t::find(hSession) == session_t::end()) return CKR_SESSION_HANDLE_INVALID; 546 | if (!soft_token->ready()) return CKR_DEVICE_REMOVED; 547 | if (soft_token->logged()) return CKR_USER_ALREADY_LOGGED_IN; 548 | 549 | 550 | std::string pin; 551 | 552 | if (pPin == NULL_PTR) { 553 | pin = ask_password(); 554 | } 555 | else { 556 | pin = std::string(reinterpret_cast(pPin), ulPinLen); 557 | } 558 | 559 | if (soft_token->login(pin)) { 560 | return CKR_OK; 561 | } 562 | else { 563 | if (soft_token->ssh_agent()) return CKR_OK; 564 | return CKR_PIN_INCORRECT; 565 | } 566 | } 567 | 568 | CK_RV C_Logout(CK_SESSION_HANDLE hSession) 569 | { 570 | LOG_G("%s session:%d", __FUNCTION__, hSession); 571 | 572 | if (!soft_token.get()) return CKR_CRYPTOKI_NOT_INITIALIZED; 573 | if (session_t::find(hSession) == session_t::end()) return CKR_SESSION_HANDLE_INVALID; 574 | if (!soft_token->ready()) return CKR_DEVICE_REMOVED; 575 | if (!soft_token->logged()) return CKR_USER_NOT_LOGGED_IN; 576 | 577 | soft_token->logout(); 578 | 579 | return CKR_OK; 580 | } 581 | 582 | CK_RV C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) 583 | { 584 | LOG_G("%s session:%d", __FUNCTION__, hSession); 585 | 586 | if (!soft_token.get()) return CKR_CRYPTOKI_NOT_INITIALIZED; 587 | if (session_t::find(hSession) == session_t::end()) return CKR_SESSION_HANDLE_INVALID; 588 | if (!soft_token->ready()) return CKR_DEVICE_REMOVED; 589 | if (!soft_token->logged()) return CKR_USER_NOT_LOGGED_IN; 590 | 591 | if (!soft_token->has_object(hKey)) return CKR_KEY_HANDLE_INVALID; 592 | 593 | const CK_BBOOL bool_true = CK_TRUE; 594 | 595 | if (!soft_token->check(hKey, {create_object(CKA_SIGN, bool_true)})) { 596 | return CKR_ARGUMENTS_BAD; 597 | } 598 | 599 | auto session = session_t::find(hSession); 600 | session->sign_key = hKey; 601 | session->sign_mechanism.mechanism = pMechanism->mechanism; 602 | session->sign_mechanism.ulParameterLen = pMechanism->ulParameterLen; 603 | memcpy(session->sign_mechanism.pParameter, pMechanism->pParameter, pMechanism->ulParameterLen); 604 | 605 | return CKR_OK; 606 | } 607 | 608 | CK_RV C_Sign(CK_SESSION_HANDLE hSession, 609 | CK_BYTE_PTR pData, 610 | CK_ULONG ulDataLen, 611 | CK_BYTE_PTR pSignature, 612 | CK_ULONG_PTR pulSignatureLen) 613 | { 614 | LOG_G("%s session:%d", __FUNCTION__, hSession); 615 | ASSERT_PTR(pData); 616 | 617 | if (!soft_token.get()) return CKR_CRYPTOKI_NOT_INITIALIZED; 618 | if (session_t::find(hSession) == session_t::end()) return CKR_SESSION_HANDLE_INVALID; 619 | if (!soft_token->ready()) return CKR_DEVICE_REMOVED; 620 | if (!soft_token->logged()) return CKR_USER_NOT_LOGGED_IN; 621 | 622 | auto session = session_t::find(hSession); 623 | 624 | if (session->sign_key == soft_token_t::handle_invalid()) { 625 | return CKR_OPERATION_NOT_INITIALIZED; 626 | } 627 | 628 | const auto signature = soft_token->sign(session->sign_key, session->sign_mechanism.mechanism, pData, ulDataLen); 629 | if (signature.size() > *pulSignatureLen) { 630 | return CKR_BUFFER_TOO_SMALL; 631 | } 632 | 633 | ASSERT_PTR(pSignature); 634 | std::copy(signature.begin(), signature.end(), pSignature); 635 | *pulSignatureLen = signature.size(); 636 | 637 | return CKR_OK; 638 | } 639 | 640 | 641 | CK_RV C_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) 642 | { 643 | LOG_G("%s session:%d", __FUNCTION__, hSession); 644 | 645 | if (!soft_token.get()) return CKR_CRYPTOKI_NOT_INITIALIZED; 646 | if (session_t::find(hSession) == session_t::end()) return CKR_SESSION_HANDLE_INVALID; 647 | if (!soft_token->ready()) return CKR_DEVICE_REMOVED; 648 | if (!soft_token->logged()) return CKR_USER_NOT_LOGGED_IN; 649 | 650 | return CKR_FUNCTION_NOT_SUPPORTED; 651 | } 652 | 653 | CK_RV C_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) 654 | { 655 | LOG_G("%s session:%d", __FUNCTION__, hSession); 656 | 657 | if (!soft_token.get()) return CKR_CRYPTOKI_NOT_INITIALIZED; 658 | if (session_t::find(hSession) == session_t::end()) return CKR_SESSION_HANDLE_INVALID; 659 | if (!soft_token->ready()) return CKR_DEVICE_REMOVED; 660 | if (!soft_token->logged()) return CKR_USER_NOT_LOGGED_IN; 661 | 662 | return CKR_OK; 663 | } 664 | 665 | CK_RV C_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject) 666 | { 667 | LOG_G("%s session:%d", __FUNCTION__, hSession); 668 | 669 | if (!soft_token.get()) return CKR_CRYPTOKI_NOT_INITIALIZED; 670 | if (session_t::find(hSession) == session_t::end()) return CKR_SESSION_HANDLE_INVALID; 671 | if (!soft_token->ready()) return CKR_DEVICE_REMOVED; 672 | 673 | if (!soft_token->logged()) { 674 | if (!soft_token->login(ask_password())) { 675 | return CKR_USER_NOT_LOGGED_IN; 676 | } 677 | } 678 | 679 | 680 | 681 | std::string label; 682 | std::vector value; 683 | 684 | std::string suf; 685 | 686 | Attributes attrs; 687 | for (CK_ULONG i = 0; i < ulCount; i++) { 688 | attrs[pTemplate[i].type] = pTemplate[i]; 689 | } 690 | 691 | for (int i = 0; i < ulCount; i++) { 692 | if(pTemplate[i].type == CKA_VALUE) { 693 | value = attribute_t(pTemplate[i]).to_bytes(); 694 | } 695 | if(pTemplate[i].type == CKA_LABEL) { 696 | label = attribute_t(pTemplate[i]).to_string(); 697 | } 698 | if(pTemplate[i].type == CKA_CLASS) { 699 | CK_OBJECT_CLASS klass = *((CK_OBJECT_CLASS*)pTemplate[i].pValue); 700 | 701 | if (klass == CKO_PUBLIC_KEY) { 702 | value = soft_token->create_key(klass, attrs); 703 | suf = ".pub"; 704 | } 705 | else if(klass == CKO_PRIVATE_KEY) { 706 | value = soft_token->create_key(klass, attrs); 707 | } 708 | } 709 | } 710 | 711 | if (label.empty()) { 712 | return CKR_TEMPLATE_INCOMPLETE; 713 | } 714 | 715 | label = label + suf; 716 | 717 | print_attributes(pTemplate, ulCount); 718 | 719 | *phObject = soft_token->write(label, value, attrs); 720 | 721 | LOG("Object created: %lu", *phObject); 722 | print_attributes(soft_token->attributes(*phObject)); 723 | return CKR_OK; 724 | } 725 | 726 | CK_RV C_InitPIN(CK_SESSION_HANDLE hSession, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) 727 | { 728 | return CKR_FUNCTION_NOT_SUPPORTED; 729 | } 730 | 731 | extern CK_FUNCTION_LIST funcs; 732 | 733 | CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) 734 | { 735 | LOG_G("%s",__FUNCTION__); 736 | *ppFunctionList = &funcs; 737 | return CKR_OK; 738 | } 739 | 740 | 741 | CK_FUNCTION_LIST funcs = { 742 | { 2, 11 }, 743 | WRAP_FUNCTION(CK_C_Initialize, exception_handler), 744 | WRAP_FUNCTION(CK_C_Finalize, exception_handler), 745 | WRAP_FUNCTION(CK_C_GetInfo, exception_handler), 746 | WRAP_FUNCTION(CK_C_GetFunctionList, exception_handler), 747 | WRAP_FUNCTION(CK_C_GetSlotList, exception_handler), 748 | WRAP_FUNCTION(CK_C_GetSlotInfo, exception_handler), 749 | WRAP_FUNCTION(CK_C_GetTokenInfo, exception_handler), 750 | WRAP_FUNCTION(CK_C_GetMechanismList, exception_handler), 751 | WRAP_FUNCTION(CK_C_GetMechanismInfo, exception_handler), 752 | WRAP_FUNCTION(CK_C_InitToken, exception_handler), 753 | WRAP_FUNCTION(CK_C_InitPIN, exception_handler), 754 | WRAP_NOT_IMPLEMENTED(CK_C_SetPIN), 755 | WRAP_FUNCTION(CK_C_OpenSession, exception_handler), 756 | WRAP_FUNCTION(CK_C_CloseSession, exception_handler), 757 | WRAP_NOT_IMPLEMENTED(CK_C_CloseAllSessions), //C_CloseAllSessions, 758 | WRAP_FUNCTION(CK_C_GetSessionInfo, exception_handler), 759 | WRAP_NOT_IMPLEMENTED(CK_C_GetOperationState), /* C_GetOperationState */ 760 | WRAP_NOT_IMPLEMENTED(CK_C_SetOperationState), /* C_SetOperationState */ 761 | WRAP_FUNCTION(CK_C_Login, exception_handler), 762 | WRAP_FUNCTION(CK_C_Logout, exception_handler), 763 | WRAP_FUNCTION(CK_C_CreateObject, exception_handler), 764 | WRAP_NOT_IMPLEMENTED(CK_C_CopyObject), /* C_CopyObject */ 765 | WRAP_NOT_IMPLEMENTED(CK_C_DestroyObject), /* C_DestroyObject */ 766 | WRAP_NOT_IMPLEMENTED(CK_C_GetObjectSize), /* C_GetObjectSize */ 767 | WRAP_FUNCTION(CK_C_GetAttributeValue, exception_handler), 768 | WRAP_NOT_IMPLEMENTED(CK_C_SetAttributeValue), /* C_SetAttributeValue */ 769 | WRAP_FUNCTION(CK_C_FindObjectsInit, exception_handler), 770 | WRAP_FUNCTION(CK_C_FindObjects, exception_handler), 771 | WRAP_FUNCTION(CK_C_FindObjectsFinal, exception_handler), 772 | WRAP_NOT_IMPLEMENTED(CK_C_EncryptInit), //C_EncryptInit, 773 | WRAP_NOT_IMPLEMENTED(CK_C_Encrypt), //C_Encrypt, 774 | WRAP_NOT_IMPLEMENTED(CK_C_EncryptUpdate), //C_EncryptUpdate, 775 | WRAP_NOT_IMPLEMENTED(CK_C_EncryptFinal), //C_EncryptFinal, 776 | 777 | WRAP_NOT_IMPLEMENTED(CK_C_DecryptInit), //C_DecryptInit, 778 | WRAP_NOT_IMPLEMENTED(CK_C_Decrypt), //C_Decrypt, 779 | WRAP_NOT_IMPLEMENTED(CK_C_DecryptUpdate), //C_DecryptUpdate, 780 | WRAP_NOT_IMPLEMENTED(CK_C_DecryptFinal), //C_DecryptFinal, 781 | 782 | WRAP_NOT_IMPLEMENTED(CK_C_DigestInit), //C_DigestInit, 783 | WRAP_NOT_IMPLEMENTED(CK_C_Digest), /* C_Digest */ 784 | WRAP_NOT_IMPLEMENTED(CK_C_DigestUpdate), /* C_DigestUpdate */ 785 | WRAP_NOT_IMPLEMENTED(CK_C_DigestKey), /* C_DigestKey */ 786 | WRAP_NOT_IMPLEMENTED(CK_C_DigestFinal), /* C_DigestFinal */ 787 | C_SignInit, 788 | C_Sign, 789 | C_SignUpdate, 790 | C_SignFinal, 791 | WRAP_NOT_IMPLEMENTED(CK_C_SignRecoverInit), /* C_SignRecoverInit */ 792 | WRAP_NOT_IMPLEMENTED(CK_C_SignRecover), /* C_SignRecover */ 793 | WRAP_NOT_IMPLEMENTED(CK_C_VerifyInit), //C_VerifyInit, 794 | WRAP_NOT_IMPLEMENTED(CK_C_Verify), //C_Verify, 795 | WRAP_NOT_IMPLEMENTED(CK_C_VerifyUpdate), //C_VerifyUpdate, 796 | WRAP_NOT_IMPLEMENTED(CK_C_VerifyFinal), //C_VerifyFinal, 797 | WRAP_NOT_IMPLEMENTED(CK_C_VerifyRecoverInit), /* C_VerifyRecoverInit */ 798 | WRAP_NOT_IMPLEMENTED(CK_C_VerifyRecover), /* C_VerifyRecover */ 799 | 800 | WRAP_NOT_IMPLEMENTED(CK_C_DigestEncryptUpdate), /* C_DigestEncryptUpdate */ 801 | WRAP_NOT_IMPLEMENTED(CK_C_DecryptDigestUpdate), /* C_DecryptDigestUpdate */ 802 | WRAP_NOT_IMPLEMENTED(CK_C_SignEncryptUpdate), /* C_SignEncryptUpdate */ 803 | WRAP_NOT_IMPLEMENTED(CK_C_DecryptVerifyUpdate), /* C_DecryptVerifyUpdate */ 804 | WRAP_NOT_IMPLEMENTED(CK_C_GenerateKey), /* C_GenerateKey */ 805 | WRAP_NOT_IMPLEMENTED(CK_C_GenerateKeyPair), /* C_GenerateKeyPair */ 806 | WRAP_NOT_IMPLEMENTED(CK_C_WrapKey), /* C_WrapKey */ 807 | WRAP_NOT_IMPLEMENTED(CK_C_UnwrapKey), /* C_UnwrapKey */ 808 | WRAP_NOT_IMPLEMENTED(CK_C_DeriveKey), /* C_DeriveKey */ 809 | WRAP_NOT_IMPLEMENTED(CK_C_SeedRandom), /* C_SeedRandom */ 810 | WRAP_NOT_IMPLEMENTED(CK_C_GenerateRandom), //C_GenerateRandom, 811 | WRAP_NOT_IMPLEMENTED(CK_C_GetFunctionStatus), /* C_GetFunctionStatus */ 812 | WRAP_NOT_IMPLEMENTED(CK_C_CancelFunction), /* C_CancelFunction */ 813 | WRAP_NOT_IMPLEMENTED(CK_C_WaitForSlotEvent) /* C_WaitForSlotEvent */ 814 | }; 815 | 816 | 817 | } 818 | 819 | 820 | 821 | 822 | 823 | --------------------------------------------------------------------------------