Statistics
| Branch: | Tag: | Revision:

root / test / ganeti.utils.x509_unittest.py @ 3b877f08

History | View | Annotate | Download (8.9 kB)

1 c50645c0 Michael Hanselmann
#!/usr/bin/python
2 c50645c0 Michael Hanselmann
#
3 c50645c0 Michael Hanselmann
4 c50645c0 Michael Hanselmann
# Copyright (C) 2006, 2007, 2010, 2011 Google Inc.
5 c50645c0 Michael Hanselmann
#
6 c50645c0 Michael Hanselmann
# This program is free software; you can redistribute it and/or modify
7 c50645c0 Michael Hanselmann
# it under the terms of the GNU General Public License as published by
8 c50645c0 Michael Hanselmann
# the Free Software Foundation; either version 2 of the License, or
9 c50645c0 Michael Hanselmann
# (at your option) any later version.
10 c50645c0 Michael Hanselmann
#
11 c50645c0 Michael Hanselmann
# This program is distributed in the hope that it will be useful, but
12 c50645c0 Michael Hanselmann
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 c50645c0 Michael Hanselmann
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 c50645c0 Michael Hanselmann
# General Public License for more details.
15 c50645c0 Michael Hanselmann
#
16 c50645c0 Michael Hanselmann
# You should have received a copy of the GNU General Public License
17 c50645c0 Michael Hanselmann
# along with this program; if not, write to the Free Software
18 c50645c0 Michael Hanselmann
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 c50645c0 Michael Hanselmann
# 02110-1301, USA.
20 c50645c0 Michael Hanselmann
21 c50645c0 Michael Hanselmann
22 c50645c0 Michael Hanselmann
"""Script for testing ganeti.utils.x509"""
23 c50645c0 Michael Hanselmann
24 c50645c0 Michael Hanselmann
import os
25 c50645c0 Michael Hanselmann
import tempfile
26 c50645c0 Michael Hanselmann
import unittest
27 c50645c0 Michael Hanselmann
import shutil
28 c50645c0 Michael Hanselmann
import time
29 c50645c0 Michael Hanselmann
import OpenSSL
30 c50645c0 Michael Hanselmann
import distutils.version
31 c50645c0 Michael Hanselmann
import string
32 c50645c0 Michael Hanselmann
33 c50645c0 Michael Hanselmann
from ganeti import constants
34 c50645c0 Michael Hanselmann
from ganeti import utils
35 c50645c0 Michael Hanselmann
from ganeti import compat
36 c50645c0 Michael Hanselmann
from ganeti import errors
37 c50645c0 Michael Hanselmann
38 c50645c0 Michael Hanselmann
import testutils
39 c50645c0 Michael Hanselmann
40 c50645c0 Michael Hanselmann
41 c50645c0 Michael Hanselmann
class TestParseAsn1Generalizedtime(unittest.TestCase):
42 c50645c0 Michael Hanselmann
  def setUp(self):
43 c50645c0 Michael Hanselmann
    self._Parse = utils.x509._ParseAsn1Generalizedtime
44 c50645c0 Michael Hanselmann
45 c50645c0 Michael Hanselmann
  def test(self):
46 c50645c0 Michael Hanselmann
    # UTC
47 c50645c0 Michael Hanselmann
    self.assertEqual(self._Parse("19700101000000Z"), 0)
48 c50645c0 Michael Hanselmann
    self.assertEqual(self._Parse("20100222174152Z"), 1266860512)
49 c50645c0 Michael Hanselmann
    self.assertEqual(self._Parse("20380119031407Z"), (2**31) - 1)
50 c50645c0 Michael Hanselmann
51 c50645c0 Michael Hanselmann
    # With offset
52 c50645c0 Michael Hanselmann
    self.assertEqual(self._Parse("20100222174152+0000"), 1266860512)
53 c50645c0 Michael Hanselmann
    self.assertEqual(self._Parse("20100223131652+0000"), 1266931012)
54 c50645c0 Michael Hanselmann
    self.assertEqual(self._Parse("20100223051808-0800"), 1266931088)
55 c50645c0 Michael Hanselmann
    self.assertEqual(self._Parse("20100224002135+1100"), 1266931295)
56 c50645c0 Michael Hanselmann
    self.assertEqual(self._Parse("19700101000000-0100"), 3600)
57 c50645c0 Michael Hanselmann
58 c50645c0 Michael Hanselmann
    # Leap seconds are not supported by datetime.datetime
59 c50645c0 Michael Hanselmann
    self.assertRaises(ValueError, self._Parse, "19841231235960+0000")
60 c50645c0 Michael Hanselmann
    self.assertRaises(ValueError, self._Parse, "19920630235960+0000")
61 c50645c0 Michael Hanselmann
62 c50645c0 Michael Hanselmann
    # Errors
63 c50645c0 Michael Hanselmann
    self.assertRaises(ValueError, self._Parse, "")
64 c50645c0 Michael Hanselmann
    self.assertRaises(ValueError, self._Parse, "invalid")
65 c50645c0 Michael Hanselmann
    self.assertRaises(ValueError, self._Parse, "20100222174152")
66 c50645c0 Michael Hanselmann
    self.assertRaises(ValueError, self._Parse, "Mon Feb 22 17:47:02 UTC 2010")
67 c50645c0 Michael Hanselmann
    self.assertRaises(ValueError, self._Parse, "2010-02-22 17:42:02")
68 c50645c0 Michael Hanselmann
69 c50645c0 Michael Hanselmann
70 c50645c0 Michael Hanselmann
class TestGetX509CertValidity(testutils.GanetiTestCase):
71 c50645c0 Michael Hanselmann
  def setUp(self):
72 c50645c0 Michael Hanselmann
    testutils.GanetiTestCase.setUp(self)
73 c50645c0 Michael Hanselmann
74 c50645c0 Michael Hanselmann
    pyopenssl_version = distutils.version.LooseVersion(OpenSSL.__version__)
75 c50645c0 Michael Hanselmann
76 c50645c0 Michael Hanselmann
    # Test whether we have pyOpenSSL 0.7 or above
77 c50645c0 Michael Hanselmann
    self.pyopenssl0_7 = (pyopenssl_version >= "0.7")
78 c50645c0 Michael Hanselmann
79 c50645c0 Michael Hanselmann
    if not self.pyopenssl0_7:
80 c50645c0 Michael Hanselmann
      warnings.warn("This test requires pyOpenSSL 0.7 or above to"
81 c50645c0 Michael Hanselmann
                    " function correctly")
82 c50645c0 Michael Hanselmann
83 c50645c0 Michael Hanselmann
  def _LoadCert(self, name):
84 c50645c0 Michael Hanselmann
    return OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
85 c50645c0 Michael Hanselmann
                                           self._ReadTestData(name))
86 c50645c0 Michael Hanselmann
87 c50645c0 Michael Hanselmann
  def test(self):
88 c50645c0 Michael Hanselmann
    validity = utils.GetX509CertValidity(self._LoadCert("cert1.pem"))
89 c50645c0 Michael Hanselmann
    if self.pyopenssl0_7:
90 c50645c0 Michael Hanselmann
      self.assertEqual(validity, (1266919967, 1267524767))
91 c50645c0 Michael Hanselmann
    else:
92 c50645c0 Michael Hanselmann
      self.assertEqual(validity, (None, None))
93 c50645c0 Michael Hanselmann
94 c50645c0 Michael Hanselmann
95 c50645c0 Michael Hanselmann
class TestSignX509Certificate(unittest.TestCase):
96 c50645c0 Michael Hanselmann
  KEY = "My private key!"
97 c50645c0 Michael Hanselmann
  KEY_OTHER = "Another key"
98 c50645c0 Michael Hanselmann
99 c50645c0 Michael Hanselmann
  def test(self):
100 c50645c0 Michael Hanselmann
    # Generate certificate valid for 5 minutes
101 c50645c0 Michael Hanselmann
    (_, cert_pem) = utils.GenerateSelfSignedX509Cert(None, 300)
102 c50645c0 Michael Hanselmann
103 c50645c0 Michael Hanselmann
    cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
104 c50645c0 Michael Hanselmann
                                           cert_pem)
105 c50645c0 Michael Hanselmann
106 c50645c0 Michael Hanselmann
    # No signature at all
107 c50645c0 Michael Hanselmann
    self.assertRaises(errors.GenericError,
108 c50645c0 Michael Hanselmann
                      utils.LoadSignedX509Certificate, cert_pem, self.KEY)
109 c50645c0 Michael Hanselmann
110 c50645c0 Michael Hanselmann
    # Invalid input
111 c50645c0 Michael Hanselmann
    self.assertRaises(errors.GenericError, utils.LoadSignedX509Certificate,
112 c50645c0 Michael Hanselmann
                      "", self.KEY)
113 c50645c0 Michael Hanselmann
    self.assertRaises(errors.GenericError, utils.LoadSignedX509Certificate,
114 c50645c0 Michael Hanselmann
                      "X-Ganeti-Signature: \n", self.KEY)
115 c50645c0 Michael Hanselmann
    self.assertRaises(errors.GenericError, utils.LoadSignedX509Certificate,
116 c50645c0 Michael Hanselmann
                      "X-Ganeti-Sign: $1234$abcdef\n", self.KEY)
117 c50645c0 Michael Hanselmann
    self.assertRaises(errors.GenericError, utils.LoadSignedX509Certificate,
118 c50645c0 Michael Hanselmann
                      "X-Ganeti-Signature: $1234567890$abcdef\n", self.KEY)
119 c50645c0 Michael Hanselmann
    self.assertRaises(errors.GenericError, utils.LoadSignedX509Certificate,
120 c50645c0 Michael Hanselmann
                      "X-Ganeti-Signature: $1234$abc\n\n" + cert_pem, self.KEY)
121 c50645c0 Michael Hanselmann
122 c50645c0 Michael Hanselmann
    # Invalid salt
123 c50645c0 Michael Hanselmann
    for salt in list("-_@$,:;/\\ \t\n"):
124 c50645c0 Michael Hanselmann
      self.assertRaises(errors.GenericError, utils.SignX509Certificate,
125 c50645c0 Michael Hanselmann
                        cert_pem, self.KEY, "foo%sbar" % salt)
126 c50645c0 Michael Hanselmann
127 c50645c0 Michael Hanselmann
    for salt in ["HelloWorld", "salt", string.letters, string.digits,
128 c50645c0 Michael Hanselmann
                 utils.GenerateSecret(numbytes=4),
129 c50645c0 Michael Hanselmann
                 utils.GenerateSecret(numbytes=16),
130 c50645c0 Michael Hanselmann
                 "{123:456}".encode("hex")]:
131 c50645c0 Michael Hanselmann
      signed_pem = utils.SignX509Certificate(cert, self.KEY, salt)
132 c50645c0 Michael Hanselmann
133 c50645c0 Michael Hanselmann
      self._Check(cert, salt, signed_pem)
134 c50645c0 Michael Hanselmann
135 c50645c0 Michael Hanselmann
      self._Check(cert, salt, "X-Another-Header: with a value\n" + signed_pem)
136 c50645c0 Michael Hanselmann
      self._Check(cert, salt, (10 * "Hello World!\n") + signed_pem)
137 c50645c0 Michael Hanselmann
      self._Check(cert, salt, (signed_pem + "\n\na few more\n"
138 c50645c0 Michael Hanselmann
                               "lines----\n------ at\nthe end!"))
139 c50645c0 Michael Hanselmann
140 c50645c0 Michael Hanselmann
  def _Check(self, cert, salt, pem):
141 c50645c0 Michael Hanselmann
    (cert2, salt2) = utils.LoadSignedX509Certificate(pem, self.KEY)
142 c50645c0 Michael Hanselmann
    self.assertEqual(salt, salt2)
143 c50645c0 Michael Hanselmann
    self.assertEqual(cert.digest("sha1"), cert2.digest("sha1"))
144 c50645c0 Michael Hanselmann
145 c50645c0 Michael Hanselmann
    # Other key
146 c50645c0 Michael Hanselmann
    self.assertRaises(errors.GenericError, utils.LoadSignedX509Certificate,
147 c50645c0 Michael Hanselmann
                      pem, self.KEY_OTHER)
148 c50645c0 Michael Hanselmann
149 c50645c0 Michael Hanselmann
150 c50645c0 Michael Hanselmann
class TestCertVerification(testutils.GanetiTestCase):
151 c50645c0 Michael Hanselmann
  def setUp(self):
152 c50645c0 Michael Hanselmann
    testutils.GanetiTestCase.setUp(self)
153 c50645c0 Michael Hanselmann
154 c50645c0 Michael Hanselmann
    self.tmpdir = tempfile.mkdtemp()
155 c50645c0 Michael Hanselmann
156 c50645c0 Michael Hanselmann
  def tearDown(self):
157 c50645c0 Michael Hanselmann
    shutil.rmtree(self.tmpdir)
158 c50645c0 Michael Hanselmann
159 c50645c0 Michael Hanselmann
  def testVerifyCertificate(self):
160 c50645c0 Michael Hanselmann
    cert_pem = utils.ReadFile(self._TestDataFilename("cert1.pem"))
161 c50645c0 Michael Hanselmann
    cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
162 c50645c0 Michael Hanselmann
                                           cert_pem)
163 c50645c0 Michael Hanselmann
164 c50645c0 Michael Hanselmann
    # Not checking return value as this certificate is expired
165 c50645c0 Michael Hanselmann
    utils.VerifyX509Certificate(cert, 30, 7)
166 c50645c0 Michael Hanselmann
167 c50645c0 Michael Hanselmann
168 c50645c0 Michael Hanselmann
class TestVerifyCertificateInner(unittest.TestCase):
169 c50645c0 Michael Hanselmann
  def test(self):
170 c50645c0 Michael Hanselmann
    vci = utils.x509._VerifyCertificateInner
171 c50645c0 Michael Hanselmann
172 c50645c0 Michael Hanselmann
    # Valid
173 c50645c0 Michael Hanselmann
    self.assertEqual(vci(False, 1263916313, 1298476313, 1266940313, 30, 7),
174 c50645c0 Michael Hanselmann
                     (None, None))
175 c50645c0 Michael Hanselmann
176 c50645c0 Michael Hanselmann
    # Not yet valid
177 c50645c0 Michael Hanselmann
    (errcode, msg) = vci(False, 1266507600, 1267544400, 1266075600, 30, 7)
178 c50645c0 Michael Hanselmann
    self.assertEqual(errcode, utils.CERT_WARNING)
179 c50645c0 Michael Hanselmann
180 c50645c0 Michael Hanselmann
    # Expiring soon
181 c50645c0 Michael Hanselmann
    (errcode, msg) = vci(False, 1266507600, 1267544400, 1266939600, 30, 7)
182 c50645c0 Michael Hanselmann
    self.assertEqual(errcode, utils.CERT_ERROR)
183 c50645c0 Michael Hanselmann
184 c50645c0 Michael Hanselmann
    (errcode, msg) = vci(False, 1266507600, 1267544400, 1266939600, 30, 1)
185 c50645c0 Michael Hanselmann
    self.assertEqual(errcode, utils.CERT_WARNING)
186 c50645c0 Michael Hanselmann
187 c50645c0 Michael Hanselmann
    (errcode, msg) = vci(False, 1266507600, None, 1266939600, 30, 7)
188 c50645c0 Michael Hanselmann
    self.assertEqual(errcode, None)
189 c50645c0 Michael Hanselmann
190 c50645c0 Michael Hanselmann
    # Expired
191 c50645c0 Michael Hanselmann
    (errcode, msg) = vci(True, 1266507600, 1267544400, 1266939600, 30, 7)
192 c50645c0 Michael Hanselmann
    self.assertEqual(errcode, utils.CERT_ERROR)
193 c50645c0 Michael Hanselmann
194 c50645c0 Michael Hanselmann
    (errcode, msg) = vci(True, None, 1267544400, 1266939600, 30, 7)
195 c50645c0 Michael Hanselmann
    self.assertEqual(errcode, utils.CERT_ERROR)
196 c50645c0 Michael Hanselmann
197 c50645c0 Michael Hanselmann
    (errcode, msg) = vci(True, 1266507600, None, 1266939600, 30, 7)
198 c50645c0 Michael Hanselmann
    self.assertEqual(errcode, utils.CERT_ERROR)
199 c50645c0 Michael Hanselmann
200 c50645c0 Michael Hanselmann
    (errcode, msg) = vci(True, None, None, 1266939600, 30, 7)
201 c50645c0 Michael Hanselmann
    self.assertEqual(errcode, utils.CERT_ERROR)
202 c50645c0 Michael Hanselmann
203 c50645c0 Michael Hanselmann
204 c50645c0 Michael Hanselmann
class TestGenerateSelfSignedX509Cert(unittest.TestCase):
205 c50645c0 Michael Hanselmann
  def setUp(self):
206 c50645c0 Michael Hanselmann
    self.tmpdir = tempfile.mkdtemp()
207 c50645c0 Michael Hanselmann
208 c50645c0 Michael Hanselmann
  def tearDown(self):
209 c50645c0 Michael Hanselmann
    shutil.rmtree(self.tmpdir)
210 c50645c0 Michael Hanselmann
211 c50645c0 Michael Hanselmann
  def _checkRsaPrivateKey(self, key):
212 c50645c0 Michael Hanselmann
    lines = key.splitlines()
213 c50645c0 Michael Hanselmann
    return ("-----BEGIN RSA PRIVATE KEY-----" in lines and
214 c50645c0 Michael Hanselmann
            "-----END RSA PRIVATE KEY-----" in lines)
215 c50645c0 Michael Hanselmann
216 c50645c0 Michael Hanselmann
  def _checkCertificate(self, cert):
217 c50645c0 Michael Hanselmann
    lines = cert.splitlines()
218 c50645c0 Michael Hanselmann
    return ("-----BEGIN CERTIFICATE-----" in lines and
219 c50645c0 Michael Hanselmann
            "-----END CERTIFICATE-----" in lines)
220 c50645c0 Michael Hanselmann
221 c50645c0 Michael Hanselmann
  def test(self):
222 c50645c0 Michael Hanselmann
    for common_name in [None, ".", "Ganeti", "node1.example.com"]:
223 c50645c0 Michael Hanselmann
      (key_pem, cert_pem) = utils.GenerateSelfSignedX509Cert(common_name, 300)
224 c50645c0 Michael Hanselmann
      self._checkRsaPrivateKey(key_pem)
225 c50645c0 Michael Hanselmann
      self._checkCertificate(cert_pem)
226 c50645c0 Michael Hanselmann
227 c50645c0 Michael Hanselmann
      key = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM,
228 c50645c0 Michael Hanselmann
                                           key_pem)
229 c50645c0 Michael Hanselmann
      self.assert_(key.bits() >= 1024)
230 c50645c0 Michael Hanselmann
      self.assertEqual(key.bits(), constants.RSA_KEY_BITS)
231 c50645c0 Michael Hanselmann
      self.assertEqual(key.type(), OpenSSL.crypto.TYPE_RSA)
232 c50645c0 Michael Hanselmann
233 c50645c0 Michael Hanselmann
      x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
234 c50645c0 Michael Hanselmann
                                             cert_pem)
235 c50645c0 Michael Hanselmann
      self.failIf(x509.has_expired())
236 c50645c0 Michael Hanselmann
      self.assertEqual(x509.get_issuer().CN, common_name)
237 c50645c0 Michael Hanselmann
      self.assertEqual(x509.get_subject().CN, common_name)
238 c50645c0 Michael Hanselmann
      self.assertEqual(x509.get_pubkey().bits(), constants.RSA_KEY_BITS)
239 c50645c0 Michael Hanselmann
240 c50645c0 Michael Hanselmann
  def testLegacy(self):
241 c50645c0 Michael Hanselmann
    cert1_filename = os.path.join(self.tmpdir, "cert1.pem")
242 c50645c0 Michael Hanselmann
243 c50645c0 Michael Hanselmann
    utils.GenerateSelfSignedSslCert(cert1_filename, validity=1)
244 c50645c0 Michael Hanselmann
245 c50645c0 Michael Hanselmann
    cert1 = utils.ReadFile(cert1_filename)
246 c50645c0 Michael Hanselmann
247 c50645c0 Michael Hanselmann
    self.assert_(self._checkRsaPrivateKey(cert1))
248 c50645c0 Michael Hanselmann
    self.assert_(self._checkCertificate(cert1))
249 c50645c0 Michael Hanselmann
250 c50645c0 Michael Hanselmann
251 c50645c0 Michael Hanselmann
if __name__ == "__main__":
252 c50645c0 Michael Hanselmann
  testutils.GanetiTestProgram()