diff options
Diffstat (limited to 'src/libstrongswan/plugins/pkcs11')
-rw-r--r-- | src/libstrongswan/plugins/pkcs11/Makefile.in | 5 | ||||
-rw-r--r-- | src/libstrongswan/plugins/pkcs11/pkcs11_dh.c | 30 | ||||
-rw-r--r-- | src/libstrongswan/plugins/pkcs11/pkcs11_library.c | 44 | ||||
-rw-r--r-- | src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c | 21 | ||||
-rw-r--r-- | src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c | 50 |
5 files changed, 126 insertions, 24 deletions
diff --git a/src/libstrongswan/plugins/pkcs11/Makefile.in b/src/libstrongswan/plugins/pkcs11/Makefile.in index 34e8d0caa..de033a3fb 100644 --- a/src/libstrongswan/plugins/pkcs11/Makefile.in +++ b/src/libstrongswan/plugins/pkcs11/Makefile.in @@ -231,6 +231,7 @@ DLLIB = @DLLIB@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ +EASY_INSTALL = @EASY_INSTALL@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ @@ -291,10 +292,12 @@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PLUGIN_CFLAGS = @PLUGIN_CFLAGS@ PTHREADLIB = @PTHREADLIB@ PYTHON = @PYTHON@ +PYTHONEGGINSTALLDIR = @PYTHONEGGINSTALLDIR@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ +PY_TEST = @PY_TEST@ RANLIB = @RANLIB@ RTLIB = @RTLIB@ RUBY = @RUBY@ @@ -368,6 +371,8 @@ json_CFLAGS = @json_CFLAGS@ json_LIBS = @json_LIBS@ libdir = @libdir@ libexecdir = @libexecdir@ +libiptc_CFLAGS = @libiptc_CFLAGS@ +libiptc_LIBS = @libiptc_LIBS@ linux_headers = @linux_headers@ localedir = @localedir@ localstatedir = @localstatedir@ diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_dh.c b/src/libstrongswan/plugins/pkcs11/pkcs11_dh.c index 36cc284bf..c0033bd8e 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_dh.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_dh.c @@ -47,7 +47,7 @@ struct private_pkcs11_dh_t { /** * Diffie Hellman group number. */ - u_int16_t group; + diffie_hellman_group_t group; /** * Handle for own private value @@ -81,7 +81,7 @@ struct private_pkcs11_dh_t { * * If this succeeds the shared secret is stored in this->secret. */ -static void derive_secret(private_pkcs11_dh_t *this, chunk_t other) +static bool derive_secret(private_pkcs11_dh_t *this, chunk_t other) { CK_OBJECT_CLASS klass = CKO_SECRET_KEY; CK_KEY_TYPE type = CKK_GENERIC_SECRET; @@ -102,19 +102,25 @@ static void derive_secret(private_pkcs11_dh_t *this, chunk_t other) if (rv != CKR_OK) { DBG1(DBG_CFG, "C_DeriveKey() error: %N", ck_rv_names, rv); - return; + return FALSE; } if (!this->lib->get_ck_attribute(this->lib, this->session, secret, CKA_VALUE, &this->secret)) { chunk_free(&this->secret); - return; + return FALSE; } + return TRUE; } -METHOD(diffie_hellman_t, set_other_public_value, void, +METHOD(diffie_hellman_t, set_other_public_value, bool, private_pkcs11_dh_t *this, chunk_t value) { + if (!diffie_hellman_verify_value(this->group, value)) + { + return FALSE; + } + switch (this->group) { case ECP_192_BIT: @@ -137,7 +143,7 @@ METHOD(diffie_hellman_t, set_other_public_value, void, if (!lib->settings->get_bool(lib->settings, "%s.ecp_x_coordinate_only", TRUE, lib->ns)) { /* we only get the x coordinate back */ - return; + return FALSE; } value = chunk_from_thing(params); break; @@ -145,24 +151,25 @@ METHOD(diffie_hellman_t, set_other_public_value, void, default: break; } - derive_secret(this, value); + return derive_secret(this, value); } -METHOD(diffie_hellman_t, get_my_public_value, void, +METHOD(diffie_hellman_t, get_my_public_value, bool, private_pkcs11_dh_t *this, chunk_t *value) { *value = chunk_clone(this->pub_key); + return TRUE; } -METHOD(diffie_hellman_t, get_shared_secret, status_t, +METHOD(diffie_hellman_t, get_shared_secret, bool, private_pkcs11_dh_t *this, chunk_t *secret) { if (!this->secret.ptr) { - return FAILED; + return FALSE; } *secret = chunk_clone(this->secret); - return SUCCESS; + return TRUE; } METHOD(diffie_hellman_t, get_dh_group, diffie_hellman_group_t, @@ -443,4 +450,3 @@ pkcs11_dh_t *pkcs11_dh_create(diffie_hellman_group_t group, } return NULL; } - diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_library.c b/src/libstrongswan/plugins/pkcs11/pkcs11_library.c index 7661473b1..dc8a1f17a 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_library.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_library.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Tobias Brunner + * Copyright (C) 2011-2015 Tobias Brunner * Hochschule fuer Technik Rapperswil * * Copyright (C) 2010 Martin Willi @@ -21,6 +21,7 @@ #include <dlfcn.h> #include <library.h> +#include <asn1/asn1.h> #include <utils/debug.h> #include <threading/mutex.h> #include <collections/linked_list.h> @@ -641,10 +642,37 @@ static void free_attrs(object_enumerator_t *this) } /** + * CKA_EC_POINT is encodeed as ASN.1 octet string, we can't handle that and + * some tokens actually return them even unwrapped. + * + * Because ASN1_OCTET_STRING is 0x04 and uncompressed EC_POINTs also begin with + * 0x04 (compressed ones with 0x02 or 0x03) there will be an attempt to parse + * unwrapped uncompressed EC_POINTs. This will fail in most cases as the length + * will not be correct, however, there is a small chance that the key's first + * byte denotes the correct length. Checking the first byte of the key should + * further reduce the risk of false positives, though. + * + * The original memory is freed if the value is unwrapped. + */ +static void unwrap_ec_point(chunk_t *data) +{ + chunk_t wrapped, unwrapped; + + wrapped = unwrapped = *data; + if (asn1_unwrap(&unwrapped, &unwrapped) == ASN1_OCTET_STRING && + unwrapped.len && unwrapped.ptr[0] >= 0x02 && unwrapped.ptr[0] <= 0x04) + { + *data = chunk_clone(unwrapped); + free(wrapped.ptr); + } +} + +/** * Get attributes for a given object during enumeration */ static bool get_attributes(object_enumerator_t *this, CK_OBJECT_HANDLE object) { + chunk_t data; CK_RV rv; int i; @@ -677,6 +705,16 @@ static bool get_attributes(object_enumerator_t *this, CK_OBJECT_HANDLE object) DBG1(DBG_CFG, "C_GetAttributeValue() error: %N", ck_rv_names, rv); return FALSE; } + for (i = 0; i < this->count; i++) + { + if (this->attr[i].type == CKA_EC_POINT) + { + data = chunk_create(this->attr[i].pValue, this->attr[i].ulValueLen); + unwrap_ec_point(&data); + this->attr[i].pValue = data.ptr; + this->attr[i].ulValueLen = data.len; + } + } return TRUE; } @@ -887,6 +925,10 @@ METHOD(pkcs11_library_t, get_ck_attribute, bool, chunk_free(data); return FALSE; } + if (attr.type == CKA_EC_POINT) + { + unwrap_ec_point(data); + } return TRUE; } diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c index bb9cc7a21..bfc545972 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Tobias Brunner + * Copyright (C) 2011-2015 Tobias Brunner * Hochschule fuer Technik Rapperswil * * Copyright (C) 2010 Martin Willi @@ -23,6 +23,7 @@ #include "pkcs11_public_key.h" #include <utils/debug.h> +#include <asn1/asn1.h> typedef struct private_pkcs11_private_key_t private_pkcs11_private_key_t; @@ -288,7 +289,23 @@ METHOD(private_key_t, sign, bool, free(buf); return FALSE; } - *signature = chunk_create(buf, len); + switch (scheme) + { + case SIGN_ECDSA_WITH_SHA1_DER: + case SIGN_ECDSA_WITH_SHA256_DER: + case SIGN_ECDSA_WITH_SHA384_DER: + case SIGN_ECDSA_WITH_SHA512_DER: + /* return an ASN.1 encoded sequence of integers r and s */ + len /= 2; + *signature = asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_integer("c", chunk_create(buf, len)), + asn1_integer("c", chunk_create(buf+len, len))); + free(buf); + break; + default: + *signature = chunk_create(buf, len); + break; + } return TRUE; } diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c b/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c index 0302c0edd..6d5211657 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Tobias Brunner + * Copyright (C) 2011-2015 Tobias Brunner * Hochschule fuer Technik Rapperswil * * Copyright (C) 2010 Martin Willi @@ -135,6 +135,7 @@ static const asn1Object_t pkinfoObjects[] = { /** * Extract the DER encoded Parameters and ECPoint from the given DER encoded * subjectPublicKeyInfo. + * Memory for ecpoint is allocated. */ static bool parse_ecdsa_public_key(chunk_t blob, chunk_t *ecparams, chunk_t *ecpoint, size_t *keylen) @@ -173,7 +174,9 @@ static bool parse_ecdsa_public_key(chunk_t blob, chunk_t *ecparams, { /* skip initial bit string octet defining 0 unused bits */ object = chunk_skip(object, 1); } - *ecpoint = object; + /* the correct way to encode an EC_POINT in PKCS#11 is as + * ASN.1 octet string */ + *ecpoint = asn1_wrap(ASN1_OCTET_STRING, "c", object); break; } } @@ -205,7 +208,8 @@ METHOD(public_key_t, verify, bool, CK_SESSION_HANDLE session; CK_RV rv; hash_algorithm_t hash_alg; - chunk_t hash = chunk_empty; + chunk_t hash = chunk_empty, parse, r, s; + size_t len; mechanism = pkcs11_signature_scheme_to_mech(scheme, this->type, this->k, &hash_alg); @@ -215,9 +219,37 @@ METHOD(public_key_t, verify, bool, signature_scheme_names, scheme); return FALSE; } - if (sig.len && sig.ptr[0] == 0) - { /* trim leading zero byte in sig */ - sig = chunk_skip(sig, 1); + switch (scheme) + { + case SIGN_ECDSA_WITH_SHA1_DER: + case SIGN_ECDSA_WITH_SHA256_DER: + case SIGN_ECDSA_WITH_SHA384_DER: + case SIGN_ECDSA_WITH_SHA512_DER: + /* PKCS#11 expects the ECDSA signatures as simple concatenation of + * r and s, so unwrap the ASN.1 encoded sequence */ + parse = sig; + if (asn1_unwrap(&parse, &parse) != ASN1_SEQUENCE || + asn1_unwrap(&parse, &r) != ASN1_INTEGER || + asn1_unwrap(&parse, &s) != ASN1_INTEGER) + { + return FALSE; + } + r = chunk_skip_zero(r); + s = chunk_skip_zero(s); + len = (get_keysize(this) + 7) / 8; + if (r.len > len || s.len > len) + { + return FALSE; + } + /* concatenate r and s (forced to the defined length) */ + sig = chunk_alloca(2*len); + memset(sig.ptr, 0, sig.len); + memcpy(sig.ptr + (len - r.len), r.ptr, r.len); + memcpy(sig.ptr + len + (len - s.len), s.ptr, s.len); + break; + default: + sig = chunk_skip_zero(sig); + break; } rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, NULL, NULL, &session); @@ -776,11 +808,11 @@ pkcs11_public_key_t *pkcs11_public_key_load(key_type_t type, va_list args) if (parse_ecdsa_public_key(blob, &ecparams, &ecpoint, &keylen)) { this = find_ecdsa_key(ecparams, ecpoint, keylen); - if (this) + if (!this) { - return &this->public; + this = create_ecdsa_key(ecparams, ecpoint, keylen); } - this = create_ecdsa_key(ecparams, ecpoint, keylen); + chunk_free(&ecpoint); if (this) { return &this->public; |