[bug] get certificate times as UTC, add tests
authorIvan Alejandro <ivanalejandro0@gmail.com>
Wed, 20 May 2015 21:39:10 +0000 (18:39 -0300)
committerIvan Alejandro <ivanalejandro0@gmail.com>
Thu, 21 May 2015 20:41:06 +0000 (17:41 -0300)
The certificate validity times were converted to local time and later on
compared with UTC time, which caused the certificate not being updated
at the right times.
Add tests to be sure this is not happenning again.
Add a joint pem file for the existing cert and key files to ease test.

- Resolves: #6994

changes/bug-6994_vert-expiration-check-problem [new file with mode: 0644]
src/leap/common/certs.py
src/leap/common/testing/leaptest_combined_keycert.pem [new file with mode: 0644]
src/leap/common/tests/test_certs.py [new file with mode: 0644]

diff --git a/changes/bug-6994_vert-expiration-check-problem b/changes/bug-6994_vert-expiration-check-problem
new file mode 100644 (file)
index 0000000..603e722
--- /dev/null
@@ -0,0 +1 @@
+- Fix time comparison between local and UTC times that caused the VPN certificates not being correctly downloaded on time. Closes #6994.
index 4fe563b..db513f6 100644 (file)
@@ -128,22 +128,23 @@ def is_valid_pemfile(cert):
     return can_load_cert_and_pkey(cert)
 
 
-def get_cert_time_boundaries(certfile):
+def get_cert_time_boundaries(certdata):
     """
-    Returns the time boundaries for the certificate saved in certfile
+    Return the time boundaries for the given certificate.
+    The returned values are UTC/GMT time.struct_time objects
 
-    :param certfile: path to certificate
-    :type certfile: str
+    :param certdata: the certificate contents
+    :type certdata: str
 
     :rtype: tuple (from, to)
     """
-    cert = get_cert_from_string(certfile)
+    cert = get_cert_from_string(certdata)
     leap_assert(cert, 'There was a problem loading the certificate')
 
     fromts, tots = (cert.get_notBefore(), cert.get_notAfter())
-    from_, to_ = map(
-        lambda ts: time.gmtime(time.mktime(dateparse(ts).timetuple())),
-        (fromts, tots))
+    from_ = dateparse(fromts).timetuple()
+    to_ = dateparse(tots).timetuple()
+
     return from_, to_
 
 
diff --git a/src/leap/common/testing/leaptest_combined_keycert.pem b/src/leap/common/testing/leaptest_combined_keycert.pem
new file mode 100644 (file)
index 0000000..f1e0fb2
--- /dev/null
@@ -0,0 +1,127 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDAT67c8y4ORa6o
+/gor3gAouJI6W6R7YlPzzh4uaba4YhqgAEZzcZ7S589CqON8Eo8G2tQvh+ZSaNmP
+idFDjFxfpb1sBMb9Nu720s0V8UMxzCDh7oyePZGdKP+F04+MkB0eHWSObBrzsjsj
+KVsD/5fUeLbd1SdK1C2cKzsoRQ+GVEyMJeiISFlV05fxdAZSybPcwH+3aiVX+7cM
+9ek8bufIeqrAfZVdvO/2Fuv6WfR2MEe32XO/9gj02XSGWd6sPXMn/lflKvNNKEWC
+UWdqTArGi0CqQ4D+Q73ruUIthCJr+7LWK+7QKG980a1RR7GZJvs3skhUDh3eua2u
+ICPiqQLlAgMBAAECggEBAKJr6j0UagaF1dFG1eJc2neKA36kXdQTpOIaaKU8haVO
+vjv6X4YrJT/tpsAfEhp9Ni1M7r7CIcXiZjVz6bkKOA5UVhqAImxEVClEuw/YN688
+P11yc3NGftBkiwNFPk0yflUr7/zV0yGVm5rD1+oVme9KkO/kkg4CDA+E9664PTdu
+S4NVvL6OgHUG2nucqIz0kzUBapo7okIkvggfldeDYF47rn/e0VikNpKkMzoCzWs+
+3ryzldfigwg18rE2nltQYk/Mi+H30iNTNEonLjs9YbiDPn8iy5SZ7xY4lAO1Urev
+skdY04hmkOzh9JEETHeTj1LUIw7tfRdS3X6B+19gkCECgYEA+41UOLBb0ZHsGjsA
+aZBtI4g8mvGTOFe/Az7Jm0404z6e8AIe4NeSJoJ6oV6WG2BmKvqTViYT2QnmauHA
+WB1xJ5fH3PK7/LjICI2QE247E294+g5p1KYysALc2fChfJNpdfETzWJAUSSBFqxb
+amCDZ4Gc8S/V44fEkJKPLuAvxL0CgYEAw7YyGsEX+lDGzumFQY4wz20+Cyvilnx0
+xoFGQ85RSprZttU64PID/u1HD9/Nv4lGcBDcTTtrmOEk9x51YzttrsPF9sn+Wj0y
+eahuR32Qc1652Y7fAKgN2vIZRFBcGpAsemcoqmYFRMImX60G0areKaclooimTbJA
+Si52P4IKnUkCgYAI+07ah1F/9hncBedJ3aJH9oFTdvSuulNTplZEeVJiGsZKA4le
+tdO+FEKUqG/rolGDj1bbaJik0zmq70yS2NpFc6HrPa+Aoohh5cwTJYhudTh4lTMq
+KJT+u9tu3KynagwF7gmq96scOpVxXc4VykRm2bXk1rRoX1yhXNpH7jFGcQKBgCn/
+v2DebzbYftGIa4BV80OQPfBHyqhgrO6sb1e9vtQzxuTlfW0ogpMCeG1/qbegzeze
+sWghiEWWi0g80RQqfK80dBcx4dObrmlNK91LpOQdP+TgNBr/9Xk22xU96YYJyoG6
+AZAPtLG8uF9v0jbMZECsDfeDO60Qw5snvViDn6OBAoGACAbbQCbuh0cduDVwn0uz
+8XDyRTKDhOsJ3p6UB1TjwvbLeoPI93Dv1gpEeoqELtCu+ZXr3+/i/IbwrxucrFNn
+L/s+4zR2mlEAxBdtCFsH/Qf7+iYpBFSo4YReXz3xR+EVTmswzodJCbtF74oQSr6o
+7d56Rd/5k2UkFeXnlGOLyAc=
+-----END PRIVATE KEY-----
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 4 (0x4)
+    Signature Algorithm: sha1WithRSAEncryption
+        Issuer: C=US, ST=CA, L=Cyberspace, O=LEAP Encryption Access Project, OU=cyberspace, CN=tests-leap.se/name=tests-leap/emailAddress=tests@leap.se
+        Validity
+            Not Before: Sep  3 17:52:16 2013 GMT
+            Not After : Sep  1 17:52:16 2023 GMT
+        Subject: C=US, ST=CA, L=Cyberspace, O=LEAP Encryption Access Project, OU=cyberspace, CN=localhost/name=tests-leap/emailAddress=tests@leap.se
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:c0:4f:ae:dc:f3:2e:0e:45:ae:a8:fe:0a:2b:de:
+                    00:28:b8:92:3a:5b:a4:7b:62:53:f3:ce:1e:2e:69:
+                    b6:b8:62:1a:a0:00:46:73:71:9e:d2:e7:cf:42:a8:
+                    e3:7c:12:8f:06:da:d4:2f:87:e6:52:68:d9:8f:89:
+                    d1:43:8c:5c:5f:a5:bd:6c:04:c6:fd:36:ee:f6:d2:
+                    cd:15:f1:43:31:cc:20:e1:ee:8c:9e:3d:91:9d:28:
+                    ff:85:d3:8f:8c:90:1d:1e:1d:64:8e:6c:1a:f3:b2:
+                    3b:23:29:5b:03:ff:97:d4:78:b6:dd:d5:27:4a:d4:
+                    2d:9c:2b:3b:28:45:0f:86:54:4c:8c:25:e8:88:48:
+                    59:55:d3:97:f1:74:06:52:c9:b3:dc:c0:7f:b7:6a:
+                    25:57:fb:b7:0c:f5:e9:3c:6e:e7:c8:7a:aa:c0:7d:
+                    95:5d:bc:ef:f6:16:eb:fa:59:f4:76:30:47:b7:d9:
+                    73:bf:f6:08:f4:d9:74:86:59:de:ac:3d:73:27:fe:
+                    57:e5:2a:f3:4d:28:45:82:51:67:6a:4c:0a:c6:8b:
+                    40:aa:43:80:fe:43:bd:eb:b9:42:2d:84:22:6b:fb:
+                    b2:d6:2b:ee:d0:28:6f:7c:d1:ad:51:47:b1:99:26:
+                    fb:37:b2:48:54:0e:1d:de:b9:ad:ae:20:23:e2:a9:
+                    02:e5
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: 
+                CA:FALSE
+            Netscape Cert Type: 
+                SSL Server
+            Netscape Comment: 
+                Easy-RSA Generated Server Certificate
+            X509v3 Subject Key Identifier: 
+                51:92:B6:A3:D7:D6:EC:8F:FC:16:C5:D4:0F:87:CC:EA:5C:7C:17:81
+            X509v3 Authority Key Identifier: 
+                keyid:36:19:70:96:A9:5C:FE:A3:82:0F:79:95:31:52:2B:4A:41:BD:81:CB
+                DirName:/C=US/ST=CA/L=Cyberspace/O=LEAP Encryption Access Project/OU=cyberspace/CN=tests-leap.se/name=tests-leap/emailAddress=tests@leap.se
+                serial:8B:BF:41:63:1E:10:6A:EC
+
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication
+            X509v3 Key Usage: 
+                Digital Signature, Key Encipherment
+    Signature Algorithm: sha1WithRSAEncryption
+         88:d9:35:e0:d9:fa:fd:6b:57:e2:4d:f6:ef:91:6f:56:a6:2b:
+         1a:1e:ec:8f:b0:18:e3:ec:ca:c9:1e:78:07:1d:0f:cf:fe:09:
+         21:84:25:c4:27:ea:22:d7:48:53:73:ed:78:0f:42:5c:c7:f7:
+         38:04:84:df:67:99:fd:75:6f:e8:dc:3b:91:ab:fa:c7:32:e5:
+         fd:3b:ce:de:7c:6a:df:39:46:1e:46:3a:4d:e1:e1:60:f3:bf:
+         aa:b2:0b:5d:ee:f2:0c:ee:82:7f:b5:02:75:04:47:d5:2b:c8:
+         e0:6d:6a:10:4a:ca:e0:c3:4f:ee:ff:15:71:37:f5:4d:95:38:
+         fe:a3:da:84:46:90:04:c2:61:86:a0:7f:e2:7d:62:46:6d:f6:
+         f8:90:51:88:c3:f2:8c:ca:b3:89:40:9f:6b:8b:33:65:e1:fd:
+         0f:8b:d7:6a:93:dc:de:be:85:07:c7:d1:1d:b5:db:70:54:9f:
+         95:d8:fb:11:f7:a7:e6:90:ba:9b:28:0e:3d:47:7a:63:6d:60:
+         44:f6:96:aa:b6:a2:bc:0a:e5:25:c8:a2:74:91:54:95:bb:e2:
+         09:01:56:73:6e:56:e8:6f:d6:a5:d8:18:96:c1:82:ef:2c:9e:
+         e2:4c:94:bc:00:71:5e:16:49:6b:e4:94:7a:d1:0c:2e:f4:19:
+         b2:2a:c2:b8
+-----BEGIN CERTIFICATE-----
+MIIFdDCCBFygAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBuDELMAkGA1UEBhMCVVMx
+CzAJBgNVBAgTAkNBMRMwEQYDVQQHEwpDeWJlcnNwYWNlMScwJQYDVQQKEx5MRUFQ
+IEVuY3J5cHRpb24gQWNjZXNzIFByb2plY3QxEzARBgNVBAsTCmN5YmVyc3BhY2Ux
+FjAUBgNVBAMTDXRlc3RzLWxlYXAuc2UxEzARBgNVBCkTCnRlc3RzLWxlYXAxHDAa
+BgkqhkiG9w0BCQEWDXRlc3RzQGxlYXAuc2UwHhcNMTMwOTAzMTc1MjE2WhcNMjMw
+OTAxMTc1MjE2WjCBtDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRMwEQYDVQQH
+EwpDeWJlcnNwYWNlMScwJQYDVQQKEx5MRUFQIEVuY3J5cHRpb24gQWNjZXNzIFBy
+b2plY3QxEzARBgNVBAsTCmN5YmVyc3BhY2UxEjAQBgNVBAMTCWxvY2FsaG9zdDET
+MBEGA1UEKRMKdGVzdHMtbGVhcDEcMBoGCSqGSIb3DQEJARYNdGVzdHNAbGVhcC5z
+ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMBPrtzzLg5Frqj+Cive
+ACi4kjpbpHtiU/POHi5ptrhiGqAARnNxntLnz0Ko43wSjwba1C+H5lJo2Y+J0UOM
+XF+lvWwExv027vbSzRXxQzHMIOHujJ49kZ0o/4XTj4yQHR4dZI5sGvOyOyMpWwP/
+l9R4tt3VJ0rULZwrOyhFD4ZUTIwl6IhIWVXTl/F0BlLJs9zAf7dqJVf7twz16Txu
+58h6qsB9lV287/YW6/pZ9HYwR7fZc7/2CPTZdIZZ3qw9cyf+V+Uq800oRYJRZ2pM
+CsaLQKpDgP5Dveu5Qi2EImv7stYr7tAob3zRrVFHsZkm+zeySFQOHd65ra4gI+Kp
+AuUCAwEAAaOCAYkwggGFMAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgZAMDQG
+CWCGSAGG+EIBDQQnFiVFYXN5LVJTQSBHZW5lcmF0ZWQgU2VydmVyIENlcnRpZmlj
+YXRlMB0GA1UdDgQWBBRRkraj19bsj/wWxdQPh8zqXHwXgTCB7QYDVR0jBIHlMIHi
+gBQ2GXCWqVz+o4IPeZUxUitKQb2By6GBvqSBuzCBuDELMAkGA1UEBhMCVVMxCzAJ
+BgNVBAgTAkNBMRMwEQYDVQQHEwpDeWJlcnNwYWNlMScwJQYDVQQKEx5MRUFQIEVu
+Y3J5cHRpb24gQWNjZXNzIFByb2plY3QxEzARBgNVBAsTCmN5YmVyc3BhY2UxFjAU
+BgNVBAMTDXRlc3RzLWxlYXAuc2UxEzARBgNVBCkTCnRlc3RzLWxlYXAxHDAaBgkq
+hkiG9w0BCQEWDXRlc3RzQGxlYXAuc2WCCQCLv0FjHhBq7DATBgNVHSUEDDAKBggr
+BgEFBQcDATALBgNVHQ8EBAMCBaAwDQYJKoZIhvcNAQEFBQADggEBAIjZNeDZ+v1r
+V+JN9u+Rb1amKxoe7I+wGOPsyskeeAcdD8/+CSGEJcQn6iLXSFNz7XgPQlzH9zgE
+hN9nmf11b+jcO5Gr+scy5f07zt58at85Rh5GOk3h4WDzv6qyC13u8gzugn+1AnUE
+R9UryOBtahBKyuDDT+7/FXE39U2VOP6j2oRGkATCYYagf+J9YkZt9viQUYjD8ozK
+s4lAn2uLM2Xh/Q+L12qT3N6+hQfH0R2123BUn5XY+xH3p+aQupsoDj1HemNtYET2
+lqq2orwK5SXIonSRVJW74gkBVnNuVuhv1qXYGJbBgu8snuJMlLwAcV4WSWvklHrR
+DC70GbIqwrg=
+-----END CERTIFICATE-----
diff --git a/src/leap/common/tests/test_certs.py b/src/leap/common/tests/test_certs.py
new file mode 100644 (file)
index 0000000..999071f
--- /dev/null
@@ -0,0 +1,97 @@
+# -*- coding: utf-8 -*-
+# test_certs.py
+# Copyright (C) 2013 LEAP
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+"""
+Tests for:
+    * leap/common/certs.py
+"""
+import os
+import time
+
+try:
+    import unittest2 as unittest
+except ImportError:
+    import unittest
+
+from leap.common import certs
+from leap.common.testing.basetest import BaseLeapTest
+
+TEST_CERT_PEM = os.path.join(
+    os.path.split(__file__)[0],
+    '..', 'testing', "leaptest_combined_keycert.pem")
+
+# Values from the test cert file:
+# Not Before: Sep  3 17:52:16 2013 GMT
+# Not After : Sep  1 17:52:16 2023 GMT
+CERT_NOT_BEFORE = (2013, 9, 3, 17, 52, 16, 1, 246, 0)
+CERT_NOT_AFTER = (2023, 9, 1, 17, 52, 16, 4, 244, 0)
+
+
+class CertsTest(BaseLeapTest):
+
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    def test_should_redownload_if_no_cert(self):
+        self.assertTrue(certs.should_redownload(certfile=""))
+
+    def test_should_redownload_if_invalid_pem(self):
+        cert_path = self.get_tempfile('test_pem_file.pem')
+
+        with open(cert_path, 'w') as f:
+            f.write('this is some invalid data for the pem file')
+
+        self.assertTrue(certs.should_redownload(cert_path))
+
+    def test_should_redownload_if_before(self):
+        new_now = lambda: time.struct_time(CERT_NOT_BEFORE)
+        self.assertTrue(certs.should_redownload(TEST_CERT_PEM, now=new_now))
+
+    def test_should_redownload_if_after(self):
+        new_now = lambda: time.struct_time(CERT_NOT_AFTER)
+        self.assertTrue(certs.should_redownload(TEST_CERT_PEM, now=new_now))
+
+    def test_not_should_redownload(self):
+        self.assertFalse(certs.should_redownload(TEST_CERT_PEM))
+
+    def test_is_valid_pemfile(self):
+        with open(TEST_CERT_PEM) as f:
+            cert_data = f.read()
+
+        self.assertTrue(certs.is_valid_pemfile(cert_data))
+
+    def test_not_is_valid_pemfile(self):
+        cert_data = 'this is some invalid data for the pem file'
+
+        self.assertFalse(certs.is_valid_pemfile(cert_data))
+
+    def test_get_cert_time_boundaries(self):
+        """
+        This test ensures us that the returned values are returned in UTC/GMT.
+        """
+        with open(TEST_CERT_PEM) as f:
+            cert_data = f.read()
+
+        valid_from, valid_to = certs.get_cert_time_boundaries(cert_data)
+        self.assertEqual(tuple(valid_from), CERT_NOT_BEFORE)
+        self.assertEqual(tuple(valid_to), CERT_NOT_AFTER)
+
+
+if __name__ == "__main__":
+    unittest.main()