Merge pull request #20 from gilles-peskine-arm/psa-copy_key

New function psa_copy_key
diff --git a/README.md b/README.md
index 5b52153..785584a 100644
--- a/README.md
+++ b/README.md
@@ -24,10 +24,24 @@
 
 ## Documentation
 
-Since the Mbed Crypto library is a reference implementation of the PSA cryptography API, the library's API documentation is the PSA cryptography API specification. The PSA cryptography API specification consists of the following documents:
+The Mbed Crypto library is a reference implementation of the PSA cryptography API. Please refer to the PSA Cryptography API documents for an overview of the library's interfaces and a detailed description of the types, macros and functions that it provides.
 
-* The [PSA Cryptography API overview](docs/PSA_Crypto_API_Overview.pdf).
-* The [PSA Cryptography API detailed function reference](docs/PSA_Crypto_API_Reference.pdf), which you can also browse in [HTML format](docs/html/modules.html).
+There are currently a few deviations where the library does not yet implement the latest version of the specification. Please refer to the [compliance issues on Github](https://github.com/ARMmbed/mbed-crypto/labels/compliance) for an up-to-date list.
+
+### PSA Cryptography API
+
+The PSA cryptography API specification consists of the following documents:
+
+* The [PSA Cryptography API overview](https://github.com/ARMmbed/mbed-crypto/blob/psa-crypto-api/docs/PSA_Cryptography_API_Specification.pdf).
+* The [PSA Cryptography API detailed function reference](https://github.com/ARMmbed/mbed-crypto/blob/psa-crypto-api/docs/PSA_Cryptography_API_Reference.pdf), which you can also browse in [HTML format](https://htmlpreview.github.io/?https://github.com/ARMmbed/mbed-crypto/blob/psa-crypto-api/docs/html/modules.html).
+
+### Browsable library documentation
+
+To generate a local copy of the library documentation in HTML format:
+
+1. Make sure that [Doxygen](http://www.doxygen.nl/) is installed. We use version 1.8.11 but slightly older or more recent versions should work.
+1. Run `make apidoc`.
+1. Browse `apidoc/index.html` or `apidoc/modules.html`.
 
 ## Compiling
 
diff --git a/docs/PSA_Crypto_API_Overview.pdf b/docs/PSA_Crypto_API_Overview.pdf
deleted file mode 100644
index ecaf399..0000000
--- a/docs/PSA_Crypto_API_Overview.pdf
+++ /dev/null
Binary files differ
diff --git a/docs/PSA_Crypto_API_Reference.pdf b/docs/PSA_Crypto_API_Reference.pdf
deleted file mode 100644
index 2315471..0000000
--- a/docs/PSA_Crypto_API_Reference.pdf
+++ /dev/null
Binary files differ
diff --git a/include/mbedtls/psa_util.h b/include/mbedtls/psa_util.h
index a78c1a9..3684e98 100644
--- a/include/mbedtls/psa_util.h
+++ b/include/mbedtls/psa_util.h
@@ -41,6 +41,7 @@
 #include "ecp.h"
 #include "md.h"
 #include "pk.h"
+#include "oid.h"
 
 /* Translations for symmetric crypto. */
 
@@ -155,6 +156,82 @@
 
 /* Translations for ECC. */
 
+static inline int mbedtls_psa_get_ecc_oid_from_id(
+    psa_ecc_curve_t curve, char const **oid, size_t *oid_len )
+{
+    switch( curve )
+    {
+#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED)
+        case PSA_ECC_CURVE_SECP192R1:
+            *oid = MBEDTLS_OID_EC_GRP_SECP192R1;
+            *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_SECP192R1 );
+            return( 0 );
+#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */
+#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED)
+        case PSA_ECC_CURVE_SECP224R1:
+            *oid = MBEDTLS_OID_EC_GRP_SECP224R1;
+            *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_SECP224R1 );
+            return( 0 );
+#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */
+#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED)
+        case PSA_ECC_CURVE_SECP256R1:
+            *oid = MBEDTLS_OID_EC_GRP_SECP256R1;
+            *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_SECP256R1 );
+            return( 0 );
+#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */
+#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED)
+        case PSA_ECC_CURVE_SECP384R1:
+            *oid = MBEDTLS_OID_EC_GRP_SECP384R1;
+            *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_SECP384R1 );
+            return( 0 );
+#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */
+#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED)
+        case PSA_ECC_CURVE_SECP521R1:
+            *oid = MBEDTLS_OID_EC_GRP_SECP521R1;
+            *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_SECP521R1 );
+            return( 0 );
+#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */
+#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED)
+        case PSA_ECC_CURVE_SECP192K1:
+            *oid = MBEDTLS_OID_EC_GRP_SECP192K1;
+            *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_SECP192K1 );
+            return( 0 );
+#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */
+#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED)
+        case PSA_ECC_CURVE_SECP224K1:
+            *oid = MBEDTLS_OID_EC_GRP_SECP224K1;
+            *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_SECP224K1 );
+            return( 0 );
+#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */
+#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED)
+        case PSA_ECC_CURVE_SECP256K1:
+            *oid = MBEDTLS_OID_EC_GRP_SECP256K1;
+            *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_SECP256K1 );
+            return( 0 );
+#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */
+#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED)
+        case PSA_ECC_CURVE_BRAINPOOL_P256R1:
+            *oid = MBEDTLS_OID_EC_GRP_BP256R1;
+            *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_BP256R1 );
+            return( 0 );
+#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */
+#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED)
+        case PSA_ECC_CURVE_BRAINPOOL_P384R1:
+            *oid = MBEDTLS_OID_EC_GRP_BP384R1;
+            *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_BP384R1 );
+            return( 0 );
+#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */
+#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED)
+        case PSA_ECC_CURVE_BRAINPOOL_P512R1:
+            *oid = MBEDTLS_OID_EC_GRP_BP512R1;
+            *oid_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_EC_GRP_BP512R1 );
+            return( 0 );
+#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */
+    }
+
+     return( -1 );
+}
+
 static inline psa_ecc_curve_t mbedtls_psa_translate_ecc_group( mbedtls_ecp_group_id grpid )
 {
     switch( grpid )
diff --git a/library/cipher.c b/library/cipher.c
index 16037fb..5d7e53f 100644
--- a/library/cipher.c
+++ b/library/cipher.c
@@ -1100,8 +1100,6 @@
          * operations, we currently don't make it
          * accessible through the cipher layer. */
         return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
-
-        return( 0 );
     }
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
diff --git a/library/pk_wrap.c b/library/pk_wrap.c
index 7f8abd4..57a3925 100644
--- a/library/pk_wrap.c
+++ b/library/pk_wrap.c
@@ -553,7 +553,7 @@
     int key_len;
     /* see ECP_PUB_DER_MAX_BYTES in pkwrite.c */
     unsigned char buf[30 + 2 * MBEDTLS_ECP_MAX_BYTES];
-    unsigned char *p = (unsigned char*) sig;
+    unsigned char *p;
     mbedtls_pk_info_t pk_info = mbedtls_eckey_info;
     psa_algorithm_t psa_sig_md, psa_md;
     psa_ecc_curve_t curve = mbedtls_psa_translate_ecc_group(
@@ -563,11 +563,12 @@
     if( curve == 0 )
         return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
 
-    /* mbedlts_pk_write_pubkey_der() expects a full PK context,
-     * re-construct one to make it happy */
+    /* mbedtls_pk_write_pubkey() expects a full PK context;
+     * re-construct one to make it happy. */
     key.pk_info = &pk_info;
     key.pk_ctx = ctx;
-    key_len = mbedtls_pk_write_pubkey_der( &key, buf, sizeof( buf ) );
+    p = buf + sizeof( buf );
+    key_len = mbedtls_pk_write_pubkey( &p, buf, &key );
     if( key_len <= 0 )
         return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
 
@@ -603,6 +604,7 @@
         goto cleanup;
     }
 
+    p = (unsigned char*) sig;
     if( ( ret = extract_ecdsa_sig( &p, sig + sig_len, buf,
                                    signature_part_size ) ) != 0 )
     {
diff --git a/library/pkwrite.c b/library/pkwrite.c
index 11a2a61..ab4f7f5 100644
--- a/library/pkwrite.c
+++ b/library/pkwrite.c
@@ -48,6 +48,7 @@
 
 #if defined(MBEDTLS_USE_PSA_CRYPTO)
 #include "psa/crypto.h"
+#include "mbedtls/psa_util.h"
 #endif
 #if defined(MBEDTLS_PLATFORM_C)
 #include "mbedtls/platform.h"
@@ -181,7 +182,8 @@
         }
         else
         {
-            memmove( *p - len, start, len );
+            *p -= len;
+            memmove( *p, start, len );
         }
     }
     else
@@ -196,16 +198,13 @@
     int ret;
     unsigned char *c;
     size_t len = 0, par_len = 0, oid_len;
+    mbedtls_pk_type_t pk_type;
     const char *oid;
 
     c = buf + size;
 
     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, key ) );
 
-    if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_OPAQUE )
-    {
-        return( (int) len );
-    }
     if( c - buf < 1 )
         return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
 
@@ -220,18 +219,51 @@
     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_BIT_STRING ) );
 
-    if( ( ret = mbedtls_oid_get_oid_by_pk_alg( mbedtls_pk_get_type( key ),
-                                       &oid, &oid_len ) ) != 0 )
-    {
-        return( ret );
-    }
-
+    pk_type = mbedtls_pk_get_type( key );
 #if defined(MBEDTLS_ECP_C)
-    if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY )
+    if( pk_type == MBEDTLS_PK_ECKEY )
     {
         MBEDTLS_ASN1_CHK_ADD( par_len, pk_write_ec_param( &c, buf, mbedtls_pk_ec( *key ) ) );
     }
 #endif
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+    if( pk_type == MBEDTLS_PK_OPAQUE )
+    {
+        psa_status_t status;
+        psa_key_type_t key_type;
+        psa_key_handle_t handle;
+        psa_ecc_curve_t curve;
+
+        handle = *((psa_key_handle_t*) key->pk_ctx );
+
+        status = psa_get_key_information( handle, &key_type,
+                                          NULL /* bitsize not needed */ );
+        if( status != PSA_SUCCESS )
+            return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED );
+
+        curve = PSA_KEY_TYPE_GET_CURVE( key_type );
+        if( curve == 0 )
+            return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
+
+        ret = mbedtls_psa_get_ecc_oid_from_id( curve, &oid, &oid_len );
+        if( ret != 0 )
+            return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
+
+        /* Write EC algorithm parameters; that's akin
+         * to pk_write_ec_param() above. */
+        MBEDTLS_ASN1_CHK_ADD( par_len, mbedtls_asn1_write_oid( &c, buf,
+                                                               oid, oid_len ) );
+
+        /* The rest of the function works as for legacy EC contexts. */
+        pk_type = MBEDTLS_PK_ECKEY;
+    }
+#endif /* MBEDTLS_USE_PSA_CRYPTO */
+
+    if( ( ret = mbedtls_oid_get_oid_by_pk_alg( pk_type, &oid,
+                                               &oid_len ) ) != 0 )
+    {
+        return( ret );
+    }
 
     MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_algorithm_identifier( &c, buf, oid, oid_len,
                                                         par_len ) );
diff --git a/library/psa_crypto_storage_its.c b/library/psa_crypto_storage_its.c
index 1c7e171..1873c69 100644
--- a/library/psa_crypto_storage_its.c
+++ b/library/psa_crypto_storage_its.c
@@ -67,7 +67,7 @@
     }
 }
 
-static uint32_t psa_its_identifier_of_slot( psa_key_id_t key )
+static psa_its_uid_t psa_its_identifier_of_slot( psa_key_id_t key )
 {
     return( key );
 }
@@ -77,7 +77,7 @@
 {
     psa_its_status_t ret;
     psa_status_t status;
-    uint32_t data_identifier = psa_its_identifier_of_slot( key );
+    psa_its_uid_t data_identifier = psa_its_identifier_of_slot( key );
     struct psa_its_info_t data_identifier_info;
 
     ret = psa_its_get_info( data_identifier, &data_identifier_info );
@@ -94,7 +94,7 @@
 int psa_is_key_present_in_storage( const psa_key_id_t key )
 {
     psa_its_status_t ret;
-    uint32_t data_identifier = psa_its_identifier_of_slot( key );
+    psa_its_uid_t data_identifier = psa_its_identifier_of_slot( key );
     struct psa_its_info_t data_identifier_info;
 
     ret = psa_its_get_info( data_identifier, &data_identifier_info );
@@ -110,7 +110,7 @@
 {
     psa_its_status_t ret;
     psa_status_t status;
-    uint32_t data_identifier = psa_its_identifier_of_slot( key );
+    psa_its_uid_t data_identifier = psa_its_identifier_of_slot( key );
     struct psa_its_info_t data_identifier_info;
 
     if( psa_is_key_present_in_storage( key ) == 1 )
@@ -145,7 +145,7 @@
 psa_status_t psa_destroy_persistent_key( const psa_key_id_t key )
 {
     psa_its_status_t ret;
-    uint32_t data_identifier = psa_its_identifier_of_slot( key );
+    psa_its_uid_t data_identifier = psa_its_identifier_of_slot( key );
     struct psa_its_info_t data_identifier_info;
 
     ret = psa_its_get_info( data_identifier, &data_identifier_info );
@@ -167,7 +167,7 @@
 {
     psa_its_status_t ret;
     psa_status_t status;
-    uint32_t data_identifier = psa_its_identifier_of_slot( key );
+    psa_its_uid_t data_identifier = psa_its_identifier_of_slot( key );
     struct psa_its_info_t data_identifier_info;
 
     ret = psa_its_get_info( data_identifier, &data_identifier_info );
diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function
index 120c171..e469318 100644
--- a/tests/suites/test_suite_pk.function
+++ b/tests/suites/test_suite_pk.function
@@ -778,44 +778,65 @@
 void pk_psa_sign(  )
 {
     mbedtls_pk_context pk;
-    psa_key_handle_t key;
-    unsigned char hash[50], sig[100], pkey[100];
-    size_t sig_len, klen = 0;
+    unsigned char hash[50], sig[100], pkey_legacy[100], pkey_psa[100];
+    unsigned char *pkey_legacy_start, *pkey_psa_start;
+    size_t sig_len, klen_legacy, klen_psa;
+    int ret;
+    psa_key_handle_t handle;
 
     /*
      * This tests making signatures with a wrapped PSA key:
-     * - generate a fresh PSA key
+     * - generate a fresh ECP legacy PK context
      * - wrap it in a PK context and make a signature this way
      * - extract the public key
      * - parse it to a PK context and verify the signature this way
      */
 
+    /* Create legacy EC public/private key in PK context. */
     mbedtls_pk_init( &pk );
+    TEST_ASSERT( mbedtls_pk_setup( &pk,
+                      mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ) ) == 0 );
+    TEST_ASSERT( mbedtls_ecp_gen_key( MBEDTLS_ECP_DP_SECP256R1,
+                                      (mbedtls_ecp_keypair*) pk.pk_ctx,
+                                      rnd_std_rand, NULL ) == 0 );
+
+    /* Export underlying public key for re-importing in a legacy context. */
+    ret = mbedtls_pk_write_pubkey_der( &pk, pkey_legacy,
+                                       sizeof( pkey_legacy ) );
+    TEST_ASSERT( ret >= 0 );
+    klen_legacy = (size_t) ret;
+    /* mbedtls_pk_write_pubkey_der() writes backwards in the data buffer. */
+    pkey_legacy_start = pkey_legacy + sizeof( pkey_legacy ) - klen_legacy;
+
+    /* Turn PK context into an opaque one. */
+    TEST_ASSERT( psa_allocate_key( &handle ) == PSA_SUCCESS );
+    TEST_ASSERT( mbedtls_pk_wrap_as_opaque( &pk, &handle,
+                                            PSA_ALG_SHA_256 ) == 0 );
 
     memset( hash, 0x2a, sizeof hash );
     memset( sig, 0, sizeof sig );
-    memset( pkey, 0, sizeof pkey );
-
-    key = pk_psa_genkey();
-    TEST_ASSERT( key != 0 );
-
-    TEST_ASSERT( mbedtls_pk_setup_opaque( &pk, key ) == 0 );
 
     TEST_ASSERT( mbedtls_pk_sign( &pk, MBEDTLS_MD_SHA256,
                  hash, sizeof hash, sig, &sig_len,
                  NULL, NULL ) == 0 );
 
-    mbedtls_pk_free( &pk );
+    /* Export underlying public key for re-importing in a psa context. */
+    ret = mbedtls_pk_write_pubkey_der( &pk, pkey_psa,
+                                       sizeof( pkey_psa ) );
+    TEST_ASSERT( ret >= 0 );
+    klen_psa = (size_t) ret;
+    /* mbedtls_pk_write_pubkey_der() writes backwards in the data buffer. */
+    pkey_psa_start = pkey_psa + sizeof( pkey_psa ) - klen_psa;
 
-    TEST_ASSERT( PSA_SUCCESS == psa_export_public_key(
-                                key, pkey, sizeof( pkey ), &klen ) );
-    TEST_ASSERT( PSA_SUCCESS == psa_destroy_key( key ) );
+    TEST_ASSERT( klen_psa == klen_legacy );
+    TEST_ASSERT( memcmp( pkey_psa_start, pkey_legacy_start, klen_psa ) == 0 );
+
+    mbedtls_pk_free( &pk );
+    TEST_ASSERT( PSA_SUCCESS == psa_destroy_key( handle ) );
 
     mbedtls_pk_init( &pk );
-
-    TEST_ASSERT( mbedtls_pk_parse_public_key( &pk, pkey, klen ) == 0 );
-
-
+    TEST_ASSERT( mbedtls_pk_parse_public_key( &pk, pkey_legacy_start,
+                                              klen_legacy ) == 0 );
     TEST_ASSERT( mbedtls_pk_verify( &pk, MBEDTLS_MD_SHA256,
                             hash, sizeof hash, sig, sig_len ) == 0 );