From 1c4738325db611771595dac2936821a6bab1a200 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 12 Oct 2018 10:35:04 +0200 Subject: [PATCH 01/13] private-key: Add optional method that returns supported signature schemes --- src/libstrongswan/credentials/keys/private_key.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/libstrongswan/credentials/keys/private_key.h b/src/libstrongswan/credentials/keys/private_key.h index d7cfdd74d..5cf8641ad 100644 --- a/src/libstrongswan/credentials/keys/private_key.h +++ b/src/libstrongswan/credentials/keys/private_key.h @@ -39,6 +39,19 @@ struct private_key_t { */ key_type_t (*get_type)(private_key_t *this); + /** + * Get signature schemes supported by this key. + * + * This is useful for keys that only support certain hash algorithms or + * require specific parameters for RSA/PSS signatures. + * + * @note Implementing this method is optional. If multiple schemes are + * returned, they should be ordered by decreasing preference. + * + * @return enumerator over signature_params_t* + */ + enumerator_t *(*supported_signature_schemes)(private_key_t *this); + /** * Create a signature over a chunk of data. * From b88f2b3815004647348cd34a355f66f7678452bf Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 12 Oct 2018 11:14:05 +0200 Subject: [PATCH 02/13] pubkey-authenticator: Query private key for supported signature schemes --- .../authenticators/pubkey_authenticator.c | 85 ++++++++++++++++--- 1 file changed, 73 insertions(+), 12 deletions(-) diff --git a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c index 1fcef03cc..c1d562a28 100644 --- a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c +++ b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c @@ -110,6 +110,40 @@ static bool build_signature_auth_data(chunk_t *auth_data, return TRUE; } +/** + * Check if the given scheme is supported by the key and, if so, add it to the + * first array (we add the scheme supported by the key in case the parameters + * are different) + */ +static void add_scheme_if_supported(array_t *selected, array_t *supported, + signature_params_t *config) +{ + signature_params_t *sup; + int i; + + if (!supported) + { + array_insert(selected, ARRAY_TAIL, signature_params_clone(config)); + return; + } + + for (i = 0; i < array_count(supported); i++) + { + array_get(supported, i, &sup); + if (signature_params_comply(sup, config)) + { + array_insert(selected, ARRAY_TAIL, signature_params_clone(sup)); + return; + } + } +} + +CALLBACK(destroy_scheme, void, + signature_params_t *params, int idx, void *user) +{ + signature_params_destroy(params); +} + /** * Selects possible signature schemes based on our configuration, the other * peer's capabilities and the private key @@ -123,10 +157,32 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat, auth_rule_t rule; key_type_t key_type; bool have_config = FALSE; - array_t *selected; + array_t *supported = NULL, *selected; selected = array_create(0, 0); key_type = private->get_type(private); + + if (private->supported_signature_schemes) + { + enumerator = private->supported_signature_schemes(private); + while (enumerator->enumerate(enumerator, &config)) + { + if (keymat->hash_algorithm_supported(keymat, + hasher_from_signature_scheme(config->scheme, + config->params))) + { + array_insert_create(&supported, ARRAY_TAIL, + signature_params_clone(config)); + } + } + enumerator->destroy(enumerator); + + if (!supported) + { + return selected; + } + } + enumerator = auth->create_enumerator(auth); while (enumerator->enumerate(enumerator, &rule, &config)) { @@ -134,21 +190,32 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat, { continue; } - have_config = TRUE; if (key_type == key_type_from_signature_scheme(config->scheme) && keymat->hash_algorithm_supported(keymat, hasher_from_signature_scheme(config->scheme, config->params))) { - array_insert(selected, ARRAY_TAIL, signature_params_clone(config)); + add_scheme_if_supported(selected, supported, config); } + have_config = TRUE; } enumerator->destroy(enumerator); - if (!have_config) + if (have_config) { - /* if no specific configuration, find schemes appropriate for the key - * and supported by the other peer */ + array_destroy_function(supported, destroy_scheme, NULL); + } + else + { + /* if we have no config, return either whatever schemes the key (and + * peer) support or.. */ + if (supported) + { + array_destroy(selected); + return supported; + } + + /* ...find schemes appropriate for the key and supported by the peer */ enumerator = signature_schemes_for_key(key_type, private->get_keysize(private)); while (enumerator->enumerate(enumerator, &config)) @@ -207,12 +274,6 @@ static array_t *select_signature_schemes(keymat_v2_t *keymat, return selected; } -CALLBACK(destroy_scheme, void, - signature_params_t *params, int idx, void *user) -{ - signature_params_destroy(params); -} - /** * Adds the given auth data to the message, either in an AUTH payload or * a NO_PPK_AUTH notify. From dd4bd21c5a22c9eb8ecc23a6ece907e95c793136 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 12 Oct 2018 11:35:09 +0200 Subject: [PATCH 03/13] pki: Query private key for supported signature schemes --- src/pki/commands/acert.c | 5 +++++ src/pki/commands/issue.c | 5 +++++ src/pki/commands/req.c | 5 +++++ src/pki/commands/self.c | 5 +++++ src/pki/commands/signcrl.c | 6 ++++++ src/pki/pki.c | 27 +++++++++++++++++++++++++-- src/pki/pki.h | 3 ++- 7 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/pki/commands/acert.c b/src/pki/commands/acert.c index d1ea5c65e..4cbe06c9e 100644 --- a/src/pki/commands/acert.c +++ b/src/pki/commands/acert.c @@ -228,6 +228,11 @@ static int acert() goto end; } scheme = get_signature_scheme(private, digest, pss); + if (!scheme) + { + error = "no signature scheme found"; + goto end; + } ac = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC, diff --git a/src/pki/commands/issue.c b/src/pki/commands/issue.c index 1ccbca89f..b117fa171 100644 --- a/src/pki/commands/issue.c +++ b/src/pki/commands/issue.c @@ -536,6 +536,11 @@ static int issue() chunk_from_chars(ASN1_SEQUENCE, 0)); } scheme = get_signature_scheme(private, digest, pss); + if (!scheme) + { + error = "no signature scheme found"; + goto end; + } cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_SIGNING_KEY, private, BUILD_SIGNING_CERT, ca, diff --git a/src/pki/commands/req.c b/src/pki/commands/req.c index cfddbc455..8f5380a4a 100644 --- a/src/pki/commands/req.c +++ b/src/pki/commands/req.c @@ -168,6 +168,11 @@ static int req() goto end; } scheme = get_signature_scheme(private, digest, pss); + if (!scheme) + { + error = "no signature scheme found"; + goto end; + } cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_PKCS10_REQUEST, BUILD_SIGNING_KEY, private, diff --git a/src/pki/commands/self.c b/src/pki/commands/self.c index 6f7adef0f..a08ee9931 100644 --- a/src/pki/commands/self.c +++ b/src/pki/commands/self.c @@ -378,6 +378,11 @@ static int self() rng->destroy(rng); } scheme = get_signature_scheme(private, digest, pss); + if (!scheme) + { + error = "no signature scheme found"; + goto end; + } cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_SIGNING_KEY, private, BUILD_PUBLIC_KEY, public, diff --git a/src/pki/commands/signcrl.c b/src/pki/commands/signcrl.c index ca208a5cf..a399d21be 100644 --- a/src/pki/commands/signcrl.c +++ b/src/pki/commands/signcrl.c @@ -399,6 +399,12 @@ static int sign_crl() chunk_increment(crl_serial); scheme = get_signature_scheme(private, digest, pss); + if (!scheme) + { + error = "no signature scheme found"; + goto error; + } + enumerator = enumerator_create_filter(list->create_enumerator(list), filter, NULL, NULL); crl = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL, diff --git a/src/pki/pki.c b/src/pki/pki.c index ec60f7d42..e647cea69 100644 --- a/src/pki/pki.c +++ b/src/pki/pki.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2017 Tobias Brunner + * Copyright (C) 2012-2018 Tobias Brunner * Copyright (C) 2009 Martin Willi * HSR Hochschule fuer Technik Rapperswil * @@ -264,7 +264,30 @@ static hash_algorithm_t get_default_digest(private_key_t *private) signature_params_t *get_signature_scheme(private_key_t *private, hash_algorithm_t digest, bool pss) { - signature_params_t *scheme; + signature_params_t *scheme, *selected = NULL; + enumerator_t *enumerator; + + if (private->supported_signature_schemes) + { + enumerator = private->supported_signature_schemes(private); + while (enumerator->enumerate(enumerator, &scheme)) + { + if (private->get_type(private) == KEY_RSA && + pss != (scheme->scheme == SIGN_RSA_EMSA_PSS)) + { + continue; + } + if (digest == HASH_UNKNOWN || + digest == hasher_from_signature_scheme(scheme->scheme, + scheme->params)) + { + selected = signature_params_clone(scheme); + break; + } + } + enumerator->destroy(enumerator); + return selected; + } if (digest == HASH_UNKNOWN) { diff --git a/src/pki/pki.h b/src/pki/pki.h index 3f0793cfd..3976c33b7 100644 --- a/src/pki/pki.h +++ b/src/pki/pki.h @@ -65,7 +65,8 @@ void set_file_mode(FILE *stream, cred_encoding_type_t enc); * @param digest hash algorithm (if HASH_UNKNOWN a default is determined * based on the key) * @param pss use PSS padding for RSA keys - * @return allocated signature scheme and parameters + * @return allocated signature scheme and parameters (NULL if none + * found) */ signature_params_t *get_signature_scheme(private_key_t *private, hash_algorithm_t digest, bool pss); From ecfe67550df6691d0e0c0a2af1e9a7accd11ff76 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 12 Oct 2018 12:11:51 +0200 Subject: [PATCH 04/13] signature-params: Provide option for maximum RSA/PSS salt length However, the length now has to be resolved early, so we don't operate on the negative constant values e.g. when generating the encoding. --- .../backend/android_private_key.c | 6 +- src/libstrongswan/credentials/auth_cfg.c | 1 + .../credentials/keys/public_key.c | 2 +- .../credentials/keys/signature_params.c | 50 ++++++++++----- .../credentials/keys/signature_params.h | 19 +++++- .../plugins/botan/botan_rsa_private_key.c | 9 +-- .../plugins/gcrypt/gcrypt_rsa_private_key.c | 6 +- .../plugins/gcrypt/gcrypt_rsa_public_key.c | 6 +- .../plugins/gmp/gmp_rsa_private_key.c | 6 +- .../plugins/gmp/gmp_rsa_public_key.c | 7 +-- .../plugins/openssl/openssl_rsa_private_key.c | 7 +-- .../plugins/openssl/openssl_rsa_public_key.c | 7 +-- src/libstrongswan/tests/suites/test_rsa.c | 2 +- .../tests/suites/test_signature_params.c | 61 +++++++++++++++++-- src/pki/pki.c | 1 + 15 files changed, 119 insertions(+), 71 deletions(-) diff --git a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_private_key.c b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_private_key.c index 21043f6f4..e1059a8f4 100644 --- a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_private_key.c +++ b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_private_key.c @@ -135,11 +135,7 @@ static bool set_pss_params(private_private_key_t *this, JNIEnv *env, { return FALSE; } - slen = hasher_hash_size(pss->hash); - if (pss->salt_len > RSA_PSS_SALT_LEN_DEFAULT) - { - slen = pss->salt_len; - } + slen = pss->salt_len; obj = (*env)->NewObject(env, cls, method_id, jhash, jmgf1, obj, slen, 1); if (!obj) { diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c index 278c67405..b04627e63 100644 --- a/src/libstrongswan/credentials/auth_cfg.c +++ b/src/libstrongswan/credentials/auth_cfg.c @@ -551,6 +551,7 @@ static signature_params_t *create_rsa_pss_constraint(char *token) .scheme = SIGN_RSA_EMSA_PSS, .params = &pss, }; + rsa_pss_params_set_salt_len(&pss, 0); params = signature_params_clone(&pss_params); } return params; diff --git a/src/libstrongswan/credentials/keys/public_key.c b/src/libstrongswan/credentials/keys/public_key.c index 89fa9b348..3ef6981f6 100644 --- a/src/libstrongswan/credentials/keys/public_key.c +++ b/src/libstrongswan/credentials/keys/public_key.c @@ -250,7 +250,7 @@ int signature_scheme_to_oid(signature_scheme_t scheme) #define PSS_PARAMS(bits) static rsa_pss_params_t pss_params_sha##bits = { \ .hash = HASH_SHA##bits, \ .mgf1_hash = HASH_SHA##bits, \ - .salt_len = RSA_PSS_SALT_LEN_DEFAULT, \ + .salt_len = HASH_SIZE_SHA##bits, \ } PSS_PARAMS(256); diff --git a/src/libstrongswan/credentials/keys/signature_params.c b/src/libstrongswan/credentials/keys/signature_params.c index 8f42fb940..d89bd2c96 100644 --- a/src/libstrongswan/credentials/keys/signature_params.c +++ b/src/libstrongswan/credentials/keys/signature_params.c @@ -18,22 +18,43 @@ #include #include -/** - * Determine the salt length in case it is not configured +/* + * Described in header */ -static ssize_t rsa_pss_salt_length(rsa_pss_params_t *pss) +bool rsa_pss_params_set_salt_len(rsa_pss_params_t *params, size_t modbits) { - ssize_t salt_len = pss->salt_len; + size_t hash_len; - if (salt_len <= RSA_PSS_SALT_LEN_DEFAULT) + if (params->salt_len < 0) { - salt_len = hasher_hash_size(pss->hash); - if (!salt_len) + hash_len = hasher_hash_size(params->hash); + if (!hash_len) { - return -1; + return FALSE; + } + + switch (params->salt_len) + { + case RSA_PSS_SALT_LEN_DEFAULT: + params->salt_len = hash_len; + break; + case RSA_PSS_SALT_LEN_MAX: + if (modbits) + { + /* emBits = modBits - 1 */ + modbits -= 1; + /* emLen = ceil(emBits/8) */ + modbits = (modbits+7) / BITS_PER_BYTE; + /* account for 0x01 separator in DB, 0xbc trailing byte */ + params->salt_len = max(0, (ssize_t)(modbits - hash_len - 2)); + break; + } + return FALSE; + default: + return FALSE; } } - return salt_len; + return TRUE; } /** @@ -68,8 +89,7 @@ static bool compare_params(signature_params_t *a, signature_params_t *b, return pss_a->hash == pss_b->hash && pss_a->mgf1_hash == pss_b->mgf1_hash && - (!strict || - rsa_pss_salt_length(pss_a) == rsa_pss_salt_length(pss_b)); + (!strict || pss_a->salt_len == pss_b->salt_len); } default: break; @@ -328,7 +348,6 @@ end: bool rsa_pss_params_build(rsa_pss_params_t *params, chunk_t *asn1) { chunk_t hash = chunk_empty, mgf = chunk_empty, slen = chunk_empty; - ssize_t salt_len; int alg; if (params->hash != HASH_SHA1) @@ -351,16 +370,15 @@ bool rsa_pss_params_build(rsa_pss_params_t *params, chunk_t *asn1) mgf = asn1_algorithmIdentifier_params(OID_MGF1, asn1_algorithmIdentifier(alg)); } - salt_len = rsa_pss_salt_length(params); - if (salt_len < 0) + if (params->salt_len < 0) { chunk_free(&hash); chunk_free(&mgf); return FALSE; } - else if (salt_len != HASH_SIZE_SHA1) + else if (params->salt_len != HASH_SIZE_SHA1) { - slen = asn1_integer("m", asn1_integer_from_uint64(salt_len)); + slen = asn1_integer("m", asn1_integer_from_uint64(params->salt_len)); } *asn1 = asn1_wrap(ASN1_SEQUENCE, "mmm", hash.len ? asn1_wrap(ASN1_CONTEXT_C_0, "m", hash) : chunk_empty, diff --git a/src/libstrongswan/credentials/keys/signature_params.h b/src/libstrongswan/credentials/keys/signature_params.h index 6934c5e88..b4169a829 100644 --- a/src/libstrongswan/credentials/keys/signature_params.h +++ b/src/libstrongswan/credentials/keys/signature_params.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Tobias Brunner + * Copyright (C) 2017-2018 Tobias Brunner * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -100,11 +100,15 @@ struct rsa_pss_params_t { hash_algorithm_t hash; /** Hash for the MGF1 function */ hash_algorithm_t mgf1_hash; - /** Salt length, use RSA_PSS_SALT_LEN_DEFAULT for length equal to hash */ + /** Salt length, use the constants below for special lengths resolved + * via rsa_pss_params_set_salt_len() */ ssize_t salt_len; /** Salt value, for unit tests (not all implementations support this) */ chunk_t salt; +/** Use a salt length equal to the length of the hash */ #define RSA_PSS_SALT_LEN_DEFAULT -1 +/** Use the maximum salt length depending on the hash and key length */ +#define RSA_PSS_SALT_LEN_MAX -2 }; /** @@ -126,4 +130,15 @@ bool rsa_pss_params_parse(chunk_t asn1, int level0, rsa_pss_params_t *params); */ bool rsa_pss_params_build(rsa_pss_params_t *params, chunk_t *asn1); +/** + * Determine and set the salt length for the given params in case constants + * are used + * + * @param params parameters to update + * @param modbits RSA modulus length in bits (required if RSA_PSS_SALT_LEN_MAX + * is used) + * @return salt length to use, negative on error + */ +bool rsa_pss_params_set_salt_len(rsa_pss_params_t *params, size_t modbits); + #endif /** SIGNATURE_PARAMS_H_ @}*/ diff --git a/src/libstrongswan/plugins/botan/botan_rsa_private_key.c b/src/libstrongswan/plugins/botan/botan_rsa_private_key.c index bb723ff95..da7dd064f 100644 --- a/src/libstrongswan/plugins/botan/botan_rsa_private_key.c +++ b/src/libstrongswan/plugins/botan/botan_rsa_private_key.c @@ -84,13 +84,8 @@ bool botan_emsa_pss_identifier(rsa_pss_params_t *params, char *id, size_t len) { return FALSE; } - - if (params->salt_len > RSA_PSS_SALT_LEN_DEFAULT) - { - return snprintf(id, len, "EMSA-PSS(%s,MGF1,%zd)", hash, - params->salt_len) < len; - } - return snprintf(id, len, "EMSA-PSS(%s,MGF1)", hash) < len; + return snprintf(id, len, "EMSA-PSS(%s,MGF1,%zd)", hash, + params->salt_len) < len; } /** diff --git a/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c b/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c index c06f43348..394b87c27 100644 --- a/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c +++ b/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c @@ -187,11 +187,7 @@ static bool sign_pkcs1(private_gcrypt_rsa_private_key_t *this, } else { - u_int slen = hasher_hash_size(hash_algorithm); - if (pss->salt_len > RSA_PSS_SALT_LEN_DEFAULT) - { - slen = pss->salt_len; - } + u_int slen = pss->salt_len; err = gcry_sexp_build(&in, NULL, "(data(flags pss)(salt-length %u)(hash %s %b))", slen, hash_name, hash.len, hash.ptr); diff --git a/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c b/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c index 9e2ac1287..bbfa5e298 100644 --- a/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c +++ b/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c @@ -139,11 +139,7 @@ static bool verify_pkcs1(private_gcrypt_rsa_public_key_t *this, if (pss) { - u_int slen = hasher_hash_size(algorithm); - if (pss->salt_len > RSA_PSS_SALT_LEN_DEFAULT) - { - slen = pss->salt_len; - } + u_int slen = pss->salt_len; err = gcry_sexp_build(&in, NULL, "(data(flags pss)(salt-length %u)(hash %s %b))", slen, hash_name, hash.len, hash.ptr); diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c index a255a40ab..2d2d5c6fb 100644 --- a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c @@ -393,15 +393,11 @@ static bool build_emsa_pss_signature(private_gmp_rsa_private_key_t *this, goto error; } - salt.len = hash.len; + salt.len = params->salt_len; if (params->salt.len) { salt = params->salt; } - else if (params->salt_len > RSA_PSS_SALT_LEN_DEFAULT) - { - salt.len = params->salt_len; - } if (emlen < (hash.len + salt.len + 2)) { /* too long */ goto error; diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c index 9b5ee67fa..f9bd1d314 100644 --- a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c @@ -205,12 +205,7 @@ static bool verify_emsa_pss_signature(private_gmp_rsa_public_key_t *this, { goto error; } - /* determine salt length */ - salt.len = hash.len; - if (params->salt_len > RSA_PSS_SALT_LEN_DEFAULT) - { - salt.len = params->salt_len; - } + salt.len = params->salt_len; /* verify general structure of EM */ maskbits = (8 * em.len) - embits; if (em.len < (hash.len + salt.len + 2) || em.ptr[em.len-1] != 0xbc || diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c index 401a51a0b..8a9fdfe25 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_private_key.c @@ -103,13 +103,8 @@ static bool build_signature(private_openssl_rsa_private_key_t *this, if (pss) { const EVP_MD *mgf1md = openssl_get_md(pss->mgf1_hash); - int slen = EVP_MD_size(md); - if (pss->salt_len > RSA_PSS_SALT_LEN_DEFAULT) - { - slen = pss->salt_len; - } if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) <= 0 || - EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, slen) <= 0 || + EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, pss->salt_len) <= 0 || EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1md) <= 0) { goto error; diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c index 20bf30ae9..38b4eda35 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c @@ -95,13 +95,8 @@ static bool verify_signature(private_openssl_rsa_public_key_t *this, if (pss) { const EVP_MD *mgf1md = openssl_get_md(pss->mgf1_hash); - int slen = EVP_MD_size(md); - if (pss->salt_len > RSA_PSS_SALT_LEN_DEFAULT) - { - slen = pss->salt_len; - } if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) <= 0 || - EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, slen) <= 0 || + EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, pss->salt_len) <= 0 || EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1md) <= 0) { goto error; diff --git a/src/libstrongswan/tests/suites/test_rsa.c b/src/libstrongswan/tests/suites/test_rsa.c index e6dc7744a..a71fa0ce5 100644 --- a/src/libstrongswan/tests/suites/test_rsa.c +++ b/src/libstrongswan/tests/suites/test_rsa.c @@ -40,7 +40,7 @@ static signature_scheme_t schemes[] = { static rsa_pss_params_t default_pss_params = { .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, - .salt_len = RSA_PSS_SALT_LEN_DEFAULT, + .salt_len = HASH_SIZE_SHA256, }; /** diff --git a/src/libstrongswan/tests/suites/test_signature_params.c b/src/libstrongswan/tests/suites/test_signature_params.c index 38cb5803f..cbf1a2861 100644 --- a/src/libstrongswan/tests/suites/test_signature_params.c +++ b/src/libstrongswan/tests/suites/test_signature_params.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 Tobias Brunner + * Copyright (C) 2017-2018 Tobias Brunner * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -138,27 +138,27 @@ static struct { 0xa1,0x1c,0x30,0x1a,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x08,0x30, 0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0xa2,0x03, 0x02,0x01,0x20), - { .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }}, + { .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = HASH_SIZE_SHA256, }}, /* default salt length: SHA-1 */ { chunk_from_chars(0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0a,0x30,0x00), - { .hash = HASH_SHA1, .mgf1_hash = HASH_SHA1, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }}, + { .hash = HASH_SHA1, .mgf1_hash = HASH_SHA1, .salt_len = HASH_SIZE_SHA1, }}, /* default salt length: SHA-224 */ { chunk_from_chars(0x30,0x23,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0a,0x30,0x16,0xa0, 0x0f,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x04,0x05,0x00, 0xa2,0x03,0x02,0x01,0x1c), - { .hash = HASH_SHA224, .mgf1_hash = HASH_SHA1, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }}, + { .hash = HASH_SHA224, .mgf1_hash = HASH_SHA1, .salt_len = HASH_SIZE_SHA224, }}, /* default salt length: SHA-384 */ { chunk_from_chars(0x30,0x23,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0a,0x30,0x16,0xa0, 0x0f,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00, 0xa2,0x03,0x02,0x01,0x30), - { .hash = HASH_SHA384, .mgf1_hash = HASH_SHA1, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }}, + { .hash = HASH_SHA384, .mgf1_hash = HASH_SHA1, .salt_len = HASH_SIZE_SHA384, }}, /* SHA-512 */ { chunk_from_chars(0x30,0x41,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0a,0x30,0x34,0xa0, 0x0f,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00, 0xa1,0x1c,0x30,0x1a,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x08,0x30, 0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0xa2,0x03, 0x02,0x01,0x40), - { .hash = HASH_SHA512, .mgf1_hash = HASH_SHA512, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }}, + { .hash = HASH_SHA512, .mgf1_hash = HASH_SHA512, .salt_len = HASH_SIZE_SHA512, }}, /* SHA-256, no salt */ { chunk_from_chars(0x30,0x41,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x0a,0x30,0x34,0xa0, 0x0f,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00, @@ -199,6 +199,8 @@ rsa_pss_params_t rsa_pss_build_invalid_tests[] = { { .hash = HASH_UNKNOWN, .mgf1_hash = HASH_SHA1, .salt_len = HASH_SIZE_SHA1, }, /* invalid mgf */ { .hash = HASH_SHA256, .mgf1_hash = HASH_UNKNOWN, .salt_len = HASH_SIZE_SHA256, }, + /* undetermined salt */ + { .hash = HASH_UNKNOWN, .mgf1_hash = HASH_SHA1, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }, }; START_TEST(test_rsa_pss_params_build_invalid) @@ -209,6 +211,49 @@ START_TEST(test_rsa_pss_params_build_invalid) } END_TEST + +static struct { + ssize_t expected; + size_t modbits; + rsa_pss_params_t params; +} rsa_pss_salt_len_tests[] = { + { HASH_SIZE_SHA256, 0, + { .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }}, + { HASH_SIZE_SHA256, 3072, + { .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_DEFAULT, }}, + { -1, 0, + { .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_MAX, }}, + { 0, 256, + { .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_MAX, }}, + { 350, 3071, + { .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_MAX, }}, + { 350, 3072, + { .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_MAX, }}, + { 350, 3073, + { .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_MAX, }}, + { 478, 4096, + { .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = RSA_PSS_SALT_LEN_MAX, }}, + { 10, 0, + { .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = 10, }}, + { 10, 3072, + { .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = 10, }}, +}; + +START_TEST(test_rsa_pss_params_set_salt_len) +{ + if (rsa_pss_params_set_salt_len(&rsa_pss_salt_len_tests[_i].params, + rsa_pss_salt_len_tests[_i].modbits)) + { + ck_assert_int_eq(rsa_pss_salt_len_tests[_i].expected, + rsa_pss_salt_len_tests[_i].params.salt_len); + } + else + { + ck_assert(rsa_pss_salt_len_tests[_i].expected < 0); + } +} +END_TEST + static rsa_pss_params_t rsa_pss_params_sha1 = { .hash = HASH_SHA1, .mgf1_hash = HASH_SHA1, .salt_len = HASH_SIZE_SHA1, }; static rsa_pss_params_t rsa_pss_params_sha256 = { .hash = HASH_SHA256, .mgf1_hash = HASH_SHA256, .salt_len = HASH_SIZE_SHA256, }; static rsa_pss_params_t rsa_pss_params_sha256_mgf1 = { .hash = HASH_SHA256, .mgf1_hash = HASH_SHA512, .salt_len = HASH_SIZE_SHA256, }; @@ -430,6 +475,10 @@ Suite *signature_params_suite_create() tcase_add_loop_test(tc, test_rsa_pss_params_build_invalid, 0, countof(rsa_pss_build_invalid_tests)); suite_add_tcase(s, tc); + tc = tcase_create("rsa/pss salt len"); + tcase_add_loop_test(tc, test_rsa_pss_params_set_salt_len, 0, countof(rsa_pss_salt_len_tests)); + suite_add_tcase(s, tc); + tc = tcase_create("params compare"); tcase_add_loop_test(tc, test_params_compare, 0, countof(params_compare_tests)); tcase_add_test(tc, test_params_compare_null); diff --git a/src/pki/pki.c b/src/pki/pki.c index e647cea69..d03e96f9b 100644 --- a/src/pki/pki.c +++ b/src/pki/pki.c @@ -304,6 +304,7 @@ signature_params_t *get_signature_scheme(private_key_t *private, .scheme = SIGN_RSA_EMSA_PSS, .params = &pss_params, }; + rsa_pss_params_set_salt_len(&pss_params, 0); scheme = signature_params_clone(&pss_scheme); } else From 532cd488e35335a4cf680d054b3d797e405de4f6 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 15 Oct 2018 13:16:06 +0200 Subject: [PATCH 05/13] libtpmtss: TSS can optionally return signature schemes supported by a key --- src/libtpmtss/tpm_tss.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libtpmtss/tpm_tss.h b/src/libtpmtss/tpm_tss.h index 11e4a7c15..a239e4dc4 100644 --- a/src/libtpmtss/tpm_tss.h +++ b/src/libtpmtss/tpm_tss.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2018 Tobias Brunner * Copyright (C) 2016 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * @@ -79,6 +80,15 @@ struct tpm_tss_t { */ chunk_t (*get_public)(tpm_tss_t *this, uint32_t handle); + /** + * Return signature schemes supported by the given key (TPM 2.0 only) + * + * @param handle key object handle + * @return enumerator over signature_params_t* + */ + enumerator_t *(*supported_signature_schemes)(tpm_tss_t *this, + uint32_t handle); + /** * Retrieve the current value of a PCR register in a given PCR bank * From 7ca3b3daee5489f6bf1f8a719e5b84db00b545ee Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 15 Oct 2018 13:28:51 +0200 Subject: [PATCH 06/13] libtpmtss: Add enumeration of supported signature schemes to TSS2 implementations --- src/libtpmtss/tpm_tss_trousers.c | 7 +++ src/libtpmtss/tpm_tss_tss2_v1.c | 89 +++++++++++++++++++++++++++++++- src/libtpmtss/tpm_tss_tss2_v2.c | 89 +++++++++++++++++++++++++++++++- 3 files changed, 181 insertions(+), 4 deletions(-) diff --git a/src/libtpmtss/tpm_tss_trousers.c b/src/libtpmtss/tpm_tss_trousers.c index 81e542d02..937373354 100644 --- a/src/libtpmtss/tpm_tss_trousers.c +++ b/src/libtpmtss/tpm_tss_trousers.c @@ -390,6 +390,12 @@ METHOD(tpm_tss_t, get_public, chunk_t, return aik_pubkey; } +METHOD(tpm_tss_t, supported_signature_schemes, enumerator_t*, + private_tpm_tss_trousers_t *this, uint32_t handle) +{ + return enumerator_create_empty(); +} + METHOD(tpm_tss_t, read_pcr, bool, private_tpm_tss_trousers_t *this, uint32_t pcr_num, chunk_t *pcr_value, hash_algorithm_t alg) @@ -642,6 +648,7 @@ tpm_tss_t *tpm_tss_trousers_create() .get_version_info = _get_version_info, .generate_aik = _generate_aik, .get_public = _get_public, + .supported_signature_schemes = _supported_signature_schemes, .read_pcr = _read_pcr, .extend_pcr = _extend_pcr, .quote = _quote, diff --git a/src/libtpmtss/tpm_tss_tss2_v1.c b/src/libtpmtss/tpm_tss_tss2_v1.c index 180e94705..26fd25ce1 100644 --- a/src/libtpmtss/tpm_tss_tss2_v1.c +++ b/src/libtpmtss/tpm_tss_tss2_v1.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2018 Tobias Brunner * Copyright (C) 2016-2018 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * @@ -523,6 +524,89 @@ METHOD(tpm_tss_t, get_public, chunk_t, return aik_pubkey; } +METHOD(tpm_tss_t, supported_signature_schemes, enumerator_t*, + private_tpm_tss_tss2_t *this, uint32_t handle) +{ + TPM2B_PUBLIC public = { { 0, } }; + hash_algorithm_t digest; + signature_params_t supported_scheme; + + if (!read_public(this, handle, &public)) + { + return enumerator_create_empty(); + } + + switch (public.t.publicArea.type) + { + case TPM_ALG_RSA: + { + TPMS_RSA_PARMS *rsa; + TPMT_RSA_SCHEME *scheme; + + rsa = &public.t.publicArea.parameters.rsaDetail; + scheme = &rsa->scheme; + digest = hash_alg_from_tpm_alg_id(scheme->details.anySig.hashAlg); + + switch (scheme->scheme) + { + case TPM_ALG_RSAPSS: + { + rsa_pss_params_t pss_params = { + .hash = digest, + .mgf1_hash = digest, + .salt_len = RSA_PSS_SALT_LEN_MAX, + }; + supported_scheme = (signature_params_t){ + .scheme = SIGN_RSA_EMSA_PSS, + .params = &pss_params, + }; + if (!rsa_pss_params_set_salt_len(&pss_params, rsa->keyBits)) + { + return enumerator_create_empty(); + } + break; + } + case TPM_ALG_RSASSA: + supported_scheme = (signature_params_t){ + .scheme = signature_scheme_from_oid( + hasher_signature_algorithm_to_oid(digest, + KEY_RSA)), + }; + break; + default: + return enumerator_create_empty(); + } + break; + } + case TPM_ALG_ECC: + { + TPMT_ECC_SCHEME *scheme; + + scheme = &public.t.publicArea.parameters.eccDetail.scheme; + digest = hash_alg_from_tpm_alg_id(scheme->details.anySig.hashAlg); + + switch (scheme->scheme) + { + case TPM_ALG_ECDSA: + supported_scheme = (signature_params_t){ + .scheme = signature_scheme_from_oid( + hasher_signature_algorithm_to_oid(digest, + KEY_ECDSA)), + }; + break; + default: + return enumerator_create_empty(); + } + break; + } + default: + DBG1(DBG_PTS, "%s unsupported AIK key type", LABEL); + return enumerator_create_empty(); + } + return enumerator_create_single(signature_params_clone(&supported_scheme), + (void*)signature_params_destroy); +} + /** * Configure a PCR Selection assuming a maximum of 24 registers */ @@ -809,7 +893,7 @@ METHOD(tpm_tss_t, quote, bool, DBG1(DBG_PTS, "%s unsupported %N signature algorithm", LABEL, tpm_alg_id_names, sig.sigAlg); return FALSE; - }; + } DBG2(DBG_PTS, "PCR digest algorithm is %N", tpm_alg_id_names, hash_alg); pcr_digest_alg = hash_alg_from_tpm_alg_id(hash_alg); @@ -1036,7 +1120,7 @@ METHOD(tpm_tss_t, sign, bool, DBG1(DBG_PTS, "%s unsupported %N signature scheme", LABEL, signature_scheme_names, scheme); return FALSE; - }; + } return TRUE; } @@ -1174,6 +1258,7 @@ tpm_tss_t *tpm_tss_tss2_create() .get_version_info = _get_version_info, .generate_aik = _generate_aik, .get_public = _get_public, + .supported_signature_schemes = _supported_signature_schemes, .read_pcr = _read_pcr, .extend_pcr = _extend_pcr, .quote = _quote, diff --git a/src/libtpmtss/tpm_tss_tss2_v2.c b/src/libtpmtss/tpm_tss_tss2_v2.c index 7cb0d48a9..f47858e70 100644 --- a/src/libtpmtss/tpm_tss_tss2_v2.c +++ b/src/libtpmtss/tpm_tss_tss2_v2.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2018 Tobias Brunner * Copyright (C) 2018 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * @@ -477,6 +478,89 @@ METHOD(tpm_tss_t, get_public, chunk_t, return aik_pubkey; } +METHOD(tpm_tss_t, supported_signature_schemes, enumerator_t*, + private_tpm_tss_tss2_t *this, uint32_t handle) +{ + TPM2B_PUBLIC public = { 0, }; + hash_algorithm_t digest; + signature_params_t supported_scheme; + + if (!read_public(this, handle, &public)) + { + return enumerator_create_empty(); + } + + switch (public.publicArea.type) + { + case TPM2_ALG_RSA: + { + TPMS_RSA_PARMS *rsa; + TPMT_RSA_SCHEME *scheme; + + rsa = &public.publicArea.parameters.rsaDetail; + scheme = &rsa->scheme; + digest = hash_alg_from_tpm_alg_id(scheme->details.anySig.hashAlg); + + switch (scheme->scheme) + { + case TPM2_ALG_RSAPSS: + { + rsa_pss_params_t pss_params = { + .hash = digest, + .mgf1_hash = digest, + .salt_len = RSA_PSS_SALT_LEN_MAX, + }; + supported_scheme = (signature_params_t){ + .scheme = SIGN_RSA_EMSA_PSS, + .params = &pss_params, + }; + if (!rsa_pss_params_set_salt_len(&pss_params, rsa->keyBits)) + { + return enumerator_create_empty(); + } + break; + } + case TPM2_ALG_RSASSA: + supported_scheme = (signature_params_t){ + .scheme = signature_scheme_from_oid( + hasher_signature_algorithm_to_oid(digest, + KEY_RSA)), + }; + break; + default: + return enumerator_create_empty(); + } + break; + } + case TPM2_ALG_ECC: + { + TPMT_ECC_SCHEME *scheme; + + scheme = &public.publicArea.parameters.eccDetail.scheme; + digest = hash_alg_from_tpm_alg_id(scheme->details.anySig.hashAlg); + + switch (scheme->scheme) + { + case TPM2_ALG_ECDSA: + supported_scheme = (signature_params_t){ + .scheme = signature_scheme_from_oid( + hasher_signature_algorithm_to_oid(digest, + KEY_ECDSA)), + }; + break; + default: + return enumerator_create_empty(); + } + break; + } + default: + DBG1(DBG_PTS, "%s unsupported AIK key type", LABEL); + return enumerator_create_empty(); + } + return enumerator_create_single(signature_params_clone(&supported_scheme), + (void*)signature_params_destroy); +} + /** * Configure a PCR Selection assuming a maximum of 24 registers */ @@ -729,7 +813,7 @@ METHOD(tpm_tss_t, quote, bool, DBG1(DBG_PTS, "%s unsupported %N signature algorithm", LABEL, tpm_alg_id_names, sig.sigAlg); return FALSE; - }; + } DBG2(DBG_PTS, "PCR digest algorithm is %N", tpm_alg_id_names, hash_alg); pcr_digest_alg = hash_alg_from_tpm_alg_id(hash_alg); @@ -940,7 +1024,7 @@ METHOD(tpm_tss_t, sign, bool, DBG1(DBG_PTS, "%s unsupported %N signature scheme", LABEL, signature_scheme_names, scheme); return FALSE; - }; + } return TRUE; } @@ -1061,6 +1145,7 @@ tpm_tss_t *tpm_tss_tss2_create() .get_version_info = _get_version_info, .generate_aik = _generate_aik, .get_public = _get_public, + .supported_signature_schemes = _supported_signature_schemes, .read_pcr = _read_pcr, .extend_pcr = _extend_pcr, .quote = _quote, From b158404c5f3a1518b96af758962201fa0dd4e960 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 15 Oct 2018 13:16:44 +0200 Subject: [PATCH 07/13] tpm: Return signature schemes supported by the key if TSS supports it --- src/libtpmtss/plugins/tpm/tpm_private_key.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libtpmtss/plugins/tpm/tpm_private_key.c b/src/libtpmtss/plugins/tpm/tpm_private_key.c index 3b7582ae3..9aeb47108 100644 --- a/src/libtpmtss/plugins/tpm/tpm_private_key.c +++ b/src/libtpmtss/plugins/tpm/tpm_private_key.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2018 Tobias Brunner * Copyright (C) 2017 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * @@ -75,6 +76,12 @@ METHOD(private_key_t, get_keysize, int, return this->pubkey->get_keysize(this->pubkey); } +METHOD(private_key_t, supported_signature_schemes, enumerator_t*, + private_tpm_private_key_t *this) +{ + return this->tpm->supported_signature_schemes(this->tpm, this->handle); +} + METHOD(private_key_t, sign, bool, private_tpm_private_key_t *this, signature_scheme_t scheme, void *params, chunk_t data, chunk_t *signature) @@ -201,6 +208,7 @@ tpm_private_key_t *tpm_private_key_connect(key_type_t type, va_list args) .sign = _sign, .decrypt = _decrypt, .get_keysize = _get_keysize, + .supported_signature_schemes = _supported_signature_schemes, .get_public_key = _get_public_key, .equals = private_key_equals, .belongs_to = private_key_belongs_to, From 526c5abd0f7fa298fecc3767ea2c2b47fbd01fc8 Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Tue, 23 Oct 2018 18:30:55 +0200 Subject: [PATCH 08/13] tpm: Check FIPS-140-2 and FIPS-186-4 compliance --- conf/plugins/tpm.opt | 4 +++ src/libtpmtss/plugins/tpm/tpm_private_key.c | 2 +- src/libtpmtss/tpm_tss.h | 2 +- src/libtpmtss/tpm_tss_tss2_v1.c | 30 ++++++++++++++++++--- src/libtpmtss/tpm_tss_tss2_v2.c | 30 ++++++++++++++++++--- 5 files changed, 60 insertions(+), 8 deletions(-) diff --git a/conf/plugins/tpm.opt b/conf/plugins/tpm.opt index df7adb098..06c88861e 100644 --- a/conf/plugins/tpm.opt +++ b/conf/plugins/tpm.opt @@ -1,6 +1,10 @@ charon.plugins.tpm.use_rng = no Whether the TPM should be used as RNG. +charon.plugins.tpm.fips_186_4 = no + Is the TPM 2.0 FIPS-186-4 compliant, forcing e.g. the use of the default + salt length instead of maximum salt length with RSAPSS padding. + charon.plugins.tpm.tcti.name = device|tabrmd Name of TPM 2.0 TCTI library. Valid values: _tabrmd_, _device_ or _mssim_. Defaults are _device_ if the _/dev/tpmrm0_ in-kernel TPM 2.0 resource manager diff --git a/src/libtpmtss/plugins/tpm/tpm_private_key.c b/src/libtpmtss/plugins/tpm/tpm_private_key.c index 9aeb47108..d946fbe56 100644 --- a/src/libtpmtss/plugins/tpm/tpm_private_key.c +++ b/src/libtpmtss/plugins/tpm/tpm_private_key.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2018 Tobias Brunner - * Copyright (C) 2017 Andreas Steffen + * Copyright (C) 2017-2018 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it diff --git a/src/libtpmtss/tpm_tss.h b/src/libtpmtss/tpm_tss.h index a239e4dc4..aab7a4d6c 100644 --- a/src/libtpmtss/tpm_tss.h +++ b/src/libtpmtss/tpm_tss.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2018 Tobias Brunner - * Copyright (C) 2016 Andreas Steffen + * Copyright (C) 2016-2018 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it diff --git a/src/libtpmtss/tpm_tss_tss2_v1.c b/src/libtpmtss/tpm_tss_tss2_v1.c index 26fd25ce1..a7b1344bd 100644 --- a/src/libtpmtss/tpm_tss_tss2_v1.c +++ b/src/libtpmtss/tpm_tss_tss2_v1.c @@ -69,6 +69,12 @@ struct private_tpm_tss_tss2_t { * List of supported algorithms */ TPM_ALG_ID supported_algs[TPM_PT_ALGORITHM_SET]; + + /** + * Is TPM FIPS 186-4 compliant ? + */ + bool fips_186_4; + }; /** @@ -154,6 +160,7 @@ static bool get_algs_capability(private_tpm_tss_tss2_t *this) TPMS_TAGGED_PROPERTY tp; TPMI_YES_NO more_data; TPM_ALG_ID alg; + bool fips_140_2 = FALSE; uint32_t rval, i, offset, revision = 0, year = 0; size_t len = BUF_LEN; char buf[BUF_LEN], manufacturer[5], vendor_string[17]; @@ -194,12 +201,25 @@ static bool get_algs_capability(private_tpm_tss_tss2_t *this) offset = 4 * (tp.property - TPM_PT_VENDOR_STRING_1); htoun32(vendor_string + offset, tp.value); break; + case TPM_PT_MODES: + if (tp.value & TPMA_MODES_FIPS_140_2) + { + this->fips_186_4 = fips_140_2 = TRUE; + } + break; default: break; } } - DBG2(DBG_PTS, "%s manufacturer: %s (%s) rev: %05.2f %u", LABEL, manufacturer, - vendor_string, (float)revision/100, year); + + if (!fips_140_2) + { + this->fips_186_4 = lib->settings->get_bool(lib->settings, + "%s.plugins.tpm.fips_186_4", FALSE, lib->ns); + } + DBG2(DBG_PTS, "%s manufacturer: %s (%s) rev: %05.2f %u %s", LABEL, + manufacturer, vendor_string, (float)revision/100, year, + fips_140_2 ? "FIPS 140-2" : (this->fips_186_4 ? "FIPS 186-4" : "")); /* get supported algorithms */ rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM_CAP_ALGS, @@ -551,10 +571,14 @@ METHOD(tpm_tss_t, supported_signature_schemes, enumerator_t*, { case TPM_ALG_RSAPSS: { + ssize_t salt_len; + + salt_len = this->fips_186_4 ? RSA_PSS_SALT_LEN_DEFAULT : + RSA_PSS_SALT_LEN_MAX; rsa_pss_params_t pss_params = { .hash = digest, .mgf1_hash = digest, - .salt_len = RSA_PSS_SALT_LEN_MAX, + .salt_len = salt_len, }; supported_scheme = (signature_params_t){ .scheme = SIGN_RSA_EMSA_PSS, diff --git a/src/libtpmtss/tpm_tss_tss2_v2.c b/src/libtpmtss/tpm_tss_tss2_v2.c index f47858e70..eb80a0e3b 100644 --- a/src/libtpmtss/tpm_tss_tss2_v2.c +++ b/src/libtpmtss/tpm_tss_tss2_v2.c @@ -65,6 +65,12 @@ struct private_tpm_tss_tss2_t { * List of supported algorithms */ TPM2_ALG_ID supported_algs[TPM2_PT_ALGORITHM_SET]; + + /** + * Is TPM FIPS 186-4 compliant ? + */ + bool fips_186_4; + }; /** @@ -153,6 +159,7 @@ static bool get_algs_capability(private_tpm_tss_tss2_t *this) TPMS_TAGGED_PROPERTY tp; TPMI_YES_NO more_data; TPM2_ALG_ID alg; + bool fips_140_2 = FALSE; uint32_t rval, i, offset, revision = 0, year = 0; size_t len = BUF_LEN; char buf[BUF_LEN], manufacturer[5], vendor_string[17]; @@ -194,12 +201,25 @@ static bool get_algs_capability(private_tpm_tss_tss2_t *this) offset = 4 * (tp.property - TPM2_PT_VENDOR_STRING_1); htoun32(vendor_string + offset, tp.value); break; + case TPM2_PT_MODES: + if (tp.value & TPMA_MODES_FIPS_140_2) + { + this->fips_186_4 = fips_140_2 = TRUE; + } + break; default: break; } } - DBG2(DBG_PTS, "%s manufacturer: %s (%s) rev: %05.2f %u", LABEL, manufacturer, - vendor_string, (float)revision/100, year); + + if (!fips_140_2) + { + this->fips_186_4 = lib->settings->get_bool(lib->settings, + "%s.plugins.tpm.fips_186_4", FALSE, lib->ns); + } + DBG2(DBG_PTS, "%s manufacturer: %s (%s) rev: %05.2f %u %s", LABEL, + manufacturer, vendor_string, (float)revision/100, year, + fips_140_2 ? "FIPS 140-2" : (this->fips_186_4 ? "FIPS 186-4" : "")); /* get supported algorithms */ rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM2_CAP_ALGS, @@ -505,10 +525,14 @@ METHOD(tpm_tss_t, supported_signature_schemes, enumerator_t*, { case TPM2_ALG_RSAPSS: { + ssize_t salt_len; + + salt_len = this->fips_186_4 ? RSA_PSS_SALT_LEN_DEFAULT : + RSA_PSS_SALT_LEN_MAX; rsa_pss_params_t pss_params = { .hash = digest, .mgf1_hash = digest, - .salt_len = RSA_PSS_SALT_LEN_MAX, + .salt_len = salt_len, }; supported_scheme = (signature_params_t){ .scheme = SIGN_RSA_EMSA_PSS, From 3150bd2b819616d53d143dcfe865b63496130237 Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Tue, 23 Oct 2018 18:55:16 +0200 Subject: [PATCH 09/13] libtpmtss: Generalize AIK keys to signature keys --- src/libtpmtss/tpm_tss_tss2_v1.c | 18 +++++++++--------- src/libtpmtss/tpm_tss_tss2_v2.c | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/libtpmtss/tpm_tss_tss2_v1.c b/src/libtpmtss/tpm_tss_tss2_v1.c index a7b1344bd..f904442ed 100644 --- a/src/libtpmtss/tpm_tss_tss2_v1.c +++ b/src/libtpmtss/tpm_tss_tss2_v1.c @@ -421,7 +421,7 @@ METHOD(tpm_tss_t, get_version_info, chunk_t, } /** - * read the public key portion of a TSS 2.0 AIK key from NVRAM + * read the public key portion of a TSS 2.0 key from NVRAM */ bool read_public(private_tpm_tss_tss2_t *this, TPMI_DH_OBJECT handle, TPM2B_PUBLIC *public) @@ -471,9 +471,9 @@ METHOD(tpm_tss_t, get_public, chunk_t, } aik_blob = chunk_create((u_char*)&public, sizeof(public)); - DBG3(DBG_LIB, "%s AIK public key blob: %B", LABEL, &aik_blob); + DBG3(DBG_LIB, "%s public key blob: %B", LABEL, &aik_blob); - /* convert TSS 2.0 AIK public key blot into PKCS#1 format */ + /* convert TSS 2.0 public key blot into PKCS#1 format */ switch (public.t.publicArea.type) { case TPM_ALG_RSA: @@ -490,12 +490,12 @@ METHOD(tpm_tss_t, get_public, chunk_t, aik_modulus = chunk_create(rsa->t.buffer, rsa->t.size); aik_exponent = chunk_from_chars(0x01, 0x00, 0x01); - /* subjectPublicKeyInfo encoding of AIK RSA key */ + /* subjectPublicKeyInfo encoding of RSA public key */ if (!lib->encoding->encode(lib->encoding, PUBKEY_SPKI_ASN1_DER, NULL, &aik_pubkey, CRED_PART_RSA_MODULUS, aik_modulus, CRED_PART_RSA_PUB_EXP, aik_exponent, CRED_PART_END)) { - DBG1(DBG_PTS, "%s subjectPublicKeyInfo encoding of AIK key " + DBG1(DBG_PTS, "%s subjectPublicKeyInfo encoding of public key " "failed", LABEL); return chunk_empty; } @@ -526,7 +526,7 @@ METHOD(tpm_tss_t, get_public, chunk_t, pos += ecc->x.t.size; /* copy y coordinate of ECC point */ memcpy(pos, ecc->y.t.buffer, ecc->y.t.size); - /* subjectPublicKeyInfo encoding of AIK ECC key */ + /* subjectPublicKeyInfo encoding of ECC public key */ aik_pubkey = asn1_wrap(ASN1_SEQUENCE, "mm", asn1_wrap(ASN1_SEQUENCE, "mm", asn1_build_known_oid(OID_EC_PUBLICKEY), @@ -536,10 +536,10 @@ METHOD(tpm_tss_t, get_public, chunk_t, break; } default: - DBG1(DBG_PTS, "%s unsupported AIK key type", LABEL); + DBG1(DBG_PTS, "%s unsupported key type", LABEL); return chunk_empty; } - DBG1(DBG_PTS, "AIK signature algorithm is %N with %N hash", + DBG1(DBG_PTS, "signature algorithm is %N with %N hash", tpm_alg_id_names, sig_alg, tpm_alg_id_names, digest_alg); return aik_pubkey; } @@ -624,7 +624,7 @@ METHOD(tpm_tss_t, supported_signature_schemes, enumerator_t*, break; } default: - DBG1(DBG_PTS, "%s unsupported AIK key type", LABEL); + DBG1(DBG_PTS, "%s unsupported key type", LABEL); return enumerator_create_empty(); } return enumerator_create_single(signature_params_clone(&supported_scheme), diff --git a/src/libtpmtss/tpm_tss_tss2_v2.c b/src/libtpmtss/tpm_tss_tss2_v2.c index eb80a0e3b..6bbbce238 100644 --- a/src/libtpmtss/tpm_tss_tss2_v2.c +++ b/src/libtpmtss/tpm_tss_tss2_v2.c @@ -381,7 +381,7 @@ METHOD(tpm_tss_t, get_version_info, chunk_t, } /** - * read the public key portion of a TSS 2.0 AIK key from NVRAM + * read the public key portion of a TSS 2.0 key from NVRAM */ bool read_public(private_tpm_tss_tss2_t *this, TPMI_DH_OBJECT handle, TPM2B_PUBLIC *public) @@ -425,9 +425,9 @@ METHOD(tpm_tss_t, get_public, chunk_t, } aik_blob = chunk_create((u_char*)&public, sizeof(public)); - DBG3(DBG_LIB, "%s AIK public key blob: %B", LABEL, &aik_blob); + DBG3(DBG_LIB, "%s public key blob: %B", LABEL, &aik_blob); - /* convert TSS 2.0 AIK public key blot into PKCS#1 format */ + /* convert TSS 2.0 public key blot into PKCS#1 format */ switch (public.publicArea.type) { case TPM2_ALG_RSA: @@ -444,12 +444,12 @@ METHOD(tpm_tss_t, get_public, chunk_t, aik_modulus = chunk_create(rsa->buffer, rsa->size); aik_exponent = chunk_from_chars(0x01, 0x00, 0x01); - /* subjectPublicKeyInfo encoding of AIK RSA key */ + /* subjectPublicKeyInfo encoding of RSA public key */ if (!lib->encoding->encode(lib->encoding, PUBKEY_SPKI_ASN1_DER, NULL, &aik_pubkey, CRED_PART_RSA_MODULUS, aik_modulus, CRED_PART_RSA_PUB_EXP, aik_exponent, CRED_PART_END)) { - DBG1(DBG_PTS, "%s subjectPublicKeyInfo encoding of AIK key " + DBG1(DBG_PTS, "%s subjectPublicKeyInfo encoding of public key " "failed", LABEL); return chunk_empty; } @@ -480,7 +480,7 @@ METHOD(tpm_tss_t, get_public, chunk_t, pos += ecc->x.size; /* copy y coordinate of ECC point */ memcpy(pos, ecc->y.buffer, ecc->y.size); - /* subjectPublicKeyInfo encoding of AIK ECC key */ + /* subjectPublicKeyInfo encoding of ECC public key */ aik_pubkey = asn1_wrap(ASN1_SEQUENCE, "mm", asn1_wrap(ASN1_SEQUENCE, "mm", asn1_build_known_oid(OID_EC_PUBLICKEY), @@ -490,10 +490,10 @@ METHOD(tpm_tss_t, get_public, chunk_t, break; } default: - DBG1(DBG_PTS, "%s unsupported AIK key type", LABEL); + DBG1(DBG_PTS, "%s unsupported key type", LABEL); return chunk_empty; } - DBG1(DBG_PTS, "AIK signature algorithm is %N with %N hash", + DBG1(DBG_PTS, "signature algorithm is %N with %N hash", tpm_alg_id_names, sig_alg, tpm_alg_id_names, digest_alg); return aik_pubkey; } @@ -578,7 +578,7 @@ METHOD(tpm_tss_t, supported_signature_schemes, enumerator_t*, break; } default: - DBG1(DBG_PTS, "%s unsupported AIK key type", LABEL); + DBG1(DBG_PTS, "%s unsupported key type", LABEL); return enumerator_create_empty(); } return enumerator_create_single(signature_params_clone(&supported_scheme), From 7b46089ea755a5c67445a815c36207c895a06d87 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 15 Oct 2018 16:33:34 +0200 Subject: [PATCH 10/13] travis: Build tmp2-tss from sources --- scripts/test.sh | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/scripts/test.sh b/scripts/test.sh index 6f97e2435..1f90b7d6d 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -32,6 +32,28 @@ build_botan() cd - } +build_tss2() +{ + TSS2_REV=2.1.0 + TSS2_PKG=tpm2-tss-$TSS2_REV + TSS2_DIR=$TRAVIS_BUILD_DIR/../$TSS2_PKG + TSS2_SRC=https://github.com/tpm2-software/tpm2-tss/releases/download/$TSS2_REV/$TSS2_PKG.tar.gz + + if test -d "$TSS2_DIR"; then + return + fi + + # the default version of libgcrypt in Ubuntu 14.04 is too old + sudo apt-get update -qq && \ + sudo apt-get install -qq libgcrypt20-dev && + curl -L $TSS2_SRC | tar xz -C $TRAVIS_BUILD_DIR/.. && + cd $TSS2_DIR && + ./configure && + sudo make -j4 install >/dev/null && + sudo ldconfig || exit $? + cd - +} + if test -z $TRAVIS_BUILD_DIR; then TRAVIS_BUILD_DIR=$PWD fi @@ -79,8 +101,6 @@ all|coverage|sonarcloud) --disable-systemd --disable-soup --disable-unwind-backtraces --disable-svc --disable-dbghelp-backtraces --disable-socket-win --disable-kernel-wfp --disable-kernel-iph --disable-winhttp" - # Ubuntu 14.04 does provide a too old libtss2-dev - CONFIG="$CONFIG --disable-tss-tss2" # Ubuntu 14.04 does not provide libnm CONFIG="$CONFIG --disable-nm" # not enabled on the build server @@ -98,6 +118,7 @@ all|coverage|sonarcloud) PYDEPS="pytest" if test "$1" = "deps"; then build_botan + build_tss2 fi ;; win*) From 1b510c046783fc3b2961a42278a5b806e3915829 Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Wed, 17 Oct 2018 10:05:31 +0200 Subject: [PATCH 11/13] pubkey-authenticator: Append RSAPSS salt length to debug output --- .../sa/ikev2/authenticators/pubkey_authenticator.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c index c1d562a28..97d33a89e 100644 --- a/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c +++ b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c @@ -371,9 +371,9 @@ static status_t sign_signature_auth(private_pubkey_authenticator_t *this, if (params->scheme == SIGN_RSA_EMSA_PSS) { rsa_pss_params_t *pss = params->params; - DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N_%N %s", id, - signature_scheme_names, params->scheme, - hash_algorithm_short_names_upper, pss->hash, + DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N_%N_SALT_%zd " + "%s", id, signature_scheme_names, params->scheme, + hash_algorithm_short_names_upper, pss->hash, pss->salt_len, status == SUCCESS ? "successful" : "failed"); } else @@ -647,9 +647,9 @@ METHOD(authenticator_t, process, status_t, else if (params->scheme == SIGN_RSA_EMSA_PSS) { rsa_pss_params_t *pss = params->params; - DBG1(DBG_IKE, "authentication of '%Y' with %N_%N successful", - id, signature_scheme_names, params->scheme, - hash_algorithm_short_names_upper, pss->hash); + DBG1(DBG_IKE, "authentication of '%Y' with %N_%N_SALT_%zd " + "successful", id, signature_scheme_names, params->scheme, + hash_algorithm_short_names_upper, pss->hash, pss->salt_len); } else { From 5e03675a197484a461b2b81390109667a6cdea35 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 19 Oct 2018 09:17:39 +0200 Subject: [PATCH 12/13] agent: Add support for RSA signatures with SHA256 and SHA512 --- .../plugins/agent/agent_private_key.c | 51 +++++++++++++++---- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/src/libstrongswan/plugins/agent/agent_private_key.c b/src/libstrongswan/plugins/agent/agent_private_key.c index 77c29916c..70bee6981 100644 --- a/src/libstrongswan/plugins/agent/agent_private_key.c +++ b/src/libstrongswan/plugins/agent/agent_private_key.c @@ -81,6 +81,14 @@ enum agent_msg_type_t { SSH_AGENT_SIGN_RESPONSE = 14, }; +/** + * Flags for signatures + */ +enum agent_signature_flags_t { + SSH_AGENT_FLAG_SHA2_256 = 2, + SSH_AGENT_FLAG_SHA2_512 = 4, +}; + /** * read a byte from a blob */ @@ -217,12 +225,29 @@ static bool read_key(private_agent_private_key_t *this, public_key_t *pubkey) } static bool scheme_supported(private_agent_private_key_t *this, - signature_scheme_t scheme) + signature_scheme_t scheme, uint32_t *flags, + char **prefix) { switch (this->pubkey->get_type(this->pubkey)) { case KEY_RSA: - return scheme == SIGN_RSA_EMSA_PKCS1_SHA1; + switch (scheme) + { + case SIGN_RSA_EMSA_PKCS1_SHA1: + *prefix = "ssh-rsa"; + return TRUE; + case SIGN_RSA_EMSA_PKCS1_SHA2_256: + *flags |= SSH_AGENT_FLAG_SHA2_256; + *prefix = "rsa-sha2-256"; + return TRUE; + case SIGN_RSA_EMSA_PKCS1_SHA2_512: + *flags |= SSH_AGENT_FLAG_SHA2_512; + *prefix = "rsa-sha2-512"; + return TRUE; + default: + break; + } + return FALSE; case KEY_ECDSA: return scheme == SIGN_ECDSA_256 || scheme == SIGN_ECDSA_384 || @@ -236,11 +261,11 @@ METHOD(private_key_t, sign, bool, private_agent_private_key_t *this, signature_scheme_t scheme, void *params, chunk_t data, chunk_t *signature) { - uint32_t len, flags; - char buf[2048]; + uint32_t len, flags = 0; + char buf[2048], *prefix = NULL; chunk_t blob; - if (!scheme_supported(this, scheme)) + if (!scheme_supported(this, scheme, &flags, &prefix)) { DBG1(DBG_LIB, "signature scheme %N not supported by ssh-agent", signature_scheme_names, scheme); @@ -272,7 +297,7 @@ METHOD(private_key_t, sign, bool, return FALSE; } - flags = htonl(0); + flags = htonl(flags); if (write(this->socket, &flags, sizeof(flags)) != sizeof(flags)) { DBG1(DBG_LIB, "writing to ssh-agent failed"); @@ -290,9 +315,15 @@ METHOD(private_key_t, sign, bool, } /* parse length */ blob = read_string(&blob); - /* check sig type */ - if (chunk_equals(read_string(&blob), chunk_from_str("ssh-rsa"))) - { /* for RSA the signature has no special encoding */ + /* verify type */ + if (prefix && !chunk_equals(read_string(&blob), chunk_from_str(prefix))) + { + DBG1(DBG_LIB, "ssh-agent didn't return requested %s signature", prefix); + return FALSE; + } + + if (this->pubkey->get_type(this->pubkey) == KEY_RSA) + { /* for RSA, the signature has no special encoding */ blob = read_string(&blob); if (blob.len) { @@ -301,7 +332,7 @@ METHOD(private_key_t, sign, bool, } } else - { /* anything else is treated as ECSDA for now */ + { /* parse ECDSA signatures */ blob = read_string(&blob); if (blob.len) { From 153eb8199a432933a011e351b24ef51570be02dd Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 19 Oct 2018 09:26:29 +0200 Subject: [PATCH 13/13] agent: Enumerate only the supported signature schemes for RSA keys SHA-384 is not supported but is selected by signature_schemes_for_key() for keys between 3072 and 7680 bits. Since this is only called for IKEv2 signature authentication we don't even provide SHA-1 anymore. We always provide both schemes, though, which is what pubkey-authenticator does too for RSA. Older agents apparently just ignore the flags and always return a SHA-1 signature. If that's the case, charon.signature_authentication has to be disabled. --- .../plugins/agent/agent_private_key.c | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/src/libstrongswan/plugins/agent/agent_private_key.c b/src/libstrongswan/plugins/agent/agent_private_key.c index 70bee6981..961b30a04 100644 --- a/src/libstrongswan/plugins/agent/agent_private_key.c +++ b/src/libstrongswan/plugins/agent/agent_private_key.c @@ -371,6 +371,76 @@ METHOD(private_key_t, get_keysize, int, return this->pubkey->get_keysize(this->pubkey); } +/** + * Private data for RSA scheme enumerator + */ +typedef struct { + enumerator_t public; + int index; + bool reverse; +} scheme_enumerator_t; + +static signature_params_t rsa_schemes[] = { + { .scheme = SIGN_RSA_EMSA_PKCS1_SHA2_256 }, + { .scheme = SIGN_RSA_EMSA_PKCS1_SHA2_512 }, +}; + +METHOD(enumerator_t, enumerate_rsa_scheme, bool, + scheme_enumerator_t *this, va_list args) +{ + signature_params_t **params; + + VA_ARGS_VGET(args, params); + + if ((this->reverse && --this->index >= 0) || + (!this->reverse && ++this->index < countof(rsa_schemes))) + { + *params = &rsa_schemes[this->index]; + return TRUE; + } + return FALSE; +} + +/** + * Create an enumerator for the supported RSA signature schemes + */ +static enumerator_t *create_rsa_enumerator(private_agent_private_key_t *this) +{ + scheme_enumerator_t *enumerator; + + INIT(enumerator, + .public = { + .enumerate = enumerator_enumerate_default, + .venumerate = _enumerate_rsa_scheme, + .destroy = (void*)free, + }, + .index = -1, + .reverse = FALSE, + ); + /* propose SHA-512 first for larger keys */ + if (get_keysize(this) > 3072) + { + enumerator->index = countof(rsa_schemes); + enumerator->reverse = TRUE; + } + return &enumerator->public; +} + +METHOD(private_key_t, supported_signature_schemes, enumerator_t*, + private_agent_private_key_t *this) +{ + switch (get_type(this)) + { + case KEY_RSA: + return create_rsa_enumerator(this); + case KEY_ECDSA: + return signature_schemes_for_key(KEY_ECDSA, get_keysize(this)); + default: + break; + } + return enumerator_create_empty(); +} + METHOD(private_key_t, get_public_key, public_key_t*, private_agent_private_key_t *this) { @@ -444,6 +514,7 @@ agent_private_key_t *agent_private_key_open(key_type_t type, va_list args) .public = { .key = { .get_type = _get_type, + .supported_signature_schemes = _supported_signature_schemes, .sign = _sign, .decrypt = _decrypt, .get_keysize = _get_keysize,