diff options
author | Tobias Brunner <tobias@strongswan.org> | 2017-09-25 14:50:20 +0200 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2017-11-08 16:48:10 +0100 |
commit | 3ce8b0556a33679f410073ef4577cc78f4282cbb (patch) | |
tree | 9825cdbbde5cadeb1577bf0a45ae7c959b61a251 /src/libstrongswan | |
parent | 89c3987baf8869fa5c1e0cd1242a560b538226f0 (diff) | |
download | strongswan-3ce8b0556a33679f410073ef4577cc78f4282cbb.tar.bz2 strongswan-3ce8b0556a33679f410073ef4577cc78f4282cbb.tar.xz |
gcrypt: Add support for RSA-PSS signatures
For salt lengths other than 20 this requires 0bd8137e68c2 ("cipher:
Add option to specify salt length for PSS verification."), which was
included in libgcrypt 1.7.0 (for Ubuntu requires 17.04). As that makes
it pretty much useless for us (SHA-1 is a MUST NOT), we require that version
to even provide the feature.
Diffstat (limited to 'src/libstrongswan')
-rw-r--r-- | src/libstrongswan/plugins/gcrypt/gcrypt_plugin.c | 6 | ||||
-rw-r--r-- | src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c | 79 | ||||
-rw-r--r-- | src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c | 73 |
3 files changed, 127 insertions, 31 deletions
diff --git a/src/libstrongswan/plugins/gcrypt/gcrypt_plugin.c b/src/libstrongswan/plugins/gcrypt/gcrypt_plugin.c index fdc2cb519..8a3de1e01 100644 --- a/src/libstrongswan/plugins/gcrypt/gcrypt_plugin.c +++ b/src/libstrongswan/plugins/gcrypt/gcrypt_plugin.c @@ -119,6 +119,9 @@ METHOD(plugin_t, get_features, int, PLUGIN_REGISTER(PRIVKEY_GEN, gcrypt_rsa_private_key_gen, FALSE), PLUGIN_PROVIDE(PRIVKEY_GEN, KEY_RSA), /* signature schemes, private */ +#if GCRYPT_VERSION_NUMBER >= 0x010700 + PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PSS), +#endif PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_NULL), PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA2_224), PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA2_256), @@ -127,6 +130,9 @@ METHOD(plugin_t, get_features, int, PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA1), PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_MD5), /* signature verification schemes */ +#if GCRYPT_VERSION_NUMBER >= 0x010700 + PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PSS), +#endif PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_NULL), PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_224), PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_256), diff --git a/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c b/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c index 6a8f6b035..5dc0bfd30 100644 --- a/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c +++ b/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_private_key.c @@ -22,6 +22,7 @@ #include <asn1/oid.h> #include <asn1/asn1.h> #include <asn1/asn1_parser.h> +#include <credentials/keys/signature_params.h> typedef struct private_gcrypt_rsa_private_key_t private_gcrypt_rsa_private_key_t; @@ -148,51 +149,89 @@ static bool sign_raw(private_gcrypt_rsa_private_key_t *this, } /** - * Sign a chunk of data using hashing and PKCS#1 encoding + * Sign a chunk of data using hashing and PKCS#1v1.5/EMSA-PSS encoding */ static bool sign_pkcs1(private_gcrypt_rsa_private_key_t *this, - hash_algorithm_t hash_algorithm, char *hash_name, + hash_algorithm_t hash_algorithm, rsa_pss_params_t *pss, chunk_t data, chunk_t *signature) { hasher_t *hasher; chunk_t hash; gcry_error_t err; gcry_sexp_t in, out; - int hash_oid; + char *hash_name = enum_to_name(hash_algorithm_short_names, hash_algorithm); - hash_oid = hasher_algorithm_to_oid(hash_algorithm); - if (hash_oid == OID_UNKNOWN) + hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm); + if (!hasher) { + DBG1(DBG_LIB, "hash algorithm %N not supported", + hash_algorithm_names, hash_algorithm); return FALSE; } - hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm); - if (!hasher || !hasher->allocate_hash(hasher, data, &hash)) + if (!hasher->allocate_hash(hasher, data, &hash)) { - DESTROY_IF(hasher); + hasher->destroy(hasher); return FALSE; } hasher->destroy(hasher); - err = gcry_sexp_build(&in, NULL, "(data(flags pkcs1)(hash %s %b))", - hash_name, hash.len, hash.ptr); + if (pss) + { + u_int slen = hasher_hash_size(hash_algorithm); + if (pss->salt_len > RSA_PSS_SALT_LEN_DEFAULT) + { + 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); + } + else + { + err = gcry_sexp_build(&in, NULL, "(data(flags pkcs1)(hash %s %b))", + hash_name, hash.len, hash.ptr); + } chunk_free(&hash); if (err) { - DBG1(DBG_LIB, "building signature S-expression failed: %s", gpg_strerror(err)); + DBG1(DBG_LIB, "building signature S-expression failed: %s", + gpg_strerror(err)); return FALSE; } err = gcry_pk_sign(&out, in, this->key); gcry_sexp_release(in); if (err) { - DBG1(DBG_LIB, "creating pkcs1 signature failed: %s", gpg_strerror(err)); + DBG1(DBG_LIB, "creating pkcs1 signature failed: %s", + gpg_strerror(err)); return FALSE; } + *signature = gcrypt_rsa_find_token(out, "s", this->key); gcry_sexp_release(out); return !!signature->len; } +#if GCRYPT_VERSION_NUMBER >= 0x010700 +/** + * Sign a chunk of data using hashing and EMSA-PSS encoding + */ +static bool sign_pss(private_gcrypt_rsa_private_key_t *this, + rsa_pss_params_t *params, chunk_t data, chunk_t *signature) +{ + if (!params) + { + return FALSE; + } + if (params->mgf1_hash != params->hash) + { + DBG1(DBG_LIB, "unable to use a different MGF1 hash for RSA-PSS"); + return FALSE; + } + return sign_pkcs1(this, params->hash, params, data, signature); +} +#endif + METHOD(private_key_t, get_type, key_type_t, private_gcrypt_rsa_private_key_t *this) { @@ -208,17 +247,21 @@ METHOD(private_key_t, sign, bool, case SIGN_RSA_EMSA_PKCS1_NULL: return sign_raw(this, data, sig); case SIGN_RSA_EMSA_PKCS1_SHA2_224: - return sign_pkcs1(this, HASH_SHA224, "sha224", data, sig); + return sign_pkcs1(this, HASH_SHA224, NULL, data, sig); case SIGN_RSA_EMSA_PKCS1_SHA2_256: - return sign_pkcs1(this, HASH_SHA256, "sha256", data, sig); + return sign_pkcs1(this, HASH_SHA256, NULL, data, sig); case SIGN_RSA_EMSA_PKCS1_SHA2_384: - return sign_pkcs1(this, HASH_SHA384, "sha384", data, sig); + return sign_pkcs1(this, HASH_SHA384, NULL, data, sig); case SIGN_RSA_EMSA_PKCS1_SHA2_512: - return sign_pkcs1(this, HASH_SHA512, "sha512", data, sig); + return sign_pkcs1(this, HASH_SHA512, NULL, data, sig); case SIGN_RSA_EMSA_PKCS1_SHA1: - return sign_pkcs1(this, HASH_SHA1, "sha1", data, sig); + return sign_pkcs1(this, HASH_SHA1, NULL, data, sig); case SIGN_RSA_EMSA_PKCS1_MD5: - return sign_pkcs1(this, HASH_MD5, "md5", data, sig); + return sign_pkcs1(this, HASH_MD5, NULL, data, sig); +#if GCRYPT_VERSION_NUMBER >= 0x010700 + case SIGN_RSA_EMSA_PSS: + return sign_pss(this, params, data, sig); +#endif default: DBG1(DBG_LIB, "signature scheme %N not supported in RSA", signature_scheme_names, scheme); diff --git a/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c b/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c index 5820a8998..9e2ac1287 100644 --- a/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c +++ b/src/libstrongswan/plugins/gcrypt/gcrypt_rsa_public_key.c @@ -1,6 +1,7 @@ /* + * Copyright (C) 2017 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi - * Hochschule fuer Technik Rapperswil + * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -22,6 +23,7 @@ #include <asn1/asn1.h> #include <asn1/asn1_parser.h> #include <crypto/hashers/hasher.h> +#include <credentials/keys/signature_params.h> typedef struct private_gcrypt_rsa_public_key_t private_gcrypt_rsa_public_key_t; @@ -109,27 +111,48 @@ static bool verify_raw(private_gcrypt_rsa_public_key_t *this, } /** - * Verification of an EMSA PKCS1 signature described in PKCS#1 + * Verification of an EMSA PKCS1v1.5 / EMSA-PSS signature described in PKCS#1 */ static bool verify_pkcs1(private_gcrypt_rsa_public_key_t *this, - hash_algorithm_t algorithm, char *hash_name, + hash_algorithm_t algorithm, rsa_pss_params_t *pss, chunk_t data, chunk_t signature) { hasher_t *hasher; chunk_t hash; gcry_error_t err; gcry_sexp_t in, sig; + char *hash_name = enum_to_name(hash_algorithm_short_names, algorithm); hasher = lib->crypto->create_hasher(lib->crypto, algorithm); - if (!hasher || !hasher->allocate_hash(hasher, data, &hash)) + if (!hasher) { - DESTROY_IF(hasher); + DBG1(DBG_LIB, "hash algorithm %N not supported", + hash_algorithm_names, algorithm); + return FALSE; + } + if (!hasher->allocate_hash(hasher, data, &hash)) + { + hasher->destroy(hasher); return FALSE; } hasher->destroy(hasher); - err = gcry_sexp_build(&in, NULL, "(data(flags pkcs1)(hash %s %b))", - hash_name, hash.len, hash.ptr); + if (pss) + { + u_int slen = hasher_hash_size(algorithm); + if (pss->salt_len > RSA_PSS_SALT_LEN_DEFAULT) + { + 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); + } + else + { + err = gcry_sexp_build(&in, NULL, "(data(flags pkcs1)(hash %s %b))", + hash_name, hash.len, hash.ptr); + } chunk_free(&hash); if (err) { @@ -159,6 +182,26 @@ static bool verify_pkcs1(private_gcrypt_rsa_public_key_t *this, return TRUE; } +#if GCRYPT_VERSION_NUMBER >= 0x010700 +/** + * Verification of an EMSA-PSS signature described in PKCS#1 + */ +static bool verify_pss(private_gcrypt_rsa_public_key_t *this, + rsa_pss_params_t *params, chunk_t data, chunk_t sig) +{ + if (!params) + { + return FALSE; + } + if (params->mgf1_hash != params->hash) + { + DBG1(DBG_LIB, "unable to use a different MGF1 hash for RSA-PSS"); + return FALSE; + } + return verify_pkcs1(this, params->hash, params, data, sig); +} +#endif + METHOD(public_key_t, get_type, key_type_t, private_gcrypt_rsa_public_key_t *this) { @@ -174,17 +217,21 @@ METHOD(public_key_t, verify, bool, case SIGN_RSA_EMSA_PKCS1_NULL: return verify_raw(this, data, signature); case SIGN_RSA_EMSA_PKCS1_SHA2_224: - return verify_pkcs1(this, HASH_SHA224, "sha224", data, signature); + return verify_pkcs1(this, HASH_SHA224, NULL, data, signature); case SIGN_RSA_EMSA_PKCS1_SHA2_256: - return verify_pkcs1(this, HASH_SHA256, "sha256", data, signature); + return verify_pkcs1(this, HASH_SHA256, NULL, data, signature); case SIGN_RSA_EMSA_PKCS1_SHA2_384: - return verify_pkcs1(this, HASH_SHA384, "sha384", data, signature); + return verify_pkcs1(this, HASH_SHA384, NULL, data, signature); case SIGN_RSA_EMSA_PKCS1_SHA2_512: - return verify_pkcs1(this, HASH_SHA512, "sha512", data, signature); + return verify_pkcs1(this, HASH_SHA512, NULL, data, signature); case SIGN_RSA_EMSA_PKCS1_SHA1: - return verify_pkcs1(this, HASH_SHA1, "sha1", data, signature); + return verify_pkcs1(this, HASH_SHA1, NULL, data, signature); case SIGN_RSA_EMSA_PKCS1_MD5: - return verify_pkcs1(this, HASH_MD5, "md5", data, signature); + return verify_pkcs1(this, HASH_MD5, NULL, data, signature); +#if GCRYPT_VERSION_NUMBER >= 0x010700 + case SIGN_RSA_EMSA_PSS: + return verify_pss(this, params, data, signature); +#endif default: DBG1(DBG_LIB, "signature scheme %N not supported in RSA", signature_scheme_names, scheme); |