Add pk_verify_ext()
diff --git a/include/polarssl/pk.h b/include/polarssl/pk.h
index 1309f70..232e175 100644
--- a/include/polarssl/pk.h
+++ b/include/polarssl/pk.h
@@ -103,6 +103,17 @@
 } pk_type_t;
 
 /**
+ * \brief           Options for RSASSA-PSS signature verification.
+ *                  See \c rsa_rsassa_pss_verify_ext()
+ */
+typedef struct
+{
+    md_type_t mgf1_hash_id;
+    int expected_salt_len;
+
+} pk_rsassa_pss_options;
+
+/**
  * \brief           Types for interfacing with the debug module
  */
 typedef enum
@@ -308,6 +319,39 @@
                const unsigned char *sig, size_t sig_len );
 
 /**
+ * \brief           Verify signature, with options
+ *
+ * \param type      Signature type to verify
+ * \param options   Pointer to type-specific options, or NULL
+ * \param ctx       PK context to use
+ * \param md_alg    Hash algorithm used (see notes)
+ * \param hash      Hash of the message to sign
+ * \param hash_len  Hash length or 0 (see notes)
+ * \param sig       Signature to verify
+ * \param sig_len   Signature length
+ *
+ * \return          0 on success (signature is valid),
+ *                  POLARSSL_ERR_PK_TYPE_MISMATCH if the PK context can't be
+ *                  used for this type of signatures,
+ *                  POLARSSL_ERR_PK_SIG_LEN_MISMATCH if the signature is
+ *                  valid but its actual length is less than sig_len,
+ *                  or a specific error code.
+ *
+ * \note            If hash_len is 0, then the length associated with md_alg
+ *                  is used instead, or an error returned if it is invalid.
+ *
+ * \note            md_alg may be POLARSSL_MD_NONE, only if hash_len != 0
+ *
+ * \note            If type is POLARSSL_PK_RSASSA_PSS, then options must point
+ *                  to a pk_rsassa_pss_options structure,
+ *                  otherwise it must be NULL.
+ */
+int pk_verify_ext( pk_type_t type, const void *options,
+                   pk_context *ctx, md_type_t md_alg,
+                   const unsigned char *hash, size_t hash_len,
+                   const unsigned char *sig, size_t sig_len );
+
+/**
  * \brief           Make signature
  *
  * \param ctx       PK context to use
diff --git a/library/pk.c b/library/pk.c
index ce17107..8000c10 100644
--- a/library/pk.c
+++ b/library/pk.c
@@ -189,6 +189,59 @@
 }
 
 /*
+ * Verify a signature with options
+ */
+int pk_verify_ext( pk_type_t type, const void *options,
+                   pk_context *ctx, md_type_t md_alg,
+                   const unsigned char *hash, size_t hash_len,
+                   const unsigned char *sig, size_t sig_len )
+{
+    if( ctx == NULL || ctx->pk_info == NULL )
+        return( POLARSSL_ERR_PK_BAD_INPUT_DATA );
+
+    if( ! pk_can_do( ctx, type ) )
+        return( POLARSSL_ERR_PK_TYPE_MISMATCH );
+
+    if( type == POLARSSL_PK_RSASSA_PSS )
+    {
+#if defined(POLARSSL_RSA_C) && defined(POLARSSL_PKCS1_V21)
+        int ret;
+        const pk_rsassa_pss_options *pss_opts;
+
+        if( options == NULL )
+            return( POLARSSL_ERR_PK_BAD_INPUT_DATA );
+
+        pss_opts = (const pk_rsassa_pss_options *) options;
+
+        if( sig_len < pk_get_len( ctx ) )
+            return( POLARSSL_ERR_RSA_VERIFY_FAILED );
+
+        ret = rsa_rsassa_pss_verify_ext( pk_rsa( *ctx ),
+                NULL, NULL, RSA_PUBLIC,
+                md_alg, hash_len, hash,
+                pss_opts->mgf1_hash_id,
+                pss_opts->expected_salt_len,
+                sig );
+        if( ret != 0 )
+            return( ret );
+
+        if( sig_len > pk_get_len( ctx ) )
+            return( POLARSSL_ERR_PK_SIG_LEN_MISMATCH );
+
+        return( 0 );
+#else
+        return( POLARSSL_ERR_PK_FEATURE_UNAVAILABLE );
+#endif
+    }
+
+    /* General case: no options */
+    if( options != NULL )
+        return( POLARSSL_ERR_PK_BAD_INPUT_DATA );
+
+    return( pk_verify( ctx, md_alg, hash, hash_len, sig, sig_len ) );
+}
+
+/*
  * Make a signature
  */
 int pk_sign( pk_context *ctx, md_type_t md_alg,
diff --git a/library/pk_wrap.c b/library/pk_wrap.c
index c0ad10d..6bfc4d2 100644
--- a/library/pk_wrap.c
+++ b/library/pk_wrap.c
@@ -52,13 +52,13 @@
 #define polarssl_free       free
 #endif
 
-/* Used by RSA-alt too */
+#if defined(POLARSSL_RSA_C)
 static int rsa_can_do( pk_type_t type )
 {
-    return( type == POLARSSL_PK_RSA );
+    return( type == POLARSSL_PK_RSA ||
+            type == POLARSSL_PK_RSASSA_PSS );
 }
 
-#if defined(POLARSSL_RSA_C)
 static size_t rsa_get_size( const void *ctx )
 {
     return( 8 * ((const rsa_context *) ctx)->len );
@@ -372,6 +372,11 @@
  * Support for alternative RSA-private implementations
  */
 
+static int rsa_alt_can_do( pk_type_t type )
+{
+    return( type == POLARSSL_PK_RSA );
+}
+
 static size_t rsa_alt_get_size( const void *ctx )
 {
     const rsa_alt_context *rsa_alt = (const rsa_alt_context *) ctx;
@@ -428,7 +433,7 @@
     POLARSSL_PK_RSA_ALT,
     "RSA-alt",
     rsa_alt_get_size,
-    rsa_can_do,
+    rsa_alt_can_do,
     NULL,
     rsa_alt_sign_wrap,
     rsa_alt_decrypt_wrap,
diff --git a/tests/suites/test_suite_pk.data b/tests/suites/test_suite_pk.data
index 974748c..c4393d6 100644
--- a/tests/suites/test_suite_pk.data
+++ b/tests/suites/test_suite_pk.data
@@ -81,3 +81,50 @@
 RSA_ALT consistency
 depends_on:POLARSSL_RSA_C:POLARSSL_PKCS1_V15:POLARSSL_GENPRIME
 pk_rsa_alt:
+
+Verify ext RSA #1 (PKCS1 v2.1, salt_len = ANY, OK)
+depends_on:POLARSSL_PKCS1_V21:POLARSSL_SHA256_C
+pk_rsa_verify_ext_test_vec:"54657374206d657373616765":POLARSSL_MD_SHA256:1024:16:"00dd118a9f99bab068ca2aea3b6a6d5997ed4ec954e40deecea07da01eaae80ec2bb1340db8a128e891324a5c5f5fad8f590d7c8cacbc5fe931dafda1223735279461abaa0572b761631b3a8afe7389b088b63993a0a25ee45d21858bab9931aedd4589a631b37fcf714089f856549f359326dd1e0e86dde52ed66b4a90bda4095":16:"010001":"0d2bdb0456a3d651d5bd48a4204493898f72cf1aaddd71387cc058bc3f4c235ea6be4010fd61b28e1fbb275462b53775c04be9022d38b6a2e0387dddba86a3f8554d2858044a59fddbd594753fc056fe33c8daddb85dc70d164690b1182209ff84824e0be10e35c379f2f378bf176a9f7cb94d95e44d90276a298c8810f741c9":POLARSSL_PK_RSASSA_PSS:POLARSSL_MD_SHA256:RSA_SALT_LEN_ANY:0
+
+Verify ext RSA #2 (PKCS1 v2.1, salt_len = ANY, wrong message)
+depends_on:POLARSSL_PKCS1_V21:POLARSSL_SHA256_C
+pk_rsa_verify_ext_test_vec:"54657374206d657373616766":POLARSSL_MD_SHA256:1024:16:"00dd118a9f99bab068ca2aea3b6a6d5997ed4ec954e40deecea07da01eaae80ec2bb1340db8a128e891324a5c5f5fad8f590d7c8cacbc5fe931dafda1223735279461abaa0572b761631b3a8afe7389b088b63993a0a25ee45d21858bab9931aedd4589a631b37fcf714089f856549f359326dd1e0e86dde52ed66b4a90bda4095":16:"010001":"0d2bdb0456a3d651d5bd48a4204493898f72cf1aaddd71387cc058bc3f4c235ea6be4010fd61b28e1fbb275462b53775c04be9022d38b6a2e0387dddba86a3f8554d2858044a59fddbd594753fc056fe33c8daddb85dc70d164690b1182209ff84824e0be10e35c379f2f378bf176a9f7cb94d95e44d90276a298c8810f741c9":POLARSSL_PK_RSASSA_PSS:POLARSSL_MD_SHA256:RSA_SALT_LEN_ANY:POLARSSL_ERR_RSA_VERIFY_FAILED
+
+Verify ext RSA #3 (PKCS1 v2.1, salt_len = 0, OK)
+depends_on:POLARSSL_PKCS1_V21:POLARSSL_SHA256_C
+pk_rsa_verify_ext_test_vec:"54657374206d657373616765":POLARSSL_MD_SHA256:1024:16:"00dd118a9f99bab068ca2aea3b6a6d5997ed4ec954e40deecea07da01eaae80ec2bb1340db8a128e891324a5c5f5fad8f590d7c8cacbc5fe931dafda1223735279461abaa0572b761631b3a8afe7389b088b63993a0a25ee45d21858bab9931aedd4589a631b37fcf714089f856549f359326dd1e0e86dde52ed66b4a90bda4095":16:"010001":"7fc506d26ca3b22922a1ce39faaedd273161b82d9443c56f1a034f131ae4a18cae1474271cb4b66a17d9707ca58b0bdbd3c406b7e65bbcc9bbbce94dc45de807b4989b23b3e4db74ca29298137837eb90cc83d3219249bc7d480fceaf075203a86e54c4ecfa4e312e39f8f69d76534089a36ed9049ca9cfd5ab1db1fa75fe5c8":POLARSSL_PK_RSASSA_PSS:POLARSSL_MD_SHA256:0:0
+
+Verify ext RSA #4 (PKCS1 v2.1, salt_len = max, OK)
+pk_rsa_verify_ext_test_vec:"54657374206d657373616765":POLARSSL_MD_SHA256:1024:16:"00dd118a9f99bab068ca2aea3b6a6d5997ed4ec954e40deecea07da01eaae80ec2bb1340db8a128e891324a5c5f5fad8f590d7c8cacbc5fe931dafda1223735279461abaa0572b761631b3a8afe7389b088b63993a0a25ee45d21858bab9931aedd4589a631b37fcf714089f856549f359326dd1e0e86dde52ed66b4a90bda4095":16:"010001":"0d2bdb0456a3d651d5bd48a4204493898f72cf1aaddd71387cc058bc3f4c235ea6be4010fd61b28e1fbb275462b53775c04be9022d38b6a2e0387dddba86a3f8554d2858044a59fddbd594753fc056fe33c8daddb85dc70d164690b1182209ff84824e0be10e35c379f2f378bf176a9f7cb94d95e44d90276a298c8810f741c9":POLARSSL_PK_RSASSA_PSS:POLARSSL_MD_SHA256:94:0
+
+Verify ext RSA #5 (PKCS1 v2.1, wrong salt_len)
+depends_on:POLARSSL_PKCS1_V21:POLARSSL_SHA256_C
+pk_rsa_verify_ext_test_vec:"54657374206d657373616765":POLARSSL_MD_SHA256:1024:16:"00dd118a9f99bab068ca2aea3b6a6d5997ed4ec954e40deecea07da01eaae80ec2bb1340db8a128e891324a5c5f5fad8f590d7c8cacbc5fe931dafda1223735279461abaa0572b761631b3a8afe7389b088b63993a0a25ee45d21858bab9931aedd4589a631b37fcf714089f856549f359326dd1e0e86dde52ed66b4a90bda4095":16:"010001":"0d2bdb0456a3d651d5bd48a4204493898f72cf1aaddd71387cc058bc3f4c235ea6be4010fd61b28e1fbb275462b53775c04be9022d38b6a2e0387dddba86a3f8554d2858044a59fddbd594753fc056fe33c8daddb85dc70d164690b1182209ff84824e0be10e35c379f2f378bf176a9f7cb94d95e44d90276a298c8810f741c9":POLARSSL_PK_RSASSA_PSS:POLARSSL_MD_SHA256:32:POLARSSL_ERR_RSA_INVALID_PADDING
+
+Verify ext RSA #6 (PKCS1 v2.1, MGF1 alg != MSG hash alg)
+depends_on:POLARSSL_PKCS1_V21:POLARSSL_SHA256_C
+pk_rsa_verify_ext_test_vec:"c0719e9a8d5d838d861dc6f675c899d2b309a3a65bb9fe6b11e5afcbf9a2c0b1":POLARSSL_MD_NONE:1024:16:"00dd118a9f99bab068ca2aea3b6a6d5997ed4ec954e40deecea07da01eaae80ec2bb1340db8a128e891324a5c5f5fad8f590d7c8cacbc5fe931dafda1223735279461abaa0572b761631b3a8afe7389b088b63993a0a25ee45d21858bab9931aedd4589a631b37fcf714089f856549f359326dd1e0e86dde52ed66b4a90bda4095":16:"010001":"0d2bdb0456a3d651d5bd48a4204493898f72cf1aaddd71387cc058bc3f4c235ea6be4010fd61b28e1fbb275462b53775c04be9022d38b6a2e0387dddba86a3f8554d2858044a59fddbd594753fc056fe33c8daddb85dc70d164690b1182209ff84824e0be10e35c379f2f378bf176a9f7cb94d95e44d90276a298c8810f741c9":POLARSSL_PK_RSASSA_PSS:POLARSSL_MD_SHA256:RSA_SALT_LEN_ANY:0
+
+Verify ext RSA #7 (PKCS1 v2.1, wrong MGF1 alg != MSG hash alg)
+depends_on:POLARSSL_PKCS1_V21:POLARSSL_SHA256_C:POLARSSL_SHA1_C
+pk_rsa_verify_ext_test_vec:"c0719e9a8d5d838d861dc6f675c899d2b309a3a65bb9fe6b11e5afcbf9a2c0b1":POLARSSL_MD_NONE:1024:16:"00dd118a9f99bab068ca2aea3b6a6d5997ed4ec954e40deecea07da01eaae80ec2bb1340db8a128e891324a5c5f5fad8f590d7c8cacbc5fe931dafda1223735279461abaa0572b761631b3a8afe7389b088b63993a0a25ee45d21858bab9931aedd4589a631b37fcf714089f856549f359326dd1e0e86dde52ed66b4a90bda4095":16:"010001":"0d2bdb0456a3d651d5bd48a4204493898f72cf1aaddd71387cc058bc3f4c235ea6be4010fd61b28e1fbb275462b53775c04be9022d38b6a2e0387dddba86a3f8554d2858044a59fddbd594753fc056fe33c8daddb85dc70d164690b1182209ff84824e0be10e35c379f2f378bf176a9f7cb94d95e44d90276a298c8810f741c9":POLARSSL_PK_RSASSA_PSS:POLARSSL_MD_SHA1:RSA_SALT_LEN_ANY:POLARSSL_ERR_RSA_INVALID_PADDING
+
+Verify ext RSA #8 (PKCS1 v2.1, RSASSA-PSS without options)
+pk_rsa_verify_ext_test_vec:"54657374206d657373616765":POLARSSL_MD_SHA256:1024:16:"00dd118a9f99bab068ca2aea3b6a6d5997ed4ec954e40deecea07da01eaae80ec2bb1340db8a128e891324a5c5f5fad8f590d7c8cacbc5fe931dafda1223735279461abaa0572b761631b3a8afe7389b088b63993a0a25ee45d21858bab9931aedd4589a631b37fcf714089f856549f359326dd1e0e86dde52ed66b4a90bda4095":16:"010001":"0d2bdb0456a3d651d5bd48a4204493898f72cf1aaddd71387cc058bc3f4c235ea6be4010fd61b28e1fbb275462b53775c04be9022d38b6a2e0387dddba86a3f8554d2858044a59fddbd594753fc056fe33c8daddb85dc70d164690b1182209ff84824e0be10e35c379f2f378bf176a9f7cb94d95e44d90276a298c8810f741c9":POLARSSL_PK_RSASSA_PSS:-1:RSA_SALT_LEN_ANY:POLARSSL_ERR_PK_BAD_INPUT_DATA
+
+Verify ext RSA #9 (PKCS1 v2.1, RSA with options)
+depends_on:POLARSSL_PKCS1_V15:POLARSSL_SHA256_C
+pk_rsa_verify_ext_test_vec:"54657374206d657373616765":POLARSSL_MD_SHA256:1024:16:"00dd118a9f99bab068ca2aea3b6a6d5997ed4ec954e40deecea07da01eaae80ec2bb1340db8a128e891324a5c5f5fad8f590d7c8cacbc5fe931dafda1223735279461abaa0572b761631b3a8afe7389b088b63993a0a25ee45d21858bab9931aedd4589a631b37fcf714089f856549f359326dd1e0e86dde52ed66b4a90bda4095":16:"010001":"0d2bdb0456a3d651d5bd48a4204493898f72cf1aaddd71387cc058bc3f4c235ea6be4010fd61b28e1fbb275462b53775c04be9022d38b6a2e0387dddba86a3f8554d2858044a59fddbd594753fc056fe33c8daddb85dc70d164690b1182209ff84824e0be10e35c379f2f378bf176a9f7cb94d95e44d90276a298c8810f741c9":POLARSSL_PK_RSA:POLARSSL_MD_SHA256:RSA_SALT_LEN_ANY:POLARSSL_ERR_PK_BAD_INPUT_DATA
+
+Verify ext RSA #10 (PKCS1 v2.1, RSA without options)
+depends_on:POLARSSL_PKCS1_V15:POLARSSL_SHA256_C
+pk_rsa_verify_ext_test_vec:"54657374206d657373616765":POLARSSL_MD_SHA256:1024:16:"00dd118a9f99bab068ca2aea3b6a6d5997ed4ec954e40deecea07da01eaae80ec2bb1340db8a128e891324a5c5f5fad8f590d7c8cacbc5fe931dafda1223735279461abaa0572b761631b3a8afe7389b088b63993a0a25ee45d21858bab9931aedd4589a631b37fcf714089f856549f359326dd1e0e86dde52ed66b4a90bda4095":16:"010001":"0d2bdb0456a3d651d5bd48a4204493898f72cf1aaddd71387cc058bc3f4c235ea6be4010fd61b28e1fbb275462b53775c04be9022d38b6a2e0387dddba86a3f8554d2858044a59fddbd594753fc056fe33c8daddb85dc70d164690b1182209ff84824e0be10e35c379f2f378bf176a9f7cb94d95e44d90276a298c8810f741c9":POLARSSL_PK_RSA:-1:RSA_SALT_LEN_ANY:POLARSSL_ERR_RSA_INVALID_PADDING
+
+Verify ext RSA #11 (PKCS1 v2.1, asking for ECDSA)
+depends_on:POLARSSL_ECDSA_C:POLARSSL_SHA256_C
+pk_rsa_verify_ext_test_vec:"54657374206d657373616765":POLARSSL_MD_SHA256:1024:16:"00dd118a9f99bab068ca2aea3b6a6d5997ed4ec954e40deecea07da01eaae80ec2bb1340db8a128e891324a5c5f5fad8f590d7c8cacbc5fe931dafda1223735279461abaa0572b761631b3a8afe7389b088b63993a0a25ee45d21858bab9931aedd4589a631b37fcf714089f856549f359326dd1e0e86dde52ed66b4a90bda4095":16:"010001":"0d2bdb0456a3d651d5bd48a4204493898f72cf1aaddd71387cc058bc3f4c235ea6be4010fd61b28e1fbb275462b53775c04be9022d38b6a2e0387dddba86a3f8554d2858044a59fddbd594753fc056fe33c8daddb85dc70d164690b1182209ff84824e0be10e35c379f2f378bf176a9f7cb94d95e44d90276a298c8810f741c9":POLARSSL_PK_ECDSA:-1:RSA_SALT_LEN_ANY:POLARSSL_ERR_PK_TYPE_MISMATCH
+
+Verify ext RSA #12 (PKCS1 v1.5, good)
+depends_on:POLARSSL_SHA1_C:POLARSSL_PKCS1_V15
+pk_rsa_verify_ext_test_vec:"206ef4bf396c6087f8229ef196fd35f37ccb8de5efcdb238f20d556668f114257a11fbe038464a67830378e62ae9791453953dac1dbd7921837ba98e84e856eb80ed9487e656d0b20c28c8ba5e35db1abbed83ed1c7720a97701f709e3547a4bfcabca9c89c57ad15c3996577a0ae36d7c7b699035242f37954646c1cd5c08ac":POLARSSL_MD_SHA1:1024:16:"e28a13548525e5f36dccb24ecb7cc332cc689dfd64012604c9c7816d72a16c3f5fcdc0e86e7c03280b1c69b586ce0cd8aec722cc73a5d3b730310bf7dfebdc77ce5d94bbc369dc18a2f7b07bd505ab0f82224aef09fdc1e5063234255e0b3c40a52e9e8ae60898eb88a766bdd788fe9493d8fd86bcdd2884d5c06216c65469e5":16:"3":"5abc01f5de25b70867ff0c24e222c61f53c88daf42586fddcd56f3c4588f074be3c328056c063388688b6385a8167957c6e5355a510e005b8a851d69c96b36ec6036644078210e5d7d326f96365ee0648882921492bc7b753eb9c26cdbab37555f210df2ca6fec1b25b463d38b81c0dcea202022b04af5da58aa03d77be949b7":POLARSSL_PK_RSA:-1:RSA_SALT_LEN_ANY:0
+
diff --git a/tests/suites/test_suite_pk.function b/tests/suites/test_suite_pk.function
index f82ed67..3da1feb 100644
--- a/tests/suites/test_suite_pk.function
+++ b/tests/suites/test_suite_pk.function
@@ -117,6 +117,71 @@
 }
 /* END_CASE */
 
+/* BEGIN_CASE depends_on:POLARSSL_RSA_C */
+void pk_rsa_verify_ext_test_vec( char *message_hex_string, int digest,
+                       int mod, int radix_N, char *input_N, int radix_E,
+                       char *input_E, char *result_hex_str,
+                       int pk_type, int mgf1_hash_id, int salt_len,
+                       int result )
+{
+    unsigned char message_str[1000];
+    unsigned char hash_result[1000];
+    unsigned char result_str[1000];
+    rsa_context *rsa;
+    pk_context pk;
+    pk_rsassa_pss_options pss_opts;
+    void *options;
+    int msg_len;
+    size_t hash_len;
+
+    pk_init( &pk );
+
+    memset( message_str, 0x00, 1000 );
+    memset( hash_result, 0x00, 1000 );
+    memset( result_str, 0x00, 1000 );
+
+    TEST_ASSERT( pk_init_ctx( &pk, pk_info_from_type( POLARSSL_PK_RSA ) ) == 0 );
+    rsa = pk_rsa( pk );
+
+    rsa->len = mod / 8;
+    TEST_ASSERT( mpi_read_string( &rsa->N, radix_N, input_N ) == 0 );
+    TEST_ASSERT( mpi_read_string( &rsa->E, radix_E, input_E ) == 0 );
+
+    msg_len = unhexify( message_str, message_hex_string );
+    unhexify( result_str, result_hex_str );
+
+    if( digest != POLARSSL_MD_NONE )
+    {
+        TEST_ASSERT( md( md_info_from_type( digest ),
+                     message_str, msg_len, hash_result ) == 0 );
+        hash_len = 0;
+    }
+    else
+    {
+        memcpy( hash_result, message_str, msg_len );
+        hash_len = msg_len;
+    }
+
+    if( mgf1_hash_id < 0 )
+    {
+        options = NULL;
+    }
+    else
+    {
+        options = &pss_opts;
+
+        pss_opts.mgf1_hash_id = mgf1_hash_id;
+        pss_opts.expected_salt_len = salt_len;
+    }
+
+    TEST_ASSERT( pk_verify_ext( pk_type, options, &pk,
+                                digest, hash_result, hash_len,
+                                result_str, pk_get_len( &pk ) ) == result );
+
+    pk_free( &pk );
+}
+/* END_CASE */
+
 /* BEGIN_CASE depends_on:POLARSSL_ECDSA_C */
 void pk_ec_test_vec( int type, int id, char *key_str,
                      char *hash_str, char * sig_str, int ret )