Merge pull request #133 from jen3andruska/patch-2
Update README.md
diff --git a/include/psa/crypto.h b/include/psa/crypto.h
index 6d31322..c3899bf 100644
--- a/include/psa/crypto.h
+++ b/include/psa/crypto.h
@@ -360,17 +360,71 @@
*/
#define PSA_KEY_TYPE_VENDOR_FLAG ((psa_key_type_t)0x80000000)
-#define PSA_KEY_TYPE_CATEGORY_MASK ((psa_key_type_t)0x7e000000)
+#define PSA_KEY_TYPE_CATEGORY_MASK ((psa_key_type_t)0x70000000)
+#define PSA_KEY_TYPE_CATEGORY_SYMMETRIC ((psa_key_type_t)0x40000000)
+#define PSA_KEY_TYPE_CATEGORY_RAW ((psa_key_type_t)0x50000000)
+#define PSA_KEY_TYPE_CATEGORY_PUBLIC_KEY ((psa_key_type_t)0x60000000)
+#define PSA_KEY_TYPE_CATEGORY_KEY_PAIR ((psa_key_type_t)0x70000000)
+
+#define PSA_KEY_TYPE_CATEGORY_FLAG_PAIR ((psa_key_type_t)0x10000000)
+
+/** Whether a key type is vendor-defined. */
+#define PSA_KEY_TYPE_IS_VENDOR_DEFINED(type) \
+ (((type) & PSA_KEY_TYPE_VENDOR_FLAG) != 0)
+
+/** Whether a key type is an unstructured array of bytes.
+ *
+ * This encompasses both symmetric keys and non-key data.
+ */
+#define PSA_KEY_TYPE_IS_UNSTRUCTURED(type) \
+ (((type) & PSA_KEY_TYPE_CATEGORY_MASK & ~(psa_key_type_t)0x10000000) == \
+ PSA_KEY_TYPE_CATEGORY_SYMMETRIC)
+
+/** Whether a key type is asymmetric: either a key pair or a public key. */
+#define PSA_KEY_TYPE_IS_ASYMMETRIC(type) \
+ (((type) & PSA_KEY_TYPE_CATEGORY_MASK \
+ & ~PSA_KEY_TYPE_CATEGORY_FLAG_PAIR) == \
+ PSA_KEY_TYPE_CATEGORY_PUBLIC_KEY)
+/** Whether a key type is the public part of a key pair. */
+#define PSA_KEY_TYPE_IS_PUBLIC_KEY(type) \
+ (((type) & PSA_KEY_TYPE_CATEGORY_MASK) == PSA_KEY_TYPE_CATEGORY_PUBLIC_KEY)
+/** Whether a key type is a key pair containing a private part and a public
+ * part. */
+#define PSA_KEY_TYPE_IS_KEYPAIR(type) \
+ (((type) & PSA_KEY_TYPE_CATEGORY_MASK) == PSA_KEY_TYPE_CATEGORY_KEY_PAIR)
+/** The key pair type corresponding to a public key type.
+ *
+ * You may also pass a key pair type as \p type, it will be left unchanged.
+ *
+ * \param type A public key type or key pair type.
+ *
+ * \return The corresponding key pair type.
+ * If \p type is not a public key or a key pair,
+ * the return value is undefined.
+ */
+#define PSA_KEY_TYPE_KEYPAIR_OF_PUBLIC_KEY(type) \
+ ((type) | PSA_KEY_TYPE_CATEGORY_FLAG_PAIR)
+/** The public key type corresponding to a key pair type.
+ *
+ * You may also pass a key pair type as \p type, it will be left unchanged.
+ *
+ * \param type A public key type or key pair type.
+ *
+ * \return The corresponding public key type.
+ * If \p type is not a public key or a key pair,
+ * the return value is undefined.
+ */
+#define PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR(type) \
+ ((type) & ~PSA_KEY_TYPE_CATEGORY_FLAG_PAIR)
+/** Whether a key type is an RSA key (pair or public-only). */
+#define PSA_KEY_TYPE_IS_RSA(type) \
+ (PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR(type) == PSA_KEY_TYPE_RSA_PUBLIC_KEY)
/** Raw data.
*
* A "key" of this type cannot be used for any cryptographic operation.
* Applications may use this type to store arbitrary data in the keystore. */
-#define PSA_KEY_TYPE_RAW_DATA ((psa_key_type_t)0x02000000)
-
-#define PSA_KEY_TYPE_CATEGORY_SYMMETRIC ((psa_key_type_t)0x04000000)
-#define PSA_KEY_TYPE_CATEGORY_ASYMMETRIC ((psa_key_type_t)0x06000000)
-#define PSA_KEY_TYPE_PAIR_FLAG ((psa_key_type_t)0x01000000)
+#define PSA_KEY_TYPE_RAW_DATA ((psa_key_type_t)0x50000001)
/** HMAC key.
*
@@ -380,21 +434,21 @@
* HMAC keys should generally have the same size as the underlying hash.
* This size can be calculated with #PSA_HASH_SIZE(\c alg) where
* \c alg is the HMAC algorithm or the underlying hash algorithm. */
-#define PSA_KEY_TYPE_HMAC ((psa_key_type_t)0x02000001)
+#define PSA_KEY_TYPE_HMAC ((psa_key_type_t)0x51000000)
/** A secret for key derivation.
*
* The key policy determines which key derivation algorithm the key
* can be used for.
*/
-#define PSA_KEY_TYPE_DERIVE ((psa_key_type_t)0x02000101)
+#define PSA_KEY_TYPE_DERIVE ((psa_key_type_t)0x52000000)
/** Key for an cipher, AEAD or MAC algorithm based on the AES block cipher.
*
* The size of the key can be 16 bytes (AES-128), 24 bytes (AES-192) or
* 32 bytes (AES-256).
*/
-#define PSA_KEY_TYPE_AES ((psa_key_type_t)0x04000001)
+#define PSA_KEY_TYPE_AES ((psa_key_type_t)0x40000001)
/** Key for a cipher or MAC algorithm based on DES or 3DES (Triple-DES).
*
@@ -405,30 +459,30 @@
* deprecated and should only be used to decrypt legacy data. 3-key 3DES
* is weak and deprecated and should only be used in legacy protocols.
*/
-#define PSA_KEY_TYPE_DES ((psa_key_type_t)0x04000002)
+#define PSA_KEY_TYPE_DES ((psa_key_type_t)0x40000002)
/** Key for an cipher, AEAD or MAC algorithm based on the
* Camellia block cipher. */
-#define PSA_KEY_TYPE_CAMELLIA ((psa_key_type_t)0x04000003)
+#define PSA_KEY_TYPE_CAMELLIA ((psa_key_type_t)0x40000003)
/** Key for the RC4 stream cipher.
*
* Note that RC4 is weak and deprecated and should only be used in
* legacy protocols. */
-#define PSA_KEY_TYPE_ARC4 ((psa_key_type_t)0x04000004)
+#define PSA_KEY_TYPE_ARC4 ((psa_key_type_t)0x40000004)
/** RSA public key. */
-#define PSA_KEY_TYPE_RSA_PUBLIC_KEY ((psa_key_type_t)0x06010000)
+#define PSA_KEY_TYPE_RSA_PUBLIC_KEY ((psa_key_type_t)0x60010000)
/** RSA key pair (private and public key). */
-#define PSA_KEY_TYPE_RSA_KEYPAIR ((psa_key_type_t)0x07010000)
+#define PSA_KEY_TYPE_RSA_KEYPAIR ((psa_key_type_t)0x70010000)
/** DSA public key. */
-#define PSA_KEY_TYPE_DSA_PUBLIC_KEY ((psa_key_type_t)0x06020000)
+#define PSA_KEY_TYPE_DSA_PUBLIC_KEY ((psa_key_type_t)0x60020000)
/** DSA key pair (private and public key). */
-#define PSA_KEY_TYPE_DSA_KEYPAIR ((psa_key_type_t)0x07020000)
+#define PSA_KEY_TYPE_DSA_KEYPAIR ((psa_key_type_t)0x70020000)
-#define PSA_KEY_TYPE_ECC_PUBLIC_KEY_BASE ((psa_key_type_t)0x06030000)
-#define PSA_KEY_TYPE_ECC_KEYPAIR_BASE ((psa_key_type_t)0x07030000)
+#define PSA_KEY_TYPE_ECC_PUBLIC_KEY_BASE ((psa_key_type_t)0x60030000)
+#define PSA_KEY_TYPE_ECC_KEYPAIR_BASE ((psa_key_type_t)0x70030000)
#define PSA_KEY_TYPE_ECC_CURVE_MASK ((psa_key_type_t)0x0000ffff)
/** Elliptic curve key pair. */
#define PSA_KEY_TYPE_ECC_KEYPAIR(curve) \
@@ -437,32 +491,6 @@
#define PSA_KEY_TYPE_ECC_PUBLIC_KEY(curve) \
(PSA_KEY_TYPE_ECC_PUBLIC_KEY_BASE | (curve))
-/** Whether a key type is vendor-defined. */
-#define PSA_KEY_TYPE_IS_VENDOR_DEFINED(type) \
- (((type) & PSA_KEY_TYPE_VENDOR_FLAG) != 0)
-
-/** Whether a key type is asymmetric: either a key pair or a public key. */
-#define PSA_KEY_TYPE_IS_ASYMMETRIC(type) \
- (((type) & PSA_KEY_TYPE_CATEGORY_MASK) == PSA_KEY_TYPE_CATEGORY_ASYMMETRIC)
-/** Whether a key type is the public part of a key pair. */
-#define PSA_KEY_TYPE_IS_PUBLIC_KEY(type) \
- (((type) & (PSA_KEY_TYPE_CATEGORY_MASK | PSA_KEY_TYPE_PAIR_FLAG)) == \
- PSA_KEY_TYPE_CATEGORY_ASYMMETRIC)
-/** Whether a key type is a key pair containing a private part and a public
- * part. */
-#define PSA_KEY_TYPE_IS_KEYPAIR(type) \
- (((type) & (PSA_KEY_TYPE_CATEGORY_MASK | PSA_KEY_TYPE_PAIR_FLAG)) == \
- (PSA_KEY_TYPE_CATEGORY_ASYMMETRIC | PSA_KEY_TYPE_PAIR_FLAG))
-/** The key pair type corresponding to a public key type. */
-#define PSA_KEY_TYPE_KEYPAIR_OF_PUBLIC_KEY(type) \
- ((type) | PSA_KEY_TYPE_PAIR_FLAG)
-/** The public key type corresponding to a key pair type. */
-#define PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR(type) \
- ((type) & ~PSA_KEY_TYPE_PAIR_FLAG)
-/** Whether a key type is an RSA key (pair or public-only). */
-#define PSA_KEY_TYPE_IS_RSA(type) \
- (PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR(type) == PSA_KEY_TYPE_RSA_PUBLIC_KEY)
-
/** Whether a key type is an elliptic curve key (pair or public-only). */
#define PSA_KEY_TYPE_IS_ECC(type) \
((PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR(type) & \
@@ -1159,10 +1187,54 @@
* - 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\#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.
+ * is the non-encrypted DER encoding of the representation defined by
+ * PKCS\#1 (RFC 8017) as `RSAPrivateKey`, version 0.
+ * ```
+ * RSAPrivateKey ::= SEQUENCE {
+ * version INTEGER, -- must be 0
+ * 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
+ * }
+ * ```
+ * - For DSA private keys (#PSA_KEY_TYPE_DSA_KEYPAIR), the format
+ * is the non-encrypted DER encoding of the representation used by
+ * OpenSSL and OpenSSH, whose structure is described in ASN.1 as follows:
+ * ```
+ * DSAPrivateKey ::= SEQUENCE {
+ * version INTEGER, -- must be 0
+ * prime INTEGER, -- p
+ * subprime INTEGER, -- q
+ * generator INTEGER, -- g
+ * public INTEGER, -- y
+ * private INTEGER, -- x
+ * }
+ * ```
+ * - For elliptic curve key pairs (key types for which
+ * #PSA_KEY_TYPE_IS_ECC_KEYPAIR is true), the format is the
+ * non-encrypted DER encoding of the representation defined by RFC 5915 as
+ * `ECPrivateKey`, version 1. The `ECParameters` field must be a
+ * `namedCurve` OID as specified in RFC 5480 §2.1.1.1. The public key
+ * must be present and must be an `ECPoint` in the same format
+ * (uncompressed variant) an ECC public key of the
+ * corresponding type exported with psa_export_public_key().
+ * ```
+ * ECPrivateKey ::= SEQUENCE {
+ * version INTEGER, -- must be 1
+ * privateKey OCTET STRING,
+ * -- `ceiling(log2(n)/8)`-byte string, big endian,
+ * -- where n is the order of the curve.
+ * parameters [0] IMPLICIT ECParameters {{ namedCurve }}, -- mandatory
+ * publicKey [1] IMPLICIT BIT STRING -- mandatory
+ * }
+ * ```
+ * - For public keys (key types for which #PSA_KEY_TYPE_IS_PUBLIC_KEY is
+ * true), the format is the same as for psa_export_public_key().
*
* \param key Slot whose content is to be exported. This must
* be an occupied key slot.
@@ -1175,6 +1247,12 @@
* \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
@@ -1190,11 +1268,70 @@
* The output of this function can be passed to psa_import_key() to
* create an object that is equivalent to the public key.
*
- * For standard key types, the output format is as follows:
+ * The format is the DER representation defined by RFC 5280 as
+ * `SubjectPublicKeyInfo`, with the `subjectPublicKey` format
+ * specified below.
+ * ```
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING }
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL }
+ * ```
*
- * - For RSA keys (#PSA_KEY_TYPE_RSA_KEYPAIR or #PSA_KEY_TYPE_RSA_PUBLIC_KEY),
- * the format is the DER representation of the public key defined by RFC 5280
- * as SubjectPublicKeyInfo.
+ * - For RSA public keys (#PSA_KEY_TYPE_RSA_PUBLIC_KEY),
+ * the `subjectPublicKey` format is defined by RFC 3279 §2.3.1 as
+ * `RSAPublicKey`,
+ * with the OID `rsaEncryption`,
+ * and with the parameters `NULL`.
+ * ```
+ * pkcs-1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840)
+ * rsadsi(113549) pkcs(1) 1 }
+ * rsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1 }
+ *
+ * RSAPublicKey ::= SEQUENCE {
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER } -- e
+ * ```
+ * - For DSA public keys (#PSA_KEY_TYPE_DSA_PUBLIC_KEY),
+ * the `subjectPublicKey` format is defined by RFC 3279 §2.3.2 as
+ * `DSAPublicKey`,
+ * with the OID `id-dsa`,
+ * and with the parameters `DSS-Parms`.
+ * ```
+ * id-dsa OBJECT IDENTIFIER ::= {
+ * iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 1 }
+ *
+ * Dss-Parms ::= SEQUENCE {
+ * p INTEGER,
+ * q INTEGER,
+ * g INTEGER }
+ * DSAPublicKey ::= INTEGER -- public key, Y
+ * ```
+ * - For elliptic curve public keys (key types for which
+ * #PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY is true),
+ * the `subjectPublicKey` format is defined by RFC 3279 §2.3.5 as
+ * `ECPoint`, which contains the uncompressed
+ * representation defined by SEC1 §2.3.3.
+ * The OID is `id-ecPublicKey`,
+ * and the parameters must be given as a `namedCurve` OID as specified in
+ * RFC 5480 §2.1.1.1 or other applicable standards.
+ * ```
+ * ansi-X9-62 OBJECT IDENTIFIER ::=
+ * { iso(1) member-body(2) us(840) 10045 }
+ * id-public-key-type OBJECT IDENTIFIER ::= { ansi-X9.62 2 }
+ * id-ecPublicKey OBJECT IDENTIFIER ::= { id-publicKeyType 1 }
+ *
+ * ECPoint ::= ...
+ * -- first 8 bits: 0x04;
+ * -- then x_P as an n-bit string, big endian;
+ * -- then y_P as a n-bit string, big endian,
+ * -- where n is the order of the curve.
+ *
+ * EcpkParameters ::= CHOICE { -- other choices are not allowed
+ * namedCurve OBJECT IDENTIFIER }
+ * ```
*
* \param key Slot whose content is to be exported. This must
* be an occupied key slot.
@@ -1206,6 +1343,14 @@
* \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 ab5b17e..c42375b 100644
--- a/include/psa/crypto_sizes.h
+++ b/include/psa/crypto_sizes.h
@@ -305,4 +305,212 @@
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 ::= ...
+ * -- first 8 bits: 0x04;
+ * -- then x_P as an n-bit string, big endian;
+ * -- then y_P as a n-bit 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(log2(n)/8)`-byte string, big endian,
+ * -- where n is the order of the curve.
+ * parameters [0] IMPLICIT ECParameters {{ NamedCurve }},
+ * publicKey [1] IMPLICIT BIT STRING
+ * }
+ *
+ * - 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.
+ *
+ * \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 */
diff --git a/library/psa_crypto.c b/library/psa_crypto.c
index 316acbe..dfbb680 100644
--- a/library/psa_crypto.c
+++ b/library/psa_crypto.c
@@ -135,9 +135,7 @@
static int key_type_is_raw_bytes( psa_key_type_t type )
{
- psa_key_type_t category = type & PSA_KEY_TYPE_CATEGORY_MASK;
- return( category == PSA_KEY_TYPE_RAW_DATA ||
- category == PSA_KEY_TYPE_CATEGORY_SYMMETRIC );
+ return( PSA_KEY_TYPE_IS_UNSTRUCTURED( type ) );
}
typedef struct
diff --git a/tests/suites/test_suite_psa_crypto.data b/tests/suites/test_suite_psa_crypto.data
index 6bdd327..01be797 100644
--- a/tests/suites/test_suite_psa_crypto.data
+++ b/tests/suites/test_suite_psa_crypto.data
@@ -140,6 +140,16 @@
depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15
import_export:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b24":PSA_KEY_TYPE_RSA_KEYPAIR:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_USAGE_SIGN | PSA_KEY_USAGE_VERIFY:1024:0:PSA_ERROR_NOT_PERMITTED:1
+# Test PEM import. Note that this is not a PSA feature, it's an Mbed TLS
+# extension which we may drop in the future.
+PSA import/export RSA public key: import PEM
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_PK_PARSE_C:MBEDTLS_PK_WRITE_C:MBEDTLS_RSA_C
+import_export:"2d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0a4d4947664d413047435371475349623344514542415155414134474e4144434269514b4267514376425830356275685074312f6274634b7850482f6c706c53710a69714a4843315165346636777353306c7835635255784a4a34524b574b41517475376242494e46454e5354765441357548596c57377249486576456a536433750a355553447641624378686c497a514b7941756557727232553036664c2b466e43775947634d6b79344b357a545474346d4f69712f2f6b637a384865476e6f5a670a3939614454615539615137336d46397277774944415141420a2d2d2d2d2d454e44205055424c4943204b45592d2d2d2d2d0a00":PSA_KEY_TYPE_RSA_PUBLIC_KEY:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_USAGE_EXPORT:1024:0:PSA_SUCCESS:0
+
+PSA import/export RSA keypair: import PEM
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_PK_PARSE_C:MBEDTLS_PK_WRITE_C:MBEDTLS_RSA_C
+import_export:"3082025e02010002818100af057d396ee84fb75fdbb5c2b13c7fe5a654aa8aa2470b541ee1feb0b12d25c79711531249e1129628042dbbb6c120d1443524ef4c0e6e1d8956eeb2077af12349ddeee54483bc06c2c61948cd02b202e796aebd94d3a7cbf859c2c1819c324cb82b9cd34ede263a2abffe4733f077869e8660f7d6834da53d690ef7985f6bc3020301000102818100874bf0ffc2f2a71d14671ddd0171c954d7fdbf50281e4f6d99ea0e1ebcf82faa58e7b595ffb293d1abe17f110b37c48cc0f36c37e84d876621d327f64bbe08457d3ec4098ba2fa0a319fba411c2841ed7be83196a8cdf9daa5d00694bc335fc4c32217fe0488bce9cb7202e59468b1ead119000477db2ca797fac19eda3f58c1024100e2ab760841bb9d30a81d222de1eb7381d82214407f1b975cbbfe4e1a9467fd98adbd78f607836ca5be1928b9d160d97fd45c12d6b52e2c9871a174c66b488113024100c5ab27602159ae7d6f20c3c2ee851e46dc112e689e28d5fcbbf990a99ef8a90b8bb44fd36467e7fc1789ceb663abda338652c3c73f111774902e840565927091024100b6cdbd354f7df579a63b48b3643e353b84898777b48b15f94e0bfc0567a6ae5911d57ad6409cf7647bf96264e9bd87eb95e263b7110b9a1f9f94acced0fafa4d024071195eec37e8d257decfc672b07ae639f10cbb9b0c739d0c809968d644a94e3fd6ed9287077a14583f379058f76a8aecd43c62dc8c0f41766650d725275ac4a1024100bb32d133edc2e048d463388b7be9cb4be29f4b6250be603e70e3647501c97ddde20a4e71be95fd5e71784e25aca4baf25be5738aae59bbfe1c997781447a2b2400":PSA_KEY_TYPE_RSA_KEYPAIR:PSA_ALG_RSA_PKCS1V15_SIGN_RAW:PSA_KEY_USAGE_EXPORT:1024:0:PSA_SUCCESS:0
+
PSA import EC keypair secp384r1: valid key but wrong curve (secp256r1)
depends_on:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_ECP_DP_SECP384R1_ENABLED
import:"3077020101042049c9a8c18c4b885638c431cf1df1c994131609b580d4fd43a0cab17db2f13eeea00a06082a8648ce3d030107a144034200047772656f814b399279d5e1f1781fac6f099a3c5ca1b0e35351834b08b65e0b572590cdaf8f769361bcf34acfc11e5e074e8426bdde04be6e653945449617de45":PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_SECP384R1):PSA_ERROR_INVALID_ARGUMENT
diff --git a/tests/suites/test_suite_psa_crypto.function b/tests/suites/test_suite_psa_crypto.function
index 04c1c79..e14b225 100644
--- a/tests/suites/test_suite_psa_crypto.function
+++ b/tests/suites/test_suite_psa_crypto.function
@@ -5,7 +5,10 @@
#include "spm/psa_defs.h"
#endif
+#include "mbedtls/asn1.h"
#include "mbedtls/asn1write.h"
+#include "mbedtls/oid.h"
+
#include "psa/crypto.h"
#define ARRAY_LENGTH( array ) ( sizeof( array ) / sizeof( *( array ) ) )
@@ -38,13 +41,6 @@
return( 1 );
}
-static int key_type_is_raw_bytes( psa_key_type_t type )
-{
- psa_key_type_t category = type & PSA_KEY_TYPE_CATEGORY_MASK;
- return( category == PSA_KEY_TYPE_RAW_DATA ||
- 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,
@@ -393,6 +389,366 @@
return( 0 );
}
+static int is_oid_of_key_type( psa_key_type_t type,
+ const uint8_t *oid, size_t oid_length )
+{
+ const uint8_t *expected_oid = NULL;
+ size_t expected_oid_length = 0;
+#if defined(MBEDTLS_RSA_C)
+ if( PSA_KEY_TYPE_IS_RSA( type ) )
+ {
+ expected_oid = (uint8_t *) MBEDTLS_OID_PKCS1_RSA;
+ expected_oid_length = sizeof( MBEDTLS_OID_PKCS1_RSA ) - 1;
+ }
+ else
+#endif /* MBEDTLS_RSA_C */
+#if defined(MBEDTLS_ECP_C)
+ if( PSA_KEY_TYPE_IS_ECC( type ) )
+ {
+ expected_oid = (uint8_t *) MBEDTLS_OID_EC_ALG_UNRESTRICTED;
+ expected_oid_length = sizeof( MBEDTLS_OID_EC_ALG_UNRESTRICTED ) - 1;
+ }
+ else
+#endif /* MBEDTLS_ECP_C */
+ {
+ char message[40];
+ mbedtls_snprintf( message, sizeof( message ),
+ "OID not known for key type=0x%08lx",
+ (unsigned long) type );
+ test_fail( message, __LINE__, __FILE__ );
+ return( 0 );
+ }
+
+ TEST_ASSERT( oid_length == expected_oid_length );
+ TEST_ASSERT( memcmp( oid, expected_oid, oid_length ) == 0 );
+ return( 1 );
+
+exit:
+ return( 0 );
+}
+
+static int asn1_skip_integer( unsigned char **p, const unsigned char *end,
+ size_t min_bits, size_t max_bits,
+ int must_be_odd )
+{
+ size_t len;
+ size_t actual_bits;
+ unsigned char msb;
+ TEST_ASSERT( mbedtls_asn1_get_tag( p, end, &len,
+ MBEDTLS_ASN1_INTEGER ) == 0 );
+ /* Tolerate a slight departure from DER encoding:
+ * - 0 may be represented by an empty string or a 1-byte string.
+ * - The sign bit may be used as a value bit. */
+ if( ( len == 1 && ( *p )[0] == 0 ) ||
+ ( len > 1 && ( *p )[0] == 0 && ( ( *p )[1] & 0x80 ) != 0 ) )
+ {
+ ++( *p );
+ --len;
+ }
+ if( min_bits == 0 && len == 0 )
+ return( 1 );
+ msb = ( *p )[0];
+ TEST_ASSERT( msb != 0 );
+ actual_bits = 8 * ( len - 1 );
+ while( msb != 0 )
+ {
+ msb >>= 1;
+ ++actual_bits;
+ }
+ TEST_ASSERT( actual_bits >= min_bits );
+ TEST_ASSERT( actual_bits <= max_bits );
+ if( must_be_odd )
+ TEST_ASSERT( ( ( *p )[len-1] & 1 ) != 0 );
+ *p += len;
+ return( 1 );
+exit:
+ return( 0 );
+}
+
+static int asn1_get_implicit_tag( unsigned char **p, const unsigned char *end,
+ size_t *len,
+ unsigned char n, unsigned char tag )
+{
+ int ret;
+ ret = mbedtls_asn1_get_tag( p, end, len,
+ MBEDTLS_ASN1_CONTEXT_SPECIFIC |
+ MBEDTLS_ASN1_CONSTRUCTED | ( n ) );
+ if( ret != 0 )
+ return( ret );
+ end = *p + *len;
+ ret = mbedtls_asn1_get_tag( p, end, len, tag );
+ if( ret != 0 )
+ return( ret );
+ if( *p + *len != end )
+ return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+ return( 0 );
+}
+
+static int exported_key_sanity_check( psa_key_type_t type, size_t bits,
+ uint8_t *exported, size_t exported_length )
+{
+ if( PSA_KEY_TYPE_IS_UNSTRUCTURED( type ) )
+ TEST_ASSERT( exported_length == ( bits + 7 ) / 8 );
+ else
+ TEST_ASSERT( exported_length <= PSA_KEY_EXPORT_MAX_SIZE( type, bits ) );
+
+#if defined(MBEDTLS_DES_C)
+ if( type == PSA_KEY_TYPE_DES )
+ {
+ /* Check the parity bits. */
+ unsigned i;
+ for( i = 0; i < bits / 8; i++ )
+ {
+ unsigned bit_count = 0;
+ unsigned m;
+ for( m = 1; m <= 0x100; m <<= 1 )
+ {
+ if( exported[i] & m )
+ ++bit_count;
+ }
+ TEST_ASSERT( bit_count % 2 != 0 );
+ }
+ }
+ else
+#endif
+
+#if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_PK_PARSE_C)
+ if( type == PSA_KEY_TYPE_RSA_KEYPAIR )
+ {
+ uint8_t *p = exported;
+ uint8_t *end = exported + exported_length;
+ size_t len;
+ /* RSAPrivateKey ::= SEQUENCE {
+ * version INTEGER, -- must be 0
+ * 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
+ * }
+ */
+ TEST_ASSERT( mbedtls_asn1_get_tag( &p, end, &len,
+ MBEDTLS_ASN1_SEQUENCE |
+ MBEDTLS_ASN1_CONSTRUCTED ) == 0 );
+ TEST_ASSERT( p + len == end );
+ if( ! asn1_skip_integer( &p, end, 0, 0, 0 ) )
+ goto exit;
+ if( ! asn1_skip_integer( &p, end, bits, bits, 1 ) )
+ goto exit;
+ if( ! asn1_skip_integer( &p, end, 2, bits, 1 ) )
+ goto exit;
+ /* Require d to be at least half the size of n. */
+ if( ! asn1_skip_integer( &p, end, bits / 2, bits, 1 ) )
+ goto exit;
+ /* Require p and q to be at most half the size of n, rounded up. */
+ if( ! asn1_skip_integer( &p, end, bits / 2, bits / 2 + 1, 1 ) )
+ goto exit;
+ if( ! asn1_skip_integer( &p, end, bits / 2, bits / 2 + 1, 1 ) )
+ goto exit;
+ if( ! asn1_skip_integer( &p, end, 1, bits / 2 + 1, 0 ) )
+ goto exit;
+ if( ! asn1_skip_integer( &p, end, 1, bits / 2 + 1, 0 ) )
+ goto exit;
+ if( ! asn1_skip_integer( &p, end, 1, bits / 2 + 1, 0 ) )
+ goto exit;
+ TEST_ASSERT( p == end );
+ }
+ else
+#endif /* MBEDTLS_RSA_C */
+
+#if defined(MBEDTLS_ECP_C)
+ if( PSA_KEY_TYPE_IS_ECC_KEYPAIR( type ) )
+ {
+ uint8_t *p = exported;
+ uint8_t *end = exported + exported_length;
+ size_t len;
+ int version;
+ /* 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
+ * }
+ */
+ TEST_ASSERT( mbedtls_asn1_get_tag( &p, end, &len,
+ MBEDTLS_ASN1_SEQUENCE |
+ MBEDTLS_ASN1_CONSTRUCTED ) == 0 );
+ TEST_ASSERT( p + len == end );
+ TEST_ASSERT( mbedtls_asn1_get_int( &p, end, &version ) == 0 );
+ TEST_ASSERT( version == 1 );
+ TEST_ASSERT( mbedtls_asn1_get_tag( &p, end, &len,
+ MBEDTLS_ASN1_OCTET_STRING ) == 0 );
+ /* Bug in Mbed TLS: the length of the octet string depends on the value */
+ // TEST_ASSERT( len == PSA_BITS_TO_BYTES( bits ) );
+ p += len;
+ TEST_ASSERT( asn1_get_implicit_tag( &p, end, &len, 0,
+ MBEDTLS_ASN1_OID ) == 0 );
+ p += len;
+ /* publicKey: ECPoint in uncompressed representation (as below) */
+ TEST_ASSERT( asn1_get_implicit_tag( &p, end, &len, 1,
+ MBEDTLS_ASN1_BIT_STRING ) == 0 );
+ TEST_ASSERT( p + len == end );
+ TEST_ASSERT( p[0] == 0 ); /* 0 unused bits in the bit string */
+ ++p;
+ TEST_ASSERT( p + 1 + 2 * PSA_BITS_TO_BYTES( bits ) == end );
+ TEST_ASSERT( p[0] == 4 );
+ }
+ else
+#endif /* MBEDTLS_ECP_C */
+
+ if( PSA_KEY_TYPE_IS_PUBLIC_KEY( type ) )
+ {
+ uint8_t *p = exported;
+ uint8_t *end = exported + exported_length;
+ size_t len;
+ mbedtls_asn1_buf alg;
+ mbedtls_asn1_buf params;
+ mbedtls_asn1_bitstring bitstring;
+ /* SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING }
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL }
+ */
+ TEST_ASSERT( mbedtls_asn1_get_tag( &p, end, &len,
+ MBEDTLS_ASN1_SEQUENCE |
+ MBEDTLS_ASN1_CONSTRUCTED ) == 0 );
+ TEST_ASSERT( p + len == end );
+ TEST_ASSERT( mbedtls_asn1_get_alg( &p, end, &alg, ¶ms ) == 0 );
+ if( ! is_oid_of_key_type( type, alg.p, alg.len ) )
+ goto exit;
+ TEST_ASSERT( mbedtls_asn1_get_bitstring( &p, end, &bitstring ) == 0 );
+ TEST_ASSERT( p == end );
+ p = bitstring.p;
+#if defined(MBEDTLS_RSA_C)
+ if( type == PSA_KEY_TYPE_RSA_PUBLIC_KEY )
+ {
+ /* RSAPublicKey ::= SEQUENCE {
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER } -- e
+ */
+ TEST_ASSERT( bitstring.unused_bits == 0 );
+ TEST_ASSERT( mbedtls_asn1_get_tag( &p, end, &len,
+ MBEDTLS_ASN1_SEQUENCE |
+ MBEDTLS_ASN1_CONSTRUCTED ) == 0 );
+ TEST_ASSERT( p + len == end );
+ if( ! asn1_skip_integer( &p, end, bits, bits, 1 ) )
+ goto exit;
+ if( ! asn1_skip_integer( &p, end, 2, bits, 1 ) )
+ goto exit;
+ TEST_ASSERT( p == end );
+ }
+ else
+#endif /* MBEDTLS_RSA_C */
+#if defined(MBEDTLS_ECP_C)
+ if( PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY( type ) )
+ {
+ /* ECPoint ::= ...
+ * -- first 8 bits: 0x04 (uncompressed representation);
+ * -- then x_P as an n-bit string, big endian;
+ * -- then y_P as a n-bit string, big endian,
+ * -- where n is the order of the curve.
+ */
+ TEST_ASSERT( bitstring.unused_bits == 0 );
+ TEST_ASSERT( p + 1 + 2 * PSA_BITS_TO_BYTES( bits ) == end );
+ TEST_ASSERT( p[0] == 4 );
+ }
+ else
+#endif /* MBEDTLS_ECP_C */
+ {
+ char message[40];
+ mbedtls_snprintf( message, sizeof( message ),
+ "No sanity check for public key type=0x%08lx",
+ (unsigned long) type );
+ test_fail( message, __LINE__, __FILE__ );
+ return( 0 );
+ }
+ }
+ else
+
+ {
+ /* No sanity checks for other types */
+ }
+
+ return( 1 );
+
+exit:
+ return( 0 );
+}
+
+static int exercise_export_key( psa_key_slot_t slot,
+ psa_key_usage_t usage )
+{
+ psa_key_type_t type;
+ size_t bits;
+ uint8_t *exported = NULL;
+ size_t exported_size = 0;
+ size_t exported_length = 0;
+ int ok = 0;
+
+ if( ( usage & PSA_KEY_USAGE_EXPORT ) == 0 )
+ {
+ TEST_ASSERT( psa_export_key( slot, NULL, 0, &exported_length ) ==
+ PSA_ERROR_NOT_PERMITTED );
+ return( 1 );
+ }
+
+ TEST_ASSERT( psa_get_key_information( slot, &type, &bits ) == PSA_SUCCESS );
+ exported_size = PSA_KEY_EXPORT_MAX_SIZE( type, bits );
+ exported = mbedtls_calloc( 1, exported_size );
+ TEST_ASSERT( exported != NULL );
+
+ TEST_ASSERT( psa_export_key( slot,
+ exported, exported_size,
+ &exported_length ) == PSA_SUCCESS );
+ ok = exported_key_sanity_check( type, bits, exported, exported_length );
+
+exit:
+ mbedtls_free( exported );
+ return( ok );
+}
+
+static int exercise_export_public_key( psa_key_slot_t slot )
+{
+ psa_key_type_t type;
+ psa_key_type_t public_type;
+ size_t bits;
+ uint8_t *exported = NULL;
+ size_t exported_size = 0;
+ size_t exported_length = 0;
+ int ok = 0;
+
+ TEST_ASSERT( psa_get_key_information( slot, &type, &bits ) == PSA_SUCCESS );
+ if( ! PSA_KEY_TYPE_IS_ASYMMETRIC( type ) )
+ {
+ TEST_ASSERT( psa_export_public_key( slot,
+ NULL, 0, &exported_length ) ==
+ PSA_ERROR_INVALID_ARGUMENT );
+ return( 1 );
+ }
+
+ public_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEYPAIR( type );
+ exported_size = PSA_KEY_EXPORT_MAX_SIZE( public_type, bits );
+ exported = mbedtls_calloc( 1, exported_size );
+ TEST_ASSERT( exported != NULL );
+
+ TEST_ASSERT( psa_export_public_key( slot,
+ exported, exported_size,
+ &exported_length ) == PSA_SUCCESS );
+ ok = exported_key_sanity_check( public_type, bits,
+ exported, exported_length );
+
+exit:
+ mbedtls_free( exported );
+ return( ok );
+}
+
static int exercise_key( psa_key_slot_t slot,
psa_key_usage_t usage,
psa_algorithm_t alg )
@@ -421,6 +777,10 @@
test_fail( message, __LINE__, __FILE__ );
ok = 0;
}
+
+ ok = ok && exercise_export_key( slot, usage );
+ ok = ok && exercise_export_public_key( slot );
+
return( ok );
}
@@ -632,6 +992,9 @@
goto destroy;
}
+ if( ! exercise_export_key( slot, usage_arg ) )
+ goto exit;
+
if( canonical_input )
{
TEST_ASSERT( exported_length == data->len );
@@ -643,7 +1006,7 @@
TEST_ASSERT( psa_import_key( slot2, type,
exported,
- export_size ) == PSA_SUCCESS );
+ exported_length ) == PSA_SUCCESS );
TEST_ASSERT( psa_export_key( slot2,
reexported,
export_size,
@@ -1128,7 +1491,7 @@
void key_lifetime( int lifetime_arg )
{
int key_slot = 1;
- psa_key_type_t key_type = PSA_ALG_CBC_BASE;
+ psa_key_type_t key_type = PSA_KEY_TYPE_RAW_DATA;
unsigned char key[32] = {0};
psa_key_lifetime_t lifetime_set = lifetime_arg;
psa_key_lifetime_t lifetime_get;
@@ -3056,10 +3419,6 @@
psa_status_t expected_status = expected_status_arg;
psa_key_type_t got_type;
size_t got_bits;
- unsigned char exported[616] = {0}; /* enough for a 1024-bit RSA key */
- size_t exported_length;
- psa_status_t expected_export_status =
- usage & PSA_KEY_USAGE_EXPORT ? PSA_SUCCESS : PSA_ERROR_NOT_PERMITTED;
psa_status_t expected_info_status =
expected_status == PSA_SUCCESS ? PSA_SUCCESS : PSA_ERROR_EMPTY_SLOT;
psa_key_policy_t policy;
@@ -3083,84 +3442,6 @@
TEST_ASSERT( got_type == type );
TEST_ASSERT( got_bits == bits );
- /* Export the key */
- TEST_ASSERT( psa_export_key( slot,
- exported, sizeof( exported ),
- &exported_length ) == expected_export_status );
- if( expected_export_status == PSA_SUCCESS )
- {
- if( key_type_is_raw_bytes( type ) )
- TEST_ASSERT( exported_length == ( bits + 7 ) / 8 );
-#if defined(MBEDTLS_DES_C)
- if( type == PSA_KEY_TYPE_DES )
- {
- /* Check the parity bits. */
- unsigned i;
- for( i = 0; i < bits / 8; i++ )
- {
- unsigned bit_count = 0;
- unsigned m;
- for( m = 1; m <= 0x100; m <<= 1 )
- {
- if( exported[i] & m )
- ++bit_count;
- }
- TEST_ASSERT( bit_count % 2 != 0 );
- }
- }
-#endif
-#if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_PK_PARSE_C)
- if( type == PSA_KEY_TYPE_RSA_KEYPAIR )
- {
- /* Sanity check: does this look like the beginning of a PKCS#8
- * RSA key pair? Assumes bits is a multiple of 8. */
- size_t n_bytes = bits / 8 + 1;
- size_t n_encoded_bytes;
- unsigned char *n_end;
- TEST_ASSERT( exported_length >= 7 + ( n_bytes + 3 ) * 9 / 2 );
- TEST_ASSERT( exported[0] == 0x30 );
- TEST_ASSERT( exported[1] == 0x82 ); // assumes >=416-bit key
- TEST_ASSERT( exported[4] == 0x02 );
- TEST_ASSERT( exported[5] == 0x01 );
- TEST_ASSERT( exported[6] == 0x00 );
- TEST_ASSERT( exported[7] == 0x02 );
- n_encoded_bytes = exported[8];
- n_end = exported + 9 + n_encoded_bytes;
- if( n_encoded_bytes & 0x80 )
- {
- n_encoded_bytes = ( n_encoded_bytes & 0x7f ) << 7;
- n_encoded_bytes |= exported[9] & 0x7f;
- n_end += 1;
- }
- /* The encoding of n should start with a 0 byte since it should
- * have its high bit set. However Mbed TLS is not compliant and
- * generates an invalid, but widely tolerated, encoding of
- * positive INTEGERs with a bit size that is a multiple of 8
- * with no leading 0 byte. Accept this here. */
- TEST_ASSERT( n_bytes == n_encoded_bytes ||
- n_bytes == n_encoded_bytes + 1 );
- if( n_bytes == n_encoded_bytes )
- TEST_ASSERT( exported[n_encoded_bytes <= 127 ? 9 : 10] == 0x00 );
- /* Sanity check: e must be 3 */
- TEST_ASSERT( n_end[0] == 0x02 );
- TEST_ASSERT( n_end[1] == 0x03 );
- TEST_ASSERT( n_end[2] == 0x01 );
- TEST_ASSERT( n_end[3] == 0x00 );
- TEST_ASSERT( n_end[4] == 0x01 );
- TEST_ASSERT( n_end[5] == 0x02 );
- }
-#endif /* MBEDTLS_RSA_C */
-#if defined(MBEDTLS_ECP_C)
- if( PSA_KEY_TYPE_IS_ECC( type ) )
- {
- /* Sanity check: does this look like the beginning of a PKCS#8
- * elliptic curve key pair? */
- TEST_ASSERT( exported_length >= bits * 3 / 8 + 10 );
- TEST_ASSERT( exported[0] == 0x30 );
- }
-#endif /* MBEDTLS_ECP_C */
- }
-
/* Do something with the key according to its type and permitted usage. */
if( ! exercise_key( slot, usage, alg ) )
goto exit;