From 0e56e90c4a6c55b280edc468ffa4cd0f10a374a7 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Thu, 21 Sep 2023 19:21:59 +0900 Subject: [PATCH] export-object: Recover public key from algorithm specific attributes Some tokens such as SoftHSMv2 omits CKA_PUBLIC_KEY_INFO when it can be derived from algorithm specific attributes, such as CKA_MODULUS and CKA_PUBLIC_EXPONENT for RSA. This adds support for it if libtasn1 is available at compile time. Signed-off-by: Daiki Ueno --- common/oid.h | 3 + common/pkix.asn | 4 + p11-kit/Makefile.am | 23 +- p11-kit/export-object.c | 416 +++++++++++++++--- .../fixtures/package-modules/twelve.module | 4 + .../package-modules/win32/twelve.module | 4 + p11-kit/meson.build | 13 +- p11-kit/mock-module-ep10.c | 194 ++++++++ p11-kit/test-export-public.sh | 90 ++++ p11-kit/test-lists.sh | 17 + p11-kit/test-objects.sh | 35 +- 11 files changed, 744 insertions(+), 59 deletions(-) create mode 100644 p11-kit/fixtures/package-modules/twelve.module create mode 100644 p11-kit/fixtures/package-modules/win32/twelve.module create mode 100644 p11-kit/mock-module-ep10.c create mode 100755 p11-kit/test-export-public.sh diff --git a/common/oid.h b/common/oid.h index 96a223a4f..eff313658 100644 --- a/common/oid.h +++ b/common/oid.h @@ -241,4 +241,7 @@ static const unsigned char P11_OID_RESERVED_PURPOSE[] = { 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x99, 0x77, 0x06, 0x0a, 0x10 }; static const char P11_OID_RESERVED_PURPOSE_STR[] = "1.3.6.1.4.1.3319.6.10.16"; +static const char P11_OID_PKIX1_RSA_STR[] = "1.2.840.113549.1.1.1"; +static const char P11_OID_PKIX1_EC_STR[] = "1.2.840.10045.2.1"; + #endif diff --git a/common/pkix.asn b/common/pkix.asn index cd2d2c6bc..45f8bc7bd 100644 --- a/common/pkix.asn +++ b/common/pkix.asn @@ -537,4 +537,8 @@ ProxyPolicy ::= SEQUENCE { policyLanguage OBJECT IDENTIFIER, policy OCTET STRING OPTIONAL } +RSAPublicKey ::= SEQUENCE { + modulus INTEGER, + publicExponent INTEGER } + END diff --git a/p11-kit/Makefile.am b/p11-kit/Makefile.am index b5195bee0..4cdc51b67 100644 --- a/p11-kit/Makefile.am +++ b/p11-kit/Makefile.am @@ -283,6 +283,11 @@ p11_kit_p11_kit_LDADD = \ $(LTLIBINTL) \ $(NULL) +if WITH_ASN1 +p11_kit_p11_kit_CFLAGS += $(LIBTASN1_CFLAGS) +p11_kit_p11_kit_LDADD += libp11-asn1.la $(LIBTASN1_LIBS) +endif + if WITH_BASH_COMPLETION bashcomp_DATA += bash-completion/p11-kit endif @@ -312,6 +317,11 @@ p11_kit_p11_kit_testable_CFLAGS = \ $(COMMON_CFLAGS) \ $(NULL) +if WITH_ASN1 +p11_kit_p11_kit_testable_CFLAGS += $(LIBTASN1_CFLAGS) +p11_kit_p11_kit_testable_LDADD += libp11-asn1.la $(LIBTASN1_LIBS) +endif + private_PROGRAMS += p11-kit/p11-kit-remote p11_kit_p11_kit_remote_SOURCES = \ @@ -416,6 +426,11 @@ sh_tests += \ p11-kit/test-lists.sh \ p11-kit/test-server.sh \ $(NULL) + +if WITH_ASN1 +sh_tests += p11-kit/test-export-public.sh +endif + endif test_conf_SOURCES = p11-kit/test-conf.c @@ -522,7 +537,8 @@ check_LTLIBRARIES += \ mock-eight.la \ mock-nine.la \ mock-ten.la \ - mock-eleven.la + mock-eleven.la \ + mock-twelve.la mock_one_la_SOURCES = p11-kit/mock-module-ep.c mock_one_la_LIBADD = libp11-test.la libp11-common.la @@ -587,6 +603,10 @@ mock_eleven_la_SOURCES = p11-kit/mock-module-ep9.c mock_eleven_la_LDFLAGS = $(mock_one_la_LDFLAGS) mock_eleven_la_LIBADD = $(mock_one_la_LIBADD) +mock_twelve_la_SOURCES = p11-kit/mock-module-ep10.c +mock_twelve_la_LDFLAGS = $(mock_one_la_LDFLAGS) +mock_twelve_la_LIBADD = $(mock_one_la_LIBADD) + EXTRA_DIST += \ p11-kit/fixtures \ p11-kit/templates \ @@ -597,4 +617,5 @@ EXTRA_DIST += \ p11-kit/test-lists.sh \ p11-kit/test-messages.sh \ p11-kit/test-server.sh \ + p11-kit/test-export-public.sh \ $(NULL) diff --git a/p11-kit/export-object.c b/p11-kit/export-object.c index 2c697a338..56e5965d3 100644 --- a/p11-kit/export-object.c +++ b/p11-kit/export-object.c @@ -31,22 +31,31 @@ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * - * Author: Zoltan Fridrich + * Author: Zoltan Fridrich , Daiki Ueno */ #include "config.h" +#include "attrs.h" #include "buffer.h" #include "constants.h" +#define P11_DEBUG_FLAG P11_DEBUG_TOOL #include "debug.h" #include "iter.h" #include "message.h" #include "pem.h" #include "tool.h" +#ifdef WITH_ASN1 +#include "asn1.h" +#include "oid.h" +#endif + #include +#include #include #include +#include #ifdef ENABLE_NLS #include @@ -59,73 +68,355 @@ int p11_kit_export_object (int argc, char *argv[]); +#ifdef WITH_ASN1 + +typedef struct { + p11_dict *defs; + P11KitIter *iter; +} ExportData; + static void -export_attribute (P11KitIter *iter, - CK_ATTRIBUTE_TYPE type, - const char *label) +export_data_uninit (ExportData *data) { - p11_buffer buf; - CK_ATTRIBUTE attr = { type, NULL_PTR, 0 }; + p11_dict_free (data->defs); +} - if (!p11_buffer_init (&buf, 0)) { - p11_message (_("failed to initialize buffer")); - return; +static void +prepend_leading_zero (CK_ATTRIBUTE *attr) +{ + if (*((unsigned char *)attr->pValue) & 0x80) { + unsigned char *padded; + + return_if_fail (attr->ulValueLen < ULONG_MAX); + padded = malloc (attr->ulValueLen + 1); + return_if_fail (padded); + memcpy (padded + 1, attr->pValue, attr->ulValueLen); + *padded = 0x00; + free (attr->pValue); + attr->pValue = padded; + attr->ulValueLen++; } +} - if (p11_kit_iter_get_attributes (iter, &attr, 1) != CKR_OK) { - p11_message (_("failed to retrieve attribute length of an object")); +unsigned char * +encode_pubkey_rsa (const ExportData *data, + CK_ATTRIBUTE *attrs, + size_t *len) +{ + asn1_node asn = NULL; + CK_ATTRIBUTE *modulus, *public_exponent; + unsigned char *der = NULL; + int result; + + modulus = p11_attrs_find_valid (attrs, CKA_MODULUS); + public_exponent = p11_attrs_find_valid (attrs, CKA_PUBLIC_EXPONENT); + + if (!modulus || !public_exponent) { + p11_message (_("failed to retrieve attributes")); goto cleanup; } - attr.pValue = malloc (attr.ulValueLen); - if (attr.pValue == NULL) { - p11_message (_("failed to allocate memory")); + asn = p11_asn1_create (data->defs, "PKIX1.RSAPublicKey"); + if (!asn) { + p11_debug ("unable to create RSAPublicKey"); + return NULL; + } + + prepend_leading_zero (modulus); + result = asn1_write_value (asn, "modulus", modulus->pValue, modulus->ulValueLen); + if (result != ASN1_SUCCESS) { + p11_debug ("unable to write modulus"); goto cleanup; } - if (p11_kit_iter_get_attributes (iter, &attr, 1) != CKR_OK) { - p11_message (_("failed to retrieve attribute of an object")); + prepend_leading_zero (public_exponent); + result = asn1_write_value (asn, "publicExponent", public_exponent->pValue, public_exponent->ulValueLen); + if (result != ASN1_SUCCESS) { + p11_debug ("unable to write publicExponent"); goto cleanup; } - if (!p11_pem_write (attr.pValue, attr.ulValueLen, label, &buf)) { - p11_message (_("failed to convert DER to PEM")); + der = p11_asn1_encode (asn, len); + if (!der) { + p11_message ("unable to encode RSAPublicKey"); goto cleanup; } - if (fwrite (buf.data, 1, buf.len, stdout) != buf.len) { - p11_message (_("failed to write PEM data to stdout")); + cleanup: + p11_asn1_free (asn); + return der; +} + +static unsigned char * +export_pubkey_rsa (const ExportData *data, + size_t *len) +{ + CK_ATTRIBUTE template[] = { + { CKA_MODULUS, }, + { CKA_PUBLIC_EXPONENT, }, + { CKA_INVALID }, + }; + CK_ATTRIBUTE *attrs = NULL; + asn1_node asn = NULL; + int result; + unsigned char *spk = NULL, *der = NULL; + const unsigned char null[] = { 0x05, 0x00 }; + size_t n_spk; + + attrs = p11_attrs_buildn (NULL, template, p11_attrs_count (template)); + if (!attrs) { + p11_debug ("unable to build attributes"); + return NULL; + } + + if (p11_kit_iter_load_attributes (data->iter, + attrs, + p11_attrs_count (attrs)) != CKR_OK) { + p11_message (_("failed to retrieve attributes")); + goto cleanup; + } + + asn = p11_asn1_create (data->defs, "PKIX1.SubjectPublicKeyInfo"); + if (!asn) { + p11_debug ("unable to create SubjectPublicKeyInfo"); + goto cleanup; + } + + result = asn1_write_value (asn, "algorithm.algorithm", + P11_OID_PKIX1_RSA_STR, 1); + if (result != ASN1_SUCCESS) { + p11_debug ("unable to write algorithm OID"); + goto cleanup; + } + + result = asn1_write_value (asn, "algorithm.parameters", + null, sizeof (null)); + if (result != ASN1_SUCCESS) { + p11_debug ("unable to write algorithm parameters"); goto cleanup; } + spk = encode_pubkey_rsa (data, attrs, &n_spk); + if (!spk) { + p11_debug ("unable to encode RSA public key"); + goto cleanup; + } + + result = asn1_write_value (asn, "subjectPublicKey", spk, n_spk * 8); + if (result != ASN1_SUCCESS) { + p11_debug ("unable to write subjectPublicKey for RSA"); + goto cleanup; + } + + der = p11_asn1_encode (asn, len); + cleanup: - p11_buffer_uninit (&buf); - free (attr.pValue); + free (spk); + p11_asn1_free (asn); + p11_attrs_free (attrs); + return der; } -static void -export_certificate (P11KitIter *iter) +static unsigned char * +export_pubkey_ec (const ExportData *data, + size_t *len) { - const char *type_str; - CK_CERTIFICATE_TYPE cert_type; - CK_ATTRIBUTE attr = { CKA_CERTIFICATE_TYPE, &cert_type, sizeof (cert_type) }; + CK_ATTRIBUTE template[] = { + { CKA_EC_PARAMS, }, + { CKA_EC_POINT, }, + { CKA_INVALID }, + }; + CK_ATTRIBUTE *attrs = NULL; + const CK_ATTRIBUTE *ec_params, *ec_point; + asn1_node asn = NULL; + int result; + unsigned char *der = NULL; + + attrs = p11_attrs_buildn (NULL, template, p11_attrs_count (template)); + return_val_if_fail (attrs, false); + + if (p11_kit_iter_load_attributes (data->iter, + attrs, + p11_attrs_count (attrs)) != CKR_OK) { + p11_message (_("failed to retrieve attributes")); + goto cleanup; + } - if (p11_kit_iter_get_attributes (iter, &attr, 1) != CKR_OK) { - p11_message (_("failed to retrieve attribute of an object")); - return; + ec_params = p11_attrs_find_valid (attrs, CKA_EC_PARAMS); + ec_point = p11_attrs_find_valid (attrs, CKA_EC_POINT); + + if (!ec_params || !ec_point) { + p11_message (_("failed to retrieve attributes")); + goto cleanup; + } + + asn = p11_asn1_create (data->defs, "PKIX1.SubjectPublicKeyInfo"); + if (!asn) { + p11_debug ("unable to create SubjectPublicKeyInfo"); + goto cleanup; + } + + result = asn1_write_value (asn, "algorithm.algorithm", + P11_OID_PKIX1_EC_STR, 1); + if (result != ASN1_SUCCESS) { + p11_debug ("unable to write algorithm OID"); + goto cleanup; + } + + result = asn1_write_value (asn, "algorithm.parameters", + ec_params->pValue, ec_params->ulValueLen); + if (result != ASN1_SUCCESS) { + p11_debug ("unable to write algorithm parameters"); + goto cleanup; + } + + /* Strip the leading 2 octets (DER header) for OCTET STRING */ + return_val_if_fail (ec_point->ulValueLen > 2, false); + result = asn1_write_value (asn, "subjectPublicKey", + ((unsigned char *)ec_point->pValue) + 2, + (ec_point->ulValueLen - 2) * 8); + if (result != ASN1_SUCCESS) { + p11_debug ("unable to write value"); + goto cleanup; } - switch (cert_type) { - case CKC_X_509: - export_attribute (iter, CKA_VALUE, "CERTIFICATE"); + der = p11_asn1_encode (asn, len); + +cleanup: + p11_asn1_free (asn); + p11_attrs_free (attrs); + return der; +} + +static unsigned char * +export_pubkey_asn1 (P11KitIter *iter, + CK_KEY_TYPE type, + size_t *len) +{ + ExportData data; + unsigned char *der = NULL; + + data.defs = p11_asn1_defs_load (); + if (!data.defs) + goto cleanup; + data.iter = iter; + + switch (type) { + case CKK_RSA: + der = export_pubkey_rsa (&data, len); break; - default: - type_str = p11_constant_nick (p11_constant_certs, cert_type); - if (type_str == NULL) - type_str = "(unknown)"; - p11_message (_("unsupported certificate type: %s"), type_str); + case CKK_EC: + der = export_pubkey_ec (&data, len); break; + default: + p11_message (_("unsupported key type: %lu"), type); + goto cleanup; + } + +cleanup: + export_data_uninit (&data); + return der; +} +#endif /* WITH_ASN1 */ + +static bool +export_pubkey (P11KitIter *iter, + p11_buffer *buf) +{ + CK_ATTRIBUTE template[] = { + { CKA_PUBLIC_KEY_INFO, }, + { CKA_KEY_TYPE, }, + }; + CK_ATTRIBUTE *attrs = NULL, *attr; + unsigned char *der = NULL; + size_t n_der; + bool ok = false; + + attrs = p11_attrs_buildn (NULL, template, 2); + return_val_if_fail (attrs, false); + + if (p11_kit_iter_load_attributes (iter, attrs, p11_attrs_count (attrs)) != CKR_OK) { + p11_message (_("failed to retrieve attributes")); + goto cleanup; + } + + attr = p11_attrs_find_valid (attrs, CKA_PUBLIC_KEY_INFO); + if (attr) { + der = attr->pValue; + attr->pValue = NULL; + n_der = attr->ulValueLen; + } else { +#ifdef WITH_ASN1 + CK_KEY_TYPE type; + + if (!p11_attrs_find_ulong (attrs, CKA_KEY_TYPE, &type)) { + p11_message (_("unable to determine key type")); + return false; + } + + der = export_pubkey_asn1 (iter, type, &n_der); +#else /* WITH_ASN1 */ + p11_message (_("ASN.1 support is not compiled in")); + goto cleanup; +#endif /* !WITH_ASN1 */ + } + + if (!der || n_der == 0 || + !p11_pem_write (der, n_der, "PUBLIC KEY", buf)) { + p11_message (_("failed to export public key")); + goto cleanup; + } + + ok = true; + +cleanup: + p11_attrs_free (attrs); + free (der); + return ok; +} + +static bool +export_certificate (P11KitIter *iter, + p11_buffer *buf) +{ + CK_CERTIFICATE_TYPE cert_type; + CK_ATTRIBUTE template[] = { + { CKA_CERTIFICATE_TYPE, }, + { CKA_VALUE, }, + }; + CK_ATTRIBUTE *attrs = NULL, *attr; + bool ok = false; + + attrs = p11_attrs_buildn (NULL, template, 2); + return_val_if_fail (attrs, false); + + if (p11_kit_iter_load_attributes (iter, attrs, p11_attrs_count (attrs)) != CKR_OK) { + p11_message (_("failed to retrieve attributes")); + goto cleanup; + } + + if (!p11_attrs_find_ulong (attrs, CKA_CERTIFICATE_TYPE, &cert_type) || + cert_type != CKC_X_509) { + p11_message (_("unrecognized certificate type")); + goto cleanup; } + + attr = p11_attrs_find_valid (attrs, CKA_VALUE); + if (!attr) { + p11_message (_("no valid certificate value")); + goto cleanup; + } + + if (!p11_pem_write (attr->pValue, attr->ulValueLen, "CERTIFICATE", buf)) { + p11_message (_("failed to convert DER to PEM")); + goto cleanup; + } + + ok = true; + + cleanup: + p11_attrs_free (attrs); + return ok; } static int @@ -138,6 +429,10 @@ export_object (const char *token_str) P11KitIter *iter = NULL; CK_OBJECT_CLASS klass; CK_ATTRIBUTE attr = { CKA_CLASS, &klass, sizeof (klass) }; + p11_buffer buf; + + if (!p11_buffer_init (&buf, 0)) + return_val_if_reached (1); uri = p11_kit_uri_new (); if (uri == NULL) { @@ -163,28 +458,43 @@ export_object (const char *token_str) } p11_kit_iter_begin (iter, modules); - while (p11_kit_iter_next (iter) == CKR_OK) { - rv = p11_kit_iter_get_attributes (iter, &attr, 1); - if (rv != CKR_OK) { - p11_message (_("failed to retrieve attribute of an object")); + rv = p11_kit_iter_next (iter); + if (rv != CKR_OK) { + if (rv == CKR_CANCEL) + p11_message (_("no matching object")); + else + p11_message (_("failed to find object: %s"), + p11_kit_strerror (rv)); + goto cleanup; + } + + if (p11_kit_iter_get_attributes (iter, &attr, 1) != CKR_OK) { + p11_message (_("failed to retrieve attribute of an object")); + goto cleanup; + } + + switch (klass) { + case CKO_CERTIFICATE: + if (!export_certificate (iter, &buf)) goto cleanup; - } + break; + case CKO_PUBLIC_KEY: + if (!export_pubkey (iter, &buf)) + goto cleanup; + break; + default: + break; + } - switch (klass) { - case CKO_CERTIFICATE: - export_certificate (iter); - break; - case CKO_PUBLIC_KEY: - export_attribute (iter, CKA_PUBLIC_KEY_INFO, "PUBLIC KEY"); - break; - default: - break; - } + if (fwrite (buf.data, 1, buf.len, stdout) != buf.len) { + p11_message (_("failed to write PEM data to stdout")); + goto cleanup; } ret = 0; cleanup: + p11_buffer_uninit (&buf); p11_kit_iter_free (iter); p11_kit_uri_free (uri); if (modules != NULL) diff --git a/p11-kit/fixtures/package-modules/twelve.module b/p11-kit/fixtures/package-modules/twelve.module new file mode 100644 index 000000000..c96a9cc0d --- /dev/null +++ b/p11-kit/fixtures/package-modules/twelve.module @@ -0,0 +1,4 @@ + +module: mock-twelve.so +managed: yes +enable-in: p11-kit-testable diff --git a/p11-kit/fixtures/package-modules/win32/twelve.module b/p11-kit/fixtures/package-modules/win32/twelve.module new file mode 100644 index 000000000..c96a9cc0d --- /dev/null +++ b/p11-kit/fixtures/package-modules/win32/twelve.module @@ -0,0 +1,4 @@ + +module: mock-twelve.so +managed: yes +enable-in: p11-kit-testable diff --git a/p11-kit/meson.build b/p11-kit/meson.build index 79190cc96..6bf9bcf3f 100644 --- a/p11-kit/meson.build +++ b/p11-kit/meson.build @@ -225,7 +225,7 @@ p11_kit_sources = [ executable('p11-kit', p11_kit_sources, c_args: common_c_args + libp11_kit_internal_c_args, - dependencies: [libp11_tool_dep] + libffi_deps + dlopen_deps, + dependencies: [libp11_tool_dep] + libp11_asn1_deps + libffi_deps + dlopen_deps, link_with: [libp11_kit, libp11_kit_internal], install: true) @@ -235,7 +235,7 @@ if get_option('test') c_args: common_c_args + libp11_kit_internal_c_args + [ '-DP11_KIT_TESTABLE' ], - dependencies: [libp11_tool_dep] + libffi_deps + dlopen_deps, + dependencies: [libp11_tool_dep] + libp11_asn1_deps + libffi_deps + dlopen_deps, link_whole: libp11_kit_testable) endif @@ -403,6 +403,12 @@ if get_option('test') env: p11_kit_tests_env) endif + if with_asn1 and host_system != 'windows' + test('test-export-public.sh', + find_program('test-export-public.sh'), + env: p11_kit_tests_env) + endif + mock_sources = { 'mock-one': ['mock-module-ep.c'], 'mock-v3-one': ['mock-module-v3-ep.c'], @@ -416,7 +422,8 @@ if get_option('test') 'mock-eight': ['mock-module-ep6.c'], 'mock-nine': ['mock-module-ep7.c'], 'mock-ten': ['mock-module-ep8.c'], - 'mock-eleven': ['mock-module-ep9.c'] + 'mock-eleven': ['mock-module-ep9.c'], + 'mock-twelve': ['mock-module-ep10.c'] } if host_system != 'windows' diff --git a/p11-kit/mock-module-ep10.c b/p11-kit/mock-module-ep10.c new file mode 100644 index 000000000..ee5fb3abe --- /dev/null +++ b/p11-kit/mock-module-ep10.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2012 Stefan Walter + * Copyright (c) 2020 Red Hat, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter , Daiki Ueno + */ + +#include "config.h" + +#define CRYPTOKI_EXPORTS 1 +#include "pkcs11.h" + +#include "attrs.h" +#include "debug.h" +#include "mock.h" +#include "test.h" +#include + +static const CK_TOKEN_INFO MOCK_TOKEN_INFO = { + "PUBKEY LABEL ", + "PUBKEY MANUFACTURER ", + "PUBKEY MODEL ", + "PUBKEY SERIAL ", + CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED | CKF_CLOCK_ON_TOKEN | CKF_TOKEN_INITIALIZED, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + { 75, 175 }, + { 85, 185 }, + { '1', '9', '9', '9', '0', '5', '2', '5', '0', '9', '1', '9', '5', '9', '0', '0' } +}; + +static uint8_t rsa_modulus[] = { + 0xc0, 0xae, 0x21, 0x2e, 0x0b, 0x11, 0xc6, 0x5b, 0x55, 0xd0, 0xcb, 0x9d, + 0x61, 0x6b, 0x76, 0xc9, 0x96, 0x16, 0x82, 0x31, 0xe1, 0xd4, 0x1d, 0x86, + 0xe4, 0x4b, 0x89, 0x0d, 0x1b, 0xe3, 0x91, 0x82, 0x06, 0x88, 0x59, 0x7a, + 0x9c, 0x39, 0x3d, 0x6a, 0x45, 0xb1, 0x6b, 0x08, 0x09, 0xa1, 0x59, 0xa7, + 0x66, 0x0d, 0xd8, 0xd1, 0xae, 0x28, 0x82, 0x4d, 0x07, 0xf3, 0xef, 0x96, + 0x5c, 0xe6, 0x63, 0x6d, 0x52, 0xf5, 0xbd, 0x8a, 0xbd, 0x7f, 0x14, 0x26, + 0xd8, 0xa3, 0x0d, 0x64, 0xf5, 0xf4, 0x4c, 0xcf, 0xde, 0x7e, 0x1d, 0x0f, + 0xf1, 0x83, 0x3c, 0x94, 0x0c, 0xb1, 0x8a, 0x20, 0xa7, 0x0b, 0x01, 0xa4, + 0x7d, 0xf6, 0xd4, 0x16, 0xa3, 0x9a, 0xfb, 0xee, 0x13, 0xff, 0x7d, 0x05, + 0x45, 0xf7, 0x97, 0x0f, 0x56, 0x1a, 0x35, 0x81, 0xf5, 0x64, 0xf7, 0xf6, + 0x08, 0xa4, 0xa5, 0x9b, 0xab, 0x94, 0x23, 0x2a, 0x85, 0x39, 0xa9, 0x31, + 0x2d, 0xc6, 0x93, 0x56, 0x3e, 0xa8, 0x5e, 0x27, 0xf8, 0x35, 0x6b, 0x60, + 0xe8, 0x47, 0x6e, 0xe8, 0x8d, 0x6b, 0x11, 0x2d, 0x6c, 0x04, 0xc9, 0xec, + 0x29, 0x04, 0x04, 0x94, 0xb5, 0xe8, 0x28, 0xb2, 0x68, 0xbe, 0x9c, 0xd9, + 0x80, 0x87, 0x89, 0x7d, 0xac, 0x57, 0x86, 0x74, 0x31, 0x7d, 0x61, 0x47, + 0xe1, 0x87, 0xb4, 0x04, 0x01, 0x78, 0x62, 0xdc, 0xe8, 0x0d, 0x75, 0xe7, + 0x49, 0xf2, 0x95, 0x8a, 0x88, 0xb0, 0x35, 0x2d, 0x3a, 0x8b, 0xa6, 0x47, + 0xf5, 0x9b, 0x5d, 0x3f, 0x6d, 0x13, 0x7b, 0x4f, 0xc1, 0x0e, 0x3c, 0x4f, + 0x32, 0x64, 0xf0, 0x9a, 0x5f, 0xe3, 0xe4, 0xd5, 0xbf, 0x9c, 0xcd, 0x0d, + 0xe2, 0xd9, 0x5d, 0x97, 0x61, 0xf1, 0x6f, 0x08, 0x04, 0x92, 0xaf, 0xa6, + 0xe1, 0xa5, 0x45, 0x60, 0x6a, 0xe9, 0xd0, 0xa3, 0xa2, 0x86, 0x00, 0xb9, + 0x90, 0x31, 0x8e, 0x7d +}; + +static uint8_t rsa_public_exponent[] = { + 0x01, 0x00, 0x01 +}; + +static uint8_t ec_params[] = { + 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07 +}; + +static uint8_t ec_point[] = { + 0x04, 0x41, 0x04, 0xb1, 0xa4, 0xc9, 0xb7, 0x47, 0x5e, 0x6d, 0x76, 0x96, + 0xec, 0x7a, 0x5c, 0xae, 0x99, 0xfb, 0x5f, 0x4e, 0xd2, 0xb1, 0x39, 0x3d, + 0xe8, 0xe2, 0x85, 0x6a, 0x5f, 0x7b, 0x47, 0x67, 0xfd, 0xc1, 0xeb, 0x66, + 0x2b, 0xf1, 0x15, 0xc9, 0x92, 0x23, 0x0a, 0xcb, 0x61, 0xe2, 0xdb, 0xe4, + 0x56, 0xdb, 0xf2, 0x56, 0xc6, 0xb0, 0x04, 0x5d, 0x00, 0xda, 0x22, 0x3b, + 0x37, 0xeb, 0x99, 0x76, 0x23, 0xec, 0x87 +}; + +static uint8_t spki[] = { + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, + 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, + 0x42, 0x00, 0x04, 0xb1, 0xa4, 0xc9, 0xb7, 0x47, 0x5e, 0x6d, 0x76, 0x96, + 0xec, 0x7a, 0x5c, 0xae, 0x99, 0xfb, 0x5f, 0x4e, 0xd2, 0xb1, 0x39, 0x3d, + 0xe8, 0xe2, 0x85, 0x6a, 0x5f, 0x7b, 0x47, 0x67, 0xfd, 0xc1, 0xeb, 0x66, + 0x2b, 0xf1, 0x15, 0xc9, 0x92, 0x23, 0x0a, 0xcb, 0x61, 0xe2, 0xdb, 0xe4, + 0x56, 0xdb, 0xf2, 0x56, 0xc6, 0xb0, 0x04, 0x5d, 0x00, 0xda, 0x22, 0x3b, + 0x37, 0xeb, 0x99, 0x76, 0x23, 0xec, 0x87 +}; + +static CK_RV +override_C_Initialize (CK_VOID_PTR init_args) +{ + CK_OBJECT_CLASS klass = CKO_PUBLIC_KEY; + CK_KEY_TYPE rsa_type = CKK_RSA; + char rsa_label[] = "RSA"; + CK_ATTRIBUTE rsa_pubkey[] = { + { CKA_CLASS, &klass, sizeof (klass) }, + { CKA_LABEL, rsa_label, sizeof (rsa_label) - 1 }, + { CKA_KEY_TYPE, &rsa_type, sizeof (rsa_type) }, + { CKA_PUBLIC_KEY_INFO, NULL, 0 }, + { CKA_MODULUS, rsa_modulus, sizeof (rsa_modulus) }, + { CKA_PUBLIC_EXPONENT, rsa_public_exponent, sizeof (rsa_public_exponent) }, + { CKA_INVALID }, + }; + CK_KEY_TYPE ec_type = CKK_EC; + char ec_label[] = "EC"; + CK_ATTRIBUTE ec_pubkey[] = { + { CKA_CLASS, &klass, sizeof (klass) }, + { CKA_LABEL, ec_label, sizeof (ec_label) - 1 }, + { CKA_KEY_TYPE, &ec_type, sizeof (ec_type) }, + { CKA_PUBLIC_KEY_INFO, NULL, 0 }, + { CKA_EC_PARAMS, ec_params, sizeof (ec_params) }, + { CKA_EC_POINT, ec_point, sizeof (ec_point) }, + { CKA_INVALID }, + }; + char spki_label[] = "SPKI"; + CK_ATTRIBUTE spki_pubkey[] = { + { CKA_CLASS, &klass, sizeof (klass) }, + { CKA_LABEL, spki_label, sizeof (spki_label) - 1 }, + { CKA_KEY_TYPE, &ec_type, sizeof (ec_type) }, + { CKA_PUBLIC_KEY_INFO, spki, sizeof (spki) }, + { CKA_INVALID }, + }; + CK_RV rv; + + rv = mock_C_Initialize (init_args); + mock_module_add_object (MOCK_SLOT_ONE_ID, rsa_pubkey); + mock_module_add_object (MOCK_SLOT_ONE_ID, ec_pubkey); + mock_module_add_object (MOCK_SLOT_ONE_ID, spki_pubkey); + return rv; +} + +static CK_RV +override_C_GetTokenInfo (CK_SLOT_ID slot_id, + CK_TOKEN_INFO_PTR info) +{ + return_val_if_fail (info != NULL, CKR_ARGUMENTS_BAD); + + if (slot_id == MOCK_SLOT_ONE_ID) { + memcpy (info, &MOCK_TOKEN_INFO, sizeof (*info)); + return CKR_OK; + } else if (slot_id == MOCK_SLOT_TWO_ID) { + return CKR_TOKEN_NOT_PRESENT; + } else { + return CKR_SLOT_ID_INVALID; + } +} + +#ifdef OS_WIN32 +__declspec(dllexport) +#endif +CK_RV +C_GetFunctionList (CK_FUNCTION_LIST_PTR_PTR list) +{ + mock_module_init (); + mock_module.C_GetFunctionList = C_GetFunctionList; + if (list == NULL) + return CKR_ARGUMENTS_BAD; + mock_module.C_Initialize = override_C_Initialize; + mock_module.C_GetTokenInfo = override_C_GetTokenInfo; + *list = &mock_module; + return CKR_OK; +} diff --git a/p11-kit/test-export-public.sh b/p11-kit/test-export-public.sh new file mode 100755 index 000000000..01d26c9aa --- /dev/null +++ b/p11-kit/test-export-public.sh @@ -0,0 +1,90 @@ +#!/bin/sh + +# Test public key export from mock-twelve.so (mock-module-ep10.c). + +test "${abs_top_builddir+set}" = set || { + echo "set abs_top_builddir" 1>&2 + exit 1 +} + +. "$abs_top_builddir/common/test-init.sh" + +setup() { + testdir=$PWD/test-objects-$$ + test -d "$testdir" || mkdir "$testdir" + cd "$testdir" +} + +teardown() { + rm -rf "$testdir" +} + +test_export_public_rsa() { + # Generated and extracted with: + # p11-kit generate-keypair --type=rsa --bits=2048 --label=RSA 'pkcs11:model=SoftHSM%20v2' + # p11tool --export 'pkcs11:model=SoftHSM%20v2;object=RSA;type=public' + cat > export.exp < export.out; then + assert_fail "unable to run: p11-kit export-object" + fi + + : ${DIFF=diff} + if ! ${DIFF} export.exp export.out > export.diff; then + sed 's/^/# /' export.diff + assert_fail "output contains incorrect result" + fi +} + +test_export_public_ec() { + # Generated and extracted with: + # p11-kit generate-keypair --type=ecdsa --curve=secp256r1 --label=EC 'pkcs11:model=SoftHSM%20v2' + # p11tool --export 'pkcs11:model=SoftHSM%20v2;object=EC;type=public' + cat > export.exp < export.out; then + assert_fail "unable to run: p11-kit export-object" + fi + + : ${DIFF=diff} + if ! ${DIFF} export.exp export.out > export.diff; then + sed 's/^/# /' export.diff + assert_fail "output contains incorrect result" + fi +} + +test_export_public_spki() { + # Generated and extracted with: + # p11-kit generate-keypair --type=ecdsa --curve=secp256r1 --label=EC 'pkcs11:model=SoftHSM%20v2' + # p11tool --export 'pkcs11:model=SoftHSM%20v2;object=EC;type=public' + cat > export.exp < export.out; then + assert_fail "unable to run: p11-kit export-object" + fi + + : ${DIFF=diff} + if ! ${DIFF} export.exp export.out > export.diff; then + sed 's/^/# /' export.diff + assert_fail "output contains incorrect result" + fi +} + +run test_export_public_rsa test_export_public_ec test_export_public_spki diff --git a/p11-kit/test-lists.sh b/p11-kit/test-lists.sh index c8279caea..fdb4ffad1 100755 --- a/p11-kit/test-lists.sh +++ b/p11-kit/test-lists.sh @@ -70,6 +70,23 @@ module: one user-pin-initialized clock-on-token token-initialized +module: twelve + uri: pkcs11:library-description=MOCK%20LIBRARY;library-manufacturer=MOCK%20MANUFACTURER + library-description: MOCK LIBRARY + library-manufacturer: MOCK MANUFACTURER + library-version: 45.145 + token: PUBKEY LABEL + uri: pkcs11:model=PUBKEY%20MODEL;manufacturer=PUBKEY%20MANUFACTURER;serial=PUBKEY%20SERIAL;token=PUBKEY%20LABEL + manufacturer: PUBKEY MANUFACTURER + model: PUBKEY MODEL + serial-number: PUBKEY SERIAL + hardware-version: 75.175 + firmware-version: 85.185 + flags: + login-required + user-pin-initialized + clock-on-token + token-initialized module: two-duplicate uri: pkcs11:library-description=MOCK%20LIBRARY;library-manufacturer=MOCK%20MANUFACTURER library-description: MOCK LIBRARY diff --git a/p11-kit/test-objects.sh b/p11-kit/test-objects.sh index 70b1fd595..8d7e20393 100755 --- a/p11-kit/test-objects.sh +++ b/p11-kit/test-objects.sh @@ -73,14 +73,41 @@ Object: #11 class: public-key label: Public prefix key Object: #12 - uri: pkcs11:model=TEST%20MODEL;manufacturer=TEST%20MANUFACTURER;serial=TEST%20SERIAL;token=TEST%20LABEL;object=TEST%20LABEL;type=data + uri: pkcs11:model=PUBKEY%20MODEL;manufacturer=PUBKEY%20MANUFACTURER;serial=PUBKEY%20SERIAL;token=PUBKEY%20LABEL;object=TEST%20LABEL;type=data class: data label: TEST LABEL Object: #13 - uri: pkcs11:model=TEST%20MODEL;manufacturer=TEST%20MANUFACTURER;serial=TEST%20SERIAL;token=TEST%20LABEL;object=Public%20Capitalize%20Key;type=public + uri: pkcs11:model=PUBKEY%20MODEL;manufacturer=PUBKEY%20MANUFACTURER;serial=PUBKEY%20SERIAL;token=PUBKEY%20LABEL;object=Public%20Capitalize%20Key;type=public class: public-key label: Public Capitalize Key Object: #14 + uri: pkcs11:model=PUBKEY%20MODEL;manufacturer=PUBKEY%20MANUFACTURER;serial=PUBKEY%20SERIAL;token=PUBKEY%20LABEL;object=Public%20prefix%20key;type=public + class: public-key + label: Public prefix key +Object: #15 + uri: pkcs11:model=PUBKEY%20MODEL;manufacturer=PUBKEY%20MANUFACTURER;serial=PUBKEY%20SERIAL;token=PUBKEY%20LABEL;object=RSA;type=public + class: public-key + key-type: rsa + label: RSA +Object: #16 + uri: pkcs11:model=PUBKEY%20MODEL;manufacturer=PUBKEY%20MANUFACTURER;serial=PUBKEY%20SERIAL;token=PUBKEY%20LABEL;object=EC;type=public + class: public-key + key-type: ec + label: EC +Object: #17 + uri: pkcs11:model=PUBKEY%20MODEL;manufacturer=PUBKEY%20MANUFACTURER;serial=PUBKEY%20SERIAL;token=PUBKEY%20LABEL;object=SPKI;type=public + class: public-key + key-type: ec + label: SPKI +Object: #18 + uri: pkcs11:model=TEST%20MODEL;manufacturer=TEST%20MANUFACTURER;serial=TEST%20SERIAL;token=TEST%20LABEL;object=TEST%20LABEL;type=data + class: data + label: TEST LABEL +Object: #19 + uri: pkcs11:model=TEST%20MODEL;manufacturer=TEST%20MANUFACTURER;serial=TEST%20SERIAL;token=TEST%20LABEL;object=Public%20Capitalize%20Key;type=public + class: public-key + label: Public Capitalize Key +Object: #20 uri: pkcs11:model=TEST%20MODEL;manufacturer=TEST%20MANUFACTURER;serial=TEST%20SERIAL;token=TEST%20LABEL;object=Public%20prefix%20key;type=public class: public-key label: Public prefix key @@ -112,6 +139,10 @@ Object: #2 class: data label: TEST LABEL Object: #3 + uri: pkcs11:model=PUBKEY%20MODEL;manufacturer=PUBKEY%20MANUFACTURER;serial=PUBKEY%20SERIAL;token=PUBKEY%20LABEL;object=TEST%20LABEL;type=data + class: data + label: TEST LABEL +Object: #4 uri: pkcs11:model=TEST%20MODEL;manufacturer=TEST%20MANUFACTURER;serial=TEST%20SERIAL;token=TEST%20LABEL;object=TEST%20LABEL;type=data class: data label: TEST LABEL