From 0cad07c2fb0f34b2ad8502433b0e387408e97e21 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 27 Jun 2018 19:49:02 +0200 Subject: [PATCH 1/7] New header crypto_sizes.h This header will contain macros that calculate buffer sizes, whose semantics are standardized but whose definitions are implementation-specific because they depend on the available algorithms and on some permitted buffer size tolerances. Move size macros from crypto_struct.h to crypto_sizes.h, because these definitions need to be available both in the frontend and in the backend, whereas structures have different contents. --- include/psa/crypto.h | 4 +++ include/psa/crypto_sizes.h | 50 +++++++++++++++++++++++++++++++++++++ include/psa/crypto_struct.h | 8 ------ 3 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 include/psa/crypto_sizes.h diff --git a/include/psa/crypto.h b/include/psa/crypto.h index dcf1ba227..8f3a7f039 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -2070,6 +2070,10 @@ psa_status_t psa_generate_key(psa_key_slot_t key, } #endif +/* The file "crypto_sizes.h" contains definitions for size calculation + * macros whose definitions are implementation-specific. */ +#include "crypto_sizes.h" + /* The file "crypto_struct.h" contains definitions for * implementation-specific structs that are declared above. */ #include "crypto_struct.h" diff --git a/include/psa/crypto_sizes.h b/include/psa/crypto_sizes.h new file mode 100644 index 000000000..1de26e6d6 --- /dev/null +++ b/include/psa/crypto_sizes.h @@ -0,0 +1,50 @@ +/** + * \file psa/crypto_sizes.h + * + * \brief PSA cryptography module: Mbed TLS buffer size macros + * + * This file contains the definitions of macros that are useful to + * compute buffer sizes. The signatures and semantics of these macros + * are standardized, but the definitions are not, because they depend on + * the available algorithms and, in some cases, on permitted tolerances + * on buffer sizes. + */ +/* + * Copyright (C) 2018, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef PSA_CRYPTO_SIZES_H +#define PSA_CRYPTO_SIZES_H + +/* Include the Mbed TLS configuration file, the way Mbed TLS does it + * in each of its header files. */ +#if !defined(MBEDTLS_CONFIG_FILE) +#include "../mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SHA512_C) +#define PSA_HASH_MAX_SIZE 64 +#define PSA_HMAC_MAX_HASH_BLOCK_SIZE 128 +#else +#define PSA_HASH_MAX_SIZE 32 +#define PSA_HMAC_MAX_HASH_BLOCK_SIZE 64 +#endif + +#endif /* PSA_CRYPTO_SIZES_H */ diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h index 0dbd86c18..1935f9099 100644 --- a/include/psa/crypto_struct.h +++ b/include/psa/crypto_struct.h @@ -45,14 +45,6 @@ #include "mbedtls/sha256.h" #include "mbedtls/sha512.h" -#if defined(MBEDTLS_SHA512_C) -#define PSA_HASH_MAX_SIZE 64 -#define PSA_HMAC_MAX_HASH_BLOCK_SIZE 128 -#else -#define PSA_HASH_MAX_SIZE 32 -#define PSA_HMAC_MAX_HASH_BLOCK_SIZE 64 -#endif - struct psa_hash_operation_s { psa_algorithm_t alg; From 49cee6c582397a55a753bffe20acc52d84ef6327 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 27 Jun 2018 21:03:58 +0200 Subject: [PATCH 2/7] Move implementation-dependent size macros to crypto_sizes.h Macros such as PSA_HASH_SIZE whose definitions can be the same everywhere except in implementations that support non-standard algorithms remain in crypto.h, at least for the time being. --- include/psa/crypto.h | 110 ----------------------------------- include/psa/crypto_sizes.h | 115 +++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 110 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 8f3a7f039..e29a464de 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -1333,28 +1333,6 @@ psa_status_t psa_hash_abort(psa_hash_operation_t *operation); * as directed by the documentation of a specific implementation. */ typedef struct psa_mac_operation_s psa_mac_operation_t; -/** The size of the output of psa_mac_finish(), in bytes. - * - * This is also the MAC size that psa_mac_verify() expects. - * - * \param key_type The type of the MAC key. - * \param key_bits The size of the MAC key in bits. - * \param alg A MAC algorithm (\c PSA_ALG_XXX value such that - * #PSA_ALG_IS_MAC(alg) is true). - * - * \return The MAC size for the specified algorithm with - * the specified key parameters. - * \return 0 if the MAC algorithm is not recognized. - * \return Either 0 or the correct size for a MAC algorithm that - * the implementation recognizes, but does not support. - * \return Unspecified if the key parameters are not consistent - * with the algorithm. - */ -#define PSA_MAC_FINAL_SIZE(key_type, key_bits, alg) \ - (PSA_ALG_IS_HMAC(alg) ? PSA_HASH_SIZE(PSA_ALG_HMAC_HASH(alg)) : \ - PSA_ALG_IS_BLOCK_CIPHER_MAC(alg) ? PSA_BLOCK_CIPHER_BLOCK_SIZE(key_type) : \ - 0) - /** Start a multipart MAC operation. * * The sequence of operations to calculate a MAC (message authentication code) @@ -1575,30 +1553,6 @@ psa_status_t psa_cipher_abort(psa_cipher_operation_t *operation); (alg) == PSA_ALG_CCM ? 16 : \ 0) -/** The maximum size of the output of psa_aead_encrypt(), in bytes. - * - * If the size of the ciphertext buffer is at least this large, it is - * guaranteed that psa_aead_encrypt() will not fail due to an - * insufficient buffer size. Depending on the algorithm, the actual size of - * the ciphertext may be smaller. - * - * \param alg An AEAD algorithm - * (\c PSA_ALG_XXX value such that - * #PSA_ALG_IS_AEAD(alg) is true). - * \param plaintext_length Size of the plaintext in bytes. - * - * \return The AEAD ciphertext size for the specified - * algorithm. - * If the AEAD algorithm is not recognized, return 0. - * An implementation may return either 0 or a - * correct size for an AEAD algorithm that it - * recognizes, but does not support. - */ -#define PSA_AEAD_ENCRYPT_OUTPUT_SIZE(alg, plaintext_length) \ - (PSA_AEAD_TAG_SIZE(alg) != 0 ? \ - (plaintext_length) + PSA_AEAD_TAG_SIZE(alg) : \ - 0) - /** Process an authenticated encryption operation. * * \param key Slot containing the key to use. @@ -1652,30 +1606,6 @@ psa_status_t psa_aead_encrypt( psa_key_slot_t key, size_t ciphertext_size, size_t *ciphertext_length ); -/** The maximum size of the output of psa_aead_decrypt(), in bytes. - * - * If the size of the plaintext buffer is at least this large, it is - * guaranteed that psa_aead_decrypt() will not fail due to an - * insufficient buffer size. Depending on the algorithm, the actual size of - * the plaintext may be smaller. - * - * \param alg An AEAD algorithm - * (\c PSA_ALG_XXX value such that - * #PSA_ALG_IS_AEAD(alg) is true). - * \param ciphertext_length Size of the plaintext in bytes. - * - * \return The AEAD ciphertext size for the specified - * algorithm. - * If the AEAD algorithm is not recognized, return 0. - * An implementation may return either 0 or a - * correct size for an AEAD algorithm that it - * recognizes, but does not support. - */ -#define PSA_AEAD_DECRYPT_OUTPUT_SIZE(alg, ciphertext_length) \ - (PSA_AEAD_TAG_SIZE(alg) != 0 ? \ - (plaintext_length) - PSA_AEAD_TAG_SIZE(alg) : \ - 0) - /** Process an authenticated decryption operation. * * \param key Slot containing the key to use. @@ -1746,38 +1676,6 @@ psa_status_t psa_aead_decrypt( psa_key_slot_t key, #define PSA_ECDSA_SIGNATURE_SIZE(curve_bits) \ (PSA_BITS_TO_BYTES(curve_bits) * 2) -/** Safe signature buffer size for psa_asymmetric_sign(). - * - * This macro returns a safe buffer size for a signature using a key - * of the specified type and size, with the specified algorithm. - * Note that the actual size of the signature may be smaller - * (some algorithms produce a variable-size signature). - * - * \warning This function may call its arguments multiple times or - * zero times, so you should not pass arguments that contain - * side effects. - * - * \param key_type An asymmetric key type (this may indifferently be a - * key pair type or a public key type). - * \param key_bits The size of the key in bits. - * \param alg The signature algorithm. - * - * \return If the parameters are valid and supported, return - * a buffer size in bytes that guarantees that - * psa_asymmetric_sign() will not fail with - * #PSA_ERROR_BUFFER_TOO_SMALL. - * If the parameters are a valid combination that is not supported - * by the implementation, this macro either shall return either a - * sensible size or 0. - * If the parameters are not valid, the - * return value is unspecified. - * - */ -#define PSA_ASYMMETRIC_SIGN_OUTPUT_SIZE(key_type, key_bits, alg) \ - (PSA_KEY_TYPE_IS_RSA(key_type) ? ((void)alg, PSA_BITS_TO_BYTES(key_bits)) : \ - PSA_KEY_TYPE_IS_ECC(key_type) ? PSA_ECDSA_SIGNATURE_SIZE(key_bits) : \ - ((void)alg, 0)) - /** * \brief Sign a hash or short message with a private key. * @@ -1880,18 +1778,10 @@ psa_status_t psa_asymmetric_verify(psa_key_slot_t key, const uint8_t *signature, size_t signature_length); -#define PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE(key_type, key_bits, alg) \ - (PSA_KEY_TYPE_IS_RSA(key_type) ? \ - ((void)alg, PSA_BITS_TO_BYTES(key_bits)) : \ - 0) #define PSA_RSA_MINIMUM_PADDING_SIZE(alg) \ (PSA_ALG_IS_RSA_OAEP_MGF1(alg) ? \ 2 * PSA_HASH_FINAL_SIZE(PSA_ALG_RSA_GET_HASH(alg)) + 1 : \ 11 /*PKCS#1v1.5*/) -#define PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(key_type, key_bits, alg) \ - (PSA_KEY_TYPE_IS_RSA(key_type) ? \ - PSA_BITS_TO_BYTES(key_bits) - PSA_RSA_MINIMUM_PADDING_SIZE(alg) : \ - 0) /** * \brief Encrypt a short message with a public key. diff --git a/include/psa/crypto_sizes.h b/include/psa/crypto_sizes.h index 1de26e6d6..d7eab4e61 100644 --- a/include/psa/crypto_sizes.h +++ b/include/psa/crypto_sizes.h @@ -8,6 +8,9 @@ * are standardized, but the definitions are not, because they depend on * the available algorithms and, in some cases, on permitted tolerances * on buffer sizes. + * + * Macros that compute sizes whose values do not depend on the + * implementation are in crypto.h. */ /* * Copyright (C) 2018, ARM Limited, All Rights Reserved @@ -47,4 +50,116 @@ #define PSA_HMAC_MAX_HASH_BLOCK_SIZE 64 #endif + +/** The size of the output of psa_mac_finish(), in bytes. + * + * This is also the MAC size that psa_mac_verify() expects. + * + * \param key_type The type of the MAC key. + * \param key_bits The size of the MAC key in bits. + * \param alg A MAC algorithm (\c PSA_ALG_XXX value such that + * #PSA_ALG_IS_MAC(alg) is true). + * + * \return The MAC size for the specified algorithm with + * the specified key parameters. + * \return 0 if the MAC algorithm is not recognized. + * \return Either 0 or the correct size for a MAC algorithm that + * the implementation recognizes, but does not support. + * \return Unspecified if the key parameters are not consistent + * with the algorithm. + */ +#define PSA_MAC_FINAL_SIZE(key_type, key_bits, alg) \ + (PSA_ALG_IS_HMAC(alg) ? PSA_HASH_SIZE(PSA_ALG_HMAC_HASH(alg)) : \ + PSA_ALG_IS_BLOCK_CIPHER_MAC(alg) ? PSA_BLOCK_CIPHER_BLOCK_SIZE(key_type) : \ + 0) + +/** The maximum size of the output of psa_aead_encrypt(), in bytes. + * + * If the size of the ciphertext buffer is at least this large, it is + * guaranteed that psa_aead_encrypt() will not fail due to an + * insufficient buffer size. Depending on the algorithm, the actual size of + * the ciphertext may be smaller. + * + * \param alg An AEAD algorithm + * (\c PSA_ALG_XXX value such that + * #PSA_ALG_IS_AEAD(alg) is true). + * \param plaintext_length Size of the plaintext in bytes. + * + * \return The AEAD ciphertext size for the specified + * algorithm. + * If the AEAD algorithm is not recognized, return 0. + * An implementation may return either 0 or a + * correct size for an AEAD algorithm that it + * recognizes, but does not support. + */ +#define PSA_AEAD_ENCRYPT_OUTPUT_SIZE(alg, plaintext_length) \ + (PSA_AEAD_TAG_SIZE(alg) != 0 ? \ + (plaintext_length) + PSA_AEAD_TAG_SIZE(alg) : \ + 0) + +/** The maximum size of the output of psa_aead_decrypt(), in bytes. + * + * If the size of the plaintext buffer is at least this large, it is + * guaranteed that psa_aead_decrypt() will not fail due to an + * insufficient buffer size. Depending on the algorithm, the actual size of + * the plaintext may be smaller. + * + * \param alg An AEAD algorithm + * (\c PSA_ALG_XXX value such that + * #PSA_ALG_IS_AEAD(alg) is true). + * \param ciphertext_length Size of the plaintext in bytes. + * + * \return The AEAD ciphertext size for the specified + * algorithm. + * If the AEAD algorithm is not recognized, return 0. + * An implementation may return either 0 or a + * correct size for an AEAD algorithm that it + * recognizes, but does not support. + */ +#define PSA_AEAD_DECRYPT_OUTPUT_SIZE(alg, ciphertext_length) \ + (PSA_AEAD_TAG_SIZE(alg) != 0 ? \ + (plaintext_length) - PSA_AEAD_TAG_SIZE(alg) : \ + 0) + +/** Safe signature buffer size for psa_asymmetric_sign(). + * + * This macro returns a safe buffer size for a signature using a key + * of the specified type and size, with the specified algorithm. + * Note that the actual size of the signature may be smaller + * (some algorithms produce a variable-size signature). + * + * \warning This function may call its arguments multiple times or + * zero times, so you should not pass arguments that contain + * side effects. + * + * \param key_type An asymmetric key type (this may indifferently be a + * key pair type or a public key type). + * \param key_bits The size of the key in bits. + * \param alg The signature algorithm. + * + * \return If the parameters are valid and supported, return + * a buffer size in bytes that guarantees that + * psa_asymmetric_sign() will not fail with + * #PSA_ERROR_BUFFER_TOO_SMALL. + * If the parameters are a valid combination that is not supported + * by the implementation, this macro either shall return either a + * sensible size or 0. + * If the parameters are not valid, the + * return value is unspecified. + * + */ +#define PSA_ASYMMETRIC_SIGN_OUTPUT_SIZE(key_type, key_bits, alg) \ + (PSA_KEY_TYPE_IS_RSA(key_type) ? ((void)alg, PSA_BITS_TO_BYTES(key_bits)) : \ + PSA_KEY_TYPE_IS_ECC(key_type) ? PSA_ECDSA_SIGNATURE_SIZE(key_bits) : \ + ((void)alg, 0)) + +#define PSA_ASYMMETRIC_ENCRYPT_OUTPUT_SIZE(key_type, key_bits, alg) \ + (PSA_KEY_TYPE_IS_RSA(key_type) ? \ + ((void)alg, PSA_BITS_TO_BYTES(key_bits)) : \ + 0) +#define PSA_ASYMMETRIC_DECRYPT_OUTPUT_SIZE(key_type, key_bits, alg) \ + (PSA_KEY_TYPE_IS_RSA(key_type) ? \ + PSA_BITS_TO_BYTES(key_bits) - PSA_RSA_MINIMUM_PADDING_SIZE(alg) : \ + 0) + #endif /* PSA_CRYPTO_SIZES_H */ From af3baabd058559821afab7d3d44c5c7253f0c9bc Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 27 Jun 2018 22:55:52 +0200 Subject: [PATCH 3/7] Define max sizes for MAC and signatures This requires defining a maximum RSA key size, since the RSA key size is the signature size. Enforce the maximum RSA key size when importing or generating a key. --- include/psa/crypto_sizes.h | 83 ++++++++++++++++++++++++++++++++++++++ library/psa_crypto.c | 14 ++++--- 2 files changed, 92 insertions(+), 5 deletions(-) diff --git a/include/psa/crypto_sizes.h b/include/psa/crypto_sizes.h index d7eab4e61..f4d2cd839 100644 --- a/include/psa/crypto_sizes.h +++ b/include/psa/crypto_sizes.h @@ -42,6 +42,14 @@ #include MBEDTLS_CONFIG_FILE #endif +/** \def PSA_HASH_MAX_SIZE + * + * Maximum size of a hash. + * + * This macro must expand to a compile-time constant integer. This value + * should be the maximum size of a hash supported by the implementation, + * in bytes, and must be no smaller than this maximum. + */ #if defined(MBEDTLS_SHA512_C) #define PSA_HASH_MAX_SIZE 64 #define PSA_HMAC_MAX_HASH_BLOCK_SIZE 128 @@ -50,6 +58,81 @@ #define PSA_HMAC_MAX_HASH_BLOCK_SIZE 64 #endif +/** \def PSA_MAC_MAX_SIZE + * + * Maximum size of a MAC. + * + * This macro must expand to a compile-time constant integer. This value + * should be the maximum size of a MAC supported by the implementation, + * in bytes, and must be no smaller than this maximum. + */ +/* All non-HMAC MACs have a maximum size that's smaller than the + * minimum possible value of PSA_HASH_MAX_SIZE in this implementation. */ +#define PSA_MAC_MAX_SIZE PSA_HASH_MAX_SIZE + +/* The maximum size of an RSA key on this implementation, in bits. + * This is a vendor-specific macro. + * + * Mbed TLS does not set a hard limit on the size of RSA keys: any key + * whose parameters fit in a bignum is accepted. However large keys can + * induce a large memory usage and long computation times. Unlike other + * auxiliary macros in this file and in crypto.h, which reflect how the + * library is configured, this macro defines how the library is + * configured. This implementation refuses to import or generate an + * RSA key whose size is larger than the value defined here. + * + * Note that an implementation may set different size limits for different + * operations, and does not need to accept all key sizes up to the limit. */ +#define PSA_VENDOR_RSA_MAX_KEY_BITS 4096 + +/* The maximum size of an ECC key on this implementation, in bits. + * This is a vendor-specific macro. */ +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +#define PSA_VENDOR_ECC_MAX_CURVE_BITS 521 +#elif defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) +#define PSA_VENDOR_ECC_MAX_CURVE_BITS 512 +#elif defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) +#define PSA_VENDOR_ECC_MAX_CURVE_BITS 448 +#elif defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +#define PSA_VENDOR_ECC_MAX_CURVE_BITS 384 +#elif defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) +#define PSA_VENDOR_ECC_MAX_CURVE_BITS 384 +#elif defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) +#define PSA_VENDOR_ECC_MAX_CURVE_BITS 256 +#elif defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +#define PSA_VENDOR_ECC_MAX_CURVE_BITS 256 +#elif defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) +#define PSA_VENDOR_ECC_MAX_CURVE_BITS 256 +#elif defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) +#define PSA_VENDOR_ECC_MAX_CURVE_BITS 255 +#elif defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) +#define PSA_VENDOR_ECC_MAX_CURVE_BITS 224 +#elif defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) +#define PSA_VENDOR_ECC_MAX_CURVE_BITS 224 +#elif defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) +#define PSA_VENDOR_ECC_MAX_CURVE_BITS 192 +#elif defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) +#define PSA_VENDOR_ECC_MAX_CURVE_BITS 192 +#else +#define PSA_VENDOR_ECC_MAX_CURVE_BITS 0 +#endif + +/** \def PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE + * + * Maximum size of an asymmetric signature. + * + * This macro must expand to a compile-time constant integer. This value + * should be the maximum size of a MAC supported by the implementation, + * in bytes, and must be no smaller than this maximum. + */ +#define PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE \ + PSA_BITS_TO_BYTES( \ + PSA_VENDOR_RSA_MAX_KEY_BITS > PSA_VENDOR_ECC_MAX_CURVE_BITS ? \ + PSA_VENDOR_RSA_MAX_KEY_BITS : \ + PSA_VENDOR_ECC_MAX_CURVE_BITS \ + ) + + /** The size of the output of psa_mac_finish(), in bytes. * diff --git a/library/psa_crypto.c b/library/psa_crypto.c index 1d8eb506d..8ce668ce3 100644 --- a/library/psa_crypto.c +++ b/library/psa_crypto.c @@ -502,7 +502,13 @@ psa_status_t psa_import_key( psa_key_slot_t key, case MBEDTLS_PK_RSA: if( type == PSA_KEY_TYPE_RSA_PUBLIC_KEY || type == PSA_KEY_TYPE_RSA_KEYPAIR ) - slot->data.rsa = mbedtls_pk_rsa( pk ); + { + mbedtls_rsa_context *rsa = mbedtls_pk_rsa( pk ); + size_t bits = mbedtls_rsa_get_bitlen( rsa ); + if( bits > PSA_VENDOR_RSA_MAX_KEY_BITS ) + return( PSA_ERROR_NOT_SUPPORTED ); + slot->data.rsa = rsa; + } else status = PSA_ERROR_INVALID_ARGUMENT; break; @@ -1579,10 +1585,6 @@ psa_status_t psa_mac_finish( psa_mac_operation_t *operation, mac_size, mac_length ) ); } -#define PSA_MAC_MAX_SIZE \ - ( MBEDTLS_MD_MAX_SIZE > MBEDTLS_MAX_BLOCK_LENGTH ? \ - MBEDTLS_MD_MAX_SIZE : \ - MBEDTLS_MAX_BLOCK_LENGTH ) psa_status_t psa_mac_verify( psa_mac_operation_t *operation, const uint8_t *mac, size_t mac_length ) @@ -2862,6 +2864,8 @@ psa_status_t psa_generate_key( psa_key_slot_t key, mbedtls_rsa_context *rsa; int ret; int exponent = 65537; + if( bits > PSA_VENDOR_RSA_MAX_KEY_BITS ) + return( PSA_ERROR_NOT_SUPPORTED ); if( parameters != NULL ) { const unsigned *p = parameters; From 2743e42580dd30a7fb0eeb8d4b9b5d90b8090f19 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Wed, 27 Jun 2018 22:57:11 +0200 Subject: [PATCH 4/7] Correct reference for RSA keypair export format --- include/psa/crypto.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/psa/crypto.h b/include/psa/crypto.h index e29a464de..07ee00061 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -900,8 +900,8 @@ psa_status_t psa_get_key_information(psa_key_slot_t key, * - For Triple-DES, the format is the concatenation of the * two or three DES keys. * - For RSA key pairs (#PSA_KEY_TYPE_RSA_KEYPAIR), the format - * is the non-encrypted DER representation defined by PKCS\#8 (RFC 5208) - * as PrivateKeyInfo. + * is the non-encrypted DER representation defined by PKCS\#1 (RFC 8017) + * as RSAPrivateKey. * - For RSA public keys (#PSA_KEY_TYPE_RSA_PUBLIC_KEY), the format * is the DER representation defined by RFC 5280 as SubjectPublicKeyInfo. * From 69c1267fd21c94cdf1f9289fd18e7cf0d36f6162 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 28 Jun 2018 00:07:19 +0200 Subject: [PATCH 5/7] Use PSA_xxx_MAX_SIZE for hash/MAC/signature size in tests In tests that had a hard-coded buffer size, use PSA_MAC_MAX_SIZE or PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE as appropriate. Test that PSA_xxx_MAX_SIZE is larger than the size used in tests that expect a specific output. --- tests/suites/test_suite_psa_crypto.function | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index 1959e13d0..03ce5b33b 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -43,7 +43,7 @@ static int exercise_mac_key( psa_key_slot_t key, { psa_mac_operation_t operation; const unsigned char input[] = "foo"; - unsigned char mac[64] = {0}; + unsigned char mac[PSA_MAC_MAX_SIZE] = {0}; size_t mac_length = sizeof( mac ); if( usage & PSA_KEY_USAGE_SIGN ) @@ -191,7 +191,7 @@ static int exercise_signature_key( psa_key_slot_t key, { unsigned char payload[16] = {1}; size_t payload_length = sizeof( payload ); - unsigned char signature[256] = {0}; + unsigned char signature[PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE] = {0}; size_t signature_length = sizeof( signature ); if( usage & PSA_KEY_USAGE_SIGN ) @@ -709,6 +709,9 @@ void hash_finish( int alg_arg, data_t *input, data_t *expected_hash ) size_t actual_hash_length; psa_hash_operation_t operation; + TEST_ASSERT( expected_hash->len == PSA_HASH_SIZE( alg ) ); + TEST_ASSERT( expected_hash->len <= PSA_HASH_MAX_SIZE ); + TEST_ASSERT( input != NULL ); TEST_ASSERT( expected_hash != NULL ); TEST_ASSERT( PSA_CRYPTO_TEST_SIZE_T_RANGE( input->len ) ); @@ -737,6 +740,9 @@ void hash_verify( int alg_arg, data_t *input, data_t *expected_hash ) psa_algorithm_t alg = alg_arg; psa_hash_operation_t operation; + TEST_ASSERT( expected_hash->len == PSA_HASH_SIZE( alg ) ); + TEST_ASSERT( expected_hash->len <= PSA_HASH_MAX_SIZE ); + TEST_ASSERT( input != NULL ); TEST_ASSERT( expected_hash != NULL ); TEST_ASSERT( PSA_CRYPTO_TEST_SIZE_T_RANGE( input->len ) ); @@ -805,6 +811,8 @@ void mac_verify( int key_type_arg, psa_mac_operation_t operation; psa_key_policy_t policy; + TEST_ASSERT( expected_mac->len <= PSA_MAC_MAX_SIZE ); + TEST_ASSERT( key != NULL ); TEST_ASSERT( input != NULL ); TEST_ASSERT( expected_mac != NULL ); @@ -1594,6 +1602,7 @@ void sign_deterministic( int key_type_arg, data_t *key_data, signature_size = PSA_ASYMMETRIC_SIGN_OUTPUT_SIZE( key_type, key_bits, alg ); TEST_ASSERT( signature_size != 0 ); + TEST_ASSERT( signature_size <= PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE ); signature = mbedtls_calloc( 1, signature_size ); TEST_ASSERT( signature != NULL ); @@ -1677,6 +1686,8 @@ void asymmetric_verify( int key_type_arg, data_t *key_data, psa_algorithm_t alg = alg_arg; psa_key_policy_t policy; + TEST_ASSERT( signature_data->len <= PSA_ASYMMETRIC_SIGNATURE_MAX_SIZE ); + TEST_ASSERT( key_data != NULL ); TEST_ASSERT( hash_data != NULL ); TEST_ASSERT( signature_data != NULL ); From 0b352bcf957694d81b747c92e6d71c6d596e84ed Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 28 Jun 2018 00:16:11 +0200 Subject: [PATCH 6/7] Test that creating RSA keys larger than the maximum fails Test keypair import, public key import and key generation. --- tests/suites/test_suite_psa_crypto.data | 9 ++ tests/suites/test_suite_psa_crypto.function | 118 ++++++++++++++++++++ 2 files changed, 127 insertions(+) diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data index 1181fcd92..b281cb3af 100644 --- a/tests/suites/test_suite_psa_crypto.data +++ b/tests/suites/test_suite_psa_crypto.data @@ -129,6 +129,12 @@ PSA import EC keypair: valid key but RSA depends_on:MBEDTLS_PK_C:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_BP512R1_ENABLED:MBEDTLS_RSA_C import:"3082013b020100024100ee2b131d6b1818a94ca8e91c42387eb15a7c271f57b89e7336b144d4535b16c83097ecdefbbb92d1b5313b5a37214d0e8f25922dca778b424b25295fc8a1a7070203010001024100978ac8eadb0dc6035347d6aba8671215ff21283385396f7897c04baf5e2a835f3b53ef80a82ed36ae687a925380b55a0c73eb85656e989dcf0ed7fb4887024e1022100fdad8e1c6853563f8b921d2d112462ae7d6b176082d2ba43e87e1a37fc1a8b33022100f0592cf4c55ba44307b18981bcdbda376c51e590ffa5345ba866f6962dca94dd02201995f1a967d44ff4a4cd1de837bc65bf97a2bf7eda730a9a62cea53254591105022027f96cf4b8ee68ff8d04062ec1ce7f18c0b74e4b3379b29f9bfea3fc8e592731022100cefa6d220496b43feb83194255d8fb930afcf46f36606e3aa0eb7a93ad88c10c":PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_BRAINPOOL_P512R1):PSA_ERROR_INVALID_ARGUMENT +PSA import RSA key pair: maximum size exceeded +import_rsa_made_up:PSA_VENDOR_RSA_MAX_KEY_BITS+8:1:PSA_ERROR_NOT_SUPPORTED + +PSA import RSA public key: maximum size exceeded +import_rsa_made_up:PSA_VENDOR_RSA_MAX_KEY_BITS+8:0:PSA_ERROR_NOT_SUPPORTED + PSA key policy set and get key_policy:PSA_KEY_USAGE_ENCRYPT:PSA_ALG_CBC_BASE | PSA_ALG_BLOCK_CIPHER_PAD_NONE @@ -681,6 +687,9 @@ PSA generate key: RSA, 512 bits, good, encrypt depends_on:MBEDTLS_RSA_C generate_key:PSA_KEY_TYPE_RSA_KEYPAIR:512:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_RSA_PKCS1V15_CRYPT:PSA_SUCCESS +PSA generate key: RSA, maximum size exceeded +generate_key:PSA_KEY_TYPE_RSA_KEYPAIR:PSA_VENDOR_RSA_MAX_KEY_BITS+1:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_ENCRYPT | PSA_KEY_USAGE_DECRYPT:PSA_ALG_RSA_PKCS1V15_CRYPT:PSA_ERROR_NOT_SUPPORTED + PSA generate key: ECC, SECP256R1, good depends_on:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECDSA_C generate_key:PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_SECP256R1):256:PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY:PSA_ALG_ECDSA_ANY:PSA_SUCCESS diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function index 03ce5b33b..0d1a25c82 100644 --- a/tests/suites/test_suite_psa_crypto.function +++ b/tests/suites/test_suite_psa_crypto.function @@ -1,5 +1,6 @@ /* BEGIN_HEADER */ #include +#include "mbedtls/asn1write.h" #include "psa/crypto.h" #if(UINT32_MAX > SIZE_MAX) @@ -37,6 +38,88 @@ static int key_type_is_raw_bytes( psa_key_type_t type ) category == PSA_KEY_TYPE_CATEGORY_SYMMETRIC ); } +/* Write the ASN.1 INTEGER with the value 2^(bits-1)+x backwards from *p. */ +static int asn1_write_10x( unsigned char **p, + unsigned char *start, + size_t bits, + unsigned char x ) +{ + int ret; + int len = bits / 8 + 1; + if( x >= 1 << bits ) + return( MBEDTLS_ERR_ASN1_INVALID_DATA ); + if( *p < start || *p - start < (ssize_t) len ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + *p -= len; + ( *p )[len-1] = x; + if( bits % 8 == 0 ) + ( *p )[1] |= 1; + else + ( *p )[0] |= 1 << ( bits % 8 ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, + MBEDTLS_ASN1_INTEGER ) ); + return( len ); +} + +static int construct_fake_rsa_key( unsigned char *buffer, + size_t buffer_size, + unsigned char **p, + size_t bits, + int keypair ) +{ + size_t half_bits = ( bits + 1 ) / 2; + int ret; + int len = 0; + /* Construct something that looks like a DER encoding of + * as defined by PKCS#1 v2.2 (RFC 8017) section A.1.2: + * RSAPrivateKey ::= SEQUENCE { + * version Version, + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * privateExponent INTEGER, -- d + * prime1 INTEGER, -- p + * prime2 INTEGER, -- q + * exponent1 INTEGER, -- d mod (p-1) + * exponent2 INTEGER, -- d mod (q-1) + * coefficient INTEGER, -- (inverse of q) mod p + * otherPrimeInfos OtherPrimeInfos OPTIONAL + * } + * Or, for a public key, the same structure with only + * version, modulus and publicExponent. + */ + *p = buffer + buffer_size; + if( keypair ) + { + MBEDTLS_ASN1_CHK_ADD( len, /* pq */ + asn1_write_10x( p, buffer, half_bits, 1 ) ); + MBEDTLS_ASN1_CHK_ADD( len, /* dq */ + asn1_write_10x( p, buffer, half_bits, 1 ) ); + MBEDTLS_ASN1_CHK_ADD( len, /* dp */ + asn1_write_10x( p, buffer, half_bits, 1 ) ); + MBEDTLS_ASN1_CHK_ADD( len, /* q */ + asn1_write_10x( p, buffer, half_bits, 1 ) ); + MBEDTLS_ASN1_CHK_ADD( len, /* p != q to pass mbedtls sanity checks */ + asn1_write_10x( p, buffer, half_bits, 3 ) ); + MBEDTLS_ASN1_CHK_ADD( len, /* d */ + asn1_write_10x( p, buffer, bits, 1 ) ); + } + MBEDTLS_ASN1_CHK_ADD( len, /* e = 65537 */ + asn1_write_10x( p, buffer, 17, 1 ) ); + MBEDTLS_ASN1_CHK_ADD( len, /* n */ + asn1_write_10x( p, buffer, bits, 1 ) ); + if( keypair ) + MBEDTLS_ASN1_CHK_ADD( len, /* version = 0 */ + mbedtls_asn1_write_int( p, buffer, 0 ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, buffer, len ) ); + { + const unsigned char tag = + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE; + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, buffer, tag ) ); + } + return( len ); +} + static int exercise_mac_key( psa_key_slot_t key, psa_key_usage_t usage, psa_algorithm_t alg ) @@ -304,6 +387,41 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void import_rsa_made_up( int bits_arg, int keypair, int expected_status_arg ) +{ + int slot = 1; + size_t bits = bits_arg; + psa_status_t expected_status = expected_status_arg; + psa_status_t status; + psa_key_type_t type = + keypair ? PSA_KEY_TYPE_RSA_KEYPAIR : PSA_KEY_TYPE_RSA_PUBLIC_KEY; + size_t buffer_size = /* Slight overapproximations */ + keypair ? bits * 9 / 16 + 80 : bits / 8 + 20; + unsigned char *buffer = mbedtls_calloc( 1, buffer_size ); + unsigned char *p; + int ret; + size_t length; + + TEST_ASSERT( psa_crypto_init( ) == PSA_SUCCESS ); + TEST_ASSERT( buffer != NULL ); + + TEST_ASSERT( ( ret = construct_fake_rsa_key( buffer, buffer_size, &p, + bits, keypair ) ) >= 0 ); + length = ret; + + /* Try importing the key */ + status = psa_import_key( slot, type, p, length ); + TEST_ASSERT( status == expected_status ); + if( status == PSA_SUCCESS ) + TEST_ASSERT( psa_destroy_key( slot ) == PSA_SUCCESS ); + +exit: + mbedtls_free( buffer ); + mbedtls_psa_crypto_free( ); +} +/* END_CASE */ + /* BEGIN_CASE */ void import_export( data_t *data, int type_arg, From 07c91f5df33631c40c3152cc0db0923580bd1ab2 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Thu, 28 Jun 2018 18:02:53 +0200 Subject: [PATCH 7/7] Add notes about the purpose and usage of auxiliary header files --- include/psa/crypto_extra.h | 5 +++++ include/psa/crypto_platform.h | 10 ++++++++++ include/psa/crypto_sizes.h | 8 ++++++++ include/psa/crypto_struct.h | 10 ++++++++++ 4 files changed, 33 insertions(+) diff --git a/include/psa/crypto_extra.h b/include/psa/crypto_extra.h index b9e12bb6f..2d03f7311 100644 --- a/include/psa/crypto_extra.h +++ b/include/psa/crypto_extra.h @@ -2,6 +2,11 @@ * \file psa/crypto_extra.h * * \brief PSA cryptography module: Mbed TLS vendor extensions + * + * \note This file may not be included directly. Applications must + * include psa/crypto.h. + * + * This file is reserved for vendor-specific definitions. */ /* * Copyright (C) 2018, ARM Limited, All Rights Reserved diff --git a/include/psa/crypto_platform.h b/include/psa/crypto_platform.h index 7aabd1bc0..9af320d1e 100644 --- a/include/psa/crypto_platform.h +++ b/include/psa/crypto_platform.h @@ -2,6 +2,16 @@ * \file psa/crypto_platform.h * * \brief PSA cryptography module: Mbed TLS platfom definitions + * + * \note This file may not be included directly. Applications must + * include psa/crypto.h. + * + * This file contains platform-dependent type definitions. + * + * In implementations with isolation between the application and the + * cryptography module, implementers should take care to ensure that + * the definitions that are exposed to applications match what the + * module implements. */ /* * Copyright (C) 2018, ARM Limited, All Rights Reserved diff --git a/include/psa/crypto_sizes.h b/include/psa/crypto_sizes.h index f4d2cd839..80b2f9d62 100644 --- a/include/psa/crypto_sizes.h +++ b/include/psa/crypto_sizes.h @@ -3,12 +3,20 @@ * * \brief PSA cryptography module: Mbed TLS buffer size macros * + * \note This file may not be included directly. Applications must + * include psa/crypto.h. + * * This file contains the definitions of macros that are useful to * compute buffer sizes. The signatures and semantics of these macros * are standardized, but the definitions are not, because they depend on * the available algorithms and, in some cases, on permitted tolerances * on buffer sizes. * + * In implementations with isolation between the application and the + * cryptography module, implementers should take care to ensure that + * the definitions that are exposed to applications match what the + * module implements. + * * Macros that compute sizes whose values do not depend on the * implementation are in crypto.h. */ diff --git a/include/psa/crypto_struct.h b/include/psa/crypto_struct.h index 1935f9099..b981f23c7 100644 --- a/include/psa/crypto_struct.h +++ b/include/psa/crypto_struct.h @@ -2,6 +2,16 @@ * \file psa/crypto_struct.h * * \brief PSA cryptography module: Mbed TLS structured type implementations + * + * \note This file may not be included directly. Applications must + * include psa/crypto.h. + * + * This file contains the definitions of some data structures with + * implementation-specific definitions. + * + * In implementations with isolation between the application and the + * cryptography module, it is expected that the front-end and the back-end + * would have different versions of this file. */ /* * Copyright (C) 2018, ARM Limited, All Rights Reserved