conftest.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. # pylint: disable=missing-docstring,invalid-name,redefined-outer-name
  2. import pytest
  3. from OpenSSL import crypto
  4. # Parameter list for valid_cert fixture
  5. VALID_CERTIFICATE_PARAMS = [
  6. {
  7. 'short_name': 'client',
  8. 'cn': 'client.example.com',
  9. 'serial': 4,
  10. 'uses': b'clientAuth',
  11. 'dns': [],
  12. 'ip': [],
  13. },
  14. {
  15. 'short_name': 'server',
  16. 'cn': 'server.example.com',
  17. 'serial': 5,
  18. 'uses': b'serverAuth',
  19. 'dns': ['kubernetes', 'openshift'],
  20. 'ip': ['10.0.0.1', '192.168.0.1']
  21. },
  22. {
  23. 'short_name': 'combined',
  24. 'cn': 'combined.example.com',
  25. # Verify that HUGE serials parse correctly.
  26. # Frobs PARSING_HEX_SERIAL in _parse_cert
  27. # See https://bugzilla.redhat.com/show_bug.cgi?id=1464240
  28. 'serial': 14449739080294792594019643629255165375,
  29. 'uses': b'clientAuth, serverAuth',
  30. 'dns': ['etcd'],
  31. 'ip': ['10.0.0.2', '192.168.0.2']
  32. }
  33. ]
  34. # Extract the short_name from VALID_CERTIFICATE_PARAMS to provide
  35. # friendly naming for the valid_cert fixture
  36. VALID_CERTIFICATE_IDS = [param['short_name'] for param in VALID_CERTIFICATE_PARAMS]
  37. @pytest.fixture(scope='session')
  38. def ca(tmpdir_factory):
  39. ca_dir = tmpdir_factory.mktemp('ca')
  40. key = crypto.PKey()
  41. key.generate_key(crypto.TYPE_RSA, 2048)
  42. cert = crypto.X509()
  43. cert.set_version(3)
  44. cert.set_serial_number(1)
  45. cert.get_subject().commonName = 'test-signer'
  46. cert.gmtime_adj_notBefore(0)
  47. cert.gmtime_adj_notAfter(24 * 60 * 60)
  48. cert.set_issuer(cert.get_subject())
  49. cert.set_pubkey(key)
  50. cert.add_extensions([
  51. crypto.X509Extension(b'basicConstraints', True, b'CA:TRUE, pathlen:0'),
  52. crypto.X509Extension(b'keyUsage', True,
  53. b'digitalSignature, keyEncipherment, keyCertSign, cRLSign'),
  54. crypto.X509Extension(b'subjectKeyIdentifier', False, b'hash', subject=cert)
  55. ])
  56. cert.add_extensions([
  57. crypto.X509Extension(b'authorityKeyIdentifier', False, b'keyid:always', issuer=cert)
  58. ])
  59. cert.sign(key, 'sha256')
  60. return {
  61. 'dir': ca_dir,
  62. 'key': key,
  63. 'cert': cert,
  64. }
  65. @pytest.fixture(scope='session',
  66. ids=VALID_CERTIFICATE_IDS,
  67. params=VALID_CERTIFICATE_PARAMS)
  68. def valid_cert(request, ca):
  69. common_name = request.param['cn']
  70. key = crypto.PKey()
  71. key.generate_key(crypto.TYPE_RSA, 2048)
  72. cert = crypto.X509()
  73. cert.set_serial_number(request.param['serial'])
  74. cert.gmtime_adj_notBefore(0)
  75. cert.gmtime_adj_notAfter(24 * 60 * 60)
  76. cert.set_issuer(ca['cert'].get_subject())
  77. cert.set_pubkey(key)
  78. cert.set_version(3)
  79. cert.get_subject().commonName = common_name
  80. cert.add_extensions([
  81. crypto.X509Extension(b'basicConstraints', True, b'CA:FALSE'),
  82. crypto.X509Extension(b'keyUsage', True, b'digitalSignature, keyEncipherment'),
  83. crypto.X509Extension(b'extendedKeyUsage', False, request.param['uses']),
  84. ])
  85. if request.param['dns'] or request.param['ip']:
  86. san_list = ['DNS:{}'.format(common_name)]
  87. san_list.extend(['DNS:{}'.format(x) for x in request.param['dns']])
  88. san_list.extend(['IP:{}'.format(x) for x in request.param['ip']])
  89. cert.add_extensions([
  90. crypto.X509Extension(b'subjectAltName', False, ', '.join(san_list).encode('utf8'))
  91. ])
  92. cert.sign(ca['key'], 'sha256')
  93. cert_contents = crypto.dump_certificate(crypto.FILETYPE_PEM, cert)
  94. cert_file = ca['dir'].join('{}.crt'.format(common_name))
  95. cert_file.write_binary(cert_contents)
  96. return {
  97. 'common_name': common_name,
  98. 'serial': request.param['serial'],
  99. 'dns': request.param['dns'],
  100. 'ip': request.param['ip'],
  101. 'uses': request.param['uses'],
  102. 'cert_file': cert_file,
  103. 'cert': cert
  104. }