PK: support for opaque keys

Add a new key pair object type: MBEDTLS_PK_OPAQUE, intended for
implementations of asymmetric cryptography operations that call an
external cryptographic module.

External cryptographic module engines must implement the API described
by a mbedtls_pk_info_t structure and, usually, a custom setup function.

Document the fields of the mbedtls_pk_info_t structure and the
requirements on a PK engine. Also document non-obvious aspects of the
behavior of the pk interface functions on opaque keys.

Change the interface of check_pair_func to take a pointer to a full
mbedtls_pk_context as its pub argument, and not just the data part of
the context. This is necessary because when prv is opaque, pub may
legitimately be of a different type (typically prv would be opaque and
pub would be transparent).
diff --git a/library/error.c b/library/error.c
index 151ca4e..d60f652 100644
--- a/library/error.c
+++ b/library/error.c
@@ -288,6 +288,12 @@
             mbedtls_snprintf( buf, buflen, "PK - Unavailable feature, e.g. RSA disabled for RSA key" );
         if( use_ret == -(MBEDTLS_ERR_PK_SIG_LEN_MISMATCH) )
             mbedtls_snprintf( buf, buflen, "PK - The signature is valid but its length is less than expected" );
+        if( use_ret == -(MBEDTLS_ERR_PK_INVALID_SIGNATURE) )
+            mbedtls_snprintf( buf, buflen, "PK - Invalid signature" );
+        if( use_ret == -(MBEDTLS_ERR_PK_BUFFER_TOO_SMALL) )
+            mbedtls_snprintf( buf, buflen, "PK - Output buffer too small" );
+        if( use_ret == -(MBEDTLS_ERR_PK_NOT_PERMITTED) )
+            mbedtls_snprintf( buf, buflen, "PK - Operation not permitted" );
 #endif /* MBEDTLS_PK_C */
 
 #if defined(MBEDTLS_PKCS12_C)
diff --git a/library/pk.c b/library/pk.c
index d080c75..d8801b5 100644
--- a/library/pk.c
+++ b/library/pk.c
@@ -94,6 +94,7 @@
             return( &mbedtls_ecdsa_info );
 #endif
         /* MBEDTLS_PK_RSA_ALT omitted on purpose */
+        /* MBEDTLS_PK_OPAQUE omitted on purpose: they can't be built by parsing */
         default:
             return( NULL );
     }
@@ -107,8 +108,11 @@
     if( ctx == NULL || info == NULL || ctx->pk_info != NULL )
         return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
 
-    if( ( ctx->pk_ctx = info->ctx_alloc_func() ) == NULL )
-        return( MBEDTLS_ERR_PK_ALLOC_FAILED );
+    if( info->ctx_alloc_func != NULL )
+    {
+        if( ( ctx->pk_ctx = info->ctx_alloc_func( ) ) == NULL )
+            return( MBEDTLS_ERR_PK_ALLOC_FAILED );
+    }
 
     ctx->pk_info = info;
 
@@ -312,24 +316,31 @@
 int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv )
 {
     if( pub == NULL || pub->pk_info == NULL ||
-        prv == NULL || prv->pk_info == NULL ||
-        prv->pk_info->check_pair_func == NULL )
+        prv == NULL || prv->pk_info == NULL )
     {
         return( MBEDTLS_ERR_PK_BAD_INPUT_DATA );
     }
 
+    if( pub->pk_info == prv->pk_info && pub->pk_ctx == prv->pk_ctx )
+        return( 0 );
+
+    if( prv->pk_info->check_pair_func == NULL )
+    {
+        return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
+    }
+
     if( prv->pk_info->type == MBEDTLS_PK_RSA_ALT )
     {
         if( pub->pk_info->type != MBEDTLS_PK_RSA )
             return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
     }
-    else
+    else if( prv->pk_info->type != MBEDTLS_PK_OPAQUE )
     {
         if( pub->pk_info != prv->pk_info )
             return( MBEDTLS_ERR_PK_TYPE_MISMATCH );
     }
 
-    return( prv->pk_info->check_pair_func( pub->pk_ctx, prv->pk_ctx ) );
+    return( prv->pk_info->check_pair_func( pub, prv->pk_ctx ) );
 }
 
 /*
@@ -384,7 +395,9 @@
 }
 
 /*
- * Access the PK type
+ * Access the PK type.
+ * For an opaque key pair object, this does not give any information on the
+ * underlying cryptographic material.
  */
 mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx )
 {
diff --git a/library/pk_wrap.c b/library/pk_wrap.c
index dafd7a4..393fdeb 100644
--- a/library/pk_wrap.c
+++ b/library/pk_wrap.c
@@ -148,10 +148,9 @@
                                        ilen, input, output ) );
 }
 
-static int rsa_check_pair_wrap( const void *pub, const void *prv )
+static int rsa_check_pair_wrap( const mbedtls_pk_context *pub, const void *prv )
 {
-    return( mbedtls_rsa_check_pub_priv( (const mbedtls_rsa_context *) pub,
-                                (const mbedtls_rsa_context *) prv ) );
+    return( mbedtls_rsa_check_pub_priv( pub->pk_ctx, prv ) );
 }
 
 static void *rsa_alloc_wrap( void )
@@ -272,10 +271,9 @@
 
 #endif /* MBEDTLS_ECDSA_C */
 
-static int eckey_check_pair( const void *pub, const void *prv )
+static int eckey_check_pair( const mbedtls_pk_context *pub, const void *prv )
 {
-    return( mbedtls_ecp_check_pub_priv( (const mbedtls_ecp_keypair *) pub,
-                                (const mbedtls_ecp_keypair *) prv ) );
+    return( mbedtls_ecp_check_pub_priv( pub->pk_ctx, prv ) );
 }
 
 static void *eckey_alloc_wrap( void )
@@ -472,14 +470,14 @@
 }
 
 #if defined(MBEDTLS_RSA_C)
-static int rsa_alt_check_pair( const void *pub, const void *prv )
+static int rsa_alt_check_pair( const mbedtls_pk_context *pub, const void *prv )
 {
     unsigned char sig[MBEDTLS_MPI_MAX_SIZE];
     unsigned char hash[32];
     size_t sig_len = 0;
     int ret;
 
-    if( rsa_alt_get_bitlen( prv ) != rsa_get_bitlen( pub ) )
+    if( rsa_alt_get_bitlen( prv ) != rsa_get_bitlen( pub->pk_ctx ) )
         return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED );
 
     memset( hash, 0x2a, sizeof( hash ) );
@@ -491,7 +489,7 @@
         return( ret );
     }
 
-    if( rsa_verify_wrap( (void *) pub, MBEDTLS_MD_NONE,
+    if( rsa_verify_wrap( pub->pk_ctx, MBEDTLS_MD_NONE,
                          hash, sizeof( hash ), sig, sig_len ) != 0 )
     {
         return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED );