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.
This commit is contained in:
@@ -119,6 +119,9 @@ METHOD(plugin_t, get_features, int,
|
|||||||
PLUGIN_REGISTER(PRIVKEY_GEN, gcrypt_rsa_private_key_gen, FALSE),
|
PLUGIN_REGISTER(PRIVKEY_GEN, gcrypt_rsa_private_key_gen, FALSE),
|
||||||
PLUGIN_PROVIDE(PRIVKEY_GEN, KEY_RSA),
|
PLUGIN_PROVIDE(PRIVKEY_GEN, KEY_RSA),
|
||||||
/* signature schemes, private */
|
/* 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_NULL),
|
||||||
PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA2_224),
|
PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA2_224),
|
||||||
PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_SHA2_256),
|
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_SHA1),
|
||||||
PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_MD5),
|
PLUGIN_PROVIDE(PRIVKEY_SIGN, SIGN_RSA_EMSA_PKCS1_MD5),
|
||||||
/* signature verification schemes */
|
/* 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_NULL),
|
||||||
PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_224),
|
PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_224),
|
||||||
PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_256),
|
PLUGIN_PROVIDE(PUBKEY_VERIFY, SIGN_RSA_EMSA_PKCS1_SHA2_256),
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <asn1/oid.h>
|
#include <asn1/oid.h>
|
||||||
#include <asn1/asn1.h>
|
#include <asn1/asn1.h>
|
||||||
#include <asn1/asn1_parser.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;
|
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,
|
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)
|
chunk_t data, chunk_t *signature)
|
||||||
{
|
{
|
||||||
hasher_t *hasher;
|
hasher_t *hasher;
|
||||||
chunk_t hash;
|
chunk_t hash;
|
||||||
gcry_error_t err;
|
gcry_error_t err;
|
||||||
gcry_sexp_t in, out;
|
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);
|
hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm);
|
||||||
if (hash_oid == OID_UNKNOWN)
|
if (!hasher)
|
||||||
{
|
{
|
||||||
|
DBG1(DBG_LIB, "hash algorithm %N not supported",
|
||||||
|
hash_algorithm_names, hash_algorithm);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm);
|
if (!hasher->allocate_hash(hasher, data, &hash))
|
||||||
if (!hasher || !hasher->allocate_hash(hasher, data, &hash))
|
|
||||||
{
|
{
|
||||||
DESTROY_IF(hasher);
|
hasher->destroy(hasher);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
hasher->destroy(hasher);
|
hasher->destroy(hasher);
|
||||||
|
|
||||||
err = gcry_sexp_build(&in, NULL, "(data(flags pkcs1)(hash %s %b))",
|
if (pss)
|
||||||
hash_name, hash.len, hash.ptr);
|
{
|
||||||
|
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);
|
chunk_free(&hash);
|
||||||
if (err)
|
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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
err = gcry_pk_sign(&out, in, this->key);
|
err = gcry_pk_sign(&out, in, this->key);
|
||||||
gcry_sexp_release(in);
|
gcry_sexp_release(in);
|
||||||
if (err)
|
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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
*signature = gcrypt_rsa_find_token(out, "s", this->key);
|
*signature = gcrypt_rsa_find_token(out, "s", this->key);
|
||||||
gcry_sexp_release(out);
|
gcry_sexp_release(out);
|
||||||
return !!signature->len;
|
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,
|
METHOD(private_key_t, get_type, key_type_t,
|
||||||
private_gcrypt_rsa_private_key_t *this)
|
private_gcrypt_rsa_private_key_t *this)
|
||||||
{
|
{
|
||||||
@@ -208,17 +247,21 @@ METHOD(private_key_t, sign, bool,
|
|||||||
case SIGN_RSA_EMSA_PKCS1_NULL:
|
case SIGN_RSA_EMSA_PKCS1_NULL:
|
||||||
return sign_raw(this, data, sig);
|
return sign_raw(this, data, sig);
|
||||||
case SIGN_RSA_EMSA_PKCS1_SHA2_224:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
default:
|
||||||
DBG1(DBG_LIB, "signature scheme %N not supported in RSA",
|
DBG1(DBG_LIB, "signature scheme %N not supported in RSA",
|
||||||
signature_scheme_names, scheme);
|
signature_scheme_names, scheme);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (C) 2017 Tobias Brunner
|
||||||
* Copyright (C) 2005-2009 Martin Willi
|
* 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
|
* 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
|
* under the terms of the GNU General Public License as published by the
|
||||||
@@ -22,6 +23,7 @@
|
|||||||
#include <asn1/asn1.h>
|
#include <asn1/asn1.h>
|
||||||
#include <asn1/asn1_parser.h>
|
#include <asn1/asn1_parser.h>
|
||||||
#include <crypto/hashers/hasher.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;
|
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,
|
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)
|
chunk_t data, chunk_t signature)
|
||||||
{
|
{
|
||||||
hasher_t *hasher;
|
hasher_t *hasher;
|
||||||
chunk_t hash;
|
chunk_t hash;
|
||||||
gcry_error_t err;
|
gcry_error_t err;
|
||||||
gcry_sexp_t in, sig;
|
gcry_sexp_t in, sig;
|
||||||
|
char *hash_name = enum_to_name(hash_algorithm_short_names, algorithm);
|
||||||
|
|
||||||
hasher = lib->crypto->create_hasher(lib->crypto, 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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
hasher->destroy(hasher);
|
hasher->destroy(hasher);
|
||||||
|
|
||||||
err = gcry_sexp_build(&in, NULL, "(data(flags pkcs1)(hash %s %b))",
|
if (pss)
|
||||||
hash_name, hash.len, hash.ptr);
|
{
|
||||||
|
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);
|
chunk_free(&hash);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
@@ -159,6 +182,26 @@ static bool verify_pkcs1(private_gcrypt_rsa_public_key_t *this,
|
|||||||
return TRUE;
|
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,
|
METHOD(public_key_t, get_type, key_type_t,
|
||||||
private_gcrypt_rsa_public_key_t *this)
|
private_gcrypt_rsa_public_key_t *this)
|
||||||
{
|
{
|
||||||
@@ -174,17 +217,21 @@ METHOD(public_key_t, verify, bool,
|
|||||||
case SIGN_RSA_EMSA_PKCS1_NULL:
|
case SIGN_RSA_EMSA_PKCS1_NULL:
|
||||||
return verify_raw(this, data, signature);
|
return verify_raw(this, data, signature);
|
||||||
case SIGN_RSA_EMSA_PKCS1_SHA2_224:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
default:
|
||||||
DBG1(DBG_LIB, "signature scheme %N not supported in RSA",
|
DBG1(DBG_LIB, "signature scheme %N not supported in RSA",
|
||||||
signature_scheme_names, scheme);
|
signature_scheme_names, scheme);
|
||||||
|
|||||||
Reference in New Issue
Block a user