diff options
author | Tobias Brunner <tobias@strongswan.org> | 2017-09-23 10:39:14 +0200 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2017-11-08 16:48:10 +0100 |
commit | 2f95d7195de834e49c54377594e4bfedab1a37a3 (patch) | |
tree | c1f0da83e81aa216c05ea4bd99f4eb9707ac5bd9 /src/libstrongswan/plugins/openssl | |
parent | 51dd2fd2db1ad3e10a20344e8025c5139455b944 (diff) | |
download | strongswan-2f95d7195de834e49c54377594e4bfedab1a37a3.tar.bz2 strongswan-2f95d7195de834e49c54377594e4bfedab1a37a3.tar.xz |
openssl: Add support for verifying RSASSA-PSS signatures
Diffstat (limited to 'src/libstrongswan/plugins/openssl')
-rw-r--r-- | src/libstrongswan/plugins/openssl/openssl_plugin.c | 1 | ||||
-rw-r--r-- | src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c | 144 |
2 files changed, 142 insertions, 3 deletions
diff --git a/src/libstrongswan/plugins/openssl/openssl_plugin.c b/src/libstrongswan/plugins/openssl/openssl_plugin.c index 163ce30f9..8b0a7c5c7 100644 --- a/src/libstrongswan/plugins/openssl/openssl_plugin.c +++ b/src/libstrongswan/plugins/openssl/openssl_plugin.c @@ -626,6 +626,7 @@ METHOD(plugin_t, get_features, int, PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_NULL), #if OPENSSL_VERSION_NUMBER >= 0x10000000L PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PSS), + PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PSS), #endif #ifndef OPENSSL_NO_SHA1 PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA1), diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c index 078b26165..20bf30ae9 100644 --- a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c +++ b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c @@ -1,7 +1,7 @@ /* + * Copyright (C) 2008-2017 Tobias Brunner * Copyright (C) 2009 Martin Willi - * Copyright (C) 2008 Tobias Brunner - * 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 @@ -19,9 +19,11 @@ #ifndef OPENSSL_NO_RSA #include "openssl_rsa_public_key.h" +#include "openssl_hasher.h" #include "openssl_util.h" #include <utils/debug.h> +#include <credentials/keys/signature_params.h> #include <openssl/bn.h> #include <openssl/evp.h> @@ -54,8 +56,138 @@ struct private_openssl_rsa_public_key_t { refcount_t ref; }; + +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + +/** + * Verify RSA signature + */ +static bool verify_signature(private_openssl_rsa_public_key_t *this, + const EVP_MD *md, rsa_pss_params_t *pss, + chunk_t data, chunk_t signature) +{ + EVP_PKEY_CTX *pctx = NULL; + EVP_MD_CTX *mctx = NULL; + EVP_PKEY *key; + int rsa_size = RSA_size(this->rsa); + bool valid = FALSE; + + /* OpenSSL expects a signature of exactly RSA size (no leading 0x00) */ + if (signature.len > rsa_size) + { + signature = chunk_skip(signature, signature.len - rsa_size); + } + + mctx = EVP_MD_CTX_create(); + key = EVP_PKEY_new(); + if (!mctx || !key) + { + goto error; + } + if (!EVP_PKEY_set1_RSA(key, this->rsa)) + { + goto error; + } + if (EVP_DigestVerifyInit(mctx, &pctx, md, NULL, key) <= 0) + { + goto error; + } + 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_mgf1_md(pctx, mgf1md) <= 0) + { + goto error; + } + } + if (EVP_DigestVerifyUpdate(mctx, data.ptr, data.len) <= 0) + { + goto error; + } + valid = (EVP_DigestVerifyFinal(mctx, signature.ptr, signature.len) == 1); + +error: + if (key) + { + EVP_PKEY_free(key); + } + if (mctx) + { + EVP_MD_CTX_destroy(mctx); + } + return valid; +} + /** - * Verification of an EMPSA PKCS1 signature described in PKCS#1 + * Verification of a signature without hashing + */ +static bool verify_plain_signature(private_openssl_rsa_public_key_t *this, + chunk_t data, chunk_t signature) +{ + char *buf; + int len, rsa_size = RSA_size(this->rsa); + bool valid = FALSE; + + /* OpenSSL expects a signature of exactly RSA size (no leading 0x00) */ + if (signature.len > rsa_size) + { + signature = chunk_skip(signature, signature.len - rsa_size); + } + buf = malloc(rsa_size); + len = RSA_public_decrypt(signature.len, signature.ptr, buf, this->rsa, + RSA_PKCS1_PADDING); + if (len != -1) + { + valid = chunk_equals_const(data, chunk_create(buf, len)); + } + free(buf); + return valid; +} + +/** + * Verification of an EMSA PKCS1 signature described in PKCS#1 + */ +static bool verify_emsa_pkcs1_signature(private_openssl_rsa_public_key_t *this, + int type, chunk_t data, chunk_t signature) +{ + const EVP_MD *md; + + if (type == NID_undef) + { + return verify_plain_signature(this, data, signature); + } + md = EVP_get_digestbynid(type); + return md && verify_signature(this, md, NULL, data, signature); +} + +/** + * Verification of an EMSA PSS signature described in PKCS#1 + */ +static bool verify_emsa_pss_signature(private_openssl_rsa_public_key_t *this, + rsa_pss_params_t *params, chunk_t data, + chunk_t signature) +{ + const EVP_MD *md; + + if (!params) + { + return FALSE; + } + md = openssl_get_md(params->hash); + return md && verify_signature(this, md, params, data, signature); +} + +#else /* OPENSSL_VERSION_NUMBER < 1.0 */ + +/** + * Verification of an EMSA PKCS1 signature described in PKCS#1 */ static bool verify_emsa_pkcs1_signature(private_openssl_rsa_public_key_t *this, int type, chunk_t data, chunk_t signature) @@ -129,6 +261,8 @@ error: return valid; } +#endif /* OPENSSL_VERSION_NUMBER < 1.0 */ + METHOD(public_key_t, get_type, key_type_t, private_openssl_rsa_public_key_t *this) { @@ -155,6 +289,10 @@ METHOD(public_key_t, verify, bool, return verify_emsa_pkcs1_signature(this, NID_sha1, data, signature); case SIGN_RSA_EMSA_PKCS1_MD5: return verify_emsa_pkcs1_signature(this, NID_md5, data, signature); +#if OPENSSL_VERSION_NUMBER >= 0x10000000L + case SIGN_RSA_EMSA_PSS: + return verify_emsa_pss_signature(this, params, data, signature); +#endif default: DBG1(DBG_LIB, "signature scheme %N not supported in RSA", signature_scheme_names, scheme); |