Merge branch 'development' into githubmaster
Added new material for yubico-piv-tool and ykcs11.
This commit is contained in:
@@ -80,3 +80,9 @@ lib/ykpiv.gcno
|
||||
tool/util.gcno
|
||||
tool/yubico-piv-tool.gcda
|
||||
tool/yubico-piv-tool.gcno
|
||||
ykcs11/.libs/
|
||||
ykcs11/*.o
|
||||
ykcs11/*.lo
|
||||
ykcs11/ykcs11.pc
|
||||
ykcs11/libykcs11.la
|
||||
ykcs11/ykcs11-version.h
|
||||
|
||||
+3
-3
@@ -25,13 +25,13 @@
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
SUBDIRS = lib tool
|
||||
SUBDIRS = lib tool ykcs11
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
EXTRA_DIST = windows.mk mac.mk tool/tests/basic.sh tools/fasc.pl
|
||||
|
||||
EXTRA_DIST += doc/Certificate_Authority_with_NEO.adoc doc/OS_X_code_signing.adoc doc/SSH_with_PIV_and_PKCS11.adoc doc/Windows_certificate.adoc doc/YubiKey_NEO_PIV_introduction.adoc
|
||||
EXTRA_DIST += doc/Certificate_Authority.adoc doc/OS_X_code_signing.adoc doc/SSH_with_PIV_and_PKCS11.adoc doc/Windows_certificate.adoc doc/YubiKey_PIV_introduction.adoc
|
||||
|
||||
if ENABLE_COV
|
||||
cov-reset:
|
||||
@@ -57,7 +57,7 @@ endif
|
||||
|
||||
if ENABLE_CPPCHECK
|
||||
cppcheck:
|
||||
$(CPPCHECK) -q -v -f --enable=all -i tool/cmdline.c lib tool
|
||||
$(CPPCHECK) -q -v -f --enable=all -i tool/cmdline.c lib tool ykcs11
|
||||
endif
|
||||
|
||||
# Maintainer rules.
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
yubico-piv-tool NEWS -- History of user-visible changes. -*- outline -*-
|
||||
|
||||
* Version 1.0.4 (unreleased)
|
||||
* Version 1.1.0 (unreleased)
|
||||
|
||||
** Support for YubiKey 4 stuff
|
||||
|
||||
* Version 1.0.3 (released 2015-10-01)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Introduction
|
||||
------------
|
||||
|
||||
The Yubico PIV tool is used for interacting with the Privilege and
|
||||
Identification Card (PIV) applet on a https://www.yubico.com[YubiKey NEO].
|
||||
Identification Card (PIV) application on a https://www.yubico.com[YubiKey].
|
||||
|
||||
With it you may generate keys on the device, importing keys and
|
||||
certificates, and create certificate requests, and other operations.
|
||||
|
||||
+14
-4
@@ -26,7 +26,7 @@
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
AC_INIT([yubico-piv-tool], [1.0.4])
|
||||
AC_INIT([yubico-piv-tool], [1.1.0])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
@@ -34,9 +34,9 @@ AC_CONFIG_MACRO_DIR([m4])
|
||||
# Interfaces changed/added/removed: CURRENT++ REVISION=0
|
||||
# Interfaces added: AGE++
|
||||
# Interfaces removed: AGE=0
|
||||
AC_SUBST([LT_CURRENT], 1)
|
||||
AC_SUBST([LT_REVISION], 9)
|
||||
AC_SUBST([LT_AGE], 0)
|
||||
AC_SUBST([LT_CURRENT], 2)
|
||||
AC_SUBST([LT_REVISION], 0)
|
||||
AC_SUBST([LT_AGE], 1)
|
||||
|
||||
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
|
||||
AM_SILENT_RULES([yes])
|
||||
@@ -52,6 +52,8 @@ PKG_PROG_PKG_CONFIG
|
||||
|
||||
PKG_CHECK_MODULES(OPENSSL, libcrypto)
|
||||
|
||||
#PKG_CHECK_MODULES([LIBNSPR], [nspr], [], [])
|
||||
|
||||
gl_LD_VERSION_SCRIPT
|
||||
gl_VALGRIND_TESTS
|
||||
|
||||
@@ -185,6 +187,11 @@ AC_SUBST(YKPIV_VERSION_MINOR, `echo $PACKAGE_VERSION | sed 's/.*\.\(.*\)\..*/\1/
|
||||
AC_SUBST(YKPIV_VERSION_PATCH, `echo $PACKAGE_VERSION | sed 's/.*\..*\.\(.*\)/\1/g'`)
|
||||
AC_SUBST(YKPIV_VERSION_NUMBER, `printf "0x%02x%02x%02x" $YKPIV_VERSION_MAJOR $YKPIV_VERSION_MINOR $YKPIV_VERSION_PATCH`)
|
||||
|
||||
AC_SUBST(YKCS11_VERSION_MAJOR, `echo $PACKAGE_VERSION | sed 's/\(.*\)\..*\..*/\1/g'`)
|
||||
AC_SUBST(YKCS11_VERSION_MINOR, `echo $PACKAGE_VERSION | sed 's/.*\.\(.*\)\..*/\1/g'`)
|
||||
AC_SUBST(YKCS11_VERSION_PATCH, `echo $PACKAGE_VERSION | sed 's/.*\..*\.\(.*\)/\1/g'`)
|
||||
AC_SUBST(YKCS11_VERSION_NUMBER, `printf "0x%02x%02x%02x" $YKCS11_VERSION_MAJOR $YKCS11_VERSION_MINOR $YKCS11_VERSION_PATCH`)
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
lib/Makefile
|
||||
@@ -193,6 +200,9 @@ AC_CONFIG_FILES([
|
||||
tool/tests/Makefile
|
||||
lib/ykpiv-version.h
|
||||
lib/ykpiv.pc
|
||||
ykcs11/Makefile
|
||||
ykcs11/ykcs11-version.h
|
||||
ykcs11/ykcs11.pc
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
Certificate Authority with NEO
|
||||
Certificate Authority with
|
||||
------------------------------
|
||||
|
||||
This document explains how to set up a Certificate Authority (CA) with
|
||||
Sub-CA private keys stored on YubiKey NEOs. Typical use for this is
|
||||
Sub-CA private keys stored on YubiKeys. Typical use for this is
|
||||
to generate HTTPS certificates for internal servers.
|
||||
|
||||
Considerations
|
||||
@@ -10,12 +10,12 @@ Considerations
|
||||
|
||||
For our example, we have chosen to use one root CA with a private key
|
||||
stored in an offline machine, that signs sub-CAs with private keys
|
||||
stored on YubiKey NEOs, which signs end-entity (EE) certs. We'll
|
||||
stored on YubiKeys, which signs end-entity (EE) certs. We'll
|
||||
generate the Sub-CA private keys on an offline host and save a copy of
|
||||
those keys.
|
||||
|
||||
We have chosen to use a RSA 3744 bit root CA key, and RSA 2048 bit
|
||||
keys for the NEO Sub-CAs and EE certificates. The NEO is limited to
|
||||
keys for the Sub-CAs and EE certificates. The is limited to
|
||||
RSA 1k and 2k keys (it supports ECDSA too but we chose to not use that
|
||||
here).
|
||||
|
||||
@@ -39,7 +39,7 @@ offline machine, booted from a LiveCD. Some additional packages may
|
||||
be required (pcscd, etc, see below) and will have to be transferred on
|
||||
a USB stick.
|
||||
|
||||
You need a YubiKey NEO with the PIV applet on, which you can purchase
|
||||
You need a YubiKey with the PIV application on, which you can purchase
|
||||
from Yubico.
|
||||
|
||||
You need to install the PKCS#11 Engine:
|
||||
@@ -89,15 +89,15 @@ You may inspect the newly generated root CA with:
|
||||
|
||||
openssl x509 -text < yubico-internal-https-ca-crt.pem
|
||||
|
||||
Preparing a Sub-CA NEO
|
||||
Preparing a Sub-CA
|
||||
----------------------
|
||||
|
||||
We need to change the management key, PIN and PUK code following the
|
||||
YubiKey-NEO-PIV-Introduction.txt document. We also want to save a
|
||||
YubiKey-PIV-Introduction.txt document. We also want to save a
|
||||
copy of these values. Here are the steps that are needed to be done
|
||||
for each new Sub-CA NEO.
|
||||
for each new Sub-CA.
|
||||
|
||||
This step is parametrized with the name of the YubiKey NEO user.
|
||||
This step is parametrized with the name of the YubiKey user.
|
||||
Generate new management code, PIN and PUK as follows:
|
||||
|
||||
user=Simon
|
||||
@@ -108,7 +108,7 @@ Generate new management code, PIN and PUK as follows:
|
||||
puk=`dd if=/dev/random bs=1 count=6 2>/dev/null | hexdump -v -e '/1 "%u"'|cut -c1-8`
|
||||
echo $puk > yubico-internal-https-$user-puk.txt
|
||||
|
||||
Configure a fresh NEO with these parameters as follows:
|
||||
Configure a fresh with these parameters as follows:
|
||||
|
||||
yubico-piv-tool -a set-mgm-key -n $key
|
||||
yubico-piv-tool -k $key -a change-pin -P 123456 -N $pin
|
||||
@@ -117,7 +117,7 @@ Configure a fresh NEO with these parameters as follows:
|
||||
Creating a Sub-CA
|
||||
-----------------
|
||||
|
||||
This step is parametrized with the name of the YubiKey NEO user. This
|
||||
This step is parametrized with the name of the YubiKey user. This
|
||||
means we will have one Sub-CA for every person authorized to sign
|
||||
certificates in our CA.
|
||||
|
||||
@@ -157,11 +157,11 @@ You may inspect the newly generated EE cert with this command:
|
||||
|
||||
openssl x509 -text < yubico-internal-https-subca-$user-crt.pem
|
||||
|
||||
Import Sub-CA key to NEO:
|
||||
Import Sub-CA key to:
|
||||
|
||||
yubico-piv-tool -k $key -a import-key -s 9c < yubico-internal-https-subca-$user-key.pem
|
||||
|
||||
Import Sub-CA cert to NEO:
|
||||
Import Sub-CA cert to:
|
||||
|
||||
yubico-piv-tool -k $key -a import-certificate -s 9c < yubico-internal-https-subca-$user-crt.pem
|
||||
|
||||
@@ -190,7 +190,7 @@ Then generate a new private key and certificate request:
|
||||
EOF
|
||||
openssl req -sha256 -new -config yubico-internal-https-ee-$host-csr.conf -key yubico-internal-https-ee-$host-key.pem -nodes -out yubico-internal-https-ee-$host-csr.pem
|
||||
|
||||
Then sign the certificate using the NEO:
|
||||
Then sign the certificate using the:
|
||||
|
||||
cat>yubico-internal-https-ee-$host-crt.conf<<EOF
|
||||
basicConstraints = critical,CA:false
|
||||
@@ -1,14 +1,14 @@
|
||||
Request, load and use OS X code signing certificates
|
||||
---------------------------------------------------
|
||||
|
||||
This is a short step-by-step on how to generate a key in the Neo,
|
||||
This is a short step-by-step on how to generate a key in the,
|
||||
create a certificate request, submit that request to apple, load the
|
||||
certificate in the Neo and use it for code signing.
|
||||
certificate in the and use it for code signing.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
* a YubiKey Neo with the PIV applet loaded
|
||||
* a YubiKey with the PIV application loaded
|
||||
* the yubico-piv-tool software
|
||||
* the OpenSC software
|
||||
* membership in the mac developer program
|
||||
@@ -45,11 +45,11 @@ Steps
|
||||
+
|
||||
NOTE: -K DER is available from version 0.1.3, with earlier convert to PEM and import.
|
||||
|
||||
8. Set a new chuid in the applet to make sure nothing is cached for the key:
|
||||
8. Set a new chuid in the application to make sure nothing is cached for the key:
|
||||
|
||||
$ yubico-piv-tool -a set-chuid
|
||||
|
||||
9. Re-plug the Neo and make sure the certificates show up under the keychain
|
||||
9. Re-plug the and make sure the certificates show up under the keychain
|
||||
"PIV_II" in Keychain Access.
|
||||
|
||||
10. Use the certificates as usual with codesign/pkgbuild/productbuild/productsign
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
Using PIV for SSH through PKCS11
|
||||
--------------------------------
|
||||
|
||||
This is a step-by-step for how to get a Neo with PIV to work for
|
||||
This is a step-by-step for how to get a with PIV to work for
|
||||
public-key authentication with OpenSSH through PKCS11.
|
||||
Primarily on a OS X or Linux system.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
* a YubiKey Neo with the PIV applet loaded
|
||||
* a YubiKey with the PIV application loaded
|
||||
* the yubico-piv-tool software
|
||||
* the OpenSC software
|
||||
* OpenSSH
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
Request and load a certificate from Windows CA
|
||||
----------------------------------------------
|
||||
|
||||
This is a short step-by-step on how to generate a key in the Neo,
|
||||
This is a short step-by-step on how to generate a key in the,
|
||||
create a certificate request, submit that request to a Windows CA
|
||||
and then load the certificate in the Neo.
|
||||
and then load the certificate in the.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
* a YubiKey Neo with the PIV applet loaded
|
||||
* a YubiKey with the PIV application loaded
|
||||
* the yubico-piv-tool software
|
||||
* credentials to request certs from a Windows CA
|
||||
|
||||
@@ -29,7 +29,7 @@ Steps
|
||||
|
||||
certreq -submit -attrib "CertificateTemplate:User" request.csr cert.crt
|
||||
|
||||
4. Load the certificate in the Neo:
|
||||
4. Load the certificate in the:
|
||||
|
||||
yubico-piv-tool -s 9a -a import-certificate -i cert.crt
|
||||
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
YKCS11
|
||||
------
|
||||
|
||||
This is a PKCS#11 module that allows to communicate with the PIV
|
||||
application running on a YubiKey.
|
||||
|
||||
BUILDING
|
||||
~~~~~~~~
|
||||
|
||||
YKCS11 is automatically built as part of `yubico-piv-tool` and the
|
||||
following command will suffice
|
||||
|
||||
----
|
||||
yubico-piv-tool$ autoreconf --install
|
||||
yubico-piv-tool$ ./configure
|
||||
yubico-piv-tool$ make
|
||||
yubico-piv-tool$ sudo make install
|
||||
----
|
||||
|
||||
More info about building yubico-piv-tool can be found in the related
|
||||
`README` file or over at
|
||||
https://developers.yubico.com/yubico-piv-tool/.
|
||||
|
||||
Once installed, the module will be found by default in
|
||||
/usr/local/lib/libykcs11.so otherwise it will be built locally in
|
||||
yubico-piv-tool/ykcs11/.libs/libykcs11.so
|
||||
|
||||
PORTABILITY
|
||||
~~~~~~~~~~~
|
||||
|
||||
The module has been developed and tested using Debian GNU/Linux and
|
||||
Ubuntu Linux. It is however possible to cross-compile it for Windows
|
||||
and Mac OS X using the relative makefiles (windows.mk and mac.mk).
|
||||
Both use PCSC as a backend.
|
||||
|
||||
Keep in mind that communication with the YubiKey is carried out over
|
||||
the CCID transport. Hence, on Mac OS X the YubiKey should be
|
||||
whitelisted (more info at https://github.com/Yubico/ifd-yubico).
|
||||
|
||||
Further testing at this stage has *not* been carried out, so
|
||||
additional tweaks might be needed to use operating systems different
|
||||
from Linux.
|
||||
|
||||
SUPPORTED FUNCTIONALITY AND KNOWN ISSUES
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
YKCS11 is not a full implementation of PKCS#11. Some functionality are
|
||||
not present and others are not yet implemented.
|
||||
|
||||
In its current form YKCS11 implements a smaller subset of
|
||||
functionality:
|
||||
|
||||
- RSA key generation +
|
||||
1024 or 2048 bit keys can be generated;
|
||||
|
||||
- EC key generation +
|
||||
curve prime256v1 is supported (256 bit keys);
|
||||
|
||||
- RSA signature +
|
||||
supported mechanisms are RSA-X-509 (raw RSA), PKCS1 (unhashed),
|
||||
PKCS1 with SHA1/256/384/512 and PSS with SHA1/256/384/512. The
|
||||
latter is implemented but has not been tested, hence is provided as
|
||||
is;
|
||||
|
||||
- ECDSA signature +
|
||||
supported mechanism are ECDSA (raw) and ECDSA with SHA1;
|
||||
|
||||
- RSA and EC public key (X.509 certificate) import;
|
||||
|
||||
- RSA and EC private key import +
|
||||
with possibility of setting individual PIN policies and touch to
|
||||
sign (where supported);
|
||||
|
||||
- Public key deletion.
|
||||
|
||||
PKCS#11 defines two types of users: a regular user and a security
|
||||
officer (SO). These have been mapped to perform regular usage of the
|
||||
private key material (PIN-associated operations) and device management
|
||||
(management-key associated operations).
|
||||
|
||||
Key Mapping
|
||||
^^^^^^^^^^^
|
||||
|
||||
The module provides four main keys that can be used. These correspond
|
||||
to the four main keys in PIV and accessible through yubico-piv-tool.
|
||||
The mapping is as follows:
|
||||
|
||||
[cols="2*^", options="header"]
|
||||
|===
|
||||
|ykcs11 id|PIV
|
||||
|0|9a
|
||||
|1|9e
|
||||
|2|9c
|
||||
|3|9d
|
||||
|===
|
||||
|
||||
PINs and Management Key
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The default user PIN for the YubiKey is `123456`. +
|
||||
The default management key is
|
||||
`010203040506070801020304050607080102030405060708`. +
|
||||
All the YubiKey personalization (e.g. changing PIN, changing
|
||||
management key, resetting PINs, resetting the application) is
|
||||
currently done using yubico-piv-tool.
|
||||
|
||||
In order to perform operations involving the private keys, a regular
|
||||
user must be logged in (i.e. using the PIN). However, given the
|
||||
different PIN policies for different keys, subsequent operations might
|
||||
require a new login. Currently this is supported by the module
|
||||
allowing multiple _Login_ operations with the appropriate user.
|
||||
According to PKCS#11 however, a special user called `CONTEXT_SPECIFIC`
|
||||
should be used for such operations. This is also supported and *might
|
||||
become the only available mechanism in the future*.
|
||||
|
||||
Key Generation
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
Key pair generation is a particular operation, in the sense that
|
||||
within PIV this is the only moment where the newly created public key
|
||||
is given back to the user. To prevent the key from being lost it is
|
||||
automatically stored within the YubiKey by wrapping it in an X.509
|
||||
certificate. This certificate is however empty. It does not have other
|
||||
valid information except for the public key.
|
||||
|
||||
DEBUGGING
|
||||
^^^^^^^^^
|
||||
|
||||
By default the module has debugging enabled. This is _highly_ verbose
|
||||
and might be confusing. In order to disable it, the two macros
|
||||
`YKCS11_DBG` and `YKCS11_DINOUT` in the file `debug.h` should be set
|
||||
to `0`. Once this is done the module must be recompiled.
|
||||
@@ -1,7 +1,7 @@
|
||||
Introduction to the YubiKey NEO PIV Applet
|
||||
==========================================
|
||||
Introduction to the YubiKey PIV Application
|
||||
===============================================
|
||||
|
||||
The YubiKey NEO supports the Personal Identity Verification (PIV) card
|
||||
The YubiKey supports the Personal Identity Verification (PIV) card
|
||||
interface specified in NIST SP 800-73 document "Cryptographic
|
||||
Algorithms and Key Sizes for PIV". This enables you to perform RSA or
|
||||
ECC sign/decrypt operations using a private key stored on the
|
||||
@@ -29,11 +29,11 @@ The maximum size of stored objects is 2005 bytes.
|
||||
Currently all functionality are available over both contact and
|
||||
contactless interfaces (contrary to what the specifications mandate).
|
||||
|
||||
Preparing a NEO for real use
|
||||
Preparing a for real use
|
||||
----------------------------
|
||||
|
||||
You would typically change the management key to make sure nobody but
|
||||
you can modify the state of the PIV applet on the NEO. Make sure to
|
||||
you can modify the state of the PIV application on the. Make sure to
|
||||
keep a copy of the key around for later use.
|
||||
|
||||
key=`dd if=/dev/random bs=1 count=24 2>/dev/null | hexdump -v -e '/1 "%02X"'`
|
||||
@@ -63,7 +63,7 @@ To reset PIN/PUK retry counter AND codes (default pin 123456 puk
|
||||
|
||||
yubico-piv-tool -k $key -a verify -P $pin -a pin-retries --pin-retries 3 --puk-retries 3
|
||||
|
||||
To reset the applet (PIN/PUK need to be blocked hence trying a couple
|
||||
To reset the application (PIN/PUK need to be blocked hence trying a couple
|
||||
of times -- you need to modify this if you have changed the default
|
||||
number of PIN/PUK retries).
|
||||
|
||||
@@ -94,7 +94,7 @@ middleware.
|
||||
Card Holder Unique Identifier
|
||||
-----------------------------
|
||||
|
||||
For the applet to be usable in windows the object CHUID (Card Holder
|
||||
For the application to be usable in windows the object CHUID (Card Holder
|
||||
Unique Identifier) has to be set and unique. The card contents are
|
||||
also aggressively cached so the CHUID has to be changed if the card
|
||||
contents change.
|
||||
+1
-1
@@ -46,7 +46,7 @@ static const err_t errors[] = {
|
||||
ERR (YKPIV_MEMORY_ERROR, "Error allocating memory"),
|
||||
ERR (YKPIV_PCSC_ERROR, "Error in PCSC call"),
|
||||
ERR (YKPIV_SIZE_ERROR, "Wrong buffer size"),
|
||||
ERR (YKPIV_APPLET_ERROR, "No PIV applet found"),
|
||||
ERR (YKPIV_APPLET_ERROR, "No PIV application found"),
|
||||
ERR (YKPIV_AUTHENTICATION_ERROR, "Error during authentication"),
|
||||
ERR (YKPIV_RANDOMNESS_ERROR, "Error getting randomness"),
|
||||
ERR (YKPIV_GENERIC_ERROR, "Something went wrong."),
|
||||
|
||||
@@ -42,9 +42,15 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define READER_LEN 32
|
||||
#define MAX_READERS 16
|
||||
|
||||
struct ykpiv_state {
|
||||
SCARDCONTEXT context;
|
||||
SCARDHANDLE card;
|
||||
unsigned long n_readers;
|
||||
char readers[MAX_READERS][READER_LEN];
|
||||
unsigned long tot_readers_len;
|
||||
int verbose;
|
||||
};
|
||||
|
||||
|
||||
+74
-53
@@ -103,6 +103,7 @@ ykpiv_rc ykpiv_init(ykpiv_state **state, int verbose) {
|
||||
}
|
||||
memset(s, 0, sizeof(ykpiv_state));
|
||||
s->verbose = verbose;
|
||||
s->context = -1;
|
||||
*state = s;
|
||||
return YKPIV_OK;
|
||||
}
|
||||
@@ -128,41 +129,15 @@ ykpiv_rc ykpiv_disconnect(ykpiv_state *state) {
|
||||
}
|
||||
|
||||
ykpiv_rc ykpiv_connect(ykpiv_state *state, const char *wanted) {
|
||||
unsigned long num_readers = 0;
|
||||
unsigned long active_protocol;
|
||||
char reader_buf[1024];
|
||||
char reader_buf[2048];
|
||||
size_t num_readers = sizeof(reader_buf);
|
||||
long rc;
|
||||
char *reader_ptr;
|
||||
|
||||
rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &state->context);
|
||||
if (rc != SCARD_S_SUCCESS) {
|
||||
if(state->verbose) {
|
||||
fprintf (stderr, "error: SCardEstablishContext failed, rc=%08lx\n", rc);
|
||||
}
|
||||
return YKPIV_PCSC_ERROR;
|
||||
}
|
||||
|
||||
rc = SCardListReaders(state->context, NULL, NULL, &num_readers);
|
||||
if (rc != SCARD_S_SUCCESS) {
|
||||
if(state->verbose) {
|
||||
fprintf (stderr, "error: SCardListReaders failed, rc=%08lx\n", rc);
|
||||
}
|
||||
SCardReleaseContext(state->context);
|
||||
return YKPIV_PCSC_ERROR;
|
||||
}
|
||||
|
||||
if (num_readers > sizeof(reader_buf)) {
|
||||
num_readers = sizeof(reader_buf);
|
||||
}
|
||||
|
||||
rc = SCardListReaders(state->context, NULL, reader_buf, &num_readers);
|
||||
if (rc != SCARD_S_SUCCESS)
|
||||
{
|
||||
if(state->verbose) {
|
||||
fprintf (stderr, "error: SCardListReaders failed, rc=%08lx\n", rc);
|
||||
}
|
||||
SCardReleaseContext(state->context);
|
||||
return YKPIV_PCSC_ERROR;
|
||||
ykpiv_rc ret = ykpiv_list_readers(state, reader_buf, &num_readers);
|
||||
if(ret != YKPIV_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for(reader_ptr = reader_buf; *reader_ptr != '\0'; reader_ptr += strlen(reader_ptr) + 1) {
|
||||
@@ -209,7 +184,7 @@ ykpiv_rc ykpiv_connect(ykpiv_state *state, const char *wanted) {
|
||||
return YKPIV_OK;
|
||||
} else {
|
||||
if(state->verbose) {
|
||||
fprintf(stderr, "Failed selecting applet: %04x\n", sw);
|
||||
fprintf(stderr, "Failed selecting application: %04x\n", sw);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,6 +201,46 @@ ykpiv_rc ykpiv_connect(ykpiv_state *state, const char *wanted) {
|
||||
return YKPIV_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
ykpiv_rc ykpiv_list_readers(ykpiv_state *state, char *readers, size_t *len) {
|
||||
unsigned long num_readers = 0;
|
||||
long rc;
|
||||
|
||||
rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &state->context);
|
||||
if (rc != SCARD_S_SUCCESS) {
|
||||
if(state->verbose) {
|
||||
fprintf (stderr, "error: SCardEstablishContext failed, rc=%08lx\n", rc);
|
||||
}
|
||||
return YKPIV_PCSC_ERROR;
|
||||
}
|
||||
|
||||
rc = SCardListReaders(state->context, NULL, NULL, &num_readers);
|
||||
if (rc != SCARD_S_SUCCESS) {
|
||||
if(state->verbose) {
|
||||
fprintf (stderr, "error: SCardListReaders failed, rc=%08lx\n", rc);
|
||||
}
|
||||
SCardReleaseContext(state->context);
|
||||
return YKPIV_PCSC_ERROR;
|
||||
}
|
||||
|
||||
if (num_readers > *len) {
|
||||
num_readers = *len;
|
||||
}
|
||||
|
||||
rc = SCardListReaders(state->context, NULL, readers, &num_readers);
|
||||
if (rc != SCARD_S_SUCCESS)
|
||||
{
|
||||
if(state->verbose) {
|
||||
fprintf (stderr, "error: SCardListReaders failed, rc=%08lx\n", rc);
|
||||
}
|
||||
SCardReleaseContext(state->context);
|
||||
return YKPIV_PCSC_ERROR;
|
||||
}
|
||||
|
||||
*len = num_readers;
|
||||
|
||||
return YKPIV_OK;
|
||||
}
|
||||
|
||||
ykpiv_rc ykpiv_transfer_data(ykpiv_state *state, const unsigned char *templ,
|
||||
const unsigned char *in_data, long in_len,
|
||||
unsigned char *out_data, unsigned long *out_len, int *sw) {
|
||||
@@ -433,6 +448,10 @@ ykpiv_rc ykpiv_authenticate(ykpiv_state *state, unsigned const char *key) {
|
||||
}
|
||||
|
||||
ykpiv_rc ykpiv_set_mgmkey(ykpiv_state *state, const unsigned char *new_key) {
|
||||
return ykpiv_set_mgmkey2(state, new_key, 0);
|
||||
}
|
||||
|
||||
ykpiv_rc ykpiv_set_mgmkey2(ykpiv_state *state, const unsigned char *new_key, const unsigned char touch) {
|
||||
APDU apdu;
|
||||
unsigned char data[261];
|
||||
unsigned long recv_len = sizeof(data);
|
||||
@@ -459,7 +478,13 @@ ykpiv_rc ykpiv_set_mgmkey(ykpiv_state *state, const unsigned char *new_key) {
|
||||
memset(apdu.raw, 0, sizeof(apdu));
|
||||
apdu.st.ins = YKPIV_INS_SET_MGMKEY;
|
||||
apdu.st.p1 = 0xff;
|
||||
if(touch == 0) {
|
||||
apdu.st.p2 = 0xff;
|
||||
} else if(touch == 1) {
|
||||
apdu.st.p2 = 0xfe;
|
||||
} else {
|
||||
return YKPIV_GENERIC_ERROR;
|
||||
}
|
||||
apdu.st.lc = DES_KEY_SZ * 3 + 3;
|
||||
apdu.st.data[0] = YKPIV_ALGO_3DES;
|
||||
apdu.st.data[1] = YKPIV_KEY_CARDMGM;
|
||||
@@ -505,7 +530,7 @@ ykpiv_rc ykpiv_hex_decode(const char *hex_in, size_t in_len,
|
||||
}
|
||||
|
||||
static ykpiv_rc _general_authenticate(ykpiv_state *state,
|
||||
const unsigned char *raw_in, size_t in_len,
|
||||
const unsigned char *sign_in, size_t in_len,
|
||||
unsigned char *out, size_t *out_len,
|
||||
unsigned char algorithm, unsigned char key, bool decipher) {
|
||||
unsigned char indata[1024];
|
||||
@@ -513,8 +538,7 @@ static ykpiv_rc _general_authenticate(ykpiv_state *state,
|
||||
unsigned char data[1024];
|
||||
unsigned char templ[] = {0, YKPIV_INS_AUTHENTICATE, algorithm, key};
|
||||
unsigned long recv_len = sizeof(data);
|
||||
unsigned char sign_in[256];
|
||||
size_t pad_len = 0;
|
||||
size_t key_len = 0;
|
||||
int sw;
|
||||
size_t bytes;
|
||||
size_t len = 0;
|
||||
@@ -522,31 +546,26 @@ static ykpiv_rc _general_authenticate(ykpiv_state *state,
|
||||
|
||||
switch(algorithm) {
|
||||
case YKPIV_ALGO_RSA1024:
|
||||
pad_len = 128;
|
||||
key_len = 128;
|
||||
case YKPIV_ALGO_RSA2048:
|
||||
if(pad_len == 0) {
|
||||
pad_len = 256;
|
||||
if(key_len == 0) {
|
||||
key_len = 256;
|
||||
}
|
||||
if(!decipher) {
|
||||
if(in_len + RSA_PKCS1_PADDING_SIZE > pad_len) {
|
||||
if(in_len != key_len) {
|
||||
return YKPIV_SIZE_ERROR;
|
||||
}
|
||||
RSA_padding_add_PKCS1_type_1(sign_in, pad_len, raw_in, in_len);
|
||||
in_len = pad_len;
|
||||
} else {
|
||||
if(in_len != pad_len) {
|
||||
return YKPIV_SIZE_ERROR;
|
||||
}
|
||||
memcpy(sign_in, raw_in, in_len);
|
||||
}
|
||||
break;
|
||||
case YKPIV_ALGO_ECCP256:
|
||||
if(!decipher && in_len > 32) {
|
||||
key_len = 32;
|
||||
case YKPIV_ALGO_ECCP384:
|
||||
if(key_len == 0) {
|
||||
key_len = 48;
|
||||
}
|
||||
if(!decipher && in_len > key_len) {
|
||||
return YKPIV_SIZE_ERROR;
|
||||
} else if(decipher && in_len != 65) {
|
||||
} else if(decipher && in_len != (key_len * 2) + 1) {
|
||||
return YKPIV_SIZE_ERROR;
|
||||
}
|
||||
memcpy(sign_in, raw_in, in_len);
|
||||
break;
|
||||
default:
|
||||
return YKPIV_ALGORITHM_ERROR;
|
||||
@@ -564,7 +583,7 @@ static ykpiv_rc _general_authenticate(ykpiv_state *state,
|
||||
dataptr += set_length(dataptr, in_len + bytes + 3);
|
||||
*dataptr++ = 0x82;
|
||||
*dataptr++ = 0x00;
|
||||
*dataptr++ = algorithm == YKPIV_ALGO_ECCP256 && decipher ? 0x85 : 0x81;
|
||||
*dataptr++ = YKPIV_IS_EC(algorithm) && decipher ? 0x85 : 0x81;
|
||||
dataptr += set_length(dataptr, in_len);
|
||||
memcpy(dataptr, sign_in, (size_t)in_len);
|
||||
dataptr += in_len;
|
||||
@@ -579,6 +598,9 @@ static ykpiv_rc _general_authenticate(ykpiv_state *state,
|
||||
if(state->verbose) {
|
||||
fprintf(stderr, "Failed sign command with code %x.\n", sw);
|
||||
}
|
||||
if (sw == 0x6982)
|
||||
return YKPIV_AUTHENTICATION_ERROR;
|
||||
else
|
||||
return YKPIV_GENERIC_ERROR;
|
||||
}
|
||||
/* skip the first 7c tag */
|
||||
@@ -619,7 +641,6 @@ ykpiv_rc ykpiv_sign_data(ykpiv_state *state,
|
||||
algorithm, key, false);
|
||||
}
|
||||
|
||||
|
||||
ykpiv_rc ykpiv_decipher_data(ykpiv_state *state, const unsigned char *in,
|
||||
size_t in_len, unsigned char *out, size_t *out_len,
|
||||
unsigned char algorithm, unsigned char key) {
|
||||
|
||||
+41
-1
@@ -65,6 +65,7 @@ extern "C"
|
||||
ykpiv_rc ykpiv_init(ykpiv_state **state, int verbose);
|
||||
ykpiv_rc ykpiv_done(ykpiv_state *state);
|
||||
ykpiv_rc ykpiv_connect(ykpiv_state *state, const char *wanted);
|
||||
ykpiv_rc ykpiv_list_readers(ykpiv_state *state, char *readers, size_t *len);
|
||||
ykpiv_rc ykpiv_disconnect(ykpiv_state *state);
|
||||
ykpiv_rc ykpiv_transfer_data(ykpiv_state *state, const unsigned char *templ,
|
||||
const unsigned char *in_data, long in_len,
|
||||
@@ -74,8 +75,11 @@ extern "C"
|
||||
ykpiv_rc ykpiv_hex_decode(const char *hex_in, size_t in_len,
|
||||
unsigned char *hex_out, size_t *out_len);
|
||||
ykpiv_rc ykpiv_sign_data(ykpiv_state *state, const unsigned char *sign_in,
|
||||
size_t in_len,unsigned char *sign_out, size_t *out_len,
|
||||
size_t in_len, unsigned char *sign_out, size_t *out_len,
|
||||
unsigned char algorithm, unsigned char key);
|
||||
ykpiv_rc ykpiv_sign_data2(ykpiv_state *state, const unsigned char *sign_in,
|
||||
size_t in_len, unsigned char *sign_out, size_t *out_len,
|
||||
unsigned char algorithm, unsigned char key, int padding); // Allow not to add padding
|
||||
ykpiv_rc ykpiv_decipher_data(ykpiv_state *state, const unsigned char *enc_in,
|
||||
size_t in_len, unsigned char *enc_out, size_t *out_len,
|
||||
unsigned char algorithm, unsigned char key);
|
||||
@@ -83,6 +87,8 @@ extern "C"
|
||||
ykpiv_rc ykpiv_verify(ykpiv_state *state, const char *pin, int *tries);
|
||||
ykpiv_rc ykpiv_fetch_object(ykpiv_state *state, int object_id,
|
||||
unsigned char *data, unsigned long *len);
|
||||
ykpiv_rc ykpiv_set_mgmkey2(ykpiv_state *state, const unsigned char *new_key,
|
||||
const unsigned char touch);
|
||||
ykpiv_rc ykpiv_save_object(ykpiv_state *state, int object_id,
|
||||
unsigned char *indata, size_t len);
|
||||
|
||||
@@ -90,6 +96,7 @@ extern "C"
|
||||
#define YKPIV_ALGO_RSA1024 0x06
|
||||
#define YKPIV_ALGO_RSA2048 0x07
|
||||
#define YKPIV_ALGO_ECCP256 0x11
|
||||
#define YKPIV_ALGO_ECCP384 0x14
|
||||
|
||||
#define YKPIV_KEY_AUTHENTICATION 0x9a
|
||||
#define YKPIV_KEY_CARDMGM 0x9b
|
||||
@@ -111,6 +118,27 @@ extern "C"
|
||||
#define YKPIV_OBJ_KEY_HISTORY 0x5fc10c
|
||||
#define YKPIV_OBJ_IRIS 0x5fc121
|
||||
|
||||
#define YKPIV_OBJ_RETIRED1 0x5fc10d
|
||||
#define YKPIV_OBJ_RETIRED2 0x5fc10e
|
||||
#define YKPIV_OBJ_RETIRED3 0x5fc10f
|
||||
#define YKPIV_OBJ_RETIRED4 0x5fc110
|
||||
#define YKPIV_OBJ_RETIRED5 0x5fc111
|
||||
#define YKPIV_OBJ_RETIRED6 0x5fc112
|
||||
#define YKPIV_OBJ_RETIRED7 0x5fc113
|
||||
#define YKPIV_OBJ_RETIRED8 0x5fc114
|
||||
#define YKPIV_OBJ_RETIRED9 0x5fc115
|
||||
#define YKPIV_OBJ_RETIRED10 0x5fc116
|
||||
#define YKPIV_OBJ_RETIRED11 0x5fc117
|
||||
#define YKPIV_OBJ_RETIRED12 0x5fc118
|
||||
#define YKPIV_OBJ_RETIRED13 0x5fc119
|
||||
#define YKPIV_OBJ_RETIRED14 0x5fc11a
|
||||
#define YKPIV_OBJ_RETIRED15 0x5fc11b
|
||||
#define YKPIV_OBJ_RETIRED16 0x5fc11c
|
||||
#define YKPIV_OBJ_RETIRED17 0x5fc11d
|
||||
#define YKPIV_OBJ_RETIRED18 0x5fc11e
|
||||
#define YKPIV_OBJ_RETIRED19 0x5fc11f
|
||||
#define YKPIV_OBJ_RETIRED20 0x5fc120
|
||||
|
||||
#define YKPIV_INS_VERIFY 0x20
|
||||
#define YKPIV_INS_CHANGE_REFERENCE 0x24
|
||||
#define YKPIV_INS_RESET_RETRY 0x2c
|
||||
@@ -126,6 +154,18 @@ extern "C"
|
||||
#define YKPIV_INS_RESET 0xfb
|
||||
#define YKPIV_INS_SET_PIN_RETRIES 0xfa
|
||||
|
||||
#define YKPIV_PINPOLICY_TAG 0xaa
|
||||
#define YKPIV_PINPOLICY_NEVER 1
|
||||
#define YKPIV_PINPOLICY_ONCE 2
|
||||
#define YKPIV_PINPOLICY_ALWAYS 3
|
||||
|
||||
#define YKPIV_TOUCHPOLICY_TAG 0xab
|
||||
#define YKPIV_TOUCHPOLICY_NEVER 1
|
||||
#define YKPIV_TOUCHPOLICY_ALWAYS 2
|
||||
|
||||
#define YKPIV_IS_EC(a) ((a == YKPIV_ALGO_ECCP256 || a == YKPIV_ALGO_ECCP384))
|
||||
#define YKPIV_IS_RSA(a) ((a == YKPIV_ALGO_RSA1024 || a == YKPIV_ALGO_RSA2048))
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -54,3 +54,10 @@ YKPIV_0.2.0
|
||||
global:
|
||||
ykpiv_decipher_data;
|
||||
} YKPIV_0.1.0;
|
||||
|
||||
YKPIV_1.1.0
|
||||
{
|
||||
global:
|
||||
ykpiv_set_mgmkey2;
|
||||
ykpiv_list_readers;
|
||||
} YKPIV_0.1.0;
|
||||
|
||||
@@ -132,7 +132,6 @@ AC_DEFUN([gl_MANYWARN_ALL_GCC],
|
||||
-Wstack-protector \
|
||||
-Woverlength-strings \
|
||||
-Wbuiltin-macro-redefined \
|
||||
-Wmudflap \
|
||||
-Wpacked-bitfield-compat \
|
||||
-Wsync-nand \
|
||||
; do
|
||||
|
||||
@@ -65,8 +65,11 @@ doit:
|
||||
chmod u+w $(PWD)/tmp/root/lib/libcrypto.1.0.0.dylib && \
|
||||
install_name_tool -id @executable_path/../lib/libcrypto.1.0.0.dylib $(PWD)/tmp/root/lib/libcrypto.1.0.0.dylib && \
|
||||
install_name_tool -id @executable_path/../lib/libykpiv.1.dylib $(PWD)/tmp/root/lib/libykpiv.1.dylib && \
|
||||
install_name_tool -id @executable_path/../lib/libykcs11.1.dylib $(PWD)/tmp/root/lib/libykcs11.1.dylib && \
|
||||
install_name_tool -change $(PWD)/tmp/root/lib/libcrypto.1.0.0.dylib @executable_path/../lib/libcrypto.1.0.0.dylib $(PWD)/tmp/root/lib/libykpiv.1.dylib && \
|
||||
install_name_tool -change $(PWD)/tmp/root/lib/libcrypto.1.0.0.dylib @executable_path/../lib/libcrypto.1.0.0.dylib $(PWD)/tmp/root/lib/libykcs11.1.dylib && \
|
||||
install_name_tool -change $(PWD)/tmp/root/lib/libcrypto.1.0.0.dylib @executable_path/../lib/libcrypto.1.0.0.dylib $(PWD)/tmp/root/bin/yubico-piv-tool && \
|
||||
install_name_tool -change $(PWD)/tmp/root/lib/libykpiv.1.dylib @executable_path/../lib/libykpiv.1.dylib $(PWD)/tmp/root/lib/libykcs11.1.dylib && \
|
||||
install_name_tool -change $(PWD)/tmp/root/lib/libykpiv.1.dylib @executable_path/../lib/libykpiv.1.dylib $(PWD)/tmp/root/bin/yubico-piv-tool ; \
|
||||
if otool -L $(PWD)/tmp/root/lib/*.dylib $(PWD)/tmp/root/bin/* | grep '$(PWD)/tmp/root' | grep -q compatibility; then \
|
||||
echo "something is incorrectly linked!"; \
|
||||
|
||||
+8
-5
@@ -32,18 +32,19 @@ option "action" a "Action to take" values="version","generate","set-mgm-key",
|
||||
"reset","pin-retries","import-key","import-certificate","set-chuid",
|
||||
"request-certificate","verify-pin","change-pin","change-puk","unblock-pin",
|
||||
"selfsign-certificate","delete-certificate","read-certificate","status",
|
||||
"test-signature","test-decipher" enum multiple
|
||||
"test-signature","test-decipher","list-readers" enum multiple
|
||||
text "
|
||||
Multiple actions may be given at once and will be executed in order
|
||||
for example --action=verify-pin --action=request-certificate\n"
|
||||
option "slot" s "What key slot to operate on" values="9a","9c","9d","9e" enum optional
|
||||
option "slot" s "What key slot to operate on" values="9a","9c","9d","9e","82","83","84","85","86","87","88","89","8a","8b","8c","8d","8e","8f","90","91","92","93","94","95" enum optional
|
||||
text "
|
||||
9a is for PIV Authentication
|
||||
9c is for Digital Signature (PIN always checked)
|
||||
9d is for Key Management
|
||||
9e is for Card Authentication (PIN never checked)\n"
|
||||
option "algorithm" A "What algorithm to use" values="RSA1024","RSA2048","ECCP256" enum optional default="RSA2048"
|
||||
option "hash" H "Hash to use for signatures" values="SHA1","SHA256","SHA512" enum optional default="SHA256"
|
||||
9e is for Card Authentication (PIN never checked)
|
||||
82-95 is for Retired Key Management\n"
|
||||
option "algorithm" A "What algorithm to use" values="RSA1024","RSA2048","ECCP256","ECCP384" enum optional default="RSA2048"
|
||||
option "hash" H "Hash to use for signatures" values="SHA1","SHA256","SHA384","SHA512" enum optional default="SHA256"
|
||||
option "new-key" n "New authentication key to use" string optional
|
||||
option "pin-retries" - "Number of retries before the pin code is blocked" int optional dependon="puk-retries"
|
||||
option "puk-retries" - "Number of retries before the puk code is blocked" int optional dependon="pin-retries"
|
||||
@@ -57,4 +58,6 @@ text "
|
||||
/CN=host.example.com/OU=test/O=example.com/\n"
|
||||
option "pin" P "Pin/puk code for verification" string optional
|
||||
option "new-pin" N "New pin/puk code for changing" string optional dependon="pin"
|
||||
option "pin-policy" - "Set pin policy for action generate or import-key" values="never","once","always" enum optional
|
||||
option "touch-policy" - "Set touch policy for action generate, import-key or set-mgm-key" values="never","always" enum optional
|
||||
option "sign" - "Sign data" flag off hidden
|
||||
|
||||
+215
@@ -82,6 +82,8 @@ unsigned char get_algorithm(EVP_PKEY *key) {
|
||||
int curve = EC_GROUP_get_curve_name(group);
|
||||
if(curve == NID_X9_62_prime256v1) {
|
||||
return YKPIV_ALGO_ECCP256;
|
||||
} else if(curve == NID_secp384r1) {
|
||||
return YKPIV_ALGO_ECCP384;
|
||||
} else {
|
||||
fprintf(stderr, "Unknown EC curve %d\n", curve);
|
||||
return 0;
|
||||
@@ -200,6 +202,66 @@ int get_object_id(enum enum_slot slot) {
|
||||
case slot_arg_9e:
|
||||
object = YKPIV_OBJ_CARD_AUTH;
|
||||
break;
|
||||
case slot_arg_82:
|
||||
object = YKPIV_OBJ_RETIRED1;
|
||||
break;
|
||||
case slot_arg_83:
|
||||
object = YKPIV_OBJ_RETIRED2;
|
||||
break;
|
||||
case slot_arg_84:
|
||||
object = YKPIV_OBJ_RETIRED3;
|
||||
break;
|
||||
case slot_arg_85:
|
||||
object = YKPIV_OBJ_RETIRED4;
|
||||
break;
|
||||
case slot_arg_86:
|
||||
object = YKPIV_OBJ_RETIRED5;
|
||||
break;
|
||||
case slot_arg_87:
|
||||
object = YKPIV_OBJ_RETIRED6;
|
||||
break;
|
||||
case slot_arg_88:
|
||||
object = YKPIV_OBJ_RETIRED7;
|
||||
break;
|
||||
case slot_arg_89:
|
||||
object = YKPIV_OBJ_RETIRED8;
|
||||
break;
|
||||
case slot_arg_8a:
|
||||
object = YKPIV_OBJ_RETIRED9;
|
||||
break;
|
||||
case slot_arg_8b:
|
||||
object = YKPIV_OBJ_RETIRED10;
|
||||
break;
|
||||
case slot_arg_8c:
|
||||
object = YKPIV_OBJ_RETIRED11;
|
||||
break;
|
||||
case slot_arg_8d:
|
||||
object = YKPIV_OBJ_RETIRED12;
|
||||
break;
|
||||
case slot_arg_8e:
|
||||
object = YKPIV_OBJ_RETIRED13;
|
||||
break;
|
||||
case slot_arg_8f:
|
||||
object = YKPIV_OBJ_RETIRED14;
|
||||
break;
|
||||
case slot_arg_90:
|
||||
object = YKPIV_OBJ_RETIRED15;
|
||||
break;
|
||||
case slot_arg_91:
|
||||
object = YKPIV_OBJ_RETIRED16;
|
||||
break;
|
||||
case slot_arg_92:
|
||||
object = YKPIV_OBJ_RETIRED17;
|
||||
break;
|
||||
case slot_arg_93:
|
||||
object = YKPIV_OBJ_RETIRED18;
|
||||
break;
|
||||
case slot_arg_94:
|
||||
object = YKPIV_OBJ_RETIRED19;
|
||||
break;
|
||||
case slot_arg_95:
|
||||
object = YKPIV_OBJ_RETIRED20;
|
||||
break;
|
||||
case slot__NULL:
|
||||
default:
|
||||
object = 0;
|
||||
@@ -207,6 +269,28 @@ int get_object_id(enum enum_slot slot) {
|
||||
return object;
|
||||
}
|
||||
|
||||
int key_to_object_id(int key) {
|
||||
int object;
|
||||
|
||||
switch(key) {
|
||||
case 0x9a:
|
||||
object = YKPIV_OBJ_AUTHENTICATION;
|
||||
break;
|
||||
case 0x9c:
|
||||
object = YKPIV_OBJ_SIGNATURE;
|
||||
break;
|
||||
case 0x9d:
|
||||
object = YKPIV_OBJ_KEY_MANAGEMENT;
|
||||
break;
|
||||
case 0x9e:
|
||||
object = YKPIV_OBJ_CARD_AUTH;
|
||||
break;
|
||||
default:
|
||||
object = 0;
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
bool set_component_with_len(unsigned char **in_ptr, const BIGNUM *bn, int element_len) {
|
||||
int real_len = BN_num_bytes(bn);
|
||||
*in_ptr += set_length(*in_ptr, element_len);
|
||||
@@ -262,3 +346,134 @@ bool read_pw(const char *name, char *pwbuf, size_t pwbuflen, int verify) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static unsigned const char sha1oid[] = {
|
||||
0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00,
|
||||
0x04, 0x14
|
||||
};
|
||||
|
||||
static unsigned const char sha256oid[] = {
|
||||
0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
|
||||
0x02, 0x01, 0x05, 0x00, 0x04, 0x20
|
||||
};
|
||||
|
||||
static unsigned const char sha384oid[] = {
|
||||
0x30, 0x41, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
|
||||
0x02, 0x02, 0x05, 0x00, 0x04, 0x30
|
||||
};
|
||||
|
||||
static unsigned const char sha512oid[] = {
|
||||
0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
|
||||
0x02, 0x03, 0x05, 0x00, 0x04, 0x40
|
||||
};
|
||||
|
||||
const EVP_MD *get_hash(enum enum_hash hash, const unsigned char **oid, size_t *oid_len) {
|
||||
switch(hash) {
|
||||
case hash_arg_SHA1:
|
||||
if(oid) {
|
||||
*oid = sha1oid;
|
||||
*oid_len = sizeof(sha1oid);
|
||||
}
|
||||
return EVP_sha1();
|
||||
case hash_arg_SHA256:
|
||||
if(oid) {
|
||||
*oid = sha256oid;
|
||||
*oid_len = sizeof(sha256oid);
|
||||
}
|
||||
return EVP_sha256();
|
||||
case hash_arg_SHA384:
|
||||
if(oid) {
|
||||
*oid = sha384oid;
|
||||
*oid_len = sizeof(sha384oid);
|
||||
}
|
||||
return EVP_sha384();
|
||||
case hash_arg_SHA512:
|
||||
if(oid) {
|
||||
*oid = sha512oid;
|
||||
*oid_len = sizeof(sha512oid);
|
||||
}
|
||||
return EVP_sha512();
|
||||
case hash__NULL:
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int get_hashnid(enum enum_hash hash, unsigned char algorithm) {
|
||||
switch(algorithm) {
|
||||
case YKPIV_ALGO_RSA1024:
|
||||
case YKPIV_ALGO_RSA2048:
|
||||
switch(hash) {
|
||||
case hash_arg_SHA1:
|
||||
return NID_sha1WithRSAEncryption;
|
||||
case hash_arg_SHA256:
|
||||
return NID_sha256WithRSAEncryption;
|
||||
case hash_arg_SHA384:
|
||||
return NID_sha384WithRSAEncryption;
|
||||
case hash_arg_SHA512:
|
||||
return NID_sha512WithRSAEncryption;
|
||||
case hash__NULL:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
case YKPIV_ALGO_ECCP256:
|
||||
case YKPIV_ALGO_ECCP384:
|
||||
switch(hash) {
|
||||
case hash_arg_SHA1:
|
||||
return NID_ecdsa_with_SHA1;
|
||||
case hash_arg_SHA256:
|
||||
return NID_ecdsa_with_SHA256;
|
||||
case hash_arg_SHA384:
|
||||
return NID_ecdsa_with_SHA384;
|
||||
case hash_arg_SHA512:
|
||||
return NID_ecdsa_with_SHA512;
|
||||
case hash__NULL:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char get_piv_algorithm(enum enum_algorithm algorithm) {
|
||||
switch(algorithm) {
|
||||
case algorithm_arg_RSA2048:
|
||||
return YKPIV_ALGO_RSA2048;
|
||||
case algorithm_arg_RSA1024:
|
||||
return YKPIV_ALGO_RSA1024;
|
||||
case algorithm_arg_ECCP256:
|
||||
return YKPIV_ALGO_ECCP256;
|
||||
case algorithm_arg_ECCP384:
|
||||
return YKPIV_ALGO_ECCP384;
|
||||
case algorithm__NULL:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char get_pin_policy(enum enum_pin_policy policy) {
|
||||
switch(policy) {
|
||||
case pin_policy_arg_never:
|
||||
return YKPIV_PINPOLICY_NEVER;
|
||||
case pin_policy_arg_once:
|
||||
return YKPIV_PINPOLICY_ONCE;
|
||||
case pin_policy_arg_always:
|
||||
return YKPIV_PINPOLICY_ALWAYS;
|
||||
case pin_policy__NULL:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char get_touch_policy(enum enum_touch_policy policy) {
|
||||
switch(policy) {
|
||||
case touch_policy_arg_never:
|
||||
return YKPIV_TOUCHPOLICY_NEVER;
|
||||
case touch_policy_arg_always:
|
||||
return YKPIV_TOUCHPOLICY_ALWAYS;
|
||||
case touch_policy__NULL:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,9 +45,15 @@ X509_NAME *parse_name(const char*);
|
||||
unsigned char get_algorithm(EVP_PKEY*);
|
||||
FILE *open_file(const char*, int);
|
||||
int get_object_id(enum enum_slot slot);
|
||||
int key_to_object_id(int key);
|
||||
bool set_component_with_len(unsigned char**, const BIGNUM*, int);
|
||||
bool prepare_rsa_signature(const unsigned char*, unsigned int, unsigned char*,
|
||||
unsigned int*, int);
|
||||
bool read_pw(const char*, char*, size_t, int);
|
||||
const EVP_MD *get_hash(enum enum_hash, const unsigned char**, size_t*);
|
||||
int get_hashnid(enum enum_hash, unsigned char);
|
||||
unsigned char get_piv_algorithm(enum enum_algorithm);
|
||||
unsigned char get_pin_policy(enum enum_pin_policy);
|
||||
unsigned char get_touch_policy(enum enum_touch_policy);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
For more information about what's happening --verbose can be added
|
||||
to any command. For much more information --verbose=2 may be used.
|
||||
|
||||
Display what version of the applet is running on the YubiKey Neo:
|
||||
Display what version of the application is running on the YubiKey:
|
||||
|
||||
yubico-piv-tool -a version
|
||||
|
||||
|
||||
+198
-233
@@ -63,20 +63,7 @@ unsigned const char chuid_tmpl[] = {
|
||||
};
|
||||
#define CHUID_GUID_OFFS 29
|
||||
|
||||
unsigned const char sha1oid[] = {
|
||||
0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00,
|
||||
0x04, 0x14
|
||||
};
|
||||
|
||||
unsigned const char sha256oid[] = {
|
||||
0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
|
||||
0x02, 0x01, 0x05, 0x00, 0x04, 0x20
|
||||
};
|
||||
|
||||
unsigned const char sha512oid[] = {
|
||||
0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04,
|
||||
0x02, 0x03, 0x05, 0x00, 0x04, 0x40
|
||||
};
|
||||
#define MAX_OID_LEN 19
|
||||
|
||||
#define KEY_LEN 24
|
||||
|
||||
@@ -88,9 +75,9 @@ static void print_version(ykpiv_state *state, const char *output_file_name) {
|
||||
}
|
||||
|
||||
if(ykpiv_get_version(state, version, sizeof(version)) == YKPIV_OK) {
|
||||
fprintf(output_file, "Applet version %s found.\n", version);
|
||||
fprintf(output_file, "Application version %s found.\n", version);
|
||||
} else {
|
||||
fprintf(stderr, "Failed to retrieve applet version.\n");
|
||||
fprintf(stderr, "Failed to retrieve application version.\n");
|
||||
}
|
||||
|
||||
if(output_file != stdout) {
|
||||
@@ -98,10 +85,31 @@ static void print_version(ykpiv_state *state, const char *output_file_name) {
|
||||
}
|
||||
}
|
||||
|
||||
static bool sign_data(ykpiv_state *state, const unsigned char *in, size_t len, unsigned char *out,
|
||||
size_t *out_len, unsigned char algorithm, int key) {
|
||||
|
||||
unsigned char signinput[1024];
|
||||
if(YKPIV_IS_RSA(algorithm)) {
|
||||
size_t padlen = algorithm == YKPIV_ALGO_RSA1024 ? 128 : 256;
|
||||
if(RSA_padding_add_PKCS1_type_1(signinput, padlen, in, len) == 0) {
|
||||
fprintf(stderr, "Failed adding padding.\n");
|
||||
return false;
|
||||
}
|
||||
in = signinput;
|
||||
len = padlen;
|
||||
}
|
||||
if(ykpiv_sign_data(state, in, len, out, out_len, algorithm, key) == YKPIV_OK) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool generate_key(ykpiv_state *state, const char *slot,
|
||||
enum enum_algorithm algorithm, const char *output_file_name,
|
||||
enum enum_key_format key_format) {
|
||||
unsigned char in_data[5];
|
||||
enum enum_key_format key_format, enum enum_pin_policy pin_policy,
|
||||
enum enum_touch_policy touch_policy) {
|
||||
unsigned char in_data[11];
|
||||
unsigned char *in_ptr = in_data;
|
||||
unsigned char data[1024];
|
||||
unsigned char templ[] = {0, YKPIV_INS_GENERATE_ASYMMERTRIC, 0, 0};
|
||||
unsigned long recv_len = sizeof(data);
|
||||
@@ -124,31 +132,46 @@ static bool generate_key(ykpiv_state *state, const char *slot,
|
||||
return false;
|
||||
}
|
||||
|
||||
in_data[0] = 0xac;
|
||||
in_data[1] = 3;
|
||||
in_data[2] = 0x80;
|
||||
in_data[3] = 1;
|
||||
switch(algorithm) {
|
||||
case algorithm_arg_RSA2048:
|
||||
in_data[4] = YKPIV_ALGO_RSA2048;
|
||||
break;
|
||||
case algorithm_arg_RSA1024:
|
||||
in_data[4] = YKPIV_ALGO_RSA1024;
|
||||
break;
|
||||
case algorithm_arg_ECCP256:
|
||||
in_data[4] = YKPIV_ALGO_ECCP256;
|
||||
break;
|
||||
case algorithm__NULL:
|
||||
default:
|
||||
*in_ptr++ = 0xac;
|
||||
*in_ptr++ = 3;
|
||||
*in_ptr++ = 0x80;
|
||||
*in_ptr++ = 1;
|
||||
*in_ptr++ = get_piv_algorithm(algorithm);
|
||||
if(in_data[4] == 0) {
|
||||
fprintf(stderr, "Unexepcted algorithm.\n");
|
||||
goto generate_out;
|
||||
}
|
||||
if(ykpiv_transfer_data(state, templ, in_data, sizeof(in_data), data,
|
||||
if(pin_policy != pin_policy__NULL) {
|
||||
in_data[1] += 3;
|
||||
*in_ptr++ = YKPIV_PINPOLICY_TAG;
|
||||
*in_ptr++ = 1;
|
||||
*in_ptr++ = get_pin_policy(pin_policy);
|
||||
}
|
||||
if(touch_policy != touch_policy__NULL) {
|
||||
in_data[1] += 3;
|
||||
*in_ptr++ = YKPIV_TOUCHPOLICY_TAG;
|
||||
*in_ptr++ = 1;
|
||||
*in_ptr++ = get_touch_policy(touch_policy);
|
||||
}
|
||||
if(ykpiv_transfer_data(state, templ, in_data, in_ptr - in_data, data,
|
||||
&recv_len, &sw) != YKPIV_OK) {
|
||||
fprintf(stderr, "Failed to communicate.\n");
|
||||
goto generate_out;
|
||||
} else if(sw != 0x9000) {
|
||||
fprintf(stderr, "Failed to generate new key.\n");
|
||||
fprintf(stderr, "Failed to generate new key (");
|
||||
if(sw == 0x6b00) {
|
||||
fprintf(stderr, "slot not supported?)\n");
|
||||
} else if(sw == 0x6a80) {
|
||||
if(pin_policy != pin_policy__NULL) {
|
||||
fprintf(stderr, "pin policy not supported?)\n");
|
||||
} else if(touch_policy != touch_policy__NULL) {
|
||||
fprintf(stderr, "touch policy not supported?)\n");
|
||||
} else {
|
||||
fprintf(stderr, "algorithm not supported?)\n");
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "error %x)\n", sw);
|
||||
}
|
||||
goto generate_out;
|
||||
}
|
||||
|
||||
@@ -187,24 +210,34 @@ static bool generate_key(ykpiv_state *state, const char *slot,
|
||||
rsa->n = bignum_n;
|
||||
rsa->e = bignum_e;
|
||||
EVP_PKEY_set1_RSA(public_key, rsa);
|
||||
} else if(algorithm == algorithm_arg_ECCP256) {
|
||||
} else if(algorithm == algorithm_arg_ECCP256 || algorithm == algorithm_arg_ECCP384) {
|
||||
EC_GROUP *group;
|
||||
unsigned char *data_ptr = data + 3;
|
||||
int nid;
|
||||
size_t len;
|
||||
|
||||
if(algorithm == algorithm_arg_ECCP256) {
|
||||
nid = NID_X9_62_prime256v1;
|
||||
len = 65;
|
||||
} else {
|
||||
nid = NID_secp384r1;
|
||||
len = 97;
|
||||
}
|
||||
|
||||
eckey = EC_KEY_new();
|
||||
group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
EC_GROUP_set_asn1_flag(group, NID_X9_62_prime256v1);
|
||||
group = EC_GROUP_new_by_curve_name(nid);
|
||||
EC_GROUP_set_asn1_flag(group, nid);
|
||||
EC_KEY_set_group(eckey, group);
|
||||
point = EC_POINT_new(group);
|
||||
if(*data_ptr++ != 0x86) {
|
||||
fprintf(stderr, "Failed to parse public key structure.\n");
|
||||
goto generate_out;
|
||||
}
|
||||
if(*data_ptr++ != 65) { /* the curve point should always be 65 bytes */
|
||||
if(*data_ptr++ != len) { /* the curve point should always be 65 bytes */
|
||||
fprintf(stderr, "Unexpected length.\n");
|
||||
goto generate_out;
|
||||
}
|
||||
if(!EC_POINT_oct2point(group, point, data_ptr, 65, NULL)) {
|
||||
if(!EC_POINT_oct2point(group, point, data_ptr, len, NULL)) {
|
||||
fprintf(stderr, "Failed to load public point.\n");
|
||||
goto generate_out;
|
||||
}
|
||||
@@ -283,7 +316,8 @@ static bool set_pin_retries(ykpiv_state *state, int pin_retries, int puk_retries
|
||||
}
|
||||
|
||||
static bool import_key(ykpiv_state *state, enum enum_key_format key_format,
|
||||
const char *input_file_name, const char *slot, char *password) {
|
||||
const char *input_file_name, const char *slot, char *password,
|
||||
enum enum_pin_policy pin_policy, enum enum_touch_policy touch_policy) {
|
||||
int key = 0;
|
||||
FILE *input_file = NULL;
|
||||
EVP_PKEY *private_key = NULL;
|
||||
@@ -336,7 +370,7 @@ static bool import_key(ykpiv_state *state, enum enum_key_format key_format,
|
||||
unsigned char *in_ptr = in_data;
|
||||
unsigned char templ[] = {0, YKPIV_INS_IMPORT_KEY, algorithm, key};
|
||||
int sw;
|
||||
if(algorithm == YKPIV_ALGO_RSA1024 || algorithm == YKPIV_ALGO_RSA2048) {
|
||||
if(YKPIV_IS_RSA(algorithm)) {
|
||||
RSA *rsa_private_key = EVP_PKEY_get1_RSA(private_key);
|
||||
unsigned char e[4];
|
||||
unsigned char *e_ptr = e;
|
||||
@@ -380,20 +414,45 @@ static bool import_key(ykpiv_state *state, enum enum_key_format key_format,
|
||||
fprintf(stderr, "Failed setting iqmp component.\n");
|
||||
goto import_out;
|
||||
}
|
||||
} else if(algorithm == YKPIV_ALGO_ECCP256) {
|
||||
} else if(YKPIV_IS_EC(algorithm)) {
|
||||
EC_KEY *ec = EVP_PKEY_get1_EC_KEY(private_key);
|
||||
const BIGNUM *s = EC_KEY_get0_private_key(ec);
|
||||
int element_len = 32;
|
||||
|
||||
if(algorithm == YKPIV_ALGO_ECCP384) {
|
||||
element_len = 48;
|
||||
}
|
||||
|
||||
*in_ptr++ = 0x06;
|
||||
if(set_component_with_len(&in_ptr, s, 32) == false) {
|
||||
if(set_component_with_len(&in_ptr, s, element_len) == false) {
|
||||
fprintf(stderr, "Failed setting ec private key.\n");
|
||||
goto import_out;
|
||||
}
|
||||
}
|
||||
|
||||
if(pin_policy != pin_policy__NULL) {
|
||||
*in_ptr++ = YKPIV_PINPOLICY_TAG;
|
||||
*in_ptr++ = 1;
|
||||
*in_ptr++ = get_pin_policy(pin_policy);
|
||||
}
|
||||
if(touch_policy != touch_policy__NULL) {
|
||||
*in_ptr++ = YKPIV_TOUCHPOLICY_TAG;
|
||||
*in_ptr++ = 1;
|
||||
*in_ptr++ = get_touch_policy(touch_policy);
|
||||
}
|
||||
|
||||
if(ykpiv_transfer_data(state, templ, in_data, in_ptr - in_data, data,
|
||||
&recv_len, &sw) != YKPIV_OK) {
|
||||
return false;
|
||||
} else if(sw == 0x6a80) {
|
||||
fprintf(stderr, "Failed import.");
|
||||
if(pin_policy != pin_policy__NULL) {
|
||||
fprintf(stderr, "Maybe pin-policy is not supported on this key?\n");
|
||||
} else if(touch_policy != touch_policy__NULL) {
|
||||
fprintf(stderr, "Maybe touch-policy is not supported on this key?\n");
|
||||
} else {
|
||||
fprintf(stderr, "Maybe algorithm is not supported on this key?\n");
|
||||
}
|
||||
} else if(sw != 0x9000) {
|
||||
fprintf(stderr, "Failed import command with code %x.\n", sw);
|
||||
} else {
|
||||
@@ -559,7 +618,7 @@ static bool request_certificate(ykpiv_state *state, enum enum_key_format key_for
|
||||
EVP_PKEY *public_key = NULL;
|
||||
const EVP_MD *md;
|
||||
bool ret = false;
|
||||
unsigned char digest[EVP_MAX_MD_SIZE + sizeof(sha512oid)]; // maximum..
|
||||
unsigned char digest[EVP_MAX_MD_SIZE + MAX_OID_LEN];
|
||||
unsigned int digest_len;
|
||||
unsigned int md_len;
|
||||
unsigned char algorithm;
|
||||
@@ -597,24 +656,8 @@ static bool request_certificate(ykpiv_state *state, enum enum_key_format key_for
|
||||
goto request_out;
|
||||
}
|
||||
|
||||
switch(hash) {
|
||||
case hash_arg_SHA1:
|
||||
md = EVP_sha1();
|
||||
oid = sha1oid;
|
||||
oid_len = sizeof(sha1oid);
|
||||
break;
|
||||
case hash_arg_SHA256:
|
||||
md = EVP_sha256();
|
||||
oid = sha256oid;
|
||||
oid_len = sizeof(sha256oid);
|
||||
break;
|
||||
case hash_arg_SHA512:
|
||||
md = EVP_sha512();
|
||||
oid = sha512oid;
|
||||
oid_len = sizeof(sha512oid);
|
||||
break;
|
||||
case hash__NULL:
|
||||
default:
|
||||
md = get_hash(hash, &oid, &oid_len);
|
||||
if(md == NULL) {
|
||||
goto request_out;
|
||||
}
|
||||
|
||||
@@ -651,54 +694,24 @@ static bool request_certificate(ykpiv_state *state, enum enum_key_format key_for
|
||||
goto request_out;
|
||||
}
|
||||
|
||||
switch(algorithm) {
|
||||
case YKPIV_ALGO_RSA1024:
|
||||
case YKPIV_ALGO_RSA2048:
|
||||
nid = get_hashnid(hash, algorithm);
|
||||
if(nid == 0) {
|
||||
fprintf(stderr, "Unsupported algorithm %x or hash %x\n", algorithm, hash);
|
||||
goto request_out;
|
||||
}
|
||||
if(YKPIV_IS_RSA(algorithm)) {
|
||||
signinput = digest;
|
||||
len = oid_len + digest_len;
|
||||
switch(hash) {
|
||||
case hash_arg_SHA1:
|
||||
nid = NID_sha1WithRSAEncryption;
|
||||
break;
|
||||
case hash_arg_SHA256:
|
||||
nid = NID_sha256WithRSAEncryption;
|
||||
break;
|
||||
case hash_arg_SHA512:
|
||||
nid = NID_sha512WithRSAEncryption;
|
||||
break;
|
||||
case hash__NULL:
|
||||
default:
|
||||
goto request_out;
|
||||
}
|
||||
break;
|
||||
case YKPIV_ALGO_ECCP256:
|
||||
} else {
|
||||
signinput = digest + oid_len;
|
||||
len = digest_len;
|
||||
switch(hash) {
|
||||
case hash_arg_SHA1:
|
||||
nid = NID_ecdsa_with_SHA1;
|
||||
break;
|
||||
case hash_arg_SHA256:
|
||||
nid = NID_ecdsa_with_SHA256;
|
||||
break;
|
||||
case hash_arg_SHA512:
|
||||
nid = NID_ecdsa_with_SHA512;
|
||||
break;
|
||||
case hash__NULL:
|
||||
default:
|
||||
goto request_out;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported algorithm %x.\n", algorithm);
|
||||
goto request_out;
|
||||
}
|
||||
|
||||
req->sig_alg->algorithm = OBJ_nid2obj(nid);
|
||||
{
|
||||
unsigned char signature[1024];
|
||||
size_t sig_len = sizeof(signature);
|
||||
if(ykpiv_sign_data(state, signinput, len, signature, &sig_len, algorithm, key)
|
||||
!= YKPIV_OK) {
|
||||
if(!sign_data(state, signinput, len, signature, &sig_len, algorithm, key)) {
|
||||
fprintf(stderr, "Failed signing request.\n");
|
||||
goto request_out;
|
||||
}
|
||||
@@ -743,7 +756,7 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo
|
||||
X509 *x509 = NULL;
|
||||
X509_NAME *name = NULL;
|
||||
const EVP_MD *md;
|
||||
unsigned char digest[EVP_MAX_MD_SIZE + sizeof(sha512oid)];
|
||||
unsigned char digest[EVP_MAX_MD_SIZE + MAX_OID_LEN];
|
||||
unsigned int digest_len;
|
||||
unsigned char algorithm;
|
||||
int key = 0;
|
||||
@@ -781,27 +794,10 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo
|
||||
goto selfsign_out;
|
||||
}
|
||||
|
||||
switch(hash) {
|
||||
case hash_arg_SHA1:
|
||||
md = EVP_sha1();
|
||||
oid = sha1oid;
|
||||
oid_len = sizeof(sha1oid);
|
||||
break;
|
||||
case hash_arg_SHA256:
|
||||
md = EVP_sha256();
|
||||
oid = sha256oid;
|
||||
oid_len = sizeof(sha256oid);
|
||||
break;
|
||||
case hash_arg_SHA512:
|
||||
md = EVP_sha512();
|
||||
oid = sha512oid;
|
||||
oid_len = sizeof(sha512oid);
|
||||
break;
|
||||
case hash__NULL:
|
||||
default:
|
||||
md = get_hash(hash, &oid, &oid_len);
|
||||
if(md == NULL) {
|
||||
goto selfsign_out;
|
||||
}
|
||||
|
||||
md_len = (unsigned int)EVP_MD_size(md);
|
||||
digest_len = sizeof(digest) - md_len;
|
||||
|
||||
@@ -843,48 +839,18 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo
|
||||
fprintf(stderr, "Failed setting certificate issuer.\n");
|
||||
goto selfsign_out;
|
||||
}
|
||||
switch(algorithm) {
|
||||
case YKPIV_ALGO_RSA1024:
|
||||
case YKPIV_ALGO_RSA2048:
|
||||
nid = get_hashnid(hash, algorithm);
|
||||
if(nid == 0) {
|
||||
goto selfsign_out;
|
||||
}
|
||||
if(YKPIV_IS_RSA(algorithm)) {
|
||||
signinput = digest;
|
||||
len = oid_len + md_len;
|
||||
switch(hash) {
|
||||
case hash_arg_SHA1:
|
||||
nid = NID_sha1WithRSAEncryption;
|
||||
break;
|
||||
case hash_arg_SHA256:
|
||||
nid = NID_sha256WithRSAEncryption;
|
||||
break;
|
||||
case hash_arg_SHA512:
|
||||
nid = NID_sha512WithRSAEncryption;
|
||||
break;
|
||||
case hash__NULL:
|
||||
default:
|
||||
goto selfsign_out;
|
||||
}
|
||||
break;
|
||||
case YKPIV_ALGO_ECCP256:
|
||||
} else {
|
||||
signinput = digest + oid_len;
|
||||
len = md_len;
|
||||
switch(hash) {
|
||||
case hash_arg_SHA1:
|
||||
nid = NID_ecdsa_with_SHA1;
|
||||
break;
|
||||
case hash_arg_SHA256:
|
||||
nid = NID_ecdsa_with_SHA256;
|
||||
break;
|
||||
case hash_arg_SHA512:
|
||||
nid = NID_ecdsa_with_SHA512;
|
||||
break;
|
||||
case hash__NULL:
|
||||
default:
|
||||
goto selfsign_out;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unsupported algorithm %x.\n", algorithm);
|
||||
goto selfsign_out;
|
||||
}
|
||||
|
||||
x509->sig_alg->algorithm = OBJ_nid2obj(nid);
|
||||
x509->cert_info->signature->algorithm = x509->sig_alg->algorithm;
|
||||
memcpy(digest, oid, oid_len);
|
||||
@@ -897,8 +863,7 @@ static bool selfsign_certificate(ykpiv_state *state, enum enum_key_format key_fo
|
||||
{
|
||||
unsigned char signature[1024];
|
||||
size_t sig_len = sizeof(signature);
|
||||
if(ykpiv_sign_data(state, signinput, len, signature, &sig_len, algorithm, key)
|
||||
!= YKPIV_OK) {
|
||||
if(!sign_data(state, signinput, len, signature, &sig_len, algorithm, key)) {
|
||||
fprintf(stderr, "Failed signing certificate.\n");
|
||||
goto selfsign_out;
|
||||
}
|
||||
@@ -1028,7 +993,7 @@ static bool change_pin(ykpiv_state *state, enum enum_action action, const char *
|
||||
if(action == action_arg_changeMINUS_pin) {
|
||||
fprintf(stderr, "The pin code is blocked, use the unblock-pin action to unblock it.\n");
|
||||
} else {
|
||||
fprintf(stderr, "The puk code is blocked, you will have to reinitialize the applet.\n");
|
||||
fprintf(stderr, "The puk code is blocked, you will have to reinitialize the application.\n");
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Failed changing/unblocking code, error: %x\n", sw);
|
||||
@@ -1138,36 +1103,16 @@ static bool sign_file(ykpiv_state *state, const char *input, const char *output,
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(algorithm) {
|
||||
case algorithm_arg_RSA2048:
|
||||
algo = YKPIV_ALGO_RSA2048;
|
||||
break;
|
||||
case algorithm_arg_RSA1024:
|
||||
algo = YKPIV_ALGO_RSA1024;
|
||||
break;
|
||||
case algorithm_arg_ECCP256:
|
||||
algo = YKPIV_ALGO_ECCP256;
|
||||
break;
|
||||
case algorithm__NULL:
|
||||
default:
|
||||
algo = get_piv_algorithm(algorithm);
|
||||
if(algo == 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
{
|
||||
EVP_MD_CTX *mdctx;
|
||||
|
||||
switch(hash) {
|
||||
case hash_arg_SHA1:
|
||||
md = EVP_sha1();
|
||||
break;
|
||||
case hash_arg_SHA256:
|
||||
md = EVP_sha256();
|
||||
break;
|
||||
case hash_arg_SHA512:
|
||||
md = EVP_sha512();
|
||||
break;
|
||||
case hash__NULL:
|
||||
default:
|
||||
md = get_hash(hash, NULL, NULL);
|
||||
if(md == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1187,16 +1132,15 @@ static bool sign_file(ykpiv_state *state, const char *input, const char *output,
|
||||
EVP_MD_CTX_destroy(mdctx);
|
||||
}
|
||||
|
||||
if(algo == YKPIV_ALGO_RSA1024 || algo == YKPIV_ALGO_RSA2048) {
|
||||
if(YKPIV_IS_RSA(algo)) {
|
||||
prepare_rsa_signature(hashed, hash_len, hashed, &hash_len, EVP_MD_type(md));
|
||||
}
|
||||
|
||||
{
|
||||
unsigned char buf[1024];
|
||||
size_t len = sizeof(buf);
|
||||
ykpiv_rc rc = ykpiv_sign_data(state, hashed, hash_len, buf, &len, algo, key);
|
||||
if(rc != YKPIV_OK) {
|
||||
fprintf(stderr, "failed signing file: %s\n", ykpiv_strerror(rc));
|
||||
if(!sign_data(state, hashed, hash_len, buf, &len, algo, key)) {
|
||||
fprintf(stderr, "failed signing file\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1268,6 +1212,9 @@ static void print_cert_info(ykpiv_state *state, enum enum_slot slot, const EVP_M
|
||||
case YKPIV_ALGO_ECCP256:
|
||||
fprintf(output, "ECCP256\n");
|
||||
break;
|
||||
case YKPIV_ALGO_ECCP384:
|
||||
fprintf(output, "ECCP384\n");
|
||||
break;
|
||||
default:
|
||||
fprintf(output, "Unknown\n");
|
||||
}
|
||||
@@ -1328,18 +1275,8 @@ static bool status(ykpiv_state *state, enum enum_hash hash,
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(hash) {
|
||||
case hash_arg_SHA1:
|
||||
md = EVP_sha1();
|
||||
break;
|
||||
case hash_arg_SHA256:
|
||||
md = EVP_sha256();
|
||||
break;
|
||||
case hash_arg_SHA512:
|
||||
md = EVP_sha512();
|
||||
break;
|
||||
case hash__NULL:
|
||||
default:
|
||||
md = get_hash(hash, NULL, NULL);
|
||||
if(md == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1404,18 +1341,8 @@ static bool test_signature(ykpiv_state *state, enum enum_slot slot,
|
||||
goto test_out;
|
||||
}
|
||||
|
||||
switch(hash) {
|
||||
case hash_arg_SHA1:
|
||||
md = EVP_sha1();
|
||||
break;
|
||||
case hash_arg_SHA256:
|
||||
md = EVP_sha256();
|
||||
break;
|
||||
case hash_arg_SHA512:
|
||||
md = EVP_sha512();
|
||||
break;
|
||||
case hash__NULL:
|
||||
default:
|
||||
md = get_hash(hash, NULL, NULL);
|
||||
if(md == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1456,14 +1383,13 @@ static bool test_signature(ykpiv_state *state, enum enum_slot slot,
|
||||
goto test_out;
|
||||
}
|
||||
sscanf(cmdline_parser_slot_values[slot], "%2x", &key);
|
||||
if(algorithm == YKPIV_ALGO_RSA1024 || algorithm == YKPIV_ALGO_RSA2048) {
|
||||
if(YKPIV_IS_RSA(algorithm)) {
|
||||
prepare_rsa_signature(data, data_len, encoded, &enc_len, EVP_MD_type(md));
|
||||
ptr = encoded;
|
||||
} else {
|
||||
enc_len = data_len;
|
||||
}
|
||||
if(ykpiv_sign_data(state, ptr, enc_len, signature, &sig_len, algorithm, key)
|
||||
!= YKPIV_OK) {
|
||||
if(!sign_data(state, ptr, enc_len, signature, &sig_len, algorithm, key)) {
|
||||
fprintf(stderr, "Failed signing test data.\n");
|
||||
goto test_out;
|
||||
}
|
||||
@@ -1490,6 +1416,7 @@ static bool test_signature(ykpiv_state *state, enum enum_slot slot,
|
||||
|
||||
break;
|
||||
case YKPIV_ALGO_ECCP256:
|
||||
case YKPIV_ALGO_ECCP384:
|
||||
{
|
||||
EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pubkey);
|
||||
if(ECDSA_verify(0, data, (int)data_len, signature, (int)sig_len, ec) == 1) {
|
||||
@@ -1561,7 +1488,7 @@ static bool test_decipher(ykpiv_state *state, enum enum_slot slot,
|
||||
goto decipher_out;
|
||||
}
|
||||
sscanf(cmdline_parser_slot_values[slot], "%2x", &key);
|
||||
if(algorithm == YKPIV_ALGO_RSA1024 || algorithm == YKPIV_ALGO_RSA2048) {
|
||||
if(YKPIV_IS_RSA(algorithm)) {
|
||||
unsigned char secret[32];
|
||||
unsigned char secret2[32];
|
||||
unsigned char data[256];
|
||||
@@ -1602,20 +1529,30 @@ static bool test_decipher(ykpiv_state *state, enum enum_slot slot,
|
||||
} else {
|
||||
fprintf(stderr, "Failed unwrapping PKCS1 envelope.\n");
|
||||
}
|
||||
} else {
|
||||
unsigned char secret[32];
|
||||
unsigned char secret2[32];
|
||||
unsigned char public_key[65];
|
||||
} else if(YKPIV_IS_EC(algorithm)) {
|
||||
unsigned char secret[48];
|
||||
unsigned char secret2[48];
|
||||
unsigned char public_key[97];
|
||||
unsigned char *ptr = public_key;
|
||||
size_t len = sizeof(secret);
|
||||
EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pubkey);
|
||||
int nid;
|
||||
size_t key_len;
|
||||
|
||||
tmpkey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
if(algorithm == YKPIV_ALGO_ECCP256) {
|
||||
nid = NID_X9_62_prime256v1;
|
||||
key_len = 32;
|
||||
} else {
|
||||
nid = NID_secp384r1;
|
||||
key_len = 48;
|
||||
}
|
||||
|
||||
tmpkey = EC_KEY_new_by_curve_name(nid);
|
||||
EC_KEY_generate_key(tmpkey);
|
||||
ECDH_compute_key(secret, len, EC_KEY_get0_public_key(ec), tmpkey, NULL);
|
||||
|
||||
i2o_ECPublicKey(tmpkey, &ptr);
|
||||
if(ykpiv_decipher_data(state, public_key, sizeof(public_key), secret2, &len, algorithm, key) != YKPIV_OK) {
|
||||
if(ykpiv_decipher_data(state, public_key, (key_len * 2) + 1, secret2, &len, algorithm, key) != YKPIV_OK) {
|
||||
fprintf(stderr, "Failed ECDH exchange!\n");
|
||||
goto decipher_out;
|
||||
}
|
||||
@@ -1625,7 +1562,7 @@ static bool test_decipher(ykpiv_state *state, enum enum_slot slot,
|
||||
fprintf(stderr, "ECDH card generated: ");
|
||||
dump_hex(secret2, len, stderr, true);
|
||||
}
|
||||
if(memcmp(secret, secret2, 32) == 0) {
|
||||
if(memcmp(secret, secret2, key_len) == 0) {
|
||||
fprintf(stderr, "Successfully performed ECDH exchange with card.\n");
|
||||
ret = true;
|
||||
} else {
|
||||
@@ -1647,6 +1584,21 @@ decipher_out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool list_readers(ykpiv_state *state) {
|
||||
char readers[2048];
|
||||
char *reader_ptr;
|
||||
size_t len = sizeof(readers);
|
||||
ykpiv_rc rc = ykpiv_list_readers(state, readers, &len);
|
||||
if(rc != YKPIV_OK) {
|
||||
fprintf(stderr, "Failed listing readers.\n");
|
||||
return false;
|
||||
}
|
||||
for(reader_ptr = readers; *reader_ptr != '\0'; reader_ptr += strlen(reader_ptr) + 1) {
|
||||
printf("%s\n", reader_ptr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
struct gengetopt_args_info args_info;
|
||||
ykpiv_state *state;
|
||||
@@ -1700,6 +1652,7 @@ int main(int argc, char *argv[]) {
|
||||
case action_arg_version:
|
||||
case action_arg_reset:
|
||||
case action_arg_status:
|
||||
case action_arg_listMINUS_readers:
|
||||
case action__NULL:
|
||||
default:
|
||||
continue;
|
||||
@@ -1744,6 +1697,7 @@ int main(int argc, char *argv[]) {
|
||||
case action_arg_status:
|
||||
case action_arg_testMINUS_signature:
|
||||
case action_arg_testMINUS_decipher:
|
||||
case action_arg_listMINUS_readers:
|
||||
case action__NULL:
|
||||
default:
|
||||
if(verbosity) {
|
||||
@@ -1769,11 +1723,11 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
if(ykpiv_authenticate(state, key) != YKPIV_OK) {
|
||||
fprintf(stderr, "Failed authentication with the applet.\n");
|
||||
fprintf(stderr, "Failed authentication with the application.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if(verbosity) {
|
||||
fprintf(stderr, "Successful applet authentication.\n");
|
||||
fprintf(stderr, "Successful application authentication.\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -1795,7 +1749,8 @@ int main(int argc, char *argv[]) {
|
||||
print_version(state, args_info.output_arg);
|
||||
break;
|
||||
case action_arg_generate:
|
||||
if(generate_key(state, args_info.slot_orig, args_info.algorithm_arg, args_info.output_arg, args_info.key_format_arg) == false) {
|
||||
if(generate_key(state, args_info.slot_orig, args_info.algorithm_arg, args_info.output_arg, args_info.key_format_arg,
|
||||
args_info.pin_policy_arg, args_info.touch_policy_arg) == false) {
|
||||
ret = EXIT_FAILURE;
|
||||
} else {
|
||||
fprintf(stderr, "Successfully generated a new private key.\n");
|
||||
@@ -1816,8 +1771,12 @@ int main(int argc, char *argv[]) {
|
||||
if(ykpiv_hex_decode(new_mgm_key, strlen(new_mgm_key), new_key, &new_key_len) != YKPIV_OK) {
|
||||
fprintf(stderr, "Failed decoding new key!\n");
|
||||
ret = EXIT_FAILURE;
|
||||
} else if(ykpiv_set_mgmkey(state, new_key) != YKPIV_OK) {
|
||||
fprintf(stderr, "Failed setting the new key!\n");
|
||||
} else if(ykpiv_set_mgmkey2(state, new_key, args_info.touch_policy_arg == touch_policy_arg_always ? 1 : 0) != YKPIV_OK) {
|
||||
fprintf(stderr, "Failed setting the new key!");
|
||||
if(args_info.touch_policy_arg != touch_policy__NULL) {
|
||||
fprintf(stderr, " Maybe touch policy is not supported on this key?");
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
ret = EXIT_FAILURE;
|
||||
} else {
|
||||
fprintf(stderr, "Successfully set new management key.\n");
|
||||
@@ -1832,7 +1791,7 @@ int main(int argc, char *argv[]) {
|
||||
fprintf(stderr, "Reset failed, are pincodes blocked?\n");
|
||||
ret = EXIT_FAILURE;
|
||||
} else {
|
||||
fprintf(stderr, "Successfully reset the applet.\n");
|
||||
fprintf(stderr, "Successfully reset the application.\n");
|
||||
}
|
||||
break;
|
||||
case action_arg_pinMINUS_retries:
|
||||
@@ -1845,7 +1804,8 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
break;
|
||||
case action_arg_importMINUS_key:
|
||||
if(import_key(state, args_info.key_format_arg, args_info.input_arg, args_info.slot_orig, args_info.password_arg) == false) {
|
||||
if(import_key(state, args_info.key_format_arg, args_info.input_arg, args_info.slot_orig, args_info.password_arg,
|
||||
args_info.pin_policy_arg, args_info.touch_policy_arg) == false) {
|
||||
ret = EXIT_FAILURE;
|
||||
} else {
|
||||
fprintf(stderr, "Successfully imported a new private key.\n");
|
||||
@@ -1932,6 +1892,11 @@ int main(int argc, char *argv[]) {
|
||||
ret = EXIT_FAILURE;
|
||||
}
|
||||
break;
|
||||
case action_arg_listMINUS_readers:
|
||||
if(list_readers(state) == false) {
|
||||
ret = EXIT_FAILURE;
|
||||
}
|
||||
break;
|
||||
case action__NULL:
|
||||
default:
|
||||
fprintf(stderr, "Wrong action. %d.\n", action);
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
For more information about what's happening \-\-verbose can be added
|
||||
to any command. For much more information \-\-verbose=2 may be used.
|
||||
|
||||
Display what version of the applet is running on the YubiKey Neo:
|
||||
Display what version of the application is running on the YubiKey:
|
||||
|
||||
yubico\-piv\-tool \-a version
|
||||
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
# Copyright (c) 2015 Yubico AB
|
||||
# All rights reserved.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Additional permission under GNU GPL version 3 section 7
|
||||
#
|
||||
# If you modify this program, or any covered work, by linking or
|
||||
# combining it with the OpenSSL project's OpenSSL library (or a
|
||||
# modified version of that library), containing parts covered by the
|
||||
# terms of the OpenSSL or SSLeay licenses, We grant you additional
|
||||
# permission to convey the resulting work. Corresponding Source for a
|
||||
# non-source form of such a combination shall include the source code
|
||||
# for the parts of OpenSSL used as well as that of the covered work.
|
||||
|
||||
SUBDIRS = .
|
||||
#tests
|
||||
|
||||
AM_CFLAGS = $(WERROR_CFLAGS) $(WARN_CFLAGS)
|
||||
AM_CPPFLAGS = $(OPENSSL_CFLAGS) $(PCSC_CFLAGS)
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/lib -I$(top_builddir)/lib
|
||||
|
||||
lib_LTLIBRARIES = libykcs11.la
|
||||
|
||||
libykcs11_la_SOURCES = ykcs11.c version.c ykcs11.pc.in ykcs11.map
|
||||
libykcs11_la_SOURCES += ykcs11.h debug.h
|
||||
libykcs11_la_SOURCES += vendors.c vendors.h vendor_ids.h
|
||||
libykcs11_la_SOURCES += slot_vendors.c slot_vendors.h
|
||||
libykcs11_la_SOURCES += token_vendors.c token_vendors.h
|
||||
libykcs11_la_SOURCES += mechanisms.c mechanisms.h
|
||||
libykcs11_la_SOURCES += yubico_slot.c yubico_slot.h yubico_token.c yubico_token.h
|
||||
libykcs11_la_SOURCES += utils.c utils.h
|
||||
libykcs11_la_SOURCES += openssl_utils.c openssl_utils.h openssl_types.h
|
||||
libykcs11_la_SOURCES += objects.c objects.h obj_types.h
|
||||
libykcs11_la_SOURCES += pkcs11.h pkcs11f.h pkcs11t.h
|
||||
|
||||
#internal.h
|
||||
#libykcs11_la_SOURCES += error.c
|
||||
#libykcs11_la_LDADD = ../lib/libykpiv.la
|
||||
#$(OPENSSL_LIBS)
|
||||
libykcs11_la_includedir = $(includedir)/ykcs11
|
||||
libykcs11_la_include_HEADERS = ykcs11-version.h
|
||||
#ykcs11.h
|
||||
EXTRA_libykcs11_la_DEPENDENCIES = ykcs11.map
|
||||
|
||||
#libykcs11_la_LIBADD = $(OPENSSL_LIBS) $(PCSC_LIBS)
|
||||
#libykcs11_la_LIBADD += $(PCSC_WIN_LIBS) $(PCSC_MACOSX_LIBS)
|
||||
libykcs11_la_LIBADD = ../lib/libykpiv.la
|
||||
libykcs11_la_LIBADD += ../tool/libpiv_util.la
|
||||
|
||||
libykcs11_la_LDFLAGS = -no-undefined
|
||||
libykcs11_la_LDFLAGS += -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
|
||||
|
||||
if HAVE_LD_VERSION_SCRIPT
|
||||
libykcs11_la_LDFLAGS += -Wl,--version-script=$(srcdir)/ykcs11.map
|
||||
else
|
||||
libykcs11_la_LDFLAGS += -export-symbols-regex '^C_.*'
|
||||
endif
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = ykcs11.pc
|
||||
|
||||
if ENABLE_COV
|
||||
AM_CFLAGS += --coverage
|
||||
AM_LDFLAGS = --coverage
|
||||
endif
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
|
||||
#define YKCS11_DBG 1 // General debug, must be either 1 or 0
|
||||
#define YKCS11_DINOUT 1 // Function in/out debug, must be either 1 or 0
|
||||
|
||||
#define D(x...) do { \
|
||||
fprintf (stderr, "debug: %s:%d (%s): ", __FILE__, __LINE__, __FUNCTION__); \
|
||||
fprintf (stderr, x); \
|
||||
fprintf (stderr, "\n"); \
|
||||
} while (0)
|
||||
|
||||
#if YKCS11_DBG
|
||||
#include <stdio.h>
|
||||
#define DBG(x...) D(x);
|
||||
#else
|
||||
#define DBG(x...)
|
||||
#endif
|
||||
|
||||
#if YKCS11_DINOUT
|
||||
#define DIN D(("In"));
|
||||
#define DOUT D(("Out"));
|
||||
#else
|
||||
#define DIN
|
||||
#define DOUT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,527 @@
|
||||
#include "mechanisms.h"
|
||||
#include "openssl_utils.h"
|
||||
#include "utils.h"
|
||||
#include "debug.h"
|
||||
#include <string.h>
|
||||
|
||||
#define F4 "\x01\x00\x01"
|
||||
#define PRIME256V1 "\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07"
|
||||
|
||||
// Supported mechanisms for signature
|
||||
static const CK_MECHANISM_TYPE sign_mechanisms[] = {
|
||||
CKM_RSA_PKCS,
|
||||
CKM_RSA_PKCS_PSS,
|
||||
CKM_RSA_X_509,
|
||||
CKM_SHA1_RSA_PKCS,
|
||||
CKM_SHA256_RSA_PKCS,
|
||||
CKM_SHA384_RSA_PKCS,
|
||||
CKM_SHA512_RSA_PKCS,
|
||||
CKM_SHA1_RSA_PKCS_PSS,
|
||||
CKM_SHA256_RSA_PKCS_PSS,
|
||||
CKM_SHA384_RSA_PKCS_PSS,
|
||||
CKM_SHA512_RSA_PKCS_PSS,
|
||||
CKM_ECDSA,
|
||||
CKM_ECDSA_SHA1,
|
||||
CKM_ECDSA_SHA256
|
||||
};
|
||||
|
||||
// Supported mechanisms for key pair generation
|
||||
static const CK_MECHANISM_TYPE generation_mechanisms[] = {
|
||||
CKM_RSA_PKCS_KEY_PAIR_GEN,
|
||||
//CKM_ECDSA_KEY_PAIR_GEN, Deperecated
|
||||
CKM_EC_KEY_PAIR_GEN
|
||||
};
|
||||
|
||||
// Supported mechanisms for hashing
|
||||
static const CK_MECHANISM_TYPE hash_mechanisms[] = {
|
||||
CKM_SHA_1,
|
||||
CKM_SHA256,
|
||||
CKM_SHA384,
|
||||
CKM_SHA512
|
||||
};
|
||||
|
||||
CK_RV check_sign_mechanism(const ykcs11_session_t *s, const CK_MECHANISM_PTR m) {
|
||||
|
||||
CK_ULONG i;
|
||||
CK_BBOOL supported = CK_FALSE;
|
||||
token_vendor_t token;
|
||||
CK_MECHANISM_INFO info;
|
||||
|
||||
// Check if the mechanism is supported by the module
|
||||
for (i = 0; i < sizeof(sign_mechanisms) / sizeof(CK_MECHANISM_TYPE); i++) {
|
||||
if (m->mechanism == sign_mechanisms[i]) {
|
||||
supported = CK_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (supported == CK_FALSE)
|
||||
return CKR_MECHANISM_INVALID;
|
||||
|
||||
// Check if the mechanism is supported by the token
|
||||
token = get_token_vendor(s->slot->token->vid);
|
||||
|
||||
if (token.get_token_mechanism_info(m->mechanism, &info) != CKR_OK)
|
||||
return CKR_MECHANISM_INVALID;
|
||||
|
||||
// TODO: also check that parametes make sense if any? And key size is in [min max]
|
||||
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
CK_BBOOL is_RSA_mechanism(CK_MECHANISM_TYPE m) {
|
||||
|
||||
switch (m) {
|
||||
case CKM_RSA_PKCS_KEY_PAIR_GEN:
|
||||
case CKM_RSA_PKCS:
|
||||
case CKM_RSA_9796:
|
||||
case CKM_RSA_X_509:
|
||||
case CKM_SHA1_RSA_PKCS:
|
||||
// case CKM_SHA224_RSA_PKCS:
|
||||
case CKM_SHA256_RSA_PKCS:
|
||||
case CKM_SHA384_RSA_PKCS:
|
||||
case CKM_SHA512_RSA_PKCS:
|
||||
// case CKM_RIPEMD128_RSA_PKCS:
|
||||
// case CKM_RIPEMD160_RSA_PKCS:
|
||||
// case CKM_RSA_PKCS_OAEP:
|
||||
// case CKM_RSA_X9_31_KEY_PAIR_GEN:
|
||||
// case CKM_RSA_X9_31:
|
||||
// case CKM_SHA1_RSA_X9_31:
|
||||
case CKM_RSA_PKCS_PSS:
|
||||
case CKM_SHA1_RSA_PKCS_PSS:
|
||||
// case CKM_SHA224_RSA_PKCS_PSS:
|
||||
case CKM_SHA256_RSA_PKCS_PSS:
|
||||
case CKM_SHA512_RSA_PKCS_PSS:
|
||||
case CKM_SHA384_RSA_PKCS_PSS:
|
||||
// case CKM_RSA_PKCS_TPM_1_1:
|
||||
// case CKM_RSA_PKCS_OAEP_TPM_1_1:
|
||||
// case CKM_RSA_AES_KEY_WRAP:
|
||||
return CK_TRUE;
|
||||
|
||||
default:
|
||||
return CK_FALSE;
|
||||
}
|
||||
|
||||
// Not reached
|
||||
return CK_FALSE;
|
||||
}
|
||||
|
||||
CK_BBOOL is_PSS_mechanism(CK_MECHANISM_TYPE m) {
|
||||
|
||||
switch (m) {
|
||||
case CKM_RSA_PKCS_PSS:
|
||||
case CKM_SHA1_RSA_PKCS_PSS:
|
||||
// case CKM_SHA224_RSA_PKCS_PSS:
|
||||
case CKM_SHA256_RSA_PKCS_PSS:
|
||||
case CKM_SHA512_RSA_PKCS_PSS:
|
||||
case CKM_SHA384_RSA_PKCS_PSS:
|
||||
return CK_TRUE;
|
||||
|
||||
default:
|
||||
return CK_FALSE;
|
||||
}
|
||||
|
||||
// Not reached
|
||||
return CK_FALSE;
|
||||
}
|
||||
|
||||
CK_BBOOL is_hashed_mechanism(CK_MECHANISM_TYPE m) {
|
||||
|
||||
switch (m) {
|
||||
case CKM_SHA1_RSA_PKCS:
|
||||
case CKM_SHA256_RSA_PKCS:
|
||||
case CKM_SHA384_RSA_PKCS:
|
||||
case CKM_SHA512_RSA_PKCS:
|
||||
case CKM_SHA1_RSA_PKCS_PSS:
|
||||
case CKM_SHA256_RSA_PKCS_PSS:
|
||||
case CKM_SHA384_RSA_PKCS_PSS:
|
||||
case CKM_SHA512_RSA_PKCS_PSS:
|
||||
case CKM_ECDSA_SHA1:
|
||||
case CKM_ECDSA_SHA256:
|
||||
case CKM_SHA_1:
|
||||
case CKM_SHA256:
|
||||
case CKM_SHA384:
|
||||
case CKM_SHA512:
|
||||
return CK_TRUE;
|
||||
|
||||
default:
|
||||
return CK_FALSE;
|
||||
}
|
||||
|
||||
// Not reached
|
||||
return CK_FALSE;
|
||||
}
|
||||
|
||||
CK_RV apply_sign_mechanism_init(op_info_t *op_info) {
|
||||
|
||||
if (op_info->type != YKCS11_SIGN)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
switch (op_info->mechanism.mechanism) {
|
||||
case CKM_RSA_PKCS:
|
||||
case CKM_RSA_PKCS_PSS:
|
||||
case CKM_RSA_X_509:
|
||||
case CKM_ECDSA:
|
||||
// No hash required for this mechanism
|
||||
op_info->op.sign.md_ctx = NULL;
|
||||
return CKR_OK;
|
||||
|
||||
case CKM_SHA1_RSA_PKCS:
|
||||
case CKM_SHA1_RSA_PKCS_PSS:
|
||||
case CKM_ECDSA_SHA1:
|
||||
return do_md_init(YKCS11_SHA1, &op_info->op.sign.md_ctx);
|
||||
|
||||
case CKM_SHA256_RSA_PKCS:
|
||||
case CKM_SHA256_RSA_PKCS_PSS:
|
||||
case CKM_ECDSA_SHA256:
|
||||
return do_md_init(YKCS11_SHA256, &op_info->op.sign.md_ctx);
|
||||
|
||||
case CKM_SHA384_RSA_PKCS:
|
||||
case CKM_SHA384_RSA_PKCS_PSS:
|
||||
return do_md_init(YKCS11_SHA384, &op_info->op.sign.md_ctx);
|
||||
|
||||
case CKM_SHA512_RSA_PKCS:
|
||||
case CKM_SHA512_RSA_PKCS_PSS:
|
||||
return do_md_init(YKCS11_SHA512, &op_info->op.sign.md_ctx);
|
||||
|
||||
default:
|
||||
return CKR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
// Never reached
|
||||
return CKR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
CK_RV apply_sign_mechanism_update(op_info_t *op_info, CK_BYTE_PTR in, CK_ULONG in_len) {
|
||||
CK_RV rv;
|
||||
|
||||
if (op_info->type != YKCS11_SIGN)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
switch (op_info->mechanism.mechanism) {
|
||||
case CKM_RSA_PKCS:
|
||||
case CKM_RSA_PKCS_PSS:
|
||||
case CKM_ECDSA:
|
||||
case CKM_RSA_X_509:
|
||||
// Mechanism not suitable for multipart signatures
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
case CKM_SHA1_RSA_PKCS:
|
||||
case CKM_SHA256_RSA_PKCS:
|
||||
case CKM_SHA384_RSA_PKCS:
|
||||
case CKM_SHA512_RSA_PKCS:
|
||||
case CKM_SHA1_RSA_PKCS_PSS:
|
||||
case CKM_SHA256_RSA_PKCS_PSS:
|
||||
case CKM_SHA384_RSA_PKCS_PSS:
|
||||
case CKM_SHA512_RSA_PKCS_PSS:
|
||||
case CKM_ECDSA_SHA1:
|
||||
case CKM_ECDSA_SHA256:
|
||||
rv = do_md_update(op_info->op.sign.md_ctx, in, in_len);
|
||||
if (rv != CKR_OK)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
return CKR_OK;
|
||||
|
||||
default:
|
||||
return CKR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CK_RV apply_sign_mechanism_finalize(op_info_t *op_info) {
|
||||
|
||||
CK_RV rv;
|
||||
int nid = NID_undef;
|
||||
RSA *rsa;
|
||||
CK_ULONG len;
|
||||
|
||||
if (op_info->type != YKCS11_SIGN)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
switch (op_info->mechanism.mechanism) {
|
||||
case CKM_SHA1_RSA_PKCS_PSS:
|
||||
case CKM_SHA256_RSA_PKCS_PSS:
|
||||
case CKM_SHA384_RSA_PKCS_PSS:
|
||||
case CKM_SHA512_RSA_PKCS_PSS:
|
||||
// Finalize the hash
|
||||
rv = do_md_finalize(op_info->op.sign.md_ctx, op_info->buf, &op_info->buf_len, &nid);
|
||||
op_info->op.sign.md_ctx = NULL;
|
||||
if (rv != CKR_OK)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
case CKM_RSA_PKCS_PSS:
|
||||
// Compute padding for all PSS variants
|
||||
// TODO: digestinfo/paraminfo ?
|
||||
|
||||
rv = do_encode_rsa_public_key(op_info->op.sign.key, op_info->op.sign.key_len, &rsa);
|
||||
if (rv != CKR_OK)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
rv = do_pkcs_pss(rsa, op_info->buf, op_info->buf_len, nid, op_info->buf, &op_info->buf_len);
|
||||
|
||||
// TODO: does rsa have to be free'd ?
|
||||
|
||||
return rv;
|
||||
|
||||
case CKM_RSA_X_509:
|
||||
// Padding in this case consists of prepending zeroes
|
||||
len = (op_info->op.sign.key_len / 8) - op_info->buf_len;
|
||||
memmove(op_info->buf + len, op_info->buf, op_info->buf_len);
|
||||
memset(op_info->buf, 0, len);
|
||||
op_info->buf_len = op_info->op.sign.key_len / 8;
|
||||
return CKR_OK;
|
||||
|
||||
case CKM_SHA1_RSA_PKCS:
|
||||
case CKM_SHA256_RSA_PKCS:
|
||||
case CKM_SHA384_RSA_PKCS:
|
||||
case CKM_SHA512_RSA_PKCS:
|
||||
// Finalize the hash add digest info
|
||||
rv = do_md_finalize(op_info->op.sign.md_ctx, op_info->buf, &op_info->buf_len, &nid);
|
||||
op_info->op.sign.md_ctx = NULL;
|
||||
if (rv != CKR_OK)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
case CKM_RSA_PKCS:
|
||||
// Add digest info if needed
|
||||
if (nid != NID_undef) {
|
||||
rv = do_pkcs_1_digest_info(op_info->buf, op_info->buf_len, nid, op_info->buf, &op_info->buf_len);
|
||||
if (rv != CKR_OK)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
// Compute padding for all PKCS1 variants
|
||||
len = op_info->buf_len;
|
||||
op_info->buf_len = sizeof(op_info->buf);
|
||||
return do_pkcs_1_t1(op_info->buf, len, op_info->buf, &op_info->buf_len, op_info->op.sign.key_len);
|
||||
|
||||
case CKM_ECDSA_SHA1:
|
||||
case CKM_ECDSA_SHA256:
|
||||
// Finalize the hash
|
||||
rv = do_md_finalize(op_info->op.sign.md_ctx, op_info->buf, &op_info->buf_len, &nid);
|
||||
op_info->op.sign.md_ctx = NULL;
|
||||
if (rv != CKR_OK)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
case CKM_ECDSA:
|
||||
return CKR_OK;
|
||||
|
||||
default:
|
||||
return CKR_FUNCTION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
CK_RV sign_mechanism_cleanup(op_info_t *op_info) {
|
||||
|
||||
if (op_info->op.sign.md_ctx != NULL) {
|
||||
do_md_cleanup(op_info->op.sign.md_ctx);
|
||||
op_info->op.sign.md_ctx = NULL;
|
||||
}
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV check_generation_mechanism(const ykcs11_session_t *s, CK_MECHANISM_PTR m) {
|
||||
|
||||
CK_ULONG i;
|
||||
CK_BBOOL supported = CK_FALSE;
|
||||
token_vendor_t token;
|
||||
CK_MECHANISM_INFO info;
|
||||
|
||||
// Check if the mechanism is supported by the module
|
||||
for (i = 0; i < sizeof(generation_mechanisms) / sizeof(CK_MECHANISM_TYPE); i++) {
|
||||
if (m->mechanism == generation_mechanisms[i]) {
|
||||
supported = CK_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (supported == CK_FALSE)
|
||||
return CKR_MECHANISM_INVALID;
|
||||
|
||||
// Check if the mechanism is supported by the token
|
||||
token = get_token_vendor(s->slot->token->vid);
|
||||
|
||||
if (token.get_token_mechanism_info(m->mechanism, &info) != CKR_OK)
|
||||
return CKR_MECHANISM_INVALID;
|
||||
|
||||
// TODO: also check that parametes make sense if any? And key size is in [min max]
|
||||
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
CK_RV check_pubkey_template(op_info_t *op_info, CK_ATTRIBUTE_PTR templ, CK_ULONG n) {
|
||||
|
||||
CK_ULONG i;
|
||||
|
||||
op_info->op.gen.rsa = is_RSA_mechanism(op_info->mechanism.mechanism);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
switch (templ[i].type) {
|
||||
case CKA_CLASS:
|
||||
if (*((CK_ULONG_PTR) templ[i].pValue) != CKO_PUBLIC_KEY)
|
||||
return CKR_TEMPLATE_INCONSISTENT;
|
||||
|
||||
break;
|
||||
|
||||
case CKA_KEY_TYPE:
|
||||
if ((op_info->op.gen.rsa == CK_TRUE && (*((CK_KEY_TYPE *)templ[i].pValue)) != CKK_RSA) ||
|
||||
(op_info->op.gen.rsa == CK_FALSE && (*((CK_KEY_TYPE *)templ[i].pValue)) != CKK_ECDSA))
|
||||
return CKR_TEMPLATE_INCONSISTENT;
|
||||
|
||||
break;
|
||||
|
||||
case CKA_PUBLIC_EXPONENT:
|
||||
if (op_info->op.gen.rsa == CK_FALSE)
|
||||
return CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
|
||||
// Only support F4
|
||||
if (templ[i].ulValueLen != 3 || memcmp((CK_BYTE_PTR)templ[i].pValue, F4, 3) != 0) {
|
||||
DBG("Unsupported public exponent");
|
||||
return CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CKA_MODULUS_BITS:
|
||||
if (op_info->op.gen.rsa == CK_FALSE)
|
||||
return CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
|
||||
if (*((CK_ULONG_PTR) templ[i].pValue) != 1024 &&
|
||||
*((CK_ULONG_PTR) templ[i].pValue) != 2048) { // TODO: make define?
|
||||
DBG("Unsupported MODULUS_BITS (key length)");
|
||||
return CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
}
|
||||
|
||||
op_info->op.gen.key_len = *((CK_ULONG_PTR) templ[i].pValue);
|
||||
break;
|
||||
|
||||
case CKA_EC_PARAMS:
|
||||
// Only support PRIME256V1
|
||||
if (templ[i].ulValueLen != 10 || memcmp((CK_BYTE_PTR)templ[i].pValue, PRIME256V1, 10) != 0)
|
||||
return CKR_CURVE_NOT_SUPPORTED;
|
||||
|
||||
op_info->op.gen.key_len = 256;
|
||||
break;
|
||||
|
||||
case CKA_ID:
|
||||
if (is_valid_key_id(*((CK_BYTE_PTR)templ[i].pValue)) == CK_FALSE)
|
||||
return CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
|
||||
op_info->op.gen.key_id = PIV_PVTK_OBJ_PIV_AUTH + *((CK_BYTE_PTR)templ[i].pValue);
|
||||
break;
|
||||
|
||||
case CKA_TOKEN:
|
||||
case CKA_ENCRYPT:
|
||||
case CKA_VERIFY:
|
||||
case CKA_WRAP:
|
||||
case CKA_DERIVE:
|
||||
// Ignore these attributes for now
|
||||
break;
|
||||
|
||||
default:
|
||||
DBG("Invalid attribute %lx in public key template", templ[i].type);
|
||||
return CKR_ATTRIBUTE_TYPE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
CK_RV check_pvtkey_template(op_info_t *op_info, CK_ATTRIBUTE_PTR templ, CK_ULONG n) {
|
||||
|
||||
CK_ULONG i;
|
||||
|
||||
op_info->op.gen.rsa = is_RSA_mechanism(op_info->mechanism.mechanism);
|
||||
op_info->op.gen.vendor_defined = 0;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
switch (templ[i].type) {
|
||||
case CKA_CLASS:
|
||||
if (*((CK_ULONG_PTR)templ[i].pValue) != CKO_PRIVATE_KEY)
|
||||
return CKR_TEMPLATE_INCONSISTENT;
|
||||
|
||||
break;
|
||||
|
||||
case CKA_KEY_TYPE:
|
||||
if ((op_info->op.gen.rsa == CK_TRUE && (*((CK_KEY_TYPE *)templ[i].pValue)) != CKK_RSA) ||
|
||||
(op_info->op.gen.rsa == CK_FALSE && (*((CK_KEY_TYPE *)templ[i].pValue)) != CKK_ECDSA))
|
||||
return CKR_TEMPLATE_INCONSISTENT;
|
||||
|
||||
break;
|
||||
|
||||
/* case CKA_MODULUS_BITS:
|
||||
if (op_info->op.gen.rsa == CK_FALSE)
|
||||
return CKR_MECHANISM_PARAM_INVALID;
|
||||
|
||||
if (*((CK_ULONG_PTR)templ[i].pValue) != 1024 &&
|
||||
*((CK_ULONG_PTR) templ[i].pValue) != 2048) // TODO: make define?
|
||||
return CKR_MECHANISM_PARAM_INVALID;
|
||||
|
||||
op_info->op.gen.key_len = *((CK_ULONG_PTR) templ[i].pValue); // TODO: check length?
|
||||
break;*/
|
||||
|
||||
case CKA_ID:
|
||||
if (is_valid_key_id(*((CK_BYTE_PTR)templ[i].pValue)) == CK_FALSE)
|
||||
return CKR_ATTRIBUTE_VALUE_INVALID;
|
||||
|
||||
// Check if ID was already specified in the public key template
|
||||
// In that case it has to match
|
||||
if (op_info->op.gen.key_id != 0 &&
|
||||
op_info->op.gen.key_id != (*((CK_BYTE_PTR)templ[i].pValue) + PIV_PVTK_OBJ_PIV_AUTH))
|
||||
return CKR_TEMPLATE_INCONSISTENT;
|
||||
|
||||
op_info->op.gen.key_id = PIV_PVTK_OBJ_PIV_AUTH + *((CK_BYTE_PTR)templ[i].pValue);
|
||||
break;
|
||||
|
||||
case CKA_VENDOR_DEFINED:
|
||||
op_info->op.gen.vendor_defined = (*((CK_ULONG_PTR)templ[i].pValue));
|
||||
|
||||
case CKA_SENSITIVE:
|
||||
case CKA_DECRYPT:
|
||||
case CKA_UNWRAP:
|
||||
case CKA_SIGN:
|
||||
case CKA_PRIVATE:
|
||||
case CKA_TOKEN:
|
||||
case CKA_DERIVE:
|
||||
// Ignore these attributes for now
|
||||
break;
|
||||
|
||||
default:
|
||||
DBG("Invalid attribute %lx in private key template", templ[i].type);
|
||||
return CKR_ATTRIBUTE_TYPE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
CK_RV check_hash_mechanism(const ykcs11_session_t *s, CK_MECHANISM_PTR m) {
|
||||
|
||||
CK_ULONG i;
|
||||
CK_BBOOL supported = CK_FALSE;
|
||||
token_vendor_t token;
|
||||
CK_MECHANISM_INFO info;
|
||||
|
||||
// Check if the mechanism is supported by the module
|
||||
for (i = 0; i < sizeof(hash_mechanisms) / sizeof(CK_MECHANISM_TYPE); i++) {
|
||||
if (m->mechanism == hash_mechanisms[i]) {
|
||||
supported = CK_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (supported == CK_FALSE)
|
||||
return CKR_MECHANISM_INVALID;
|
||||
|
||||
// Check if the mechanism is supported by the token
|
||||
token = get_token_vendor(s->slot->token->vid);
|
||||
|
||||
if (token.get_token_mechanism_info(m->mechanism, &info) != CKR_OK)
|
||||
return CKR_MECHANISM_INVALID;
|
||||
|
||||
// TODO: also check that parametes make sense if any? And key size is in [min max]
|
||||
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef MECHANISMS_H
|
||||
#define MECHANISMS_H
|
||||
|
||||
#include "ykcs11.h"
|
||||
|
||||
CK_RV check_sign_mechanism(const ykcs11_session_t *s, CK_MECHANISM_PTR m);
|
||||
CK_BBOOL is_RSA_mechanism(CK_MECHANISM_TYPE m);
|
||||
CK_BBOOL is_PSS_mechanism(CK_MECHANISM_TYPE m);
|
||||
CK_BBOOL is_hashed_mechanism(CK_MECHANISM_TYPE m);
|
||||
|
||||
CK_RV apply_sign_mechanism_init(op_info_t *op_info);
|
||||
CK_RV apply_sign_mechanism_update(op_info_t *op_info, CK_BYTE_PTR in, CK_ULONG in_len);
|
||||
CK_RV apply_sign_mechanism_finalize(op_info_t *op_info);
|
||||
CK_RV sign_mechanism_cleanup(op_info_t *op_info);
|
||||
|
||||
CK_RV check_generation_mechanism(const ykcs11_session_t *s, CK_MECHANISM_PTR m);
|
||||
CK_RV check_pubkey_template(op_info_t *op_info, CK_ATTRIBUTE_PTR templ, CK_ULONG n); // TODO: Move to objects.c
|
||||
CK_RV check_pvtkey_template(op_info_t *op_info, CK_ATTRIBUTE_PTR templ, CK_ULONG n); // TODO: Move to objects.c
|
||||
|
||||
CK_RV check_hash_mechanism(const ykcs11_session_t *s, CK_MECHANISM_PTR m);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,136 @@
|
||||
#ifndef OBJ_TYPES_H
|
||||
#define OBJ_TYPES_H
|
||||
|
||||
#include "pkcs11t.h"
|
||||
|
||||
#include <openssl/x509.h>
|
||||
|
||||
// TODO: this is mostly from OpenSC, how to give credit?
|
||||
typedef enum {
|
||||
PIV_DATA_OBJ_X509_PIV_AUTH = 0, // PIV authentication
|
||||
PIV_DATA_OBJ_X509_CARD_AUTH, // Certificate for card authentication
|
||||
PIV_DATA_OBJ_X509_DS, // Certificate for digital signature
|
||||
PIV_DATA_OBJ_X509_KM, // Certificate for key management
|
||||
PIV_DATA_OBJ_CCC, // Card capability container
|
||||
PIV_DATA_OBJ_CHUI, // Cardholder unique id
|
||||
PIV_DATA_OBJ_CHF, // Cardholder fingerprints
|
||||
PIV_DATA_OBJ_SEC_OBJ, // Security object
|
||||
PIV_DATA_OBJ_CHFI, // Cardholder facial images
|
||||
PIV_DATA_OBJ_PI, // Cardholder printed information
|
||||
PIV_DATA_OBJ_DISCOVERY, // Discovery object
|
||||
PIV_DATA_OBJ_HISTORY, // History object
|
||||
PIV_DATA_OBJ_RETIRED_X509_1, // Retired certificate for KM 1
|
||||
PIV_DATA_OBJ_RETIRED_X509_2, // Retired certificate for KM 2
|
||||
PIV_DATA_OBJ_RETIRED_X509_3, // Retired certificate for KM 3
|
||||
PIV_DATA_OBJ_RETIRED_X509_4, // Retired certificate for KM 4
|
||||
PIV_DATA_OBJ_RETIRED_X509_5, // Retired certificate for KM 5
|
||||
PIV_DATA_OBJ_RETIRED_X509_6, // Retired certificate for KM 6
|
||||
PIV_DATA_OBJ_RETIRED_X509_7, // Retired certificate for KM 7
|
||||
PIV_DATA_OBJ_RETIRED_X509_8, // Retired certificate for KM 8
|
||||
PIV_DATA_OBJ_RETIRED_X509_9, // Retired certificate for KM 9
|
||||
PIV_DATA_OBJ_RETIRED_X509_10, // Retired certificate for KM 10
|
||||
PIV_DATA_OBJ_RETIRED_X509_11, // Retired certificate for KM 11
|
||||
PIV_DATA_OBJ_RETIRED_X509_12, // Retired certificate for KM 12
|
||||
PIV_DATA_OBJ_RETIRED_X509_13, // Retired certificate for KM 13
|
||||
PIV_DATA_OBJ_RETIRED_X509_14, // Retired certificate for KM 14
|
||||
PIV_DATA_OBJ_RETIRED_X509_15, // Retired certificate for KM 15
|
||||
PIV_DATA_OBJ_RETIRED_X509_16, // Retired certificate for KM 16
|
||||
PIV_DATA_OBJ_RETIRED_X509_17, // Retired certificate for KM 17
|
||||
PIV_DATA_OBJ_RETIRED_X509_18, // Retired certificate for KM 18
|
||||
PIV_DATA_OBJ_RETIRED_X509_19, // Retired certificate for KM 19
|
||||
PIV_DATA_OBJ_RETIRED_X509_20, // Retired certificate for KM 20
|
||||
PIV_DATA_OBJ_IRIS_IMAGE, // Cardholder iris images
|
||||
PIV_DATA_OBJ_BITGT, // Biometric information templates group template
|
||||
PIV_DATA_OBJ_SM_SIGNER, // Secure messaging signer
|
||||
PIV_DATA_OBJ_PC_REF_DATA, // Pairing code reference data
|
||||
/* PIV_DATA_OBJ_9B03, // NON-STANDARD TODO: remove?
|
||||
PIV_DATA_OBJ_9A06, // NON-STANDARD
|
||||
PIV_DATA_OBJ_9C06, // NON-STANDARD
|
||||
PIV_DATA_OBJ_9D06, // NON-STANDARD
|
||||
PIV_DATA_OBJ_9E06, // NON-STANDARD
|
||||
PIV_DATA_OBJ_8206, // NON-STANDARD
|
||||
PIV_DATA_OBJ_8306, // NON-STANDARD
|
||||
PIV_DATA_OBJ_8406, // NON-STANDARD
|
||||
PIV_DATA_OBJ_8506, // NON-STANDARD
|
||||
PIV_DATA_OBJ_8606, // NON-STANDARD
|
||||
PIV_DATA_OBJ_8706, // NON-STANDARD
|
||||
PIV_DATA_OBJ_8806, // NON-STANDARD
|
||||
PIV_DATA_OBJ_8906, // NON-STANDARD
|
||||
PIV_DATA_OBJ_8A06, // NON-STANDARD
|
||||
PIV_DATA_OBJ_8B06, // NON-STANDARD
|
||||
PIV_DATA_OBJ_8C06, // NON-STANDARD
|
||||
PIV_DATA_OBJ_8D06, // NON-STANDARD
|
||||
PIV_DATA_OBJ_8E06, // NON-STANDARD
|
||||
PIV_DATA_OBJ_8F06, // NON-STANDARD
|
||||
PIV_DATA_OBJ_9006, // NON-STANDARD
|
||||
PIV_DATA_OBJ_9106, // NON-STANDARD
|
||||
PIV_DATA_OBJ_9206, // NON-STANDARD
|
||||
PIV_DATA_OBJ_9306, // NON-STANDARD
|
||||
PIV_DATA_OBJ_9406, // NON-STANDARD
|
||||
PIV_DATA_OBJ_9506, // NON-STANDARD*/
|
||||
PIV_DATA_OBJ_LAST,
|
||||
|
||||
PIV_CERT_OBJ_X509_PIV_AUTH, // PIV authentication
|
||||
PIV_CERT_OBJ_X509_CARD_AUTH, // Certificate for card authentication
|
||||
PIV_CERT_OBJ_X509_DS, // Certificate for digital signature
|
||||
PIV_CERT_OBJ_X509_KM, // Certificate for key management
|
||||
PIV_CERT_OBJ_LAST,
|
||||
|
||||
PIV_PVTK_OBJ_PIV_AUTH, // Private key for PIV authentication
|
||||
PIV_PVTK_OBJ_CARD_AUTH, // Private Key for card authentication
|
||||
PIV_PVTK_OBJ_DS, // Private Key for digital signature
|
||||
PIV_PVTK_OBJ_KM, // Private Key for key management
|
||||
PIV_PVTK_OBJ_LAST,
|
||||
|
||||
PIV_PUBK_OBJ_PIV_AUTH, // Public key for PIV authentication
|
||||
PIV_PUBK_OBJ_CARD_AUTH, // Public Key for card authentication
|
||||
PIV_PUBK_OBJ_DS, // Public Key for digital signature
|
||||
PIV_PUBK_OBJ_KM, // Public Key for key management
|
||||
PIV_PUBK_OBJ_LAST
|
||||
|
||||
} piv_obj_id_t;
|
||||
|
||||
#define OBJECT_INVALID (PIV_PUBK_OBJ_LAST + 1)
|
||||
|
||||
typedef CK_RV (*get_attr_f)(CK_OBJECT_HANDLE, CK_ATTRIBUTE_PTR);
|
||||
|
||||
typedef struct {
|
||||
const char *oid;
|
||||
CK_BYTE tag_len;
|
||||
CK_BYTE tag_value[3]; // TODO: needed?
|
||||
CK_BYTE containerid[2]; /* will use as relative paths for simulation */ // TODO: needed?
|
||||
} piv_data_obj_t;
|
||||
|
||||
typedef struct {
|
||||
X509 *data;
|
||||
} piv_cert_obj_t;
|
||||
|
||||
typedef struct { // TODO: enough to use the public key for the parameters?
|
||||
CK_BBOOL decrypt;
|
||||
CK_BBOOL sign;
|
||||
CK_BBOOL unwrap;
|
||||
CK_BBOOL derive;
|
||||
CK_BBOOL always_auth;
|
||||
} piv_pvtk_obj_t;
|
||||
|
||||
typedef struct {
|
||||
EVP_PKEY *data; // TODO: make custom type for this and X509
|
||||
CK_BBOOL encrypt;
|
||||
CK_BBOOL verify;
|
||||
CK_BBOOL wrap;
|
||||
CK_BBOOL derive;
|
||||
} piv_pubk_obj_t;
|
||||
|
||||
typedef struct {
|
||||
piv_obj_id_t piv_id; // TODO: technically redundant
|
||||
CK_BBOOL token; // TODO: not used yet
|
||||
CK_BBOOL private;
|
||||
CK_BBOOL modifiable;
|
||||
const char *label;
|
||||
CK_BBOOL copyable; // TODO: Optional, not used so far (default TRUE)
|
||||
CK_BBOOL destroyable; // TODO: Optional, not used so far (default TRUE)
|
||||
get_attr_f get_attribute;
|
||||
CK_BYTE sub_id; // Sub-object id
|
||||
} piv_obj_t;
|
||||
|
||||
#endif
|
||||
+1292
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
||||
#ifndef OBJECTS_H
|
||||
#define OBJECTS_H
|
||||
|
||||
#include "ykcs11.h"
|
||||
|
||||
CK_ULONG piv_2_ykpiv(piv_obj_id_t id);
|
||||
|
||||
CK_RV get_attribute(ykcs11_session_t *s, CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR template);
|
||||
CK_BBOOL attribute_match(ykcs11_session_t *s, CK_OBJECT_HANDLE obj, CK_ATTRIBUTE_PTR attribute);
|
||||
CK_BBOOL is_private_object(ykcs11_session_t *s, CK_OBJECT_HANDLE obj);
|
||||
|
||||
CK_RV get_available_certificate_ids(ykcs11_session_t *s, piv_obj_id_t *cert_ids, CK_ULONG n_certs);
|
||||
CK_RV store_cert(piv_obj_id_t cert_id, CK_BYTE_PTR data, CK_ULONG len);
|
||||
CK_RV delete_cert(piv_obj_id_t cert_id);
|
||||
|
||||
CK_RV check_create_cert(CK_ATTRIBUTE_PTR templ, CK_ULONG n, CK_BYTE_PTR id,
|
||||
CK_BYTE_PTR *value, CK_ULONG_PTR cert_len);
|
||||
CK_RV check_create_ec_key(CK_ATTRIBUTE_PTR templ, CK_ULONG n, CK_BYTE_PTR id,
|
||||
CK_BYTE_PTR *value, CK_ULONG_PTR value_len, CK_ULONG_PTR vendor_defined);
|
||||
CK_RV check_create_rsa_key(CK_ATTRIBUTE_PTR templ, CK_ULONG n, CK_BYTE_PTR id,
|
||||
CK_BYTE_PTR *p, CK_BYTE_PTR *q, CK_BYTE_PTR *dp,
|
||||
CK_BYTE_PTR *dq, CK_BYTE_PTR *qinv, CK_ULONG_PTR value_len, CK_ULONG_PTR vendor_defined);
|
||||
CK_RV check_delete_cert(CK_OBJECT_HANDLE hObject, CK_BYTE_PTR id);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef OPENSSL_TYPES_H
|
||||
#define OPENSSL_TYPES_H
|
||||
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/ec.h>
|
||||
|
||||
typedef enum {
|
||||
YKCS11_NO_HASH,
|
||||
YKCS11_SHA1,
|
||||
//YKCS11_SHA224,
|
||||
YKCS11_SHA256,
|
||||
YKCS11_SHA384,
|
||||
YKCS11_SHA512,
|
||||
//YKCS11_RIPEMD128_RSA_PKCS,
|
||||
//YKCS11_RIPEMD160
|
||||
} hash_t;
|
||||
|
||||
typedef EVP_MD_CTX ykcs11_md_ctx_t;
|
||||
//typedef EVP_PKEY ykcs11_evp_pkey_t;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,613 @@
|
||||
#include "openssl_utils.h"
|
||||
#include <stdbool.h>
|
||||
#include "../tool/util.h" // TODO: share this better?
|
||||
#include "debug.h"
|
||||
#include <string.h>
|
||||
|
||||
CK_RV do_store_cert(CK_BYTE_PTR data, CK_ULONG len, X509 **cert) {
|
||||
|
||||
const unsigned char *p = data; // Mandatory temp variable required by OpenSSL
|
||||
int cert_len;
|
||||
|
||||
if (*p == 0x70) {
|
||||
// The certificate is in "PIV" format 0x70 len 0x30 len ...
|
||||
p++;
|
||||
p += get_length(p, &cert_len);
|
||||
}
|
||||
else {
|
||||
// Raw certificate 0x30 len ...
|
||||
cert_len = 0;
|
||||
cert_len += get_length(p + 1, &cert_len) + 1;
|
||||
}
|
||||
|
||||
if ((CK_ULONG)cert_len > len)
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
|
||||
*cert = d2i_X509(NULL, &p, cert_len);
|
||||
if (*cert == NULL)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
CK_RV do_create_empty_cert(CK_BYTE_PTR in, CK_ULONG in_len, CK_BBOOL is_rsa,
|
||||
CK_BYTE_PTR out, CK_ULONG_PTR out_len) {
|
||||
|
||||
X509 *cert = NULL;
|
||||
EVP_PKEY *key = NULL;
|
||||
RSA *rsa = NULL;
|
||||
BIGNUM *bignum_n = NULL;
|
||||
BIGNUM *bignum_e = NULL;
|
||||
EC_KEY *eck = NULL;
|
||||
EC_GROUP *ecg = NULL;
|
||||
EC_POINT *ecp = NULL;
|
||||
ASN1_TIME *tm = NULL;
|
||||
|
||||
unsigned char *data_ptr;
|
||||
unsigned char *p;
|
||||
int len;
|
||||
|
||||
CK_RV rv = CKR_FUNCTION_FAILED;
|
||||
|
||||
cert = X509_new();
|
||||
if (cert == NULL)
|
||||
goto create_empty_cert_cleanup;
|
||||
|
||||
key = EVP_PKEY_new();
|
||||
if (key == NULL)
|
||||
goto create_empty_cert_cleanup;
|
||||
|
||||
if (is_rsa) {
|
||||
// RSA
|
||||
rsa = RSA_new();
|
||||
if (rsa == NULL)
|
||||
goto create_empty_cert_cleanup;
|
||||
|
||||
data_ptr = in + 5;
|
||||
if (*data_ptr != 0x81)
|
||||
goto create_empty_cert_cleanup;
|
||||
|
||||
data_ptr++;
|
||||
data_ptr += get_length(data_ptr, &len);
|
||||
bignum_n = BN_bin2bn(data_ptr, len, NULL);
|
||||
if(bignum_n == NULL)
|
||||
goto create_empty_cert_cleanup;
|
||||
|
||||
data_ptr += len;
|
||||
|
||||
if(*data_ptr != 0x82)
|
||||
goto create_empty_cert_cleanup;
|
||||
|
||||
data_ptr++;
|
||||
data_ptr += get_length(data_ptr, &len);
|
||||
bignum_e = BN_bin2bn(data_ptr, len, NULL);
|
||||
if(bignum_e == NULL)
|
||||
goto create_empty_cert_cleanup;
|
||||
|
||||
rsa->n = bignum_n;
|
||||
rsa->e = bignum_e;
|
||||
|
||||
if (EVP_PKEY_set1_RSA(key, rsa) == 0)
|
||||
goto create_empty_cert_cleanup;
|
||||
}
|
||||
else {
|
||||
// ECCP256
|
||||
data_ptr = in + 3;
|
||||
|
||||
eck = EC_KEY_new();
|
||||
if (eck == NULL)
|
||||
goto create_empty_cert_cleanup;
|
||||
|
||||
ecg = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
if (ecg == NULL)
|
||||
goto create_empty_cert_cleanup;
|
||||
|
||||
EC_GROUP_set_asn1_flag(ecg, NID_X9_62_prime256v1);
|
||||
EC_KEY_set_group(eck, ecg);
|
||||
ecp = EC_POINT_new(ecg);
|
||||
|
||||
if(*data_ptr++ != 0x86)
|
||||
goto create_empty_cert_cleanup;
|
||||
|
||||
// The curve point should always be 65 bytes
|
||||
if (*data_ptr++ != 65)
|
||||
goto create_empty_cert_cleanup;
|
||||
|
||||
if (EC_POINT_oct2point(ecg, ecp, data_ptr, 65, NULL) == 0)
|
||||
goto create_empty_cert_cleanup;
|
||||
|
||||
if (EC_KEY_set_public_key(eck, ecp) == 0)
|
||||
goto create_empty_cert_cleanup;
|
||||
|
||||
if (EVP_PKEY_set1_EC_KEY(key, eck) == 0)
|
||||
goto create_empty_cert_cleanup;
|
||||
}
|
||||
|
||||
if (X509_set_pubkey(cert, key) == 0) // TODO: there is also X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey);
|
||||
goto create_empty_cert_cleanup;
|
||||
|
||||
tm = ASN1_TIME_new();
|
||||
if (tm == NULL)
|
||||
goto create_empty_cert_cleanup;
|
||||
|
||||
ASN1_TIME_set_string(tm, "000001010000Z");
|
||||
X509_set_notBefore(cert, tm);
|
||||
X509_set_notAfter(cert, tm);
|
||||
|
||||
// Manually set the signature algorithms.
|
||||
// OpenSSL 1.0.1i complains about empty DER fields
|
||||
// 8 => md5WithRsaEncryption
|
||||
cert->sig_alg->algorithm = OBJ_nid2obj(8);
|
||||
cert->cert_info->signature->algorithm = OBJ_nid2obj(8);
|
||||
|
||||
// Manually set a signature (same reason as before)
|
||||
ASN1_BIT_STRING_set_bit(cert->signature, 8, 1);
|
||||
ASN1_BIT_STRING_set(cert->signature, "\x00", 1);
|
||||
|
||||
len = i2d_X509(cert, NULL);
|
||||
if (len < 0)
|
||||
goto create_empty_cert_cleanup;
|
||||
|
||||
if ((CK_ULONG)len > *out_len) {
|
||||
rv = CKR_BUFFER_TOO_SMALL;
|
||||
goto create_empty_cert_cleanup;
|
||||
}
|
||||
|
||||
p = out;
|
||||
if ((*out_len = (CK_ULONG) i2d_X509(cert, &p)) == 0)
|
||||
goto create_empty_cert_cleanup;
|
||||
|
||||
/********************/
|
||||
/*BIO *STDout = BIO_new_fp(stderr, BIO_NOCLOSE);
|
||||
|
||||
X509_print_ex(STDout, cert, 0, 0);
|
||||
|
||||
BIO_free(STDout);*/
|
||||
/********************/
|
||||
|
||||
rv = CKR_OK;
|
||||
|
||||
create_empty_cert_cleanup:
|
||||
|
||||
if (tm != NULL) {
|
||||
ASN1_STRING_free(tm);
|
||||
tm = NULL;
|
||||
}
|
||||
|
||||
if (bignum_n != NULL) {
|
||||
BN_free(bignum_n);
|
||||
bignum_n = NULL;
|
||||
}
|
||||
|
||||
if (bignum_e != NULL) {
|
||||
BN_free(bignum_e);
|
||||
bignum_e = NULL;
|
||||
}
|
||||
|
||||
/* if (rsa != NULL) { // TODO: adding this generates an error. Automatically free'd by EVP_PKEY_free ?
|
||||
RSA_free(rsa);
|
||||
rsa = NULL;
|
||||
}*/
|
||||
|
||||
if (ecp != NULL) {
|
||||
EC_POINT_free(ecp);
|
||||
ecp = NULL;
|
||||
}
|
||||
|
||||
if (ecg != NULL) {
|
||||
EC_GROUP_free(ecg);
|
||||
ecg = NULL;
|
||||
}
|
||||
|
||||
if (eck != NULL) {
|
||||
EC_KEY_free(eck);
|
||||
eck = NULL;
|
||||
}
|
||||
|
||||
if (key != NULL) {
|
||||
EVP_PKEY_free(key);
|
||||
key = NULL;
|
||||
}
|
||||
|
||||
if (cert != NULL) {
|
||||
X509_free(cert);
|
||||
cert = NULL;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
CK_RV do_check_cert(CK_BYTE_PTR in, CK_ULONG_PTR cert_len) {
|
||||
|
||||
X509 *cert;
|
||||
const unsigned char *p = in; // Mandatory temp variable required by OpenSSL
|
||||
int len;
|
||||
|
||||
len = 0;
|
||||
len += get_length(p + 1, &len) + 1;
|
||||
|
||||
*cert_len = (CK_ULONG) len;
|
||||
|
||||
cert = d2i_X509(NULL, &p, (long) *cert_len);
|
||||
if (cert == NULL)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV do_get_raw_cert(X509 *cert, CK_BYTE_PTR out, CK_ULONG_PTR out_len) {
|
||||
|
||||
CK_BYTE_PTR p;
|
||||
int len;
|
||||
|
||||
len = i2d_X509(cert, NULL);
|
||||
|
||||
if (len < 0)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
if ((CK_ULONG)len > *out_len)
|
||||
return CKR_BUFFER_TOO_SMALL;
|
||||
|
||||
p = out;
|
||||
if ((*out_len = (CK_ULONG) i2d_X509(cert, &p)) == 0)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV do_delete_cert(X509 **cert) {
|
||||
|
||||
X509_free(*cert);
|
||||
cert = NULL;
|
||||
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
/*CK_RV free_cert(X509 *cert) {
|
||||
|
||||
X509_free((X509 *) cert);
|
||||
|
||||
return CKR_OK;
|
||||
}*/
|
||||
|
||||
|
||||
CK_RV do_store_pubk(X509 *cert, EVP_PKEY **key) {
|
||||
|
||||
*key = X509_get_pubkey(cert);
|
||||
|
||||
if (*key == NULL)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
CK_KEY_TYPE do_get_key_type(EVP_PKEY *key) {
|
||||
|
||||
switch (key->type) {
|
||||
case EVP_PKEY_RSA:
|
||||
case EVP_PKEY_RSA2:
|
||||
return CKK_RSA;
|
||||
|
||||
case EVP_PKEY_EC:
|
||||
return CKK_ECDSA;
|
||||
|
||||
default:
|
||||
return CKK_VENDOR_DEFINED; // Actually an error
|
||||
}
|
||||
}
|
||||
|
||||
CK_ULONG do_get_rsa_modulus_length(EVP_PKEY *key) {
|
||||
|
||||
CK_ULONG key_len = 0;
|
||||
RSA *rsa;
|
||||
|
||||
rsa = EVP_PKEY_get1_RSA(key);
|
||||
if (rsa == NULL)
|
||||
return 0;
|
||||
|
||||
key_len = (CK_ULONG) (RSA_size(rsa) * 8); // There is also RSA_bits but only in >= 1.1.0
|
||||
|
||||
RSA_free(rsa);
|
||||
rsa = NULL;
|
||||
|
||||
return key_len;
|
||||
|
||||
}
|
||||
|
||||
CK_ULONG do_get_public_exponent(EVP_PKEY *key) {
|
||||
|
||||
CK_ULONG e = 0;
|
||||
RSA *rsa;
|
||||
|
||||
rsa = EVP_PKEY_get1_RSA(key);
|
||||
if (rsa == NULL)
|
||||
return 0;
|
||||
|
||||
BN_bn2bin(rsa->e, (unsigned char *)&e);
|
||||
|
||||
RSA_free(rsa);
|
||||
rsa = NULL;
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
/* #include <stdio.h> */
|
||||
/* #include <openssl/err.h> */
|
||||
/* ERR_load_crypto_strings(); */
|
||||
/* //SSL_load_error_strings(); */
|
||||
/* fprintf(stderr, "ERROR %s\n", ERR_error_string(ERR_get_error(), NULL)); */
|
||||
CK_RV do_get_public_key(EVP_PKEY *key, CK_BYTE_PTR data, CK_ULONG_PTR len) {
|
||||
|
||||
RSA *rsa;
|
||||
unsigned char *p;
|
||||
|
||||
EC_KEY *eck;
|
||||
const EC_GROUP *ecg; // Alternative solution is to get i2d_PUBKEY and manually offset
|
||||
const EC_POINT *ecp;
|
||||
point_conversion_form_t pcf = POINT_CONVERSION_UNCOMPRESSED;
|
||||
|
||||
switch(key->type) {
|
||||
case EVP_PKEY_RSA:
|
||||
case EVP_PKEY_RSA2:
|
||||
|
||||
rsa = EVP_PKEY_get1_RSA(key);
|
||||
|
||||
if ((CK_ULONG)RSA_size(rsa) > *len) {
|
||||
RSA_free(rsa);
|
||||
rsa = NULL;
|
||||
return CKR_BUFFER_TOO_SMALL;
|
||||
}
|
||||
|
||||
p = data;
|
||||
|
||||
if ((*len = (CK_ULONG) i2d_RSAPublicKey(rsa, &p)) == 0) {
|
||||
RSA_free(rsa);
|
||||
rsa = NULL;
|
||||
return CKR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
// TODO: this is the correct thing to do so that we strip out the exponent
|
||||
// OTOH we also need a function to get the exponent out with CKA_PUBLIC_EXPONENT
|
||||
/*BN_bn2bin(rsa->n, data);
|
||||
*len = 256;*/
|
||||
|
||||
/* fprintf(stderr, "Public key is: \n"); */
|
||||
/* dump_hex(data, *len, stderr, CK_TRUE); */
|
||||
|
||||
break;
|
||||
|
||||
case EVP_PKEY_EC:
|
||||
eck = EVP_PKEY_get1_EC_KEY(key);
|
||||
ecg = EC_KEY_get0_group(eck);
|
||||
ecp = EC_KEY_get0_public_key(eck);
|
||||
|
||||
// Add the DER structure with length after extracting the point
|
||||
data[0] = 0x04;
|
||||
|
||||
if ((*len = EC_POINT_point2oct(ecg, ecp, pcf, data + 2, *len - 2, NULL)) == 0) {
|
||||
EC_KEY_free(eck);
|
||||
eck = NULL;
|
||||
return CKR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
data[1] = *len;
|
||||
|
||||
*len += 2;
|
||||
|
||||
EC_KEY_free(eck);
|
||||
eck = NULL;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return CKR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
CK_RV do_encode_rsa_public_key(CK_BYTE_PTR data, CK_ULONG len, RSA **key) {
|
||||
|
||||
const unsigned char *p = data;
|
||||
|
||||
if (data == NULL)
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
|
||||
if ((*key = d2i_RSAPublicKey(NULL, &p, (long) len)) == NULL)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
CK_RV do_get_curve_parameters(EVP_PKEY *key, CK_BYTE_PTR data, CK_ULONG_PTR len) {
|
||||
|
||||
EC_KEY *eck;
|
||||
const EC_GROUP *ecg;
|
||||
unsigned char *p;
|
||||
|
||||
eck = EVP_PKEY_get1_EC_KEY(key);
|
||||
ecg = EC_KEY_get0_group(eck);
|
||||
|
||||
p = data;
|
||||
|
||||
if ((*len = (CK_ULONG) i2d_ECPKParameters(ecg, &p)) == 0) {
|
||||
EC_KEY_free(eck);
|
||||
eck = NULL;
|
||||
return CKR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
EC_KEY_free(eck);
|
||||
eck = NULL;
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV do_delete_pubk(EVP_PKEY **key) {
|
||||
|
||||
EVP_PKEY_free(*key);
|
||||
key = NULL;
|
||||
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
/*CK_RV free_key(EVP_PKEY *key) {
|
||||
|
||||
EVP_PKEY_free(key);
|
||||
|
||||
return CKR_OK;
|
||||
|
||||
}*/
|
||||
|
||||
CK_RV do_pkcs_1_t1(CK_BYTE_PTR in, CK_ULONG in_len, CK_BYTE_PTR out, CK_ULONG_PTR out_len, CK_ULONG key_len) {
|
||||
unsigned char buffer[512];
|
||||
|
||||
key_len /= 8;
|
||||
DBG("Apply padding to %lu bytes and get %lu\n", in_len, key_len);
|
||||
|
||||
// TODO: rand must be seeded first (should be automatic)
|
||||
if (*out_len < key_len)
|
||||
return CKR_BUFFER_TOO_SMALL;
|
||||
|
||||
if (RSA_padding_add_PKCS1_type_1(buffer, key_len, in, in_len) == 0)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
memcpy(out, buffer, key_len);
|
||||
*out_len = key_len;
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV do_pkcs_1_digest_info(CK_BYTE_PTR in, CK_ULONG in_len, int nid, CK_BYTE_PTR out, CK_ULONG_PTR out_len) {
|
||||
|
||||
unsigned int len;
|
||||
CK_RV rv;
|
||||
|
||||
rv = prepare_rsa_signature(in, in_len, out, &len, nid);
|
||||
if (!rv)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
*out_len = len;
|
||||
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
CK_RV do_pkcs_pss(RSA *key, CK_BYTE_PTR in, CK_ULONG in_len, int nid,
|
||||
CK_BYTE_PTR out, CK_ULONG_PTR out_len) {
|
||||
unsigned char em[512]; // Max for this is ceil((|key_len_bits| - 1) / 8)
|
||||
|
||||
OpenSSL_add_all_digests();
|
||||
|
||||
// TODO: rand must be seeded first (should be automatic)
|
||||
if (*out_len < (CK_ULONG)RSA_size(key))
|
||||
return CKR_BUFFER_TOO_SMALL;
|
||||
|
||||
DBG("Apply PSS padding to %lu bytes and get %d\n", in_len, RSA_size(key));
|
||||
|
||||
if (out != in)
|
||||
memcpy(out, in, in_len);
|
||||
|
||||
// In case of raw PSS (no hash) this function will fail because OpenSSL requires an MD
|
||||
if (RSA_padding_add_PKCS1_PSS(key, em, out, EVP_get_digestbynid(nid), -2) == 0) {
|
||||
EVP_cleanup();
|
||||
return CKR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
*out_len = (CK_ULONG) RSA_size(key);
|
||||
|
||||
EVP_cleanup();
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV do_md_init(hash_t hash, ykcs11_md_ctx_t **ctx) {
|
||||
|
||||
const EVP_MD *md;
|
||||
|
||||
switch (hash) {
|
||||
case YKCS11_NO_HASH:
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
case YKCS11_SHA1:
|
||||
md = EVP_sha1();
|
||||
break;
|
||||
|
||||
//case YKCS11_SHA224:
|
||||
|
||||
case YKCS11_SHA256:
|
||||
md = EVP_sha256();
|
||||
break;
|
||||
|
||||
case YKCS11_SHA384:
|
||||
md = EVP_sha384();
|
||||
break;
|
||||
|
||||
case YKCS11_SHA512:
|
||||
md = EVP_sha512();
|
||||
break;
|
||||
|
||||
//case YKCS11_RIPEMD128_RSA_PKCS_HASH:
|
||||
//case YKCS11_RIPEMD160_HASH:
|
||||
|
||||
default:
|
||||
return CKR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
*ctx = EVP_MD_CTX_create();
|
||||
|
||||
// The OpenSSL function above never fail
|
||||
if (EVP_DigestInit_ex(*ctx, md, NULL) == 0) {
|
||||
EVP_MD_CTX_destroy((EVP_MD_CTX *)*ctx);
|
||||
return CKR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV do_md_update(ykcs11_md_ctx_t *ctx, CK_BYTE_PTR in, CK_ULONG in_len) {
|
||||
|
||||
if (EVP_DigestUpdate(ctx, in, in_len) != 1) {
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
return CKR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
CK_RV do_md_finalize(ykcs11_md_ctx_t *ctx, CK_BYTE_PTR out, CK_ULONG_PTR out_len, int *nid) {
|
||||
|
||||
int rv;
|
||||
unsigned int len;
|
||||
|
||||
// Keep track of the md type if requested
|
||||
if (nid != NULL)
|
||||
*nid = EVP_MD_CTX_type(ctx);
|
||||
|
||||
// Finalize digest and store result
|
||||
rv = EVP_DigestFinal_ex(ctx, out, &len);
|
||||
|
||||
// Destroy the md context
|
||||
EVP_MD_CTX_destroy(ctx);
|
||||
|
||||
// Error if the previous call failed
|
||||
if (rv != 1)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
*out_len = len;
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV do_md_cleanup(ykcs11_md_ctx_t *ctx) {
|
||||
|
||||
EVP_MD_CTX_destroy((EVP_MD_CTX *) ctx);
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#ifndef OPENSSL_UTIL_H
|
||||
#define OPENSSL_UTIL_H
|
||||
|
||||
/* #include <openssl/x509.h> */
|
||||
/* #include <openssl/evp.h> */
|
||||
/* #include <openssl/rsa.h> */
|
||||
/* #include <openssl/ec.h> */
|
||||
|
||||
#include "openssl_types.h"
|
||||
#include "pkcs11t.h"
|
||||
|
||||
CK_RV do_store_cert(CK_BYTE_PTR data, CK_ULONG len, X509 **cert);
|
||||
CK_RV do_create_empty_cert(CK_BYTE_PTR in, CK_ULONG in_len, CK_BBOOL is_rsa,
|
||||
CK_BYTE_PTR out, CK_ULONG_PTR out_len);
|
||||
CK_RV do_check_cert(CK_BYTE_PTR in, CK_ULONG_PTR cert_len);
|
||||
CK_RV do_get_raw_cert(X509 *cert, CK_BYTE_PTR out, CK_ULONG_PTR out_len);
|
||||
CK_RV do_delete_cert(X509 **cert);
|
||||
//CK_RV free_cert(X509 *cert);
|
||||
|
||||
CK_RV do_store_pubk(X509 *cert, EVP_PKEY **key);
|
||||
CK_KEY_TYPE do_get_key_type(EVP_PKEY *key);
|
||||
CK_ULONG do_get_rsa_modulus_length(EVP_PKEY *key);
|
||||
CK_ULONG do_get_public_exponent(EVP_PKEY *key);
|
||||
CK_RV do_get_public_key(EVP_PKEY *key, CK_BYTE_PTR data, CK_ULONG_PTR len);
|
||||
CK_RV do_encode_rsa_public_key(CK_BYTE_PTR data, CK_ULONG len, RSA **key);
|
||||
CK_RV do_get_curve_parameters(EVP_PKEY *key, CK_BYTE_PTR data, CK_ULONG_PTR len);
|
||||
CK_RV do_delete_pubk(EVP_PKEY **key);
|
||||
//CK_RV free_key(EVP_PKEY *key);
|
||||
|
||||
CK_RV do_pkcs_1_t1(CK_BYTE_PTR in, CK_ULONG in_len, CK_BYTE_PTR out, CK_ULONG_PTR out_len, CK_ULONG key_len);
|
||||
CK_RV do_pkcs_1_digest_info(CK_BYTE_PTR in, CK_ULONG in_len, int nid, CK_BYTE_PTR out, CK_ULONG_PTR out_len);
|
||||
|
||||
CK_RV do_pkcs_pss(RSA *key, CK_BYTE_PTR in, CK_ULONG in_len, int nid,
|
||||
CK_BYTE_PTR out, CK_ULONG_PTR out_len);
|
||||
|
||||
CK_RV do_md_init(hash_t hash, ykcs11_md_ctx_t **ctx);
|
||||
CK_RV do_md_update(ykcs11_md_ctx_t *ctx, CK_BYTE_PTR in, CK_ULONG in_len);
|
||||
CK_RV do_md_finalize(ykcs11_md_ctx_t *ctx, CK_BYTE_PTR out, CK_ULONG_PTR out_len, int *nid);
|
||||
CK_RV do_md_cleanup(ykcs11_md_ctx_t *ctx);
|
||||
|
||||
#endif
|
||||
+324
@@ -0,0 +1,324 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape security libraries.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
/*
|
||||
* Copyright (C) 1994-1999 RSA Security Inc. Licence to copy this document
|
||||
* is granted provided that it is identified as "RSA Security In.c Public-Key
|
||||
* Cryptography Standards (PKCS)" in all material mentioning or referencing
|
||||
* this document.
|
||||
*/
|
||||
#ifndef _PKCS11_H_
|
||||
#define _PKCS11_H_ 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Before including this file (pkcs11.h) (or pkcs11t.h by
|
||||
* itself), 6 platform-specific macros must be defined. These
|
||||
* macros are described below, and typical definitions for them
|
||||
* are also given. Be advised that these definitions can depend
|
||||
* on both the platform and the compiler used (and possibly also
|
||||
* on whether a PKCS #11 library is linked statically or
|
||||
* dynamically).
|
||||
*
|
||||
* In addition to defining these 6 macros, the packing convention
|
||||
* for PKCS #11 structures should be set. The PKCS #11
|
||||
* convention on packing is that structures should be 1-byte
|
||||
* aligned.
|
||||
*
|
||||
* In a Win32 environment, this might be done by using the
|
||||
* following preprocessor directive before including pkcs11.h
|
||||
* or pkcs11t.h:
|
||||
*
|
||||
* #pragma pack(push, cryptoki, 1)
|
||||
*
|
||||
* and using the following preprocessor directive after including
|
||||
* pkcs11.h or pkcs11t.h:
|
||||
*
|
||||
* #pragma pack(pop, cryptoki)
|
||||
*
|
||||
* In a Win16 environment, this might be done by using the
|
||||
* following preprocessor directive before including pkcs11.h
|
||||
* or pkcs11t.h:
|
||||
*
|
||||
* #pragma pack(1)
|
||||
*
|
||||
* In a UNIX environment, you're on your own here. You might
|
||||
* not need to do anything.
|
||||
*
|
||||
*
|
||||
* Now for the macros:
|
||||
*
|
||||
*
|
||||
* 1. CK_PTR: The indirection string for making a pointer to an
|
||||
* object. It can be used like this:
|
||||
*
|
||||
* typedef CK_BYTE CK_PTR CK_BYTE_PTR;
|
||||
*
|
||||
* In a Win32 environment, it might be defined by
|
||||
*
|
||||
* #define CK_PTR *
|
||||
*
|
||||
* In a Win16 environment, it might be defined by
|
||||
*
|
||||
* #define CK_PTR far *
|
||||
*
|
||||
* In a UNIX environment, it might be defined by
|
||||
*
|
||||
* #define CK_PTR *
|
||||
*
|
||||
*
|
||||
* 2. CK_DEFINE_FUNCTION(returnType, name): A macro which makes
|
||||
* an exportable PKCS #11 library function definition out of a
|
||||
* return type and a function name. It should be used in the
|
||||
* following fashion to define the exposed PKCS #11 functions in
|
||||
* a PKCS #11 library:
|
||||
*
|
||||
* CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(
|
||||
* CK_VOID_PTR pReserved
|
||||
* )
|
||||
* {
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* For defining a function in a Win32 PKCS #11 .dll, it might be
|
||||
* defined by
|
||||
*
|
||||
* #define CK_DEFINE_FUNCTION(returnType, name) \
|
||||
* returnType __declspec(dllexport) name
|
||||
*
|
||||
* For defining a function in a Win16 PKCS #11 .dll, it might be
|
||||
* defined by
|
||||
*
|
||||
* #define CK_DEFINE_FUNCTION(returnType, name) \
|
||||
* returnType __export _far _pascal name
|
||||
*
|
||||
* In a UNIX environment, it might be defined by
|
||||
*
|
||||
* #define CK_DEFINE_FUNCTION(returnType, name) \
|
||||
* returnType name
|
||||
*
|
||||
*
|
||||
* 3. CK_DECLARE_FUNCTION(returnType, name): A macro which makes
|
||||
* an importable PKCS #11 library function declaration out of a
|
||||
* return type and a function name. It should be used in the
|
||||
* following fashion:
|
||||
*
|
||||
* extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)(
|
||||
* CK_VOID_PTR pReserved
|
||||
* );
|
||||
*
|
||||
* For declaring a function in a Win32 PKCS #11 .dll, it might
|
||||
* be defined by
|
||||
*
|
||||
* #define CK_DECLARE_FUNCTION(returnType, name) \
|
||||
* returnType __declspec(dllimport) name
|
||||
*
|
||||
* For declaring a function in a Win16 PKCS #11 .dll, it might
|
||||
* be defined by
|
||||
*
|
||||
* #define CK_DECLARE_FUNCTION(returnType, name) \
|
||||
* returnType __export _far _pascal name
|
||||
*
|
||||
* In a UNIX environment, it might be defined by
|
||||
*
|
||||
* #define CK_DECLARE_FUNCTION(returnType, name) \
|
||||
* returnType name
|
||||
*
|
||||
*
|
||||
* 4. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro
|
||||
* which makes a PKCS #11 API function pointer declaration or
|
||||
* function pointer type declaration out of a return type and a
|
||||
* function name. It should be used in the following fashion:
|
||||
*
|
||||
* // Define funcPtr to be a pointer to a PKCS #11 API function
|
||||
* // taking arguments args and returning CK_RV.
|
||||
* CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args);
|
||||
*
|
||||
* or
|
||||
*
|
||||
* // Define funcPtrType to be the type of a pointer to a
|
||||
* // PKCS #11 API function taking arguments args and returning
|
||||
* // CK_RV, and then define funcPtr to be a variable of type
|
||||
* // funcPtrType.
|
||||
* typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args);
|
||||
* funcPtrType funcPtr;
|
||||
*
|
||||
* For accessing functions in a Win32 PKCS #11 .dll, in might be
|
||||
* defined by
|
||||
*
|
||||
* #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
|
||||
* returnType __declspec(dllimport) (* name)
|
||||
*
|
||||
* For accessing functions in a Win16 PKCS #11 .dll, it might be
|
||||
* defined by
|
||||
*
|
||||
* #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
|
||||
* returnType __export _far _pascal (* name)
|
||||
*
|
||||
* In a UNIX environment, it might be defined by
|
||||
*
|
||||
* #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
|
||||
* returnType (* name)
|
||||
*
|
||||
*
|
||||
* 5. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes
|
||||
* a function pointer type for an application callback out of
|
||||
* a return type for the callback and a name for the callback.
|
||||
* It should be used in the following fashion:
|
||||
*
|
||||
* CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args);
|
||||
*
|
||||
* to declare a function pointer, myCallback, to a callback
|
||||
* which takes arguments args and returns a CK_RV. It can also
|
||||
* be used like this:
|
||||
*
|
||||
* typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args);
|
||||
* myCallbackType myCallback;
|
||||
*
|
||||
* In a Win32 environment, it might be defined by
|
||||
*
|
||||
* #define CK_CALLBACK_FUNCTION(returnType, name) \
|
||||
* returnType (* name)
|
||||
*
|
||||
* In a Win16 environment, it might be defined by
|
||||
*
|
||||
* #define CK_CALLBACK_FUNCTION(returnType, name) \
|
||||
* returnType _far _pascal (* name)
|
||||
*
|
||||
* In a UNIX environment, it might be defined by
|
||||
*
|
||||
* #define CK_CALLBACK_FUNCTION(returnType, name) \
|
||||
* returnType (* name)
|
||||
*
|
||||
*
|
||||
* 6. NULL_PTR: This macro is the value of a NULL pointer.
|
||||
*
|
||||
* In any ANSI/ISO C environment (and in many others as well),
|
||||
* this should be defined by
|
||||
*
|
||||
* #ifndef NULL_PTR
|
||||
* #define NULL_PTR 0
|
||||
* #endif
|
||||
*/
|
||||
|
||||
|
||||
/* All the various PKCS #11 types and #define'd values are in the
|
||||
* file pkcs11t.h. */
|
||||
#include "pkcs11t.h"
|
||||
|
||||
#define __PASTE(x,y) x##y
|
||||
|
||||
|
||||
/* packing defines */
|
||||
//#include "pkcs11p.h" // TODO: msc specific?
|
||||
/* ==============================================================
|
||||
* Define the "extern" form of all the entry points.
|
||||
* ==============================================================
|
||||
*/
|
||||
|
||||
#define CK_NEED_ARG_LIST 1
|
||||
#define CK_PKCS11_FUNCTION_INFO(name) \
|
||||
CK_DECLARE_FUNCTION(CK_RV, name)
|
||||
|
||||
/* pkcs11f.h has all the information about the PKCS #11
|
||||
* function prototypes. */
|
||||
#include "pkcs11f.h"
|
||||
|
||||
#undef CK_NEED_ARG_LIST
|
||||
#undef CK_PKCS11_FUNCTION_INFO
|
||||
|
||||
|
||||
/* ==============================================================
|
||||
* Define the typedef form of all the entry points. That is, for
|
||||
* each PKCS #11 function C_XXX, define a type CK_C_XXX which is
|
||||
* a pointer to that kind of function.
|
||||
* ==============================================================
|
||||
*/
|
||||
|
||||
#define CK_NEED_ARG_LIST 1
|
||||
#define CK_PKCS11_FUNCTION_INFO(name) \
|
||||
typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name))
|
||||
|
||||
/* pkcs11f.h has all the information about the PKCS #11
|
||||
* function prototypes. */
|
||||
#include "pkcs11f.h"
|
||||
|
||||
#undef CK_NEED_ARG_LIST
|
||||
#undef CK_PKCS11_FUNCTION_INFO
|
||||
|
||||
|
||||
/* ==============================================================
|
||||
* Define structed vector of entry points. A CK_FUNCTION_LIST
|
||||
* contains a CK_VERSION indicating a library's PKCS #11 version
|
||||
* and then a whole slew of function pointers to the routines in
|
||||
* the library. This type was declared, but not defined, in
|
||||
* pkcs11t.h.
|
||||
* ==============================================================
|
||||
*/
|
||||
|
||||
#define CK_PKCS11_FUNCTION_INFO(name) \
|
||||
__PASTE(CK_,name) name;
|
||||
|
||||
struct CK_FUNCTION_LIST {
|
||||
|
||||
CK_VERSION version; /* PKCS #11 version */
|
||||
|
||||
/* Pile all the function pointers into the CK_FUNCTION_LIST. */
|
||||
/* pkcs11f.h has all the information about the PKCS #11
|
||||
* function prototypes. */
|
||||
#include "pkcs11f.h"
|
||||
|
||||
};
|
||||
|
||||
#undef CK_PKCS11_FUNCTION_INFO
|
||||
|
||||
|
||||
#undef __PASTE
|
||||
|
||||
/* unpack */
|
||||
//#include "pkcs11u.h" // TODO: msc specific?
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Functions called directly by applications to configure the FIPS token.
|
||||
*/
|
||||
extern void PK11_ConfigurePKCS11(char *man, char *libdes, char *tokdes,
|
||||
char *ptokdes, char *slotdes, char *pslotdes, char *fslotdes,
|
||||
char *fpslotdes, int minPwd, int pwdRequired);
|
||||
extern void PK11_ConfigureFIPS(char *slotdes, char *pslotdes);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,933 @@
|
||||
/*
|
||||
* The contents of this file are subject to the Mozilla Public
|
||||
* License Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License. You may obtain a copy of
|
||||
* the License at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS
|
||||
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
* implied. See the License for the specific language governing
|
||||
* rights and limitations under the License.
|
||||
*
|
||||
* The Original Code is the Netscape security libraries.
|
||||
*
|
||||
* The Initial Developer of the Original Code is Netscape
|
||||
* Communications Corporation. Portions created by Netscape are
|
||||
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License Version 2 or later (the
|
||||
* "GPL"), in which case the provisions of the GPL are applicable
|
||||
* instead of those above. If you wish to allow use of your
|
||||
* version of this file only under the terms of the GPL and not to
|
||||
* allow others to use your version of this file under the MPL,
|
||||
* indicate your decision by deleting the provisions above and
|
||||
* replace them with the notice and other provisions required by
|
||||
* the GPL. If you do not delete the provisions above, a recipient
|
||||
* may use your version of this file under either the MPL or the
|
||||
* GPL.
|
||||
*/
|
||||
/*
|
||||
* Copyright (C) 1994-1999 RSA Security Inc. Licence to copy this document
|
||||
* is granted provided that it is identified as "RSA Security In.c Public-Key
|
||||
* Cryptography Standards (PKCS)" in all material mentioning or referencing
|
||||
* this document.
|
||||
*/
|
||||
/* This function contains pretty much everything about all the */
|
||||
/* PKCS #11 function prototypes. Because this information is */
|
||||
/* used for more than just declaring function prototypes, the */
|
||||
/* order of the functions appearing herein is important, and */
|
||||
/* should not be altered. */
|
||||
|
||||
|
||||
|
||||
/* General-purpose */
|
||||
|
||||
/* C_Initialize initializes the PKCS #11 library. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_Initialize)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_VOID_PTR pInitArgs /* if this is not NULL_PTR, it gets
|
||||
* cast to CK_C_INITIALIZE_ARGS_PTR
|
||||
* and dereferenced */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_Finalize indicates that an application is done with the
|
||||
* PKCS #11 library. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_Finalize)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_VOID_PTR pReserved /* reserved. Should be NULL_PTR */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GetInfo returns general information about PKCS #11. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetInfo)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_INFO_PTR pInfo /* location that receives information */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GetFunctionList returns the function list. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetFunctionList)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_FUNCTION_LIST_PTR_PTR ppFunctionList /* receives pointer to
|
||||
* function list */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Slot and token management */
|
||||
|
||||
/* C_GetSlotList obtains a list of slots in the system. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetSlotList)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_BBOOL tokenPresent, /* only slots with tokens? */
|
||||
CK_SLOT_ID_PTR pSlotList, /* receives array of slot IDs */
|
||||
CK_ULONG_PTR pulCount /* receives number of slots */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GetSlotInfo obtains information about a particular slot in
|
||||
* the system. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SLOT_ID slotID, /* the ID of the slot */
|
||||
CK_SLOT_INFO_PTR pInfo /* receives the slot information */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GetTokenInfo obtains information about a particular token
|
||||
* in the system. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SLOT_ID slotID, /* ID of the token's slot */
|
||||
CK_TOKEN_INFO_PTR pInfo /* receives the token information */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GetMechanismList obtains a list of mechanism types
|
||||
* supported by a token. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetMechanismList)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SLOT_ID slotID, /* ID of token's slot */
|
||||
CK_MECHANISM_TYPE_PTR pMechanismList, /* gets mech. array */
|
||||
CK_ULONG_PTR pulCount /* gets # of mechs. */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GetMechanismInfo obtains information about a particular
|
||||
* mechanism possibly supported by a token. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SLOT_ID slotID, /* ID of the token's slot */
|
||||
CK_MECHANISM_TYPE type, /* type of mechanism */
|
||||
CK_MECHANISM_INFO_PTR pInfo /* receives mechanism info */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_InitToken initializes a token. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_InitToken)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SLOT_ID slotID, /* ID of the token's slot */
|
||||
CK_CHAR_PTR pPin, /* the SO's initial PIN */
|
||||
CK_ULONG ulPinLen, /* length in bytes of the PIN */
|
||||
CK_CHAR_PTR pLabel /* 32-byte token label (blank padded) */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_InitPIN initializes the normal user's PIN. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_InitPIN)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_CHAR_PTR pPin, /* the normal user's PIN */
|
||||
CK_ULONG ulPinLen /* length in bytes of the PIN */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_SetPIN modifies the PIN of the user who is logged in. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_SetPIN)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_CHAR_PTR pOldPin, /* the old PIN */
|
||||
CK_ULONG ulOldLen, /* length of the old PIN */
|
||||
CK_CHAR_PTR pNewPin, /* the new PIN */
|
||||
CK_ULONG ulNewLen /* length of the new PIN */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Session management */
|
||||
|
||||
/* C_OpenSession opens a session between an application and a
|
||||
* token. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_OpenSession)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SLOT_ID slotID, /* the slot's ID */
|
||||
CK_FLAGS flags, /* from CK_SESSION_INFO */
|
||||
CK_VOID_PTR pApplication, /* passed to callback */
|
||||
CK_NOTIFY Notify, /* callback function */
|
||||
CK_SESSION_HANDLE_PTR phSession /* gets session handle */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_CloseSession closes a session between an application and a
|
||||
* token. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_CloseSession)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession /* the session's handle */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_CloseAllSessions closes all sessions with a token. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SLOT_ID slotID /* the token's slot */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GetSessionInfo obtains information about the session. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_SESSION_INFO_PTR pInfo /* receives session info */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GetOperationState obtains the state of the cryptographic operation
|
||||
* in a session. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetOperationState)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_BYTE_PTR pOperationState, /* gets state */
|
||||
CK_ULONG_PTR pulOperationStateLen /* gets state length */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_SetOperationState restores the state of the cryptographic
|
||||
* operation in a session. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_SetOperationState)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_BYTE_PTR pOperationState, /* holds state */
|
||||
CK_ULONG ulOperationStateLen, /* holds state length */
|
||||
CK_OBJECT_HANDLE hEncryptionKey, /* en/decryption key */
|
||||
CK_OBJECT_HANDLE hAuthenticationKey /* sign/verify key */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_Login logs a user into a token. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_Login)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_USER_TYPE userType, /* the user type */
|
||||
CK_CHAR_PTR pPin, /* the user's PIN */
|
||||
CK_ULONG ulPinLen /* the length of the PIN */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_Logout logs a user out from a token. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_Logout)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession /* the session's handle */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Object management */
|
||||
|
||||
/* C_CreateObject creates a new object. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_CreateObject)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_ATTRIBUTE_PTR pTemplate, /* the object's template */
|
||||
CK_ULONG ulCount, /* attributes in template */
|
||||
CK_OBJECT_HANDLE_PTR phObject /* gets new object's handle. */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_CopyObject copies an object, creating a new object for the
|
||||
* copy. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_CopyObject)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_OBJECT_HANDLE hObject, /* the object's handle */
|
||||
CK_ATTRIBUTE_PTR pTemplate, /* template for new object */
|
||||
CK_ULONG ulCount, /* attributes in template */
|
||||
CK_OBJECT_HANDLE_PTR phNewObject /* receives handle of copy */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_DestroyObject destroys an object. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_DestroyObject)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_OBJECT_HANDLE hObject /* the object's handle */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GetObjectSize gets the size of an object in bytes. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetObjectSize)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_OBJECT_HANDLE hObject, /* the object's handle */
|
||||
CK_ULONG_PTR pulSize /* receives size of object */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GetAttributeValue obtains the value of one or more object
|
||||
* attributes. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_OBJECT_HANDLE hObject, /* the object's handle */
|
||||
CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs; gets vals */
|
||||
CK_ULONG ulCount /* attributes in template */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_SetAttributeValue modifies the value of one or more object
|
||||
* attributes */
|
||||
CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_OBJECT_HANDLE hObject, /* the object's handle */
|
||||
CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs and values */
|
||||
CK_ULONG ulCount /* attributes in template */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_FindObjectsInit initializes a search for token and session
|
||||
* objects that match a template. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_ATTRIBUTE_PTR pTemplate, /* attribute values to match */
|
||||
CK_ULONG ulCount /* attrs in search template */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_FindObjects continues a search for token and session
|
||||
* objects that match a template, obtaining additional object
|
||||
* handles. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_FindObjects)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_OBJECT_HANDLE_PTR phObject, /* gets obj. handles */
|
||||
CK_ULONG ulMaxObjectCount, /* max handles to get */
|
||||
CK_ULONG_PTR pulObjectCount /* actual # returned */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_FindObjectsFinal finishes a search for token and session
|
||||
* objects. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession /* the session's handle */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Encryption and decryption */
|
||||
|
||||
/* C_EncryptInit initializes an encryption operation. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_EncryptInit)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */
|
||||
CK_OBJECT_HANDLE hKey /* handle of encryption key */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_Encrypt encrypts single-part data. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_Encrypt)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_BYTE_PTR pData, /* the plaintext data */
|
||||
CK_ULONG ulDataLen, /* bytes of plaintext */
|
||||
CK_BYTE_PTR pEncryptedData, /* gets ciphertext */
|
||||
CK_ULONG_PTR pulEncryptedDataLen /* gets c-text size */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_EncryptUpdate continues a multiple-part encryption
|
||||
* operation. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_BYTE_PTR pPart, /* the plaintext data */
|
||||
CK_ULONG ulPartLen, /* plaintext data len */
|
||||
CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
|
||||
CK_ULONG_PTR pulEncryptedPartLen /* gets c-text size */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_EncryptFinal finishes a multiple-part encryption
|
||||
* operation. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_EncryptFinal)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session handle */
|
||||
CK_BYTE_PTR pLastEncryptedPart, /* last c-text */
|
||||
CK_ULONG_PTR pulLastEncryptedPartLen /* gets last size */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_DecryptInit initializes a decryption operation. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_DecryptInit)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */
|
||||
CK_OBJECT_HANDLE hKey /* handle of decryption key */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_Decrypt decrypts encrypted data in a single part. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_Decrypt)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_BYTE_PTR pEncryptedData, /* ciphertext */
|
||||
CK_ULONG ulEncryptedDataLen, /* ciphertext length */
|
||||
CK_BYTE_PTR pData, /* gets plaintext */
|
||||
CK_ULONG_PTR pulDataLen /* gets p-text size */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_DecryptUpdate continues a multiple-part decryption
|
||||
* operation. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_BYTE_PTR pEncryptedPart, /* encrypted data */
|
||||
CK_ULONG ulEncryptedPartLen, /* input length */
|
||||
CK_BYTE_PTR pPart, /* gets plaintext */
|
||||
CK_ULONG_PTR pulPartLen /* p-text size */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_DecryptFinal finishes a multiple-part decryption
|
||||
* operation. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_DecryptFinal)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pLastPart, /* gets plaintext */
|
||||
CK_ULONG_PTR pulLastPartLen /* p-text size */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Message digesting */
|
||||
|
||||
/* C_DigestInit initializes a message-digesting operation. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_DigestInit)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_MECHANISM_PTR pMechanism /* the digesting mechanism */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_Digest digests data in a single part. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_Digest)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pData, /* data to be digested */
|
||||
CK_ULONG ulDataLen, /* bytes of data to digest */
|
||||
CK_BYTE_PTR pDigest, /* gets the message digest */
|
||||
CK_ULONG_PTR pulDigestLen /* gets digest length */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_DigestUpdate continues a multiple-part message-digesting
|
||||
* operation. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_DigestUpdate)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pPart, /* data to be digested */
|
||||
CK_ULONG ulPartLen /* bytes of data to be digested */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_DigestKey continues a multi-part message-digesting
|
||||
* operation, by digesting the value of a secret key as part of
|
||||
* the data already digested. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_DigestKey)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_OBJECT_HANDLE hKey /* secret key to digest */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_DigestFinal finishes a multiple-part message-digesting
|
||||
* operation. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_DigestFinal)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pDigest, /* gets the message digest */
|
||||
CK_ULONG_PTR pulDigestLen /* gets byte count of digest */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Signing and MACing */
|
||||
|
||||
/* C_SignInit initializes a signature (private key encryption)
|
||||
* operation, where the signature is (will be) an appendix to
|
||||
* the data, and plaintext cannot be recovered from the
|
||||
*signature. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_SignInit)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
|
||||
CK_OBJECT_HANDLE hKey /* handle of signature key */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_Sign signs (encrypts with private key) data in a single
|
||||
* part, where the signature is (will be) an appendix to the
|
||||
* data, and plaintext cannot be recovered from the signature. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_Sign)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pData, /* the data to sign */
|
||||
CK_ULONG ulDataLen, /* count of bytes to sign */
|
||||
CK_BYTE_PTR pSignature, /* gets the signature */
|
||||
CK_ULONG_PTR pulSignatureLen /* gets signature length */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_SignUpdate continues a multiple-part signature operation,
|
||||
* where the signature is (will be) an appendix to the data,
|
||||
* and plaintext cannot be recovered from the signature. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_SignUpdate)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pPart, /* the data to sign */
|
||||
CK_ULONG ulPartLen /* count of bytes to sign */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_SignFinal finishes a multiple-part signature operation,
|
||||
* returning the signature. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_SignFinal)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pSignature, /* gets the signature */
|
||||
CK_ULONG_PTR pulSignatureLen /* gets signature length */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_SignRecoverInit initializes a signature operation, where
|
||||
* the data can be recovered from the signature. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* the signature mechanism */
|
||||
CK_OBJECT_HANDLE hKey /* handle of the signature key */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_SignRecover signs data in a single operation, where the
|
||||
* data can be recovered from the signature. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_SignRecover)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pData, /* the data to sign */
|
||||
CK_ULONG ulDataLen, /* count of bytes to sign */
|
||||
CK_BYTE_PTR pSignature, /* gets the signature */
|
||||
CK_ULONG_PTR pulSignatureLen /* gets signature length */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Verifying signatures and MACs */
|
||||
|
||||
/* C_VerifyInit initializes a verification operation, where the
|
||||
* signature is an appendix to the data, and plaintext cannot
|
||||
* cannot be recovered from the signature (e.g. DSA). */
|
||||
CK_PKCS11_FUNCTION_INFO(C_VerifyInit)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
|
||||
CK_OBJECT_HANDLE hKey /* verification key */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_Verify verifies a signature in a single-part operation,
|
||||
* where the signature is an appendix to the data, and plaintext
|
||||
* cannot be recovered from the signature. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_Verify)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pData, /* signed data */
|
||||
CK_ULONG ulDataLen, /* length of signed data */
|
||||
CK_BYTE_PTR pSignature, /* signature */
|
||||
CK_ULONG ulSignatureLen /* signature length*/
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_VerifyUpdate continues a multiple-part verification
|
||||
* operation, where the signature is an appendix to the data,
|
||||
* and plaintext cannot be recovered from the signature. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pPart, /* signed data */
|
||||
CK_ULONG ulPartLen /* length of signed data */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_VerifyFinal finishes a multiple-part verification
|
||||
* operation, checking the signature. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_VerifyFinal)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pSignature, /* signature to verify */
|
||||
CK_ULONG ulSignatureLen /* signature length */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_VerifyRecoverInit initializes a signature verification
|
||||
* operation, where the data is recovered from the signature. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
|
||||
CK_OBJECT_HANDLE hKey /* verification key */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_VerifyRecover verifies a signature in a single-part
|
||||
* operation, where the data is recovered from the signature. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_VerifyRecover)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pSignature, /* signature to verify */
|
||||
CK_ULONG ulSignatureLen, /* signature length */
|
||||
CK_BYTE_PTR pData, /* gets signed data */
|
||||
CK_ULONG_PTR pulDataLen /* gets signed data len */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Dual-function cryptographic operations */
|
||||
|
||||
/* C_DigestEncryptUpdate continues a multiple-part digesting
|
||||
* and encryption operation. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_BYTE_PTR pPart, /* the plaintext data */
|
||||
CK_ULONG ulPartLen, /* plaintext length */
|
||||
CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
|
||||
CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_DecryptDigestUpdate continues a multiple-part decryption and
|
||||
* digesting operation. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_BYTE_PTR pEncryptedPart, /* ciphertext */
|
||||
CK_ULONG ulEncryptedPartLen, /* ciphertext length */
|
||||
CK_BYTE_PTR pPart, /* gets plaintext */
|
||||
CK_ULONG_PTR pulPartLen /* gets plaintext len */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_SignEncryptUpdate continues a multiple-part signing and
|
||||
* encryption operation. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_BYTE_PTR pPart, /* the plaintext data */
|
||||
CK_ULONG ulPartLen, /* plaintext length */
|
||||
CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */
|
||||
CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_DecryptVerifyUpdate continues a multiple-part decryption and
|
||||
* verify operation. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_BYTE_PTR pEncryptedPart, /* ciphertext */
|
||||
CK_ULONG ulEncryptedPartLen, /* ciphertext length */
|
||||
CK_BYTE_PTR pPart, /* gets plaintext */
|
||||
CK_ULONG_PTR pulPartLen /* gets p-text length */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Key management */
|
||||
|
||||
/* C_GenerateKey generates a secret key, creating a new key
|
||||
* object. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GenerateKey)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* key generation mech. */
|
||||
CK_ATTRIBUTE_PTR pTemplate, /* template for new key */
|
||||
CK_ULONG ulCount, /* # of attrs in template */
|
||||
CK_OBJECT_HANDLE_PTR phKey /* gets handle of new key */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GenerateKeyPair generates a public-key/private-key pair,
|
||||
* creating new key objects. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session
|
||||
* handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* key-gen
|
||||
* mech. */
|
||||
CK_ATTRIBUTE_PTR pPublicKeyTemplate, /* template
|
||||
* for pub.
|
||||
* key */
|
||||
CK_ULONG ulPublicKeyAttributeCount, /* # pub.
|
||||
* attrs. */
|
||||
CK_ATTRIBUTE_PTR pPrivateKeyTemplate, /* template
|
||||
* for priv.
|
||||
* key */
|
||||
CK_ULONG ulPrivateKeyAttributeCount, /* # priv.
|
||||
* attrs. */
|
||||
CK_OBJECT_HANDLE_PTR phPublicKey, /* gets pub.
|
||||
* key
|
||||
* handle */
|
||||
CK_OBJECT_HANDLE_PTR phPrivateKey /* gets
|
||||
* priv. key
|
||||
* handle */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_WrapKey wraps (i.e., encrypts) a key. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_WrapKey)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* the wrapping mechanism */
|
||||
CK_OBJECT_HANDLE hWrappingKey, /* wrapping key */
|
||||
CK_OBJECT_HANDLE hKey, /* key to be wrapped */
|
||||
CK_BYTE_PTR pWrappedKey, /* gets wrapped key */
|
||||
CK_ULONG_PTR pulWrappedKeyLen /* gets wrapped key size */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new
|
||||
* key object. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_UnwrapKey)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* unwrapping mech. */
|
||||
CK_OBJECT_HANDLE hUnwrappingKey, /* unwrapping key */
|
||||
CK_BYTE_PTR pWrappedKey, /* the wrapped key */
|
||||
CK_ULONG ulWrappedKeyLen, /* wrapped key len */
|
||||
CK_ATTRIBUTE_PTR pTemplate, /* new key template */
|
||||
CK_ULONG ulAttributeCount, /* template length */
|
||||
CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_DeriveKey derives a key from a base key, creating a new key
|
||||
* object. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_DeriveKey)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* session's handle */
|
||||
CK_MECHANISM_PTR pMechanism, /* key deriv. mech. */
|
||||
CK_OBJECT_HANDLE hBaseKey, /* base key */
|
||||
CK_ATTRIBUTE_PTR pTemplate, /* new key template */
|
||||
CK_ULONG ulAttributeCount, /* template length */
|
||||
CK_OBJECT_HANDLE_PTR phKey /* gets new handle */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Random number generation */
|
||||
|
||||
/* C_SeedRandom mixes additional seed material into the token's
|
||||
* random number generator. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_SeedRandom)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pSeed, /* the seed material */
|
||||
CK_ULONG ulSeedLen /* length of seed material */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_GenerateRandom generates random data. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GenerateRandom)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR RandomData, /* receives the random data */
|
||||
CK_ULONG ulRandomLen /* # of bytes to generate */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Parallel function management */
|
||||
|
||||
/* C_GetFunctionStatus is a legacy function; it obtains an
|
||||
* updated status of a function running in parallel with an
|
||||
* application. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession /* the session's handle */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* C_CancelFunction is a legacy function; it cancels a function
|
||||
* running in parallel. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_CancelFunction)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_SESSION_HANDLE hSession /* the session's handle */
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Functions added in for PKCS #11 Version 2.01 or later */
|
||||
|
||||
/* C_WaitForSlotEvent waits for a slot event (token insertion,
|
||||
* removal, etc.) to occur. */
|
||||
CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent)
|
||||
#ifdef CK_NEED_ARG_LIST
|
||||
(
|
||||
CK_FLAGS flags, /* blocking/nonblocking flag */
|
||||
CK_SLOT_ID_PTR pSlot, /* location that receives the slot ID */
|
||||
CK_VOID_PTR pRserved /* reserved. Should be NULL_PTR */
|
||||
);
|
||||
#endif
|
||||
+1195
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,24 @@
|
||||
#include "slot_vendors.h"
|
||||
#include "yubico_slot.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
slot_vendor_t get_slot_vendor(vendor_id_t vid) {
|
||||
slot_vendor_t v;
|
||||
|
||||
switch (vid) {
|
||||
case YUBICO:
|
||||
v.get_slot_manufacturer = YUBICO_get_slot_manufacturer;
|
||||
v.get_slot_flags = YUBICO_get_slot_flags;
|
||||
v.get_slot_version = YUBICO_get_slot_version;
|
||||
break;
|
||||
|
||||
case UNKNOWN:
|
||||
default:
|
||||
v.get_slot_manufacturer = NULL;
|
||||
v.get_slot_flags = NULL;
|
||||
v.get_slot_version = NULL;
|
||||
}
|
||||
|
||||
return v;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef SLOT_VENDORS_H
|
||||
#define SLOT_VENDORS_H
|
||||
|
||||
#include "pkcs11.h"
|
||||
#include "vendor_ids.h"
|
||||
|
||||
typedef CK_RV (*get_s_manufacturer_f)(CK_UTF8CHAR_PTR, CK_ULONG);
|
||||
typedef CK_RV (*get_s_flags_f)(CK_FLAGS_PTR);
|
||||
typedef CK_RV (*get_s_version_f)(CK_VERSION_PTR);
|
||||
|
||||
|
||||
typedef struct {
|
||||
get_s_manufacturer_f get_slot_manufacturer;
|
||||
get_s_flags_f get_slot_flags;
|
||||
get_s_version_f get_slot_version;
|
||||
} slot_vendor_t;
|
||||
|
||||
slot_vendor_t get_slot_vendor(vendor_id_t vid);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,315 @@
|
||||
#include "token_vendors.h"
|
||||
#include "yubico_token.h"
|
||||
#include "openssl_utils.h"
|
||||
#include <string.h>
|
||||
#include "debug.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "../tool/util.h"
|
||||
|
||||
static CK_RV COMMON_token_login(ykpiv_state *state, CK_USER_TYPE user, CK_UTF8CHAR_PTR pin, CK_ULONG pin_len) {
|
||||
|
||||
int tries = 0; // TODO: this is effectively disregarded, should we add a better value in ykpiv_verify?
|
||||
unsigned char key[24];
|
||||
size_t key_len = sizeof(key);
|
||||
|
||||
if (user == CKU_USER) {
|
||||
if (ykpiv_verify(state, (char *)pin, &tries) != YKPIV_OK) {
|
||||
DBG("Failed to login");
|
||||
return CKR_PIN_INCORRECT;
|
||||
}
|
||||
}
|
||||
else if (user == CKU_SO) {
|
||||
if(ykpiv_hex_decode((char *)pin, pin_len, key, &key_len) != YKPIV_OK) {
|
||||
DBG("Failed decoding key");
|
||||
return CKR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
if(ykpiv_authenticate(state, key) != YKPIV_OK) {
|
||||
DBG("Failed to authenticate");
|
||||
return CKR_PIN_INCORRECT;
|
||||
}
|
||||
}
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
static CK_RV COMMON_token_generate_key(ykpiv_state *state, CK_BBOOL rsa,
|
||||
CK_BYTE key, CK_ULONG key_len, CK_ULONG vendor_defined) {
|
||||
// TODO: make a function in ykpiv for this
|
||||
unsigned char in_data[11];
|
||||
unsigned char *in_ptr = in_data;
|
||||
unsigned char data[1024];
|
||||
unsigned char templ[] = {0, YKPIV_INS_GENERATE_ASYMMERTRIC, 0, 0};
|
||||
unsigned char *certptr;
|
||||
unsigned long recv_len = sizeof(data);
|
||||
int len_bytes;
|
||||
int sw;
|
||||
|
||||
CK_RV rv;
|
||||
|
||||
templ[3] = key;
|
||||
|
||||
*in_ptr++ = 0xac;
|
||||
*in_ptr++ = 3;
|
||||
*in_ptr++ = 0x80;
|
||||
*in_ptr++ = 1;
|
||||
|
||||
switch(key_len) {
|
||||
case 2048:
|
||||
if (rsa == CK_TRUE)
|
||||
in_data[4] = YKPIV_ALGO_RSA2048;
|
||||
else
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
break;
|
||||
|
||||
case 1024:
|
||||
if (rsa == CK_TRUE)
|
||||
*in_ptr++ = YKPIV_ALGO_RSA1024;
|
||||
else
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
break;
|
||||
|
||||
case 256:
|
||||
if (rsa == CK_FALSE)
|
||||
*in_ptr++ = YKPIV_ALGO_ECCP256;
|
||||
else
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return CKR_FUNCTION_FAILED;
|
||||
}
|
||||
// PIN policy and touch
|
||||
if (vendor_defined != 0) {
|
||||
if (vendor_defined & CKA_PIN_ONCE) {
|
||||
in_data[1] += 3;
|
||||
*in_ptr++ = YKPIV_PINPOLICY_TAG;
|
||||
*in_ptr++ = 0x01;
|
||||
*in_ptr++ = YKPIV_PINPOLICY_ONCE;
|
||||
}
|
||||
else if (vendor_defined & CKA_PIN_ALWAYS) {
|
||||
in_data[1] += 3;
|
||||
*in_ptr++ = YKPIV_PINPOLICY_TAG;
|
||||
*in_ptr++ = 0x01;
|
||||
*in_ptr++ = YKPIV_PINPOLICY_ALWAYS;
|
||||
}
|
||||
|
||||
if (vendor_defined & CKA_TOUCH_ALWAYS) {
|
||||
in_data[1] += 3;
|
||||
*in_ptr++ = YKPIV_TOUCHPOLICY_TAG;
|
||||
*in_ptr++ = 0x01;
|
||||
*in_ptr++ = YKPIV_TOUCHPOLICY_ALWAYS;
|
||||
}
|
||||
}
|
||||
|
||||
if(ykpiv_transfer_data(state, templ, in_data, in_ptr - in_data, data, &recv_len, &sw) != YKPIV_OK ||
|
||||
sw != 0x9000)
|
||||
return CKR_DEVICE_ERROR;
|
||||
|
||||
// Create a new empty certificate for the key
|
||||
recv_len = sizeof(data);
|
||||
if ((rv = do_create_empty_cert(data, recv_len, rsa, data, &recv_len)) != CKR_OK)
|
||||
return rv;
|
||||
|
||||
if (recv_len < 0x80)
|
||||
len_bytes = 1;
|
||||
else if (recv_len < 0xff)
|
||||
len_bytes = 2;
|
||||
else
|
||||
len_bytes = 3;
|
||||
|
||||
certptr = data;
|
||||
memmove(data + len_bytes + 1, data, recv_len);
|
||||
|
||||
*certptr++ = 0x70;
|
||||
certptr += set_length(certptr, recv_len);
|
||||
certptr += recv_len;
|
||||
*certptr++ = 0x71;
|
||||
*certptr++ = 1;
|
||||
*certptr++ = 0; /* certinfo (gzip etc) */
|
||||
*certptr++ = 0xfe; /* LRC */
|
||||
*certptr++ = 0;
|
||||
|
||||
// Store the certificate into the token
|
||||
if (ykpiv_save_object(state, key_to_object_id(key), data, (size_t)(certptr - data)) != YKPIV_OK)
|
||||
return CKR_DEVICE_ERROR;
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
static CK_RV COMMON_token_import_cert(ykpiv_state *state, CK_ULONG cert_id, CK_BYTE_PTR in) {
|
||||
|
||||
unsigned char certdata[2100];
|
||||
unsigned char *certptr;
|
||||
CK_ULONG cert_len;
|
||||
|
||||
CK_RV rv;
|
||||
|
||||
// Check whether or not we have a valid cert
|
||||
if ((rv = do_check_cert(in, &cert_len)) != CKR_OK)
|
||||
return rv;
|
||||
|
||||
if (cert_len > 2100)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
certptr = certdata;
|
||||
|
||||
*certptr++ = 0x70;
|
||||
certptr += set_length(certptr, cert_len);
|
||||
memcpy(certptr, in, cert_len);
|
||||
certptr += cert_len;
|
||||
|
||||
*certptr++ = 0x71;
|
||||
*certptr++ = 1;
|
||||
*certptr++ = 0; /* certinfo (gzip etc) */
|
||||
*certptr++ = 0xfe; /* LRC */
|
||||
*certptr++ = 0;
|
||||
|
||||
// Store the certificate into the token
|
||||
if (ykpiv_save_object(state, cert_id, certdata, (size_t)(certptr - certdata)) != YKPIV_OK)
|
||||
return CKR_DEVICE_ERROR;
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV COMMON_token_import_private_key(ykpiv_state *state, CK_BYTE key_id, CK_BYTE_PTR p, CK_BYTE_PTR q,
|
||||
CK_BYTE_PTR dp, CK_BYTE_PTR dq, CK_BYTE_PTR qinv,
|
||||
CK_BYTE_PTR ec_data, CK_ULONG elem_len, CK_ULONG vendor_defined) {
|
||||
|
||||
unsigned char key_data[1024];
|
||||
unsigned char *in_ptr = key_data;
|
||||
unsigned char templ[] = {0, YKPIV_INS_IMPORT_KEY, 0, key_id};
|
||||
unsigned char data[0xff];
|
||||
unsigned long recv_len = sizeof(data);
|
||||
int sw;
|
||||
|
||||
if (elem_len == 128) // TODO: add a flag to check algo type ?
|
||||
templ[2] = YKPIV_ALGO_RSA2048;
|
||||
else if (elem_len == 64)
|
||||
templ[2] = YKPIV_ALGO_RSA1024;
|
||||
else if(elem_len == 32)
|
||||
templ[2] = YKPIV_ALGO_ECCP256;
|
||||
|
||||
if (templ[2] == YKPIV_ALGO_RSA1024 ||templ[2] == YKPIV_ALGO_RSA2048) {
|
||||
*in_ptr++ = 0x01;
|
||||
in_ptr += set_length(in_ptr, elem_len);
|
||||
memcpy(in_ptr, p, (size_t)(elem_len));
|
||||
in_ptr += elem_len;
|
||||
|
||||
*in_ptr++ = 0x02;
|
||||
in_ptr += set_length(in_ptr, elem_len);
|
||||
memcpy(in_ptr, q, (size_t)(elem_len));
|
||||
in_ptr += elem_len;
|
||||
|
||||
*in_ptr++ = 0x03;
|
||||
in_ptr += set_length(in_ptr, elem_len);
|
||||
memcpy(in_ptr, dp, (size_t)(elem_len));
|
||||
in_ptr += elem_len;
|
||||
|
||||
*in_ptr++ = 0x04;
|
||||
in_ptr += set_length(in_ptr, elem_len);
|
||||
memcpy(in_ptr, dq, (size_t)(elem_len));
|
||||
in_ptr += elem_len;
|
||||
|
||||
*in_ptr++ = 0x05;
|
||||
in_ptr += set_length(in_ptr, elem_len);
|
||||
memcpy(in_ptr, qinv, (size_t)(elem_len));
|
||||
in_ptr += elem_len;
|
||||
}
|
||||
else if (templ[2] == YKPIV_ALGO_ECCP256) {
|
||||
*in_ptr++ = 0x06;
|
||||
in_ptr += set_length(in_ptr, elem_len);
|
||||
memcpy(in_ptr, ec_data, (size_t)(elem_len));
|
||||
in_ptr += elem_len;
|
||||
}
|
||||
|
||||
// PIN policy and touch
|
||||
if (vendor_defined != 0) {
|
||||
if (vendor_defined & CKA_PIN_ONCE) {
|
||||
*in_ptr++ = YKPIV_PINPOLICY_TAG;
|
||||
*in_ptr++ = 0x01;
|
||||
*in_ptr++ = YKPIV_PINPOLICY_ONCE;
|
||||
}
|
||||
else if (vendor_defined & CKA_PIN_ALWAYS) {
|
||||
*in_ptr++ = YKPIV_PINPOLICY_TAG;
|
||||
*in_ptr++ = 0x01;
|
||||
*in_ptr++ = YKPIV_PINPOLICY_ALWAYS;
|
||||
}
|
||||
|
||||
if (vendor_defined & CKA_TOUCH_ALWAYS) {
|
||||
*in_ptr++ = YKPIV_TOUCHPOLICY_TAG;
|
||||
*in_ptr++ = 0x01;
|
||||
*in_ptr++ = YKPIV_TOUCHPOLICY_ALWAYS;
|
||||
}
|
||||
}
|
||||
|
||||
if (ykpiv_transfer_data(state, templ, key_data, in_ptr - key_data, data, &recv_len, &sw) != YKPIV_OK)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
if (sw != 0x9000)
|
||||
return CKR_DEVICE_ERROR;
|
||||
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
CK_RV COMMON_token_delete_cert(ykpiv_state *state, CK_ULONG cert_id) {
|
||||
|
||||
if (ykpiv_save_object(state, cert_id, NULL, 0) != YKPIV_OK)
|
||||
return CKR_DEVICE_ERROR;
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
token_vendor_t get_token_vendor(vendor_id_t vid) {
|
||||
token_vendor_t v;
|
||||
|
||||
switch (vid) {
|
||||
case YUBICO:
|
||||
v.get_token_label = YUBICO_get_token_label;
|
||||
v.get_token_manufacturer = YUBICO_get_token_manufacturer;
|
||||
v.get_token_model = YUBICO_get_token_model;
|
||||
v.get_token_flags = YUBICO_get_token_flags;
|
||||
v.get_token_version = YUBICO_get_token_version;
|
||||
v.get_token_serial = YUBICO_get_token_serial;
|
||||
v.get_token_mechanisms_num = YUBICO_get_token_mechanisms_num;
|
||||
v.get_token_mechanism_list = YUBICO_get_token_mechanism_list;
|
||||
v.get_token_mechanism_info = YUBICO_get_token_mechanism_info;
|
||||
v.get_token_objects_num = YUBICO_get_token_objects_num;
|
||||
v.get_token_object_list = YUBICO_get_token_object_list;
|
||||
v.get_token_raw_certificate = YUBICO_get_token_raw_certificate;
|
||||
v.token_login = COMMON_token_login;
|
||||
v.token_generate_key = COMMON_token_generate_key;
|
||||
v.token_import_cert = COMMON_token_import_cert;
|
||||
v.token_import_private_key = COMMON_token_import_private_key;
|
||||
v.token_delete_cert = COMMON_token_delete_cert;
|
||||
break;
|
||||
|
||||
case UNKNOWN:
|
||||
default:
|
||||
v.get_token_label = NULL;
|
||||
v.get_token_manufacturer = NULL;
|
||||
v.get_token_model = NULL;
|
||||
v.get_token_flags = NULL;
|
||||
v.get_token_version = NULL;
|
||||
v.get_token_serial = NULL;
|
||||
v.get_token_mechanisms_num = NULL;
|
||||
v.get_token_mechanism_list = NULL;
|
||||
v.get_token_mechanism_info = NULL;
|
||||
v.get_token_objects_num = NULL;
|
||||
v.get_token_object_list = NULL;
|
||||
v.get_token_raw_certificate = NULL;
|
||||
v.token_login = NULL;
|
||||
v.token_generate_key = NULL;
|
||||
v.token_import_cert = NULL;
|
||||
v.token_import_private_key = NULL;
|
||||
v.token_delete_cert = NULL;
|
||||
}
|
||||
|
||||
return v;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
#ifndef TOKEN_VENDORS_H
|
||||
#define TOKEN_VENDORS_H
|
||||
|
||||
#include "pkcs11.h"
|
||||
#include "vendor_ids.h"
|
||||
#include "obj_types.h"
|
||||
#include <ykpiv.h>
|
||||
|
||||
typedef CK_RV (*get_t_label_f)(CK_UTF8CHAR_PTR, CK_ULONG);
|
||||
typedef CK_RV (*get_t_manufacturer_f)(CK_UTF8CHAR_PTR, CK_ULONG);
|
||||
typedef CK_RV (*get_t_model_f)(ykpiv_state *, CK_UTF8CHAR_PTR, CK_ULONG);
|
||||
typedef CK_RV (*get_t_flags_f)(CK_FLAGS_PTR);
|
||||
typedef CK_RV (*get_t_version_f)(CK_UTF8CHAR_PTR, CK_ULONG, CK_VERSION_PTR);
|
||||
typedef CK_RV (*get_t_serial_f)(CK_CHAR_PTR, CK_ULONG);
|
||||
typedef CK_RV (*get_t_mechanisms_num_f)(CK_ULONG_PTR);
|
||||
typedef CK_RV (*get_t_mechanism_list_f)(CK_MECHANISM_TYPE_PTR, CK_ULONG);
|
||||
typedef CK_RV (*get_t_mechanism_info_f)(CK_MECHANISM_TYPE, CK_MECHANISM_INFO_PTR);
|
||||
typedef CK_RV (*get_t_objects_num_f)(ykpiv_state *, CK_ULONG_PTR, CK_ULONG_PTR);
|
||||
typedef CK_RV (*get_t_object_list_f)(ykpiv_state *, piv_obj_id_t *, CK_ULONG);
|
||||
typedef CK_RV (*get_t_raw_certificate_f)(ykpiv_state *, piv_obj_id_t, CK_BYTE_PTR, CK_ULONG_PTR);
|
||||
|
||||
// Common token functions below
|
||||
typedef CK_RV (*t_login_f)(ykpiv_state *, CK_USER_TYPE, CK_UTF8CHAR_PTR, CK_ULONG);
|
||||
typedef CK_RV (*t_generate_key_f)(ykpiv_state *, CK_BBOOL, CK_BYTE, CK_ULONG, CK_ULONG);
|
||||
typedef CK_RV (*t_import_cert_f)(ykpiv_state *, CK_ULONG, CK_BYTE_PTR);
|
||||
typedef CK_RV (*t_import_private_key_f)(ykpiv_state *, CK_BYTE, CK_BYTE_PTR, CK_BYTE_PTR, CK_BYTE_PTR,
|
||||
CK_BYTE_PTR, CK_BYTE_PTR, CK_BYTE_PTR, CK_ULONG, CK_ULONG);
|
||||
typedef CK_RV (*t_delete_cert_f)(ykpiv_state *, CK_ULONG);
|
||||
|
||||
// TODO: replace all the common calls with functions defined in .c that use libykpiv
|
||||
|
||||
typedef struct {
|
||||
get_t_label_f get_token_label;
|
||||
get_t_manufacturer_f get_token_manufacturer;
|
||||
get_t_model_f get_token_model;
|
||||
get_t_flags_f get_token_flags;
|
||||
get_t_version_f get_token_version;
|
||||
get_t_serial_f get_token_serial;
|
||||
get_t_mechanisms_num_f get_token_mechanisms_num;
|
||||
get_t_mechanism_list_f get_token_mechanism_list;
|
||||
get_t_mechanism_info_f get_token_mechanism_info;
|
||||
get_t_objects_num_f get_token_objects_num;
|
||||
get_t_object_list_f get_token_object_list;
|
||||
get_t_raw_certificate_f get_token_raw_certificate;
|
||||
t_login_f token_login;
|
||||
t_generate_key_f token_generate_key;
|
||||
t_import_cert_f token_import_cert;
|
||||
t_import_private_key_f token_import_private_key;
|
||||
t_delete_cert_f token_delete_cert;
|
||||
} token_vendor_t;
|
||||
|
||||
token_vendor_t get_token_vendor(vendor_id_t vid);
|
||||
|
||||
#endif
|
||||
+199
@@ -0,0 +1,199 @@
|
||||
#include "utils.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
CK_BBOOL has_token(const ykcs11_slot_t *slot) {
|
||||
|
||||
return (slot->info.flags & CKF_TOKEN_PRESENT);
|
||||
|
||||
}
|
||||
|
||||
CK_RV parse_readers(ykpiv_state *state, const CK_BYTE_PTR readers, const CK_ULONG len,
|
||||
ykcs11_slot_t *slots, CK_ULONG_PTR n_slots, CK_ULONG_PTR n_with_token) {
|
||||
|
||||
CK_BYTE i;
|
||||
CK_BYTE_PTR p;
|
||||
CK_BYTE_PTR s;
|
||||
CK_ULONG l;
|
||||
slot_vendor_t slot;
|
||||
|
||||
*n_slots = 0;
|
||||
*n_with_token = 0;
|
||||
p = readers;
|
||||
|
||||
/*
|
||||
* According to pcsc-lite, the format of a reader name is:
|
||||
* name [interface] (serial) index slot
|
||||
* http://ludovicrousseau.blogspot.se/2010/05/what-is-in-pcsc-reader-name.html
|
||||
*/
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (readers[i] == '\0' && i != len - 1) {
|
||||
slots[*n_slots].vid = get_vendor_id(p);
|
||||
|
||||
if (slots[*n_slots].vid == UNKNOWN) { // TODO: distinguish between tokenless and unsupported?
|
||||
// Unknown slot, just save what info we have
|
||||
memset(&slots[*n_slots].info, 0, sizeof(CK_SLOT_INFO));
|
||||
memset(slots[*n_slots].info.slotDescription, ' ', sizeof(slots[*n_slots].info.slotDescription));
|
||||
if (strlen(p) <= sizeof(slots[*n_slots].info.slotDescription))
|
||||
strncpy(slots[*n_slots].info.slotDescription, p, strlen(p));
|
||||
else
|
||||
strncpy(slots[*n_slots].info.slotDescription, p, sizeof(slots[*n_slots].info.slotDescription));
|
||||
}
|
||||
else {
|
||||
// Supported slot
|
||||
slot = get_slot_vendor(slots[*n_slots].vid);
|
||||
|
||||
// Values must NOT be null terminated and ' ' padded
|
||||
|
||||
memset(slots[*n_slots].info.slotDescription, ' ', sizeof(slots[*n_slots].info.slotDescription));
|
||||
s = slots[*n_slots].info.slotDescription;
|
||||
l = sizeof(slots[*n_slots].info.slotDescription);
|
||||
strncpy((char *)s, (char*)p, l);
|
||||
|
||||
memset(slots[*n_slots].info.manufacturerID, ' ', sizeof(slots[*n_slots].info.manufacturerID));
|
||||
s = slots[*n_slots].info.manufacturerID;
|
||||
l = sizeof(slots[*n_slots].info.manufacturerID);
|
||||
if(slot.get_slot_manufacturer(s, l) != CKR_OK)
|
||||
goto failure;
|
||||
|
||||
if (slot.get_slot_flags(&slots[*n_slots].info.flags) != CKR_OK)
|
||||
goto failure;
|
||||
|
||||
// Treating hw and fw version the same
|
||||
if (slot.get_slot_version(&slots[*n_slots].info.hardwareVersion) != CKR_OK)
|
||||
goto failure;
|
||||
|
||||
if (slot.get_slot_version(&slots[*n_slots].info.firmwareVersion) != CKR_OK)
|
||||
goto failure;
|
||||
|
||||
if (has_token(slots + *n_slots)) {
|
||||
// Save token information
|
||||
(*n_with_token)++;
|
||||
|
||||
if (create_token(state, p, slots + *n_slots) != CKR_OK)
|
||||
goto failure;
|
||||
}
|
||||
}
|
||||
(*n_slots)++;
|
||||
p += i + 1;
|
||||
}
|
||||
|
||||
return CKR_OK;
|
||||
|
||||
failure:
|
||||
// TODO: destroy all token objects
|
||||
for (i = 0; i < *n_slots; i++)
|
||||
if (has_token(slots + i))
|
||||
destroy_token(slots + i);
|
||||
|
||||
return CKR_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
CK_RV create_token(ykpiv_state *state, CK_BYTE_PTR p, ykcs11_slot_t *slot) {
|
||||
|
||||
token_vendor_t token;
|
||||
CK_TOKEN_INFO_PTR t_info;
|
||||
|
||||
slot->token = malloc(sizeof(ykcs11_token_t)); // TODO: free
|
||||
if (slot->token == NULL)
|
||||
return CKR_HOST_MEMORY;
|
||||
|
||||
slot->token->vid = YUBICO; // TODO: this must become "slot_vendor.get_token_vid()"
|
||||
token = get_token_vendor(slot->token->vid);
|
||||
|
||||
t_info = &slot->token->info;
|
||||
|
||||
memset(t_info->label, ' ', sizeof(t_info->label));
|
||||
if (token.get_token_label(t_info->label, sizeof(t_info->label)) != CKR_OK)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
memset(t_info->manufacturerID, ' ', sizeof(t_info->manufacturerID));
|
||||
if(token.get_token_manufacturer(t_info->manufacturerID, sizeof(t_info->manufacturerID)) != CKR_OK)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
if (ykpiv_connect(state, (char *)p) != YKPIV_OK)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
memset(t_info->model, ' ', sizeof(t_info->model));
|
||||
if(token.get_token_model(state, t_info->model, sizeof(t_info->model)) != CKR_OK)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
ykpiv_disconnect(state);
|
||||
|
||||
memset(t_info->serialNumber, ' ', sizeof(t_info->serialNumber));
|
||||
if(token.get_token_serial(t_info->serialNumber, sizeof(t_info->serialNumber)) != CKR_OK)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
if (token.get_token_flags(&t_info->flags) != CKR_OK)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
t_info->ulMaxSessionCount = CK_UNAVAILABLE_INFORMATION;
|
||||
|
||||
t_info->ulSessionCount = CK_UNAVAILABLE_INFORMATION;
|
||||
|
||||
t_info->ulMaxRwSessionCount = CK_UNAVAILABLE_INFORMATION;
|
||||
|
||||
t_info->ulRwSessionCount = CK_UNAVAILABLE_INFORMATION;
|
||||
|
||||
t_info->ulMaxPinLen = 8;
|
||||
|
||||
t_info->ulMinPinLen = 6;
|
||||
|
||||
t_info->ulTotalPublicMemory = CK_UNAVAILABLE_INFORMATION;
|
||||
|
||||
t_info->ulFreePublicMemory = CK_UNAVAILABLE_INFORMATION;
|
||||
|
||||
t_info->ulTotalPrivateMemory = CK_UNAVAILABLE_INFORMATION;
|
||||
|
||||
t_info->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION;
|
||||
|
||||
//ykpiv_get_version(piv_state, buf, sizeof(buf));
|
||||
//if (token_vendor.get_token_version(buf, strlen(buf), &ver) != CKR_OK) // TODO: fix this
|
||||
// return CKR_FUNCTION_FAILED;
|
||||
|
||||
//t_info->hardwareVersion = ver; // version number of hardware // TODO: fix
|
||||
|
||||
//t_info->firmwareVersion = ver; // version number of firmware // TODO: fix
|
||||
|
||||
memset(t_info->utcTime, ' ', sizeof(t_info->utcTime)); // No clock present, clear
|
||||
|
||||
// TODO: also get token objects here? (and destroy on failure)
|
||||
slot->token->objects = NULL;
|
||||
slot->token->n_objects = 0;
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
void destroy_token(ykcs11_slot_t *slot) {
|
||||
free(slot->token);
|
||||
slot->token = NULL;
|
||||
}
|
||||
|
||||
CK_BBOOL is_valid_key_id(CK_BYTE id) {
|
||||
|
||||
// Valid ids are 0, 1, 2, 3
|
||||
if (id > 3)
|
||||
return CK_FALSE;
|
||||
|
||||
return CK_TRUE;
|
||||
}
|
||||
|
||||
void strip_DER_encoding_from_ECSIG(CK_BYTE_PTR data, CK_ULONG_PTR len) {
|
||||
|
||||
CK_BYTE_PTR ptr;
|
||||
CK_ULONG n_len;
|
||||
|
||||
// Maximum DER length for P256 is 2 + 2 + 33 + 2 + 33 = 72
|
||||
if (*len <= 72)
|
||||
n_len = 32;
|
||||
else
|
||||
n_len = 48;
|
||||
|
||||
ptr = data + 4;
|
||||
if (*ptr == 0)
|
||||
ptr++;
|
||||
|
||||
memmove(data, ptr, n_len);
|
||||
memmove(data+n_len, data + *len - n_len, n_len);
|
||||
|
||||
*len = n_len * 2;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef UTILS_H
|
||||
#define UTILS_H
|
||||
|
||||
#include "ykcs11.h"
|
||||
|
||||
CK_BBOOL has_token(const ykcs11_slot_t *slot);
|
||||
CK_RV parse_readers(ykpiv_state *state,const CK_BYTE_PTR readers, const CK_ULONG len,
|
||||
ykcs11_slot_t *slots, CK_ULONG_PTR n_slots, CK_ULONG_PTR n_with_token);
|
||||
CK_RV create_token(ykpiv_state *state, CK_BYTE_PTR p, ykcs11_slot_t *slot);
|
||||
void destroy_token(ykcs11_slot_t *slot);
|
||||
|
||||
CK_BBOOL is_valid_key_id(CK_BYTE id);
|
||||
|
||||
void strip_DER_encoding_from_ECSIG(CK_BYTE_PTR data, CK_ULONG_PTR len);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef VENDOR_IDS_H
|
||||
#define VENDOR_IDS_H
|
||||
|
||||
typedef enum {
|
||||
UNKNOWN = 0x00,
|
||||
YUBICO = 0x01
|
||||
} vendor_id_t;
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
#include "vendors.h"
|
||||
#include <string.h>
|
||||
|
||||
vendor_id_t get_vendor_id(char *vendor_name) {
|
||||
|
||||
if (strstr(vendor_name, "Yubico") != NULL)
|
||||
return YUBICO;
|
||||
|
||||
return UNKNOWN;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef VENDORS_H
|
||||
#define VENDORS_H
|
||||
|
||||
#include "vendor_ids.h"
|
||||
#include "slot_vendors.h"
|
||||
#include "token_vendors.h"
|
||||
|
||||
vendor_id_t get_vendor_id(char *vendor_name);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Yubico AB
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional permission under GNU GPL version 3 section 7
|
||||
*
|
||||
* If you modify this program, or any covered work, by linking or
|
||||
* combining it with the OpenSSL project's OpenSSL library (or a
|
||||
* modified version of that library), containing parts covered by the
|
||||
* terms of the OpenSSL or SSLeay licenses, We grant you additional
|
||||
* permission to convey the resulting work. Corresponding Source for a
|
||||
* non-source form of such a combination shall include the source code
|
||||
* for the parts of OpenSSL used as well as that of the covered work.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ykcs11-version.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* From http://article.gmane.org/gmane.os.freebsd.devel.hackers/23606 */
|
||||
static int my_strverscmp (const char *s1, const char *s2)
|
||||
{
|
||||
static const char *digits = "0123456789";
|
||||
size_t p1, p2;
|
||||
|
||||
p1 = strcspn (s1, digits);
|
||||
p2 = strcspn (s2, digits);
|
||||
while (p1 == p2 && s1[p1] != '\0' && s2[p2] != '\0') {
|
||||
int ret, lz1, lz2;
|
||||
/* Different prefix */
|
||||
if ((ret = strncmp (s1, s2, p1)) != 0)
|
||||
return ret;
|
||||
|
||||
s1 += p1;
|
||||
s2 += p2;
|
||||
|
||||
lz1 = lz2 = 0;
|
||||
if (*s1 == '0')
|
||||
lz1 = 1;
|
||||
if (*s2 == '0')
|
||||
lz2 = 1;
|
||||
|
||||
if (lz1 > lz2)
|
||||
return -1;
|
||||
else if (lz1 < lz2)
|
||||
return 1;
|
||||
else if (lz1 == 1) {
|
||||
/*
|
||||
* If the common prefix for s1 and s2 consists only of zeros, then the
|
||||
* "longer" number has to compare less. Otherwise the comparison needs
|
||||
* to be numerical (just fallthrough). See
|
||||
* http://refspecs.freestandards.org/LSB_2.0.1/LSB-generic/
|
||||
* LSB-generic/baselib-strverscmp.html
|
||||
*/
|
||||
while (*s1 == '0' && *s2 == '0') {
|
||||
++s1;
|
||||
++s2;
|
||||
}
|
||||
|
||||
p1 = strspn (s1, digits);
|
||||
p2 = strspn (s2, digits);
|
||||
|
||||
/* Catch empty strings */
|
||||
if (p1 == 0 && p2 > 0)
|
||||
return 1;
|
||||
else if (p2 == 0 && p1 > 0)
|
||||
return -1;
|
||||
|
||||
/* Prefixes are not same */
|
||||
if (*s1 != *s2 && *s1 != '0' && *s2 != '0') {
|
||||
if (p1 < p2)
|
||||
return 1;
|
||||
else if (p1 > p2)
|
||||
return -1;
|
||||
} else {
|
||||
if (p1 < p2)
|
||||
ret = strncmp (s1, s2, p1);
|
||||
else if (p1 > p2)
|
||||
ret = strncmp (s1, s2, p2);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
p1 = strspn (s1, digits);
|
||||
p2 = strspn (s2, digits);
|
||||
|
||||
if (p1 < p2)
|
||||
return -1;
|
||||
else if (p1 > p2)
|
||||
return 1;
|
||||
else if ((ret = strncmp (s1, s2, p1)) != 0)
|
||||
return ret;
|
||||
|
||||
/* Numbers are equal or not present, try with next ones. */
|
||||
s1 += p1;
|
||||
s2 += p2;
|
||||
p1 = strcspn (s1, digits);
|
||||
p2 = strcspn (s2, digits);
|
||||
}
|
||||
|
||||
return strcmp (s1, s2);
|
||||
}
|
||||
|
||||
/**
|
||||
* ykcs11_check_version:
|
||||
* @req_version: Required version number, or NULL.
|
||||
*
|
||||
* Check that the version of the library is at minimum the requested
|
||||
* one and return the version string; return NULL if the condition is
|
||||
* not satisfied. If a NULL is passed to this function, no check is
|
||||
* done, but the version string is simply returned.
|
||||
*
|
||||
* See %YKCS11_VERSION_STRING for a suitable @req_version string.
|
||||
*
|
||||
* Return value: Version string of run-time library, or NULL if the
|
||||
* run-time library does not meet the required version number.
|
||||
*/
|
||||
const char * ykcs11_check_version (const char *req_version)
|
||||
{
|
||||
if (!req_version
|
||||
|| my_strverscmp (req_version, YKCS11_VERSION_STRING) <= 0)
|
||||
return YKCS11_VERSION_STRING;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Yubico AB
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional permission under GNU GPL version 3 section 7
|
||||
*
|
||||
* If you modify this program, or any covered work, by linking or
|
||||
* combining it with the OpenSSL project's OpenSSL library (or a
|
||||
* modified version of that library), containing parts covered by the
|
||||
* terms of the OpenSSL or SSLeay licenses, We grant you additional
|
||||
* permission to convey the resulting work. Corresponding Source for a
|
||||
* non-source form of such a combination shall include the source code
|
||||
* for the parts of OpenSSL used as well as that of the covered work.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef YKCS11_VERSION_H
|
||||
#define YKCS11_VERSION_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* YKCS11_VERSION_STRING
|
||||
*
|
||||
* Pre-processor symbol with a string that describe the header file
|
||||
* version number. Used together with ykneomgr_check_version() to verify
|
||||
* header file and run-time library consistency.
|
||||
*/
|
||||
#define YKCS11_VERSION_STRING "@VERSION@"
|
||||
|
||||
/**
|
||||
* YKCS11_VERSION_NUMBER
|
||||
*
|
||||
* Pre-processor symbol with a hexadecimal value describing the header
|
||||
* file version number. For example, when the header version is 1.2.3
|
||||
* this symbol will have the value 0x01020300. The last two digits
|
||||
* are only used between public releases, and will otherwise be 00.
|
||||
*/
|
||||
#define YKCS11_VERSION_NUMBER @YKCS11_VERSION_NUMBER@
|
||||
|
||||
/**
|
||||
* YKCS11_VERSION_MAJOR
|
||||
*
|
||||
* Pre-processor symbol with a decimal value that describe the major
|
||||
* level of the header file version number. For example, when the
|
||||
* header version is 1.2.3 this symbol will be 1.
|
||||
*/
|
||||
#define YKCS11_VERSION_MAJOR @YKCS11_VERSION_MAJOR@
|
||||
|
||||
/**
|
||||
* YKCS11_VERSION_MINOR
|
||||
*
|
||||
* Pre-processor symbol with a decimal value that describe the minor
|
||||
* level of the header file version number. For example, when the
|
||||
* header version is 1.2.3 this symbol will be 2.
|
||||
*/
|
||||
#define YKCS11_VERSION_MINOR @YKCS11_VERSION_MINOR@
|
||||
|
||||
/**
|
||||
* YKCS11_VERSION_PATCH
|
||||
*
|
||||
* Pre-processor symbol with a decimal value that describe the patch
|
||||
* level of the header file version number. For example, when the
|
||||
* header version is 1.2.3 this symbol will be 3.
|
||||
*/
|
||||
#define YKCS11_VERSION_PATCH @YKCS11_VERSION_PATCH@
|
||||
|
||||
const char *ykcs11_check_version (const char *req_version);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+2391
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,77 @@
|
||||
#ifndef YKCS11_H
|
||||
#define YKCS11_H
|
||||
|
||||
#include "pkcs11t.h"
|
||||
#include "obj_types.h"
|
||||
#include "openssl_types.h"
|
||||
#include "vendors.h"
|
||||
|
||||
#define YKCS11_OP_BUFSIZE 4096
|
||||
|
||||
typedef struct {
|
||||
vendor_id_t vid;
|
||||
CK_TOKEN_INFO info;
|
||||
piv_obj_id_t *objects; // List of objects in the token
|
||||
CK_ULONG n_objects; // TOTAL number of objects in the token
|
||||
CK_ULONG n_certs; // Number of certificate objects in the token (portion of n_objects)
|
||||
} ykcs11_token_t;
|
||||
|
||||
typedef struct {
|
||||
vendor_id_t vid;
|
||||
CK_SLOT_INFO info;
|
||||
ykcs11_token_t *token;
|
||||
} ykcs11_slot_t;
|
||||
|
||||
typedef struct {
|
||||
CK_SESSION_HANDLE handle;
|
||||
CK_SESSION_INFO info; /* slotid, state, flags, deviceerror */
|
||||
ykcs11_slot_t *slot;
|
||||
} ykcs11_session_t;
|
||||
|
||||
typedef enum {
|
||||
YKCS11_NOOP,
|
||||
YKCS11_GEN,
|
||||
YKCS11_SIGN,
|
||||
YKCS11_HASH,
|
||||
YKCS11_DECRYPT
|
||||
} ykcs11_op_type_t;
|
||||
|
||||
typedef struct {
|
||||
CK_BBOOL rsa; // RSA or EC key
|
||||
CK_BYTE key_id; // Key id
|
||||
CK_ULONG key_len; // Length in bits
|
||||
CK_ULONG vendor_defined; // Additional parameters (touch and PIN policy)
|
||||
} gen_info_t;
|
||||
|
||||
typedef struct {
|
||||
ykcs11_md_ctx_t *md_ctx; // Digest context
|
||||
CK_BYTE_PTR key; // Raw public key (needed for PSS)
|
||||
CK_BYTE algo; // Algo for ykpiv // TODO: infer this from the key length?
|
||||
CK_ULONG key_id; // Key id for ykpiv // TODO: make this a BYTE and store the id {0, 1, 2, 3}
|
||||
CK_ULONG key_len; // Length in bits
|
||||
} sign_info_t;
|
||||
|
||||
typedef struct {
|
||||
CK_BYTE todo;
|
||||
} hash_info_t;
|
||||
|
||||
typedef struct {
|
||||
CK_BYTE todo;
|
||||
} decrypt_info_t;
|
||||
|
||||
typedef union {
|
||||
gen_info_t gen;
|
||||
sign_info_t sign;
|
||||
hash_info_t hash;
|
||||
decrypt_info_t decrypt;
|
||||
} op_t;
|
||||
|
||||
typedef struct {
|
||||
ykcs11_op_type_t type;
|
||||
CK_MECHANISM mechanism;
|
||||
op_t op;
|
||||
CK_BYTE buf[YKCS11_OP_BUFSIZE];
|
||||
CK_ULONG buf_len;
|
||||
} op_info_t;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
# Copyright (c) 2014 Yubico AB
|
||||
# All rights reserved.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Additional permission under GNU GPL version 3 section 7
|
||||
#
|
||||
# If you modify this program, or any covered work, by linking or
|
||||
# combining it with the OpenSSL project's OpenSSL library (or a
|
||||
# modified version of that library), containing parts covered by the
|
||||
# terms of the OpenSSL or SSLeay licenses, We grant you additional
|
||||
# permission to convey the resulting work. Corresponding Source for a
|
||||
# non-source form of such a combination shall include the source code
|
||||
# for the parts of OpenSSL used as well as that of the covered work.
|
||||
|
||||
YKCS11_0.1.0
|
||||
{
|
||||
global:
|
||||
C_Initialize;
|
||||
C_GetFunctionList;
|
||||
# TODO: add more here
|
||||
local:
|
||||
*;
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: @PACKAGE@
|
||||
Description: Yubico PIV PKCS#11 Module
|
||||
URL: https://www.yubico.com/
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -lykcs11
|
||||
Cflags: -I${includedir}/ykpiv
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#include "yubico_slot.h"
|
||||
#include "pkcs11.h"
|
||||
#include <string.h>
|
||||
|
||||
static const CK_UTF8CHAR_PTR slot_manufacturer = "Yubico";
|
||||
static const CK_FLAGS slot_flags = CKF_TOKEN_PRESENT | CKF_HW_SLOT;
|
||||
static const CK_VERSION slot_version = {1, 0};
|
||||
|
||||
CK_RV YUBICO_get_slot_manufacturer(CK_UTF8CHAR_PTR str, CK_ULONG len) {
|
||||
|
||||
if (strlen(slot_manufacturer) > len)
|
||||
return CKR_BUFFER_TOO_SMALL;
|
||||
|
||||
memcpy(str, slot_manufacturer, strlen(slot_manufacturer));
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
CK_RV YUBICO_get_slot_flags(CK_FLAGS_PTR flags) {
|
||||
|
||||
*flags = slot_flags;
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
CK_RV YUBICO_get_slot_version(CK_VERSION_PTR version) {
|
||||
|
||||
version->major = slot_version.major;
|
||||
version->minor = slot_version.minor;
|
||||
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef YUBICO_SLOT_H
|
||||
#define YUBICO_SLOT_H
|
||||
|
||||
#include "pkcs11.h"
|
||||
|
||||
CK_RV YUBICO_get_slot_manufacturer(CK_UTF8CHAR_PTR str, CK_ULONG len);
|
||||
CK_RV YUBICO_get_slot_flags(CK_FLAGS_PTR flags);
|
||||
CK_RV YUBICO_get_slot_version(CK_VERSION_PTR version);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,319 @@
|
||||
#include "yubico_token.h"
|
||||
#include "pkcs11.h"
|
||||
#include <string.h>
|
||||
#include "debug.h"
|
||||
#include "objects.h"
|
||||
|
||||
#define MIN_RSA_KEY_SIZE 1024
|
||||
#define MAX_RSA_KEY_SIZE 2048
|
||||
#define MIN_ECC_KEY_SIZE 256
|
||||
#define MAX_ECC_KEY_SIZE 384
|
||||
|
||||
static const char *token_label = "YubiKey PIV";
|
||||
static const char *token_manufacturer = "Yubico";
|
||||
static const char *token_model = "YubiKey XXX";
|
||||
static const CK_FLAGS token_flags = CKF_RNG | CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED | CKF_TOKEN_INITIALIZED;
|
||||
static const char *token_serial = "1234";
|
||||
static const CK_MECHANISM_TYPE token_mechanisms[] = { // KEEP ALIGNED WITH token_mechanism_infos
|
||||
CKM_RSA_PKCS_KEY_PAIR_GEN,
|
||||
CKM_RSA_PKCS,
|
||||
CKM_RSA_PKCS_PSS,
|
||||
CKM_RSA_X_509,
|
||||
CKM_SHA1_RSA_PKCS,
|
||||
CKM_SHA256_RSA_PKCS,
|
||||
CKM_SHA384_RSA_PKCS,
|
||||
CKM_SHA512_RSA_PKCS,
|
||||
CKM_SHA1_RSA_PKCS_PSS,
|
||||
CKM_SHA256_RSA_PKCS_PSS,
|
||||
CKM_SHA384_RSA_PKCS_PSS,
|
||||
CKM_SHA512_RSA_PKCS_PSS,
|
||||
CKM_EC_KEY_PAIR_GEN,
|
||||
//CKM_ECDSA_KEY_PAIR_GEN, Same as CKM_EC_KEY_PAIR_GEN, deprecated in 2.11
|
||||
CKM_ECDSA,
|
||||
CKM_ECDSA_SHA1,
|
||||
CKM_ECDSA_SHA256,
|
||||
CKM_SHA_1,
|
||||
CKM_SHA256,
|
||||
CKM_SHA384,
|
||||
CKM_SHA512
|
||||
// SUPPORT FOR OATH?
|
||||
};
|
||||
static const CK_ULONG token_mechanisms_num = sizeof(token_mechanisms) / sizeof(CK_MECHANISM_TYPE);
|
||||
|
||||
static const CK_MECHANISM_INFO token_mechanism_infos[] = { // KEEP ALIGNED WITH token_mechanisms
|
||||
{MIN_RSA_KEY_SIZE, MAX_RSA_KEY_SIZE, CKF_HW | CKF_GENERATE_KEY_PAIR}, // CKM_RSA_PKCS_KEY_PAIR_GEN
|
||||
{MIN_RSA_KEY_SIZE, MAX_RSA_KEY_SIZE, CKF_HW | CKF_DECRYPT | CKF_SIGN}, // CKM_RSA_PKCS
|
||||
{MIN_RSA_KEY_SIZE, MAX_RSA_KEY_SIZE, CKF_HW | CKF_SIGN}, // CKM_RSA_PKCS_PSS
|
||||
{MIN_RSA_KEY_SIZE, MAX_RSA_KEY_SIZE, CKF_HW | CKF_DECRYPT | CKF_SIGN}, // CKM_RSA_X_509
|
||||
{MIN_RSA_KEY_SIZE, MAX_RSA_KEY_SIZE, CKF_HW | CKF_SIGN}, // CKM_SHA1_RSA_PKCS
|
||||
{MIN_RSA_KEY_SIZE, MAX_RSA_KEY_SIZE, CKF_HW | CKF_SIGN}, // CKM_SHA256_RSA_PKCS
|
||||
{MIN_RSA_KEY_SIZE, MAX_RSA_KEY_SIZE, CKF_HW | CKF_SIGN}, // CKM_SHA384_RSA_PKCS
|
||||
{MIN_RSA_KEY_SIZE, MAX_RSA_KEY_SIZE, CKF_HW | CKF_SIGN}, // CKM_SHA512_RSA_PKCS
|
||||
{MIN_RSA_KEY_SIZE, MAX_RSA_KEY_SIZE, CKF_HW | CKF_SIGN}, // CKM_SHA1_RSA_PKCS_PSS
|
||||
{MIN_RSA_KEY_SIZE, MAX_RSA_KEY_SIZE, CKF_HW | CKF_SIGN}, // CKM_SHA256_RSA_PKCS_PSS
|
||||
{MIN_RSA_KEY_SIZE, MAX_RSA_KEY_SIZE, CKF_HW | CKF_SIGN}, // CKM_SHA384_RSA_PKCS_PSS
|
||||
{MIN_RSA_KEY_SIZE, MAX_RSA_KEY_SIZE, CKF_HW | CKF_SIGN}, // CKM_SHA512_RSA_PKCS_PSS
|
||||
{MIN_ECC_KEY_SIZE, MAX_ECC_KEY_SIZE, CKF_HW | CKF_GENERATE_KEY_PAIR}, // CKM_EC_KEY_PAIR_GEN
|
||||
//{, , }, // CKM_ECDSA_KEY_PAIR_GEN Same as CKM_EC_KEY_PAIR_GEN deprecated in 2.11
|
||||
{MIN_ECC_KEY_SIZE, MAX_ECC_KEY_SIZE, CKF_HW | CKF_SIGN}, // CKM_ECDSA
|
||||
{MIN_ECC_KEY_SIZE, MAX_ECC_KEY_SIZE, CKF_HW | CKF_SIGN}, // CKM_ECDSA_SHA1
|
||||
{MIN_ECC_KEY_SIZE, MAX_ECC_KEY_SIZE, CKF_HW | CKF_SIGN}, // CKM_ECDSA_SHA256
|
||||
{0, 0, CKF_DIGEST}, // CKM_SHA_1
|
||||
{0, 0, CKF_DIGEST}, // CKM_SHA256
|
||||
{0, 0, CKF_DIGEST}, // CKM_SHA384
|
||||
{0, 0, CKF_DIGEST} // CKM_SHA512
|
||||
};
|
||||
|
||||
static const piv_obj_id_t token_objects[] = { // TODO: is there a way to get this from the token?
|
||||
PIV_DATA_OBJ_X509_PIV_AUTH, // PIV authentication
|
||||
PIV_DATA_OBJ_X509_CARD_AUTH, // Certificate for card authentication
|
||||
PIV_DATA_OBJ_X509_DS, // Certificate for digital signature
|
||||
PIV_DATA_OBJ_X509_KM, // Certificate for key management
|
||||
PIV_DATA_OBJ_CCC, // Card capability container
|
||||
PIV_DATA_OBJ_CHUI, // Cardholder unique id
|
||||
PIV_DATA_OBJ_CHF, // Cardholder fingerprints
|
||||
PIV_DATA_OBJ_SEC_OBJ, // Security object
|
||||
PIV_DATA_OBJ_CHFI, // Cardholder facial images
|
||||
//PIV_DATA_OBJ_PI, // Cardholder printed information
|
||||
//PIV_DATA_OBJ_DISCOVERY, // Discovery object
|
||||
//PIV_DATA_OBJ_HISTORY, // History object
|
||||
/* PIV_DATA_OBJ_RETIRED_X509_1, // Retired certificate for KM 1
|
||||
PIV_DATA_OBJ_RETIRED_X509_2, // Retired certificate for KM 2
|
||||
PIV_DATA_OBJ_RETIRED_X509_3, // Retired certificate for KM 3
|
||||
PIV_DATA_OBJ_RETIRED_X509_4, // Retired certificate for KM 4
|
||||
PIV_DATA_OBJ_RETIRED_X509_5, // Retired certificate for KM 5
|
||||
PIV_DATA_OBJ_RETIRED_X509_6, // Retired certificate for KM 6
|
||||
PIV_DATA_OBJ_RETIRED_X509_7, // Retired certificate for KM 7
|
||||
PIV_DATA_OBJ_RETIRED_X509_8, // Retired certificate for KM 8
|
||||
PIV_DATA_OBJ_RETIRED_X509_9, // Retired certificate for KM 9
|
||||
PIV_DATA_OBJ_RETIRED_X509_10, // Retired certificate for KM 10
|
||||
PIV_DATA_OBJ_RETIRED_X509_11, // Retired certificate for KM 11
|
||||
PIV_DATA_OBJ_RETIRED_X509_12, // Retired certificate for KM 12
|
||||
PIV_DATA_OBJ_RETIRED_X509_13, // Retired certificate for KM 13
|
||||
PIV_DATA_OBJ_RETIRED_X509_14, // Retired certificate for KM 14
|
||||
PIV_DATA_OBJ_RETIRED_X509_15, // Retired certificate for KM 15
|
||||
PIV_DATA_OBJ_RETIRED_X509_16, // Retired certificate for KM 16
|
||||
PIV_DATA_OBJ_RETIRED_X509_17, // Retired certificate for KM 17
|
||||
PIV_DATA_OBJ_RETIRED_X509_18, // Retired certificate for KM 18
|
||||
PIV_DATA_OBJ_RETIRED_X509_19, // Retired certificate for KM 19
|
||||
PIV_DATA_OBJ_RETIRED_X509_20, // Retired certificate for KM 20*/
|
||||
//PIV_DATA_OBJ_IRIS_IMAGE, // Cardholder iris images
|
||||
//PIV_DATA_OBJ_BITGT, // Biometric information templates group template
|
||||
//PIV_DATA_OBJ_SM_SIGNER, // Secure messaging signer
|
||||
//PIV_DATA_OBJ_PC_REF_DATA, // Pairing code reference data
|
||||
};
|
||||
static const CK_ULONG token_objects_num = sizeof(token_objects) / sizeof(piv_obj_id_t);
|
||||
|
||||
CK_RV YUBICO_get_token_label(CK_UTF8CHAR_PTR str, CK_ULONG len) {
|
||||
|
||||
if (strlen(token_label) > len)
|
||||
return CKR_BUFFER_TOO_SMALL;
|
||||
|
||||
memcpy(str, token_label, strlen(token_label));
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
CK_RV YUBICO_get_token_manufacturer(CK_UTF8CHAR_PTR str, CK_ULONG len) {
|
||||
|
||||
if (strlen(token_manufacturer) > len)
|
||||
return CKR_BUFFER_TOO_SMALL;
|
||||
|
||||
memcpy(str, token_manufacturer, strlen(token_manufacturer));
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
#include "debug.h"
|
||||
CK_RV YUBICO_get_token_model(ykpiv_state *state, CK_UTF8CHAR_PTR str, CK_ULONG len) {
|
||||
|
||||
char buf[16];
|
||||
|
||||
if (strlen(token_model) > len)
|
||||
return CKR_BUFFER_TOO_SMALL;
|
||||
|
||||
if (ykpiv_get_version(state, buf, sizeof(buf)) != YKPIV_OK)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
memcpy(str, token_model, strlen(token_model));
|
||||
|
||||
if (buf[0] >= '4')
|
||||
memcpy(str + strlen(token_model) - 3, "YK4", 3);
|
||||
else
|
||||
memcpy(str + strlen(token_model) - 3, "NEO", 3);
|
||||
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
CK_RV YUBICO_get_token_flags(CK_FLAGS_PTR flags) {
|
||||
|
||||
*flags = token_flags;
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
CK_RV YUBICO_get_token_version(CK_UTF8CHAR_PTR v_str, CK_ULONG len, CK_VERSION_PTR version) {
|
||||
|
||||
CK_VERSION v = {0, 0};
|
||||
unsigned int i = 0;
|
||||
|
||||
while (i < len && v_str[i] != '.') {
|
||||
v.major *= 10;
|
||||
v.major += v_str[i++] - '0';
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
while (i < len && v_str[i] != '.') {
|
||||
v.minor *= 10;
|
||||
v.minor += v_str[i++] - '0';
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
while (i < len && v_str[i] != '.') {
|
||||
v.minor *= 10;
|
||||
v.minor += v_str[i++] - '0';
|
||||
}
|
||||
|
||||
version->major = v.major;
|
||||
version->minor = v.minor;
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV YUBICO_get_token_serial(CK_CHAR_PTR str, CK_ULONG len) {
|
||||
|
||||
if (strlen(token_serial) > len)
|
||||
return CKR_BUFFER_TOO_SMALL;
|
||||
|
||||
memcpy(str, token_serial, strlen(token_serial));
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
CK_RV YUBICO_get_token_mechanisms_num(CK_ULONG_PTR num) {
|
||||
|
||||
*num = token_mechanisms_num;
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
CK_RV YUBICO_get_token_mechanism_list(CK_MECHANISM_TYPE_PTR mec, CK_ULONG num) {
|
||||
|
||||
if (token_mechanisms_num > num)
|
||||
return CKR_BUFFER_TOO_SMALL;
|
||||
|
||||
memcpy(mec, token_mechanisms, token_mechanisms_num * sizeof(CK_MECHANISM_TYPE));
|
||||
return CKR_OK;
|
||||
|
||||
}
|
||||
|
||||
CK_RV YUBICO_get_token_mechanism_info(CK_MECHANISM_TYPE mec, CK_MECHANISM_INFO_PTR info) {
|
||||
|
||||
CK_ULONG i;
|
||||
|
||||
for (i = 0; i < token_mechanisms_num; i++)
|
||||
if (token_mechanisms[i] == mec) {
|
||||
memcpy((CK_BYTE_PTR) info, (CK_BYTE_PTR) (token_mechanism_infos + i), sizeof(CK_MECHANISM_INFO));
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
return CKR_MECHANISM_INVALID;
|
||||
|
||||
}
|
||||
|
||||
static CK_RV get_objects(ykpiv_state *state, CK_BBOOL num_only,
|
||||
piv_obj_id_t *obj, CK_ULONG_PTR len, CK_ULONG_PTR num_certs) {
|
||||
CK_BYTE buf[2048];
|
||||
CK_ULONG buf_len;
|
||||
|
||||
piv_obj_id_t certs[4]; // TODO: this can be > 4 if there are retired keys
|
||||
piv_obj_id_t pvtkeys[4];
|
||||
piv_obj_id_t pubkeys[4];
|
||||
CK_ULONG n_cert = 0;
|
||||
|
||||
if (state == NULL || len == NULL_PTR)
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
|
||||
if (num_only == CK_FALSE && obj == NULL)
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
|
||||
buf_len = sizeof(buf);
|
||||
if (ykpiv_fetch_object(state, YKPIV_OBJ_AUTHENTICATION, buf, &buf_len) == YKPIV_OK) {
|
||||
certs[n_cert] = PIV_CERT_OBJ_X509_PIV_AUTH;
|
||||
pvtkeys[n_cert] = PIV_PVTK_OBJ_PIV_AUTH;
|
||||
pubkeys[n_cert] = PIV_PUBK_OBJ_PIV_AUTH;
|
||||
n_cert++;
|
||||
DBG("Found AUTH cert (9a)");
|
||||
}
|
||||
|
||||
buf_len = sizeof(buf);
|
||||
if (ykpiv_fetch_object(state, YKPIV_OBJ_CARD_AUTH, buf, &buf_len) == YKPIV_OK) {
|
||||
certs[n_cert] = PIV_CERT_OBJ_X509_CARD_AUTH;
|
||||
pvtkeys[n_cert] = PIV_PVTK_OBJ_CARD_AUTH;
|
||||
pubkeys[n_cert] = PIV_PUBK_OBJ_CARD_AUTH;
|
||||
n_cert++;
|
||||
DBG("Found CARD AUTH cert (9e)");
|
||||
}
|
||||
|
||||
buf_len = sizeof(buf);
|
||||
if (ykpiv_fetch_object(state, YKPIV_OBJ_SIGNATURE, buf, &buf_len) == YKPIV_OK) {
|
||||
certs[n_cert] = PIV_CERT_OBJ_X509_DS;
|
||||
pvtkeys[n_cert] = PIV_PVTK_OBJ_DS;
|
||||
pubkeys[n_cert] = PIV_PUBK_OBJ_DS;
|
||||
n_cert++;
|
||||
DBG("Found SIGNATURE cert (9c)");
|
||||
}
|
||||
|
||||
buf_len = sizeof(buf);
|
||||
if (ykpiv_fetch_object(state, YKPIV_OBJ_KEY_MANAGEMENT, buf, &buf_len) == YKPIV_OK) {
|
||||
certs[n_cert] = PIV_CERT_OBJ_X509_KM;
|
||||
pvtkeys[n_cert] = PIV_PVTK_OBJ_KM;
|
||||
pubkeys[n_cert] = PIV_PUBK_OBJ_KM;
|
||||
n_cert++;
|
||||
DBG("Found KMK cert (9d)");
|
||||
}
|
||||
|
||||
DBG("The total number of objects for this token is %lu", (n_cert * 3) + token_objects_num);
|
||||
|
||||
if (num_only == CK_TRUE) {
|
||||
// We just want the number of objects
|
||||
// Each cert object counts for 3: cert, pub key, pvt key
|
||||
*len = (n_cert * 3) + token_objects_num;
|
||||
if (num_certs != NULL)
|
||||
*num_certs = n_cert;
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
if (*len < (n_cert * 3) + token_objects_num)
|
||||
return CKR_BUFFER_TOO_SMALL;
|
||||
|
||||
// Copy mandatory data objects
|
||||
memcpy(obj, token_objects, token_objects_num * sizeof(piv_obj_id_t));
|
||||
|
||||
// Copy certificates
|
||||
if (n_cert > 0) {
|
||||
memcpy(obj + token_objects_num, certs, n_cert * sizeof(piv_obj_id_t));
|
||||
memcpy(obj + token_objects_num + n_cert, pvtkeys, n_cert * sizeof(piv_obj_id_t));
|
||||
memcpy(obj + token_objects_num + (2 * n_cert), pubkeys, n_cert * sizeof(piv_obj_id_t));
|
||||
}
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
CK_RV YUBICO_get_token_objects_num(ykpiv_state *state, CK_ULONG_PTR num, CK_ULONG_PTR num_certs) {
|
||||
return get_objects(state, CK_TRUE, NULL, num, num_certs);
|
||||
}
|
||||
|
||||
CK_RV YUBICO_get_token_object_list(ykpiv_state *state, piv_obj_id_t *obj, CK_ULONG num) {
|
||||
return get_objects(state, CK_FALSE, obj, &num, NULL);
|
||||
}
|
||||
|
||||
CK_RV YUBICO_get_token_raw_certificate(ykpiv_state *state, piv_obj_id_t obj, CK_BYTE_PTR data, CK_ULONG_PTR len) {
|
||||
|
||||
if (ykpiv_fetch_object(state, piv_2_ykpiv(obj), data, len) != YKPIV_OK)
|
||||
return CKR_FUNCTION_FAILED;
|
||||
|
||||
return CKR_OK;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef YUBICO_TOKEN_H
|
||||
#define YUBICO_TOKEN_H
|
||||
|
||||
#include "pkcs11.h"
|
||||
#include "obj_types.h"
|
||||
#include <ykpiv.h>
|
||||
|
||||
CK_RV YUBICO_get_token_label(CK_UTF8CHAR_PTR str, CK_ULONG len);
|
||||
CK_RV YUBICO_get_token_manufacturer(CK_UTF8CHAR_PTR str, CK_ULONG len);
|
||||
CK_RV YUBICO_get_token_model(ykpiv_state *state, CK_UTF8CHAR_PTR str, CK_ULONG len);
|
||||
CK_RV YUBICO_get_token_flags(CK_FLAGS_PTR flags);
|
||||
CK_RV YUBICO_get_token_serial(CK_CHAR_PTR str, CK_ULONG len);
|
||||
CK_RV YUBICO_get_token_version(CK_UTF8CHAR_PTR v_str, CK_ULONG v_str_len, CK_VERSION_PTR version);
|
||||
CK_RV YUBICO_get_token_mechanisms_num(CK_ULONG_PTR num);
|
||||
CK_RV YUBICO_get_token_mechanism_list(CK_MECHANISM_TYPE_PTR mec, CK_ULONG num);
|
||||
CK_RV YUBICO_get_token_mechanism_info(CK_MECHANISM_TYPE mec, CK_MECHANISM_INFO_PTR info);
|
||||
CK_RV YUBICO_get_token_objects_num(ykpiv_state *state, CK_ULONG_PTR num, CK_ULONG_PTR num_certs);
|
||||
CK_RV YUBICO_get_token_object_list(ykpiv_state *state, piv_obj_id_t *obj, CK_ULONG num);
|
||||
CK_RV YUBICO_get_token_raw_certificate(ykpiv_state *state, piv_obj_id_t obj, CK_BYTE_PTR data, CK_ULONG_PTR len);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user