From 49769fff53f31ad61d011f7bc9bc0a8504b4cf02 Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Fri, 26 Jan 2024 19:58:23 +0100 Subject: [PATCH] pkcs11: Support RSA-PSS signatures --- conf/plugins/pkcs11.opt | 5 + .../plugins/pkcs11/pkcs11_private_key.c | 169 ++++++++++++++++-- .../plugins/pkcs11/pkcs11_private_key.h | 3 + .../plugins/pkcs11/pkcs11_public_key.c | 26 ++- 4 files changed, 184 insertions(+), 19 deletions(-) diff --git a/conf/plugins/pkcs11.opt b/conf/plugins/pkcs11.opt index 8f328f0879..4c9f81ed2e 100644 --- a/conf/plugins/pkcs11.opt +++ b/conf/plugins/pkcs11.opt @@ -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). diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c index 6f70d48bab..83b6f2c7ef 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c @@ -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, diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.h b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.h index c353178d68..08c272e3cb 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.h +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.h @@ -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); diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c b/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c index 62e754de7b..2298be16ea 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c @@ -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, -- 2.47.2