diff --git a/include/psa/crypto.h b/include/psa/crypto.h index 837f737c3..87f2d60b7 100644 --- a/include/psa/crypto.h +++ b/include/psa/crypto.h @@ -1243,6 +1243,12 @@ psa_status_t psa_get_key_information(psa_key_slot_t key, * \retval #PSA_ERROR_EMPTY_SLOT * \retval #PSA_ERROR_NOT_PERMITTED * \retval #PSA_ERROR_NOT_SUPPORTED + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p data buffer is too small. You can determine a + * sufficient buffer size by calling + * #PSA_KEY_EXPORT_MAX_SIZE(\c type, \c bits) + * where \c type is the key type + * and \c bits is the key size in bits. * \retval #PSA_ERROR_COMMUNICATION_FAILURE * \retval #PSA_ERROR_HARDWARE_FAILURE * \retval #PSA_ERROR_TAMPERING_DETECTED @@ -1332,6 +1338,14 @@ psa_status_t psa_export_key(psa_key_slot_t key, * \retval #PSA_SUCCESS * \retval #PSA_ERROR_EMPTY_SLOT * \retval #PSA_ERROR_INVALID_ARGUMENT + * The key is neither a public key nor a key pair. + * \retval #PSA_ERROR_NOT_SUPPORTED + * \retval #PSA_ERROR_BUFFER_TOO_SMALL + * The size of the \p data buffer is too small. You can determine a + * sufficient buffer size by calling + * #PSA_KEY_EXPORT_MAX_SIZE(#PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR(\c type), \c bits) + * where \c type is the key type + * and \c bits is the key size in bits. * \retval #PSA_ERROR_COMMUNICATION_FAILURE * \retval #PSA_ERROR_HARDWARE_FAILURE * \retval #PSA_ERROR_TAMPERING_DETECTED diff --git a/include/psa/crypto_sizes.h b/include/psa/crypto_sizes.h index ab5b17e19..bc8edc612 100644 --- a/include/psa/crypto_sizes.h +++ b/include/psa/crypto_sizes.h @@ -305,4 +305,213 @@ PSA_BITS_TO_BYTES(key_bits) - PSA_RSA_MINIMUM_PADDING_SIZE(alg) : \ 0) +/* Maximum size of the ASN.1 encoding of an INTEGER with the specified + * number of bits. + * + * This definition assumes that bits <= 2^19 - 9 so that the length field + * is at most 3 bytes. The length of the encoding is the length of the + * bit string padded to a whole number of bytes plus: + * - 1 type byte; + * - 1 to 3 length bytes; + * - 0 to 1 bytes of leading 0 due to the sign bit. + */ +#define PSA_KEY_EXPORT_ASN1_INTEGER_MAX_SIZE(bits) \ + ((bits) / 8 + 5) + +/* Maximum size of the export encoding of an RSA public key. + * Assumes that the public exponent is less than 2^32. + * + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } -- contains RSAPublicKey + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters NULL } + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER } -- e + * + * - 3 * 4 bytes of SEQUENCE overhead; + * - 1 + 1 + 9 bytes of algorithm (RSA OID); + * - 2 bytes of NULL; + * - 4 bytes of BIT STRING overhead; + * - n : INTEGER; + * - 7 bytes for the public exponent. + */ +#define PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(key_bits) \ + (PSA_KEY_EXPORT_ASN1_INTEGER_MAX_SIZE(key_bits) + 36) + +/* Maximum size of the export encoding of an RSA key pair. + * Assumes thatthe public exponent is less than 2^32 and that the size + * difference between the two primes is at most 1 bit. + * + * RSAPrivateKey ::= SEQUENCE { + * version Version, -- 0 + * modulus INTEGER, -- N-bit + * publicExponent INTEGER, -- 32-bit + * privateExponent INTEGER, -- N-bit + * prime1 INTEGER, -- N/2-bit + * prime2 INTEGER, -- N/2-bit + * exponent1 INTEGER, -- N/2-bit + * exponent2 INTEGER, -- N/2-bit + * coefficient INTEGER, -- N/2-bit + * } + * + * - 4 bytes of SEQUENCE overhead; + * - 3 bytes of version; + * - 7 half-size INTEGERs plus 2 full-size INTEGERs, + * overapproximated as 9 half-size INTEGERS; + * - 7 bytes for the public exponent. + */ +#define PSA_KEY_EXPORT_RSA_KEYPAIR_MAX_SIZE(key_bits) \ + (9 * PSA_KEY_EXPORT_ASN1_INTEGER_MAX_SIZE((key_bits) / 2 + 1) + 14) + +/* Maximum size of the export encoding of a DSA public key. + * + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } -- contains DSAPublicKey + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters Dss-Parms } -- SEQUENCE of 3 INTEGERs + * DSAPublicKey ::= INTEGER -- public key, Y + * + * - 3 * 4 bytes of SEQUENCE overhead; + * - 1 + 1 + 7 bytes of algorithm (DSA OID); + * - 4 bytes of BIT STRING overhead; + * - 3 full-size INTEGERs (p, g, y); + * - 1 + 1 + 32 bytes for 1 sub-size INTEGER (q <= 256 bits). + */ +#define PSA_KEY_EXPORT_DSA_PUBLIC_KEY_MAX_SIZE(key_bits) \ + (PSA_KEY_EXPORT_ASN1_INTEGER_MAX_SIZE(key_bits) * 3 + 59) + +/* Maximum size of the export encoding of a DSA key pair. + * + * DSAPrivateKey ::= SEQUENCE { + * version Version, -- 0 + * prime INTEGER, -- p + * subprime INTEGER, -- q + * generator INTEGER, -- g + * public INTEGER, -- y + * private INTEGER, -- x + * } + * + * - 4 bytes of SEQUENCE overhead; + * - 3 bytes of version; + * - 3 full-size INTEGERs (p, g, y); + * - 2 * (1 + 1 + 32) bytes for 2 sub-size INTEGERs (q, x <= 256 bits). + */ +#define PSA_KEY_EXPORT_DSA_KEYPAIR_MAX_SIZE(key_bits) \ + (PSA_KEY_EXPORT_ASN1_INTEGER_MAX_SIZE(key_bits) * 3 + 75) + +/* Maximum size of the export encoding of an ECC public key. + * + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } -- contains ECPoint + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters OBJECT IDENTIFIER } -- namedCurve + * ECPoint ::= OCTET STRING + * -- first byte: 0x04; + * -- then x_P as a `ceiling(log_{256}(n))`-byte string, big endian; + * -- then y_P as a `ceiling(log_{256}(n))`-byte string, big endian, + * -- where n is the order of the curve. + * + * - 2 * 4 bytes of SEQUENCE overhead; + * - 1 + 1 + 7 bytes of algorithm (id-ecPublicKey OID); + * - 1 + 1 + 12 bytes of namedCurve OID; + * - 4 bytes of BIT STRING overhead; + * - 1 byte + 2 * point size in ECPoint. + */ +#define PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits) \ + (2 * PSA_BITS_TO_BYTES(key_bits) + 36) + +/* Maximum size of the export encoding of an ECC key pair. + * + * ECPrivateKey ::= SEQUENCE { + * version INTEGER, -- must be 1 + * privateKey OCTET STRING, + * -- `ceiling(log_{256}(n))`-byte string, big endian, + * -- where n is the order of the curve. + * parameters ECParameters {{ NamedCurve }}, -- mandatory + * publicKey BIT STRING -- mandatory + * } + * + * - 4 bytes of SEQUENCE overhead; + * - 1 * point size in privateKey + * - 1 + 1 + 12 bytes of namedCurve OID; + * - 4 bytes of BIT STRING overhead; + * - public key as for #PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE. + */ +#define PSA_KEY_EXPORT_ECC_KEYPAIR_MAX_SIZE(key_bits) \ + (3 * PSA_BITS_TO_BYTES(key_bits) + 56) + +/** Safe output buffer size for psa_export_key() or psa_export_public_key(). + * + * This macro returns a compile-time constant if its arguments are + * compile-time constants. + * + * \warning This function may call its arguments multiple times or + * zero times, so you should not pass arguments that contain + * side effects. + * + * The following code illustrates how to allocate enough memory to export + * a key by querying the key type and size at runtime. + * \code{c} + * psa_key_type_t key_type; + * size_t key_bits; + * psa_status_t status; + * status = psa_get_key_information(key, &key_type, &key_bits); + * if (status != PSA_SUCCESS) handle_error(...); + * size_t buffer_size = PSA_KEY_EXPORT_MAX_SIZE(key_type, key_bits); + * unsigned char *buffer = malloc(buffer_size); + * if (buffer != NULL) handle_error(...); + * size_t buffer_length; + * status = psa_export_key(key, buffer, buffer_size, &buffer_length); + * if (status != PSA_SUCCESS) handle_error(...); + * \endcode + * + * For psa_export_public_key(), calculate the buffer size from the + * public key type. You can use the macro #PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR + * to convert a key pair type to the corresponding public key type. + * \code{c} + * psa_key_type_t key_type; + * size_t key_bits; + * psa_status_t status; + * status = psa_get_key_information(key, &key_type, &key_bits); + * if (status != PSA_SUCCESS) handle_error(...); + * psa_key_type_t public_key_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR(key_type); + * size_t buffer_size = PSA_KEY_EXPORT_MAX_SIZE(public_key_type, key_bits); + * unsigned char *buffer = malloc(buffer_size); + * if (buffer != NULL) handle_error(...); + * size_t buffer_length; + * status = psa_export_public_key(key, buffer, buffer_size, &buffer_length); + * if (status != PSA_SUCCESS) handle_error(...); + * \endcode + * + * \param key_type A supported 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_KEY_EXPORT_MAX_SIZE(key_type, key_bits) \ + (PSA_KEY_TYPE_IS_UNSTRUCTURED(key_type) ? PSA_BITS_TO_BYTES(key_bits) : \ + (key_type) == PSA_KEY_TYPE_RSA_KEYPAIR ? PSA_KEY_EXPORT_RSA_KEYPAIR_MAX_SIZE(key_bits) : \ + (key_type) == PSA_KEY_TYPE_RSA_PUBLIC_KEY ? PSA_KEY_EXPORT_RSA_PUBLIC_KEY_MAX_SIZE(key_bits) : \ + (key_type) == PSA_KEY_TYPE_DSA_KEYPAIR ? PSA_KEY_EXPORT_DSA_KEYPAIR_MAX_SIZE(key_bits) : \ + (key_type) == PSA_KEY_TYPE_DSA_PUBLIC_KEY ? PSA_KEY_EXPORT_DSA_PUBLIC_KEY_MAX_SIZE(key_bits) : \ + PSA_KEY_TYPE_IS_ECC_KEYPAIR(key_type) ? PSA_KEY_EXPORT_ECC_KEYPAIR_MAX_SIZE(key_bits) : \ + PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY(key_type) ? PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits) : \ + 0) + #endif /* PSA_CRYPTO_SIZES_H */