pkcs11: Support RSA-PSS signatures

This commit is contained in:
Andreas Steffen
2024-02-21 11:22:33 +01:00
committed by Tobias Brunner
parent f739657aac
commit 49769fff53
4 changed files with 184 additions and 19 deletions
+5
View File
@@ -30,3 +30,8 @@ charon.plugins.pkcs11.use_pubkey = no
charon.plugins.pkcs11.use_rng = no
Whether the PKCS#11 modules should be used as RNG.
charon.plugins.pkcs11.use_rsa_pss_hashers = no
Whether the PKCS#11 modules should try to use internal hashing for RSA-PSS
signatures (some PKCS#11 libraries don't implement internal hashing
in conjunction with RSA-PSS correctly).
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2011-2016 Tobias Brunner
* Copyright (C) 2010 Martin Willi
* Copyright (C) 2024 Andreas Steffen
*
* Copyright (C) secunet Security Networks AG
*
@@ -144,6 +145,7 @@ static bool is_mechanism_supported(pkcs11_library_t *p11, CK_SLOT_ID slot,
CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(pkcs11_library_t *p11,
CK_SLOT_ID slot,
signature_scheme_t scheme,
void *params,
key_type_t type, size_t keylen,
hash_algorithm_t *hash)
{
@@ -174,6 +176,8 @@ CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(pkcs11_library_t *p11,
KEY_RSA, 0, HASH_SHA1},
{SIGN_RSA_EMSA_PKCS1_MD5, {CKM_MD5_RSA_PKCS, NULL, 0},
KEY_RSA, 0, HASH_UNKNOWN},
{SIGN_RSA_EMSA_PSS, {CKM_RSA_PKCS_PSS, NULL, 0},
KEY_RSA, 0, HASH_UNKNOWN},
{SIGN_ECDSA_WITH_NULL, {CKM_ECDSA, NULL, 0},
KEY_ECDSA, 0, HASH_UNKNOWN},
{SIGN_ECDSA_WITH_SHA1_DER, {CKM_ECDSA_SHA1, NULL, 0},
@@ -191,6 +195,11 @@ CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(pkcs11_library_t *p11,
{SIGN_ECDSA_521, {CKM_ECDSA, NULL, 0},
KEY_ECDSA, 521, HASH_SHA512},
};
CK_MECHANISM_PTR mechanism;
CK_RSA_PKCS_PSS_PARAMS *rsa_pkcs_pss_params;
rsa_pss_params_t *rsa_pss_params;
hash_algorithm_t hash_alg = HASH_UNKNOWN;;
int i;
for (i = 0; i < countof(mappings); i++)
@@ -204,11 +213,145 @@ CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(pkcs11_library_t *p11,
{
continue;
}
mechanism = malloc_thing(CK_MECHANISM);
*mechanism = mappings[i].mechanism;
if (scheme == SIGN_RSA_EMSA_PSS)
{
rsa_pss_params = (rsa_pss_params_t*)params;
INIT(rsa_pkcs_pss_params,
.sLen = rsa_pss_params->salt_len
);
if (lib->settings->get_bool(lib->settings,
"%s.plugins.pkcs11.use_rsa_pss_hashers", FALSE, lib->ns))
{
switch (rsa_pss_params->hash)
{
case HASH_SHA256:
mechanism->mechanism = CKM_SHA256_RSA_PKCS_PSS;
break;
case HASH_SHA384:
mechanism->mechanism = CKM_SHA384_RSA_PKCS_PSS;
break;
case HASH_SHA512:
mechanism->mechanism = CKM_SHA512_RSA_PKCS_PSS;
break;
case HASH_SHA224:
mechanism->mechanism = CKM_SHA224_RSA_PKCS_PSS;
break;
case HASH_SHA1:
mechanism->mechanism = CKM_SHA1_RSA_PKCS_PSS;
break;
case HASH_SHA3_256:
mechanism->mechanism = CKM_SHA3_256_RSA_PKCS_PSS;
break;
case HASH_SHA3_384:
mechanism->mechanism = CKM_SHA3_384_RSA_PKCS_PSS;
break;
case HASH_SHA3_512:
mechanism->mechanism = CKM_SHA3_512_RSA_PKCS_PSS;
break;
case HASH_SHA3_224:
mechanism->mechanism = CKM_SHA3_224_RSA_PKCS_PSS;
break;
default:
free(rsa_pkcs_pss_params);
free(mechanism);
return NULL;
}
if (!is_mechanism_supported(p11, slot, mechanism))
{
/* revert to external hashing */
mechanism->mechanism = CKM_RSA_PKCS_PSS;
hash_alg = rsa_pss_params->hash;
}
}
else
{
/* use external hashing */
hash_alg = rsa_pss_params->hash;
}
switch (rsa_pss_params->hash)
{
case HASH_SHA256:
rsa_pkcs_pss_params->hashAlg = CKM_SHA256;
break;
case HASH_SHA384:
rsa_pkcs_pss_params->hashAlg = CKM_SHA384;
break;
case HASH_SHA512:
rsa_pkcs_pss_params->hashAlg = CKM_SHA512;
break;
case HASH_SHA224:
rsa_pkcs_pss_params->hashAlg = CKM_SHA224;
break;
case HASH_SHA1:
rsa_pkcs_pss_params->hashAlg = CKM_SHA_1;
break;
case HASH_SHA3_256:
rsa_pkcs_pss_params->hashAlg = CKM_SHA3_256;
break;
case HASH_SHA3_384:
rsa_pkcs_pss_params->hashAlg = CKM_SHA3_384;
break;
case HASH_SHA3_512:
rsa_pkcs_pss_params->hashAlg = CKM_SHA3_512;
break;
case HASH_SHA3_224:
rsa_pkcs_pss_params->hashAlg = CKM_SHA3_224;
break;
default:
free(rsa_pkcs_pss_params);
free(mechanism);
return NULL;
}
switch (rsa_pss_params->mgf1_hash)
{
case HASH_SHA256:
rsa_pkcs_pss_params->mgf = CKG_MGF1_SHA256;
break;
case HASH_SHA384:
rsa_pkcs_pss_params->mgf = CKG_MGF1_SHA384;
break;
case HASH_SHA512:
rsa_pkcs_pss_params->mgf = CKG_MGF1_SHA512;
break;
case HASH_SHA224:
rsa_pkcs_pss_params->mgf = CKG_MGF1_SHA224;
break;
case HASH_SHA1:
rsa_pkcs_pss_params->mgf = CKG_MGF1_SHA1;
break;
case HASH_SHA3_256:
rsa_pkcs_pss_params->mgf = CKG_MGF1_SHA3_256;
break;
case HASH_SHA3_384:
rsa_pkcs_pss_params->mgf = CKG_MGF1_SHA3_384;
break;
case HASH_SHA3_512:
rsa_pkcs_pss_params->mgf = CKG_MGF1_SHA3_512;
break;
case HASH_SHA3_224:
rsa_pkcs_pss_params->mgf = CKG_MGF1_SHA3_224;
break;
default:
free(rsa_pkcs_pss_params);
free(mechanism);
return NULL;
}
mechanism->pParameter = rsa_pkcs_pss_params;
mechanism->ulParameterLen = sizeof(CK_RSA_PKCS_PSS_PARAMS);
}
else
{
hash_alg = mappings[i].hash;
}
if (hash)
{
*hash = mappings[i].hash;
*hash = hash_alg;
}
return &mappings[i].mechanism;
return mechanism;
}
}
return NULL;
@@ -286,10 +429,11 @@ METHOD(private_key_t, sign, bool,
CK_RV rv;
hash_algorithm_t hash_alg;
chunk_t hash = chunk_empty;
bool success = FALSE;
mechanism = pkcs11_signature_scheme_to_mech(this->lib, this->slot, scheme,
this->type, get_keysize(this),
&hash_alg);
params, this->type,
get_keysize(this), &hash_alg);
if (!mechanism)
{
DBG1(DBG_LIB, "signature scheme %N not supported",
@@ -301,19 +445,19 @@ METHOD(private_key_t, sign, bool,
if (rv != CKR_OK)
{
DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
return FALSE;
goto end;
}
rv = this->lib->f->C_SignInit(session, mechanism, this->object);
if (this->reauth && !reauth(this, session))
{
this->lib->f->C_CloseSession(session);
return FALSE;
goto end;
}
if (rv != CKR_OK)
{
this->lib->f->C_CloseSession(session);
DBG1(DBG_LIB, "C_SignInit() failed: %N", ck_rv_names, rv);
return FALSE;
goto end;
}
if (hash_alg != HASH_UNKNOWN)
{
@@ -324,7 +468,7 @@ METHOD(private_key_t, sign, bool,
{
DESTROY_IF(hasher);
this->lib->f->C_CloseSession(session);
return FALSE;
goto end;
}
hasher->destroy(hasher);
switch (scheme)
@@ -357,7 +501,7 @@ METHOD(private_key_t, sign, bool,
{
DBG1(DBG_LIB, "C_Sign() failed: %N", ck_rv_names, rv);
free(buf);
return FALSE;
goto end;
}
switch (scheme)
{
@@ -382,7 +526,12 @@ METHOD(private_key_t, sign, bool,
*signature = chunk_create(buf, len);
break;
}
return TRUE;
success = TRUE;
end:
free(mechanism->pParameter);
free(mechanism);
return success;
}
METHOD(private_key_t, decrypt, bool,
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2011 Tobias Brunner
* Copyright (C) 2010 Martin Willi
* Copyright (C) 2024 Andreas Steffen
*
* Copyright (C) secunet Security Networks AG
*
@@ -61,6 +62,7 @@ pkcs11_private_key_t *pkcs11_private_key_connect(key_type_t type, va_list args);
* @param lib PKCS#11 library of the token the key resides on
* @param slot slot of the token
* @param scheme signature scheme
* @param params optional signature scheme parameters
* @param type key type
* @param keylen key length in bits
* @param hash hash algorithm to apply first (HASH_UNKNOWN if none)
@@ -68,6 +70,7 @@ pkcs11_private_key_t *pkcs11_private_key_connect(key_type_t type, va_list args);
CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(pkcs11_library_t *lib,
CK_SLOT_ID slot,
signature_scheme_t scheme,
void *params,
key_type_t type, size_t keylen,
hash_algorithm_t *hash);
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2011-2015 Tobias Brunner
* Copyright (C) 2010 Martin Willi
* Copyright (C) 2024 Andreas Steffen
*
* Copyright (C) secunet Security Networks AG
*
@@ -209,14 +210,16 @@ METHOD(public_key_t, verify, bool,
hash_algorithm_t hash_alg;
chunk_t hash = chunk_empty, parse, r, s;
size_t len;
bool success = FALSE;
mechanism = pkcs11_signature_scheme_to_mech(this->lib, this->slot, scheme,
this->type, this->k, &hash_alg);
params, this->type, this->k,
&hash_alg);
if (!mechanism)
{
DBG1(DBG_LIB, "signature scheme %N not supported",
signature_scheme_names, scheme);
return FALSE;
goto end;
}
switch (scheme)
{
@@ -231,14 +234,14 @@ METHOD(public_key_t, verify, bool,
asn1_unwrap(&parse, &r) != ASN1_INTEGER ||
asn1_unwrap(&parse, &s) != ASN1_INTEGER)
{
return FALSE;
goto end;
}
r = chunk_skip_zero(r);
s = chunk_skip_zero(s);
len = (get_keysize(this) + 7) / 8;
if (r.len > len || s.len > len)
{
return FALSE;
goto end;
}
/* concatenate r and s (forced to the defined length) */
sig = chunk_alloca(2*len);
@@ -255,14 +258,14 @@ METHOD(public_key_t, verify, bool,
if (rv != CKR_OK)
{
DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
return FALSE;
goto end;
}
rv = this->lib->f->C_VerifyInit(session, mechanism, this->object);
if (rv != CKR_OK)
{
this->lib->f->C_CloseSession(session);
DBG1(DBG_LIB, "C_VerifyInit() failed: %N", ck_rv_names, rv);
return FALSE;
goto end;
}
if (hash_alg != HASH_UNKNOWN)
{
@@ -273,7 +276,7 @@ METHOD(public_key_t, verify, bool,
{
DESTROY_IF(hasher);
this->lib->f->C_CloseSession(session);
return FALSE;
goto end;
}
hasher->destroy(hasher);
switch (scheme)
@@ -299,9 +302,14 @@ METHOD(public_key_t, verify, bool,
if (rv != CKR_OK)
{
DBG1(DBG_LIB, "C_Verify() failed: %N", ck_rv_names, rv);
return FALSE;
goto end;
}
return TRUE;
success = TRUE;
end:
free(mechanism->pParameter);
free(mechanism);
return success;
}
METHOD(public_key_t, encrypt, bool,