Skip to content

Commit 43bafcc

Browse files
authored
Merge pull request #15 from gilles-peskine-arm/psa-signature_policy_wildcard
Support wildcard hash in signature policies
2 parents d46548c + 763fb9a commit 43bafcc

File tree

6 files changed

+224
-31
lines changed

6 files changed

+224
-31
lines changed

include/psa/crypto_values.h

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,7 @@
641641
(((alg) & PSA_ALG_CATEGORY_MASK) == PSA_ALG_CATEGORY_KEY_SELECTION)
642642

643643
#define PSA_ALG_HASH_MASK ((psa_algorithm_t)0x000000ff)
644+
644645
#define PSA_ALG_MD2 ((psa_algorithm_t)0x01000001)
645646
#define PSA_ALG_MD4 ((psa_algorithm_t)0x01000002)
646647
#define PSA_ALG_MD5 ((psa_algorithm_t)0x01000003)
@@ -667,6 +668,44 @@
667668
/** SHA3-512 */
668669
#define PSA_ALG_SHA3_512 ((psa_algorithm_t)0x01000013)
669670

671+
/** In a hash-and-sign algorithm policy, allow any hash algorithm.
672+
*
673+
* This value may be used to form the algorithm usage field of a policy
674+
* for a signature algorithm that is parametrized by a hash. The key
675+
* may then be used to perform operations using the same signature
676+
* algorithm parametrized with any supported hash.
677+
*
678+
* That is, suppose that `PSA_xxx_SIGNATURE` is one of the following macros:
679+
* - #PSA_ALG_RSA_PKCS1V15_SIGN, #PSA_ALG_RSA_PSS,
680+
* - #PSA_ALG_DSA, #PSA_ALG_DETERMINISTIC_DSA,
681+
* - #PSA_ALG_ECDSA, #PSA_ALG_DETERMINISTIC_ECDSA.
682+
* Then you may create and use a key as follows:
683+
* - Set the key usage field using #PSA_ALG_ANY_HASH, for example:
684+
* ```
685+
* psa_key_policy_set_usage(&policy,
686+
* PSA_KEY_USAGE_SIGN, //or PSA_KEY_USAGE_VERIFY
687+
* PSA_xxx_SIGNATURE(PSA_ALG_ANY_HASH));
688+
* psa_set_key_policy(handle, &policy);
689+
* ```
690+
* - Import or generate key material.
691+
* - Call psa_asymmetric_sign() or psa_asymmetric_verify(), passing
692+
* an algorithm built from `PSA_xxx_SIGNATURE` and a specific hash. Each
693+
* call to sign or verify a message may use a different hash.
694+
* ```
695+
* psa_asymmetric_sign(handle, PSA_xxx_SIGNATURE(PSA_ALG_SHA_256), ...);
696+
* psa_asymmetric_sign(handle, PSA_xxx_SIGNATURE(PSA_ALG_SHA_512), ...);
697+
* psa_asymmetric_sign(handle, PSA_xxx_SIGNATURE(PSA_ALG_SHA3_256), ...);
698+
* ```
699+
*
700+
* This value may not be used to build other algorithms that are
701+
* parametrized over a hash. For any valid use of this macro to build
702+
* an algorithm `\p alg`, #PSA_ALG_IS_HASH_AND_SIGN(\p alg) is true.
703+
*
704+
* This value may not be used to build an algorithm specification to
705+
* perform an operation. It is only valid to build policies.
706+
*/
707+
#define PSA_ALG_ANY_HASH ((psa_algorithm_t)0x010000ff)
708+
670709
#define PSA_ALG_MAC_SUBCATEGORY_MASK ((psa_algorithm_t)0x00c00000)
671710
#define PSA_ALG_HMAC_BASE ((psa_algorithm_t)0x02800000)
672711
/** Macro to build an HMAC algorithm.
@@ -914,6 +953,8 @@
914953
*
915954
* \param hash_alg A hash algorithm (\c PSA_ALG_XXX value such that
916955
* #PSA_ALG_IS_HASH(\p hash_alg) is true).
956+
* This includes #PSA_ALG_ANY_HASH
957+
* when specifying the algorithm in a usage policy.
917958
*
918959
* \return The corresponding RSA PKCS#1 v1.5 signature algorithm.
919960
* \return Unspecified if \p alg is not a supported
@@ -943,6 +984,8 @@
943984
*
944985
* \param hash_alg A hash algorithm (\c PSA_ALG_XXX value such that
945986
* #PSA_ALG_IS_HASH(\p hash_alg) is true).
987+
* This includes #PSA_ALG_ANY_HASH
988+
* when specifying the algorithm in a usage policy.
946989
*
947990
* \return The corresponding RSA PSS signature algorithm.
948991
* \return Unspecified if \p alg is not a supported
@@ -961,6 +1004,8 @@
9611004
*
9621005
* \param hash_alg A hash algorithm (\c PSA_ALG_XXX value such that
9631006
* #PSA_ALG_IS_HASH(\p hash_alg) is true).
1007+
* This includes #PSA_ALG_ANY_HASH
1008+
* when specifying the algorithm in a usage policy.
9641009
*
9651010
* \return The corresponding DSA signature algorithm.
9661011
* \return Unspecified if \p alg is not a supported
@@ -996,6 +1041,8 @@
9961041
*
9971042
* \param hash_alg A hash algorithm (\c PSA_ALG_XXX value such that
9981043
* #PSA_ALG_IS_HASH(\p hash_alg) is true).
1044+
* This includes #PSA_ALG_ANY_HASH
1045+
* when specifying the algorithm in a usage policy.
9991046
*
10001047
* \return The corresponding ECDSA signature algorithm.
10011048
* \return Unspecified if \p alg is not a supported
@@ -1028,6 +1075,8 @@
10281075
*
10291076
* \param hash_alg A hash algorithm (\c PSA_ALG_XXX value such that
10301077
* #PSA_ALG_IS_HASH(\p hash_alg) is true).
1078+
* This includes #PSA_ALG_ANY_HASH
1079+
* when specifying the algorithm in a usage policy.
10311080
*
10321081
* \return The corresponding deterministic ECDSA signature
10331082
* algorithm.
@@ -1046,6 +1095,23 @@
10461095
#define PSA_ALG_IS_RANDOMIZED_ECDSA(alg) \
10471096
(PSA_ALG_IS_ECDSA(alg) && !PSA_ALG_ECDSA_IS_DETERMINISTIC(alg))
10481097

1098+
/** Whether the specified algorithm is a hash-and-sign algorithm.
1099+
*
1100+
* Hash-and-sign algorithms are public-key signature algorithms structured
1101+
* in two parts: first the calculation of a hash in a way that does not
1102+
* depend on the key, then the calculation of a signature from the
1103+
* hash value and the key.
1104+
*
1105+
* \param alg An algorithm identifier (value of type #psa_algorithm_t).
1106+
*
1107+
* \return 1 if \p alg is a hash-and-sign algorithm, 0 otherwise.
1108+
* This macro may return either 0 or 1 if \p alg is not a supported
1109+
* algorithm identifier.
1110+
*/
1111+
#define PSA_ALG_IS_HASH_AND_SIGN(alg) \
1112+
(PSA_ALG_IS_RSA_PSS(alg) || PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) || \
1113+
PSA_ALG_IS_DSA(alg) || PSA_ALG_IS_ECDSA(alg))
1114+
10491115
/** Get the hash used by a hash-and-sign signature algorithm.
10501116
*
10511117
* A hash-and-sign algorithm is a signature algorithm which is
@@ -1065,8 +1131,7 @@
10651131
* if it is not supported by the implementation.
10661132
*/
10671133
#define PSA_ALG_SIGN_GET_HASH(alg) \
1068-
(PSA_ALG_IS_RSA_PSS(alg) || PSA_ALG_IS_RSA_PKCS1V15_SIGN(alg) || \
1069-
PSA_ALG_IS_DSA(alg) || PSA_ALG_IS_ECDSA(alg) ? \
1134+
(PSA_ALG_IS_HASH_AND_SIGN(alg) ? \
10701135
((alg) & PSA_ALG_HASH_MASK) == 0 ? /*"raw" algorithm*/ 0 : \
10711136
((alg) & PSA_ALG_HASH_MASK) | PSA_ALG_CATEGORY_HASH : \
10721137
0)
@@ -1325,6 +1390,24 @@
13251390
#define PSA_ALG_IS_ECDH(alg) \
13261391
(PSA_ALG_KEY_AGREEMENT_GET_BASE(alg) == PSA_ALG_ECDH_BASE)
13271392

1393+
/** Whether the specified algorithm encoding is a wildcard.
1394+
*
1395+
* Wildcard values may only be used to set the usage algorithm field in
1396+
* a policy, not to perform an operation.
1397+
*
1398+
* \param alg An algorithm identifier (value of type #psa_algorithm_t).
1399+
*
1400+
* \return 1 if \c alg is a wildcard algorithm encoding.
1401+
* \return 0 if \c alg is a non-wildcard algorithm encoding (suitable for
1402+
* an operation).
1403+
* \return This macro may return either 0 or 1 if \c alg is not a supported
1404+
* algorithm identifier.
1405+
*/
1406+
#define PSA_ALG_IS_WILDCARD(alg) \
1407+
(PSA_ALG_IS_HASH_AND_SIGN(alg) ? \
1408+
PSA_ALG_SIGN_GET_HASH(alg) == PSA_ALG_ANY_HASH : \
1409+
(alg) == PSA_ALG_ANY_HASH)
1410+
13281411
/**@}*/
13291412

13301413
/** \defgroup key_lifetimes Key lifetimes

library/psa_crypto.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,29 @@ static psa_status_t psa_get_empty_key_slot( psa_key_handle_t handle,
748748
return( status );
749749
}
750750

751+
/** Test whether a policy permits an algorithm.
752+
*
753+
* The caller must test usage flags separately.
754+
*/
755+
static int psa_key_policy_permits( const psa_key_policy_t *policy,
756+
psa_algorithm_t alg )
757+
{
758+
/* Common case: the policy only allows alg. */
759+
if( alg == policy->alg )
760+
return( 1 );
761+
/* If policy->alg is a hash-and-sign with a wildcard for the hash,
762+
* and alg is the same hash-and-sign family with any hash,
763+
* then alg is compliant with policy->alg. */
764+
if( PSA_ALG_IS_HASH_AND_SIGN( alg ) &&
765+
PSA_ALG_SIGN_GET_HASH( policy->alg ) == PSA_ALG_ANY_HASH )
766+
{
767+
return( ( policy->alg & ~PSA_ALG_HASH_MASK ) ==
768+
( alg & ~PSA_ALG_HASH_MASK ) );
769+
}
770+
/* If it isn't permitted, it's forbidden. */
771+
return( 0 );
772+
}
773+
751774
/** Retrieve a slot which must contain a key. The key must have allow all the
752775
* usage flags set in \p usage. If \p alg is nonzero, the key must allow
753776
* operations with this algorithm. */
@@ -775,7 +798,9 @@ static psa_status_t psa_get_key_from_slot( psa_key_handle_t handle,
775798
usage &= ~PSA_KEY_USAGE_EXPORT;
776799
if( ( slot->policy.usage & usage ) != usage )
777800
return( PSA_ERROR_NOT_PERMITTED );
778-
if( alg != 0 && ( alg != slot->policy.alg ) )
801+
802+
/* Enforce that the usage policy permits the requested algortihm. */
803+
if( alg != 0 && ! psa_key_policy_permits( &slot->policy, alg ) )
779804
return( PSA_ERROR_NOT_PERMITTED );
780805

781806
*p_slot = slot;

0 commit comments

Comments
 (0)