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, &params ) == 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;