Correctly handle leap year in x509_date_is_valid()

This patch ensures that invalid dates on leap years with 100 or 400
years intervals are handled correctly.
diff --git a/ChangeLog b/ChangeLog
index 9e025da..6a1be98 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -11,6 +11,9 @@
    * Parse signature algorithm extension when renegotiating. Previously,
      renegotiated handshakes would only accept signatures using SHA-1
      regardless of the peer's preferences, or fail if SHA-1 was disabled.
+   * Fix leap year calculation in x509_date_is_valid() to ensure that invalid
+     dates on leap years with 100 and 400 intervals are handled correctly. Found
+     by Nicholas Wilson. #694
 
 = mbed TLS 1.3.21 branch released 2017-08-10
 
diff --git a/library/x509.c b/library/x509.c
index 3619aee..cb6fc6c 100644
--- a/library/x509.c
+++ b/library/x509.c
@@ -499,6 +499,7 @@
 static int x509_date_is_valid(const x509_time *t)
 {
     int ret = POLARSSL_ERR_X509_INVALID_DATE;
+    int month_len;
 
     CHECK_RANGE( 0, 9999, t->year );
     CHECK_RANGE( 0, 23,   t->hour );
@@ -508,17 +509,22 @@
     switch( t->mon )
     {
         case 1: case 3: case 5: case 7: case 8: case 10: case 12:
-            CHECK_RANGE( 1, 31, t->day );
+            month_len = 31;
             break;
         case 4: case 6: case 9: case 11:
-            CHECK_RANGE( 1, 30, t->day );
+            month_len = 30;
             break;
         case 2:
-            CHECK_RANGE( 1, 28 + (t->year % 4 == 0), t->day );
+            if( ( !( t->year % 4 ) && t->year % 100 ) ||
+                !( t->year % 400 ) )
+                month_len = 29;
+            else
+                month_len = 28;
             break;
         default:
             return( ret );
     }
+    CHECK_RANGE( 1, month_len, t->day );
 
     return( 0 );
 }
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index 135ec60..44028af 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -1546,3 +1546,19 @@
 X509 Get time (UTC invalid sec)
 depends_on:POLARSSL_X509_USE_C
 x509_get_time:ASN1_UTC_TIME:"001130235960Z":POLARSSL_ERR_X509_INVALID_DATE:0:0:0:0:0:0
+
+X509 Get time (Generalized Time invalid leap year multiple of 4 and 100)
+depends_on:POLARSSL_X509_USE_C
+x509_get_time:ASN1_GENERALIZED_TIME:"19000229000000Z":POLARSSL_ERR_X509_INVALID_DATE:0:0:0:0:0:0
+
+X509 Get time (Generalized Time year multiple of 4 and not multiple of 100)
+depends_on:POLARSSL_X509_USE_C
+x509_get_time:ASN1_GENERALIZED_TIME:"19920229000000Z":0:1992:2:29:0:0:0
+
+X509 Get time (Generalized Time year multiple of 400)
+depends_on:POLARSSL_X509_USE_C
+x509_get_time:ASN1_GENERALIZED_TIME:"20000229000000Z":0:2000:2:29:0:0:0
+
+X509 Get time (Generalized Time invalid leap year not multiple of 4, 100 or 400)
+depends_on:POLARSSL_X509_USE_C
+x509_get_time:ASN1_GENERALIZED_TIME:"19910229000000Z":POLARSSL_ERR_X509_INVALID_DATE:0:0:0:0:0:0