summaryrefslogtreecommitdiff
path: root/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c')
-rw-r--r--src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c146
1 files changed, 142 insertions, 4 deletions
diff --git a/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c b/src/libstrongswan/plugins/openssl/openssl_rsa_public_key.c
index d3a644f72..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)
{
@@ -137,7 +271,7 @@ METHOD(public_key_t, get_type, key_type_t,
METHOD(public_key_t, verify, bool,
private_openssl_rsa_public_key_t *this, signature_scheme_t scheme,
- chunk_t data, chunk_t signature)
+ void *params, chunk_t data, chunk_t signature)
{
switch (scheme)
{
@@ -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);