Implement record checking API

This commit implements the record checking API

   mbedtls_ssl_check_record()

on top of the restructured incoming record stack.

Specifically, it makes use of the fact that the core processing routines

  ssl_parse_record_header()
  mbedtls_ssl_decrypt_buf()

now operate on instances of the SSL record structure mbedtls_record
instead of the previous mbedtls_ssl_context::in_xxx fields.
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 37a3f74..3502f05 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -123,14 +123,69 @@
 static void ssl_update_in_pointers( mbedtls_ssl_context *ssl );
 
 #if defined(MBEDTLS_SSL_RECORD_CHECKING)
+static int ssl_parse_record_header( mbedtls_ssl_context const *ssl,
+                                    unsigned char *buf,
+                                    size_t len,
+                                    mbedtls_record *rec );
+
 int mbedtls_ssl_check_record( mbedtls_ssl_context const *ssl,
                               unsigned char *buf,
                               size_t buflen )
 {
-    ((void) ssl);
-    ((void) buf);
-    ((void) buflen);
-    return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
+    int ret = 0;
+    mbedtls_record rec;
+    MBEDTLS_SSL_DEBUG_MSG( 1, ( "=> mbedtls_ssl_check_record" ) );
+    MBEDTLS_SSL_DEBUG_BUF( 3, "record buffer", buf, buflen );
+
+    /* We don't support record checking in TLS because
+     * (a) there doesn't seem to be a usecase for it, and
+     * (b) In SSLv3 and TLS 1.0, CBC record decryption has state
+     *     and we'd need to backup the transform here.
+     */
+#if defined(MBEDTLS_SSL_PROTO_TLS)
+    if( MBEDTLS_SSL_TRANSPORT_IS_TLS( ssl->conf->transport ) )
+    {
+        ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE;
+        goto exit;
+    }
+    MBEDTLS_SSL_TRANSPORT_ELSE
+#endif /* MBEDTLS_SSL_PROTO_TLS */
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+   {
+       ret = ssl_parse_record_header( ssl, buf, buflen, &rec );
+       if( ret != 0 )
+       {
+           MBEDTLS_SSL_DEBUG_RET( 3, "ssl_parse_record_header", ret );
+           goto exit;
+       }
+
+       if( ssl->transform_in != NULL )
+       {
+           ret = mbedtls_ssl_decrypt_buf( ssl, ssl->transform_in, &rec );
+           if( ret != 0 )
+           {
+               MBEDTLS_SSL_DEBUG_RET( 3, "mbedtls_ssl_decrypt_buf", ret );
+               goto exit;
+           }
+       }
+   }
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
+exit:
+    /* On success, we have decrypted the buffer in-place, so make
+     * sure we don't leak any plaintext data. */
+    mbedtls_platform_zeroize( buf, buflen );
+
+    /* For the purpose of this API, treat messages with unexpected CID
+     * as well as such from future epochs as unexpected. */
+    if( ret == MBEDTLS_ERR_SSL_UNEXPECTED_CID ||
+        ret == MBEDTLS_ERR_SSL_EARLY_MESSAGE )
+    {
+        ret = MBEDTLS_ERR_SSL_UNEXPECTED_RECORD;
+    }
+
+    MBEDTLS_SSL_DEBUG_MSG( 1, ( "<= mbedtls_ssl_check_record" ) );
+    return( ret );
 }
 #endif /* MBEDTLS_SSL_RECORD_CHECKING */
 
@@ -4826,7 +4881,8 @@
     {
         if( ssl_check_record_type( rec->type ) )
         {
-            MBEDTLS_SSL_DEBUG_MSG( 1, ( "unknown record type" ) );
+            MBEDTLS_SSL_DEBUG_MSG( 1, ( "unknown record type %u",
+                                        (unsigned) rec->type ) );
             return( MBEDTLS_ERR_SSL_INVALID_RECORD );
         }
     }