Merge branch 'crypto_util_test' of git://github.com/kuba/lets-encrypt-preview into kuba-crypto_util_test

This commit is contained in:
James Kasten 2014-12-14 04:24:28 -08:00
commit 24a8c3dd40
13 changed files with 361 additions and 123 deletions

View file

@ -118,11 +118,6 @@ class Client(object):
# Make sure we have key and csr to perform challenges
self.init_key_csr()
# TODO: Handle this exception/problem
if not crypto_util.csr_matches_names(self.csr.data, self.names):
raise errors.LetsEncryptClientError(
"CSR subject does not contain one of the specified names")
# Perform Challenges
responses, challenge_objs = self.verify_identity(challenge_msg)
# Get Authorization

View file

@ -1,6 +1,5 @@
"""Let's Encrypt client crypto utility functions"""
import binascii
import hashlib
import logging
import time
@ -15,13 +14,6 @@ from letsencrypt.client import CONFIG
from letsencrypt.client import le_util
# TODO: All of these functions need unit tests
def b64_cert_to_pem(b64_der_cert):
return M2Crypto.X509.load_cert_der_string(
le_util.jose_b64decode(b64_der_cert)).as_pem()
def create_sig(msg, key_str, nonce=None, nonce_len=CONFIG.NONCE_SIZE):
"""Create signature with nonce prepended to the message.
@ -76,27 +68,15 @@ def leading_zeros(arg):
return arg
def sha256(arg):
return hashlib.sha256(arg).hexdigest()
# based on M2Crypto unit test written by Toby Allsopp
def make_key(bits=CONFIG.RSA_KEY_SIZE):
"""
Returns new RSA key in PEM form with specified bits
"""
# Python Crypto module doesn't produce any stdout
key = Crypto.PublicKey.RSA.generate(bits)
# rsa = M2Crypto.RSA.gen_key(bits, 65537)
# key_pem = rsa.as_pem(cipher=None)
# rsa = None # should not be freed here
return key.exportKey(format='PEM')
def make_csr(key_str, domains):
"""
Returns new CSR in PEM and DER form using key_file containing all domains
"""Generate a CSR.
:param str key_str: RSA key.
:param list domains: Domains included in the certificate.
:returns: new CSR in PEM and DER form containing all domains
:rtype: tuple
"""
assert domains, "Must provide one or more hostnames for the CSR."
rsa_key = M2Crypto.RSA.load_key_string(key_str)
@ -115,7 +95,7 @@ def make_csr(key_str, domains):
extstack = M2Crypto.X509.X509_Extension_Stack()
ext = M2Crypto.X509.new_extension(
'subjectAltName', ", ".join(["DNS:%s" % d for d in domains]))
'subjectAltName', ", ".join("DNS:%s" % d for d in domains))
extstack.push(ext)
csr.add_extensions(extstack)
@ -126,10 +106,82 @@ def make_csr(key_str, domains):
return csr.as_pem(), csr.as_der()
def make_ss_cert(key_str, domains):
# WARNING: the csr and private key file are possible attack vectors for TOCTOU
# We should either...
# A. Do more checks to verify that the CSR is trusted/valid
# B. Audit the parsing code for vulnerabilities
def valid_csr(csr):
"""Validate CSR.
Check if `csr` is a valid CSR for the given domains.
:param str csr: CSR in PEM.
:returns: Validity of CSR.
:rtype: bool
"""
try:
csr_obj = M2Crypto.X509.load_request_string(csr)
return bool(csr_obj.verify(csr_obj.get_pubkey()))
except M2Crypto.X509.X509Error:
return False
def csr_matches_pubkey(csr, privkey):
"""Does private key correspond to the subject public key in the CSR?
:param str csr: CSR in PEM.
:param str privkey: Private key file contents
:returns: Correspondence of private key to CSR subject public key.
:rtype: bool
"""
csr_obj = M2Crypto.X509.load_request_string(csr)
privkey_obj = M2Crypto.RSA.load_key_string(privkey)
return csr_obj.get_pubkey().get_rsa().pub() == privkey_obj.pub()
# based on M2Crypto unit test written by Toby Allsopp
def make_key(bits=CONFIG.RSA_KEY_SIZE):
"""Generate PEM encoded RSA key.
:param int bits: Number of bits, at least 1024.
:returns: new RSA key in PEM form with specified number of bits
:rtype: str
"""
# rsa = M2Crypto.RSA.gen_key(bits, 65537)
# key_pem = rsa.as_pem(cipher=None)
# rsa = None # should not be freed here
# Python Crypto module doesn't produce any stdout
return Crypto.PublicKey.RSA.generate(bits).exportKey(format='PEM')
def valid_privkey(privkey):
"""Is valid RSA private key?
:param str privkey: Private key file contents
:returns: Validity of private key.
:rtype: bool
"""
try:
return bool(M2Crypto.RSA.load_key_string(privkey).check_key())
except M2Crypto.RSA.RSAError:
return False
def make_ss_cert(key_str, domains, not_before=None,
validity=(7 * 24 * 60 * 60)):
"""Returns new self-signed cert in PEM form.
Uses key_str and contains all domains.
"""
assert domains, "Must provide one or more hostnames for the CSR."
@ -142,11 +194,11 @@ def make_ss_cert(key_str, domains):
cert.set_serial_number(1337)
cert.set_version(2)
current_ts = long(time.time())
current_ts = long(time.time() if not_before is None else not_before)
current = M2Crypto.ASN1.ASN1_UTCTIME()
current.set_time(current_ts)
expire = M2Crypto.ASN1.ASN1_UTCTIME()
expire.set_time((7 * 24 * 60 * 60) + current_ts)
expire.set_time(current_ts + validity)
cert.set_not_before(current)
cert.set_not_after(expire)
@ -158,11 +210,13 @@ def make_ss_cert(key_str, domains):
subject.CN = domains[0]
cert.set_issuer(cert.get_subject())
cert.add_ext(M2Crypto.X509.new_extension('basicConstraints', 'CA:FALSE'))
# cert.add_ext(M2Crypto.X509.new_extension(
# 'extendedKeyUsage', 'TLS Web Server Authentication'))
cert.add_ext(M2Crypto.X509.new_extension(
'subjectAltName', ", ".join(["DNS:%s" % d for d in domains])))
if len(domains) > 1:
cert.add_ext(M2Crypto.X509.new_extension(
'basicConstraints', 'CA:FALSE'))
# cert.add_ext(M2Crypto.X509.new_extension(
# 'extendedKeyUsage', 'TLS Web Server Authentication'))
cert.add_ext(M2Crypto.X509.new_extension(
'subjectAltName', ", ".join(["DNS:%s" % d for d in domains])))
cert.sign(pubkey, 'sha256')
assert cert.verify(pubkey)
@ -200,75 +254,6 @@ def get_cert_info(filename):
}
# WARNING: the csr and private key file are possible attack vectors for TOCTOU
# We should either...
# A. Do more checks to verify that the CSR is trusted/valid
# B. Audit the parsing code for vulnerabilities
def valid_csr(csr):
"""Validate CSR.
Check if `csr` is a valid CSR for the given domains.
:param str csr: CSR file contents
:returns: Validity of CSR.
:rtype: bool
"""
try:
csr_obj = M2Crypto.X509.load_request_string(csr)
return bool(csr_obj.verify(csr_obj.get_pubkey()))
except M2Crypto.X509.X509Error:
return False
def csr_matches_names(csr, domains):
"""Check if CSR contains the subject of one of the domains.
M2Crypto currently does not expose the OpenSSL interface to
also check the SAN extension. This is insufficient for full testing
:param str csr: CSR file contents
:param list domains: Domains the CSR should contain.
:returns: If the CSR subject contains one of the domains
:rtype: bool
"""
try:
csr_obj = M2Crypto.X509.load_request_der_string(csr)
return csr_obj.get_subject().CN in domains
except M2Crypto.X509.X509Error:
return False
def valid_privkey(privkey):
"""Is valid RSA private key?
:param str privkey: Private key file contents
:returns: Validity of private key.
:rtype: bool
"""
try:
return bool(M2Crypto.RSA.load_key_string(privkey).check_key())
except M2Crypto.RSA.RSAError:
return False
def csr_matches_pubkey(csr, privkey):
"""Does private key correspond to the subject public key in the CSR?
:param str csr: CSR file contents
:param str privkey: Private key file contents
:returns: Correspondence of private key to CSR subject public key.
:rtype: bool
"""
csr_obj = M2Crypto.X509.load_request_string(csr)
privkey_obj = M2Crypto.RSA.load_key_string(privkey)
return csr_obj.get_pubkey().get_rsa().pub() == privkey_obj.pub()
def b64_cert_to_pem(b64_der_cert):
return M2Crypto.X509.load_cert_der_string(
le_util.jose_b64decode(b64_der_cert)).as_pem()

View file

@ -1,4 +1,5 @@
"""Tests for letsencrypt.client.acme."""
import pkg_resources
import unittest
import jsonschema
@ -58,15 +59,8 @@ class MessageFactoriesTest(unittest.TestCase):
"""Tests for ACME message factories from letsencrypt.client.acme."""
def setUp(self):
self.privkey = """-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBAKx1c7RR7R/drnBSQ/zfx1vQLHUbFLh1AQQQ5R8DZUXd36efNK79
vukFhN9HFoHZiUvOjm0c+pVE6K+EdE/twuUCAwEAAQJAMbrEnJCrQe8YqAbw1/Bn
elAzIamndfE3U8bTavf9sgFpS4HL83rhd6PDbvx81ucaJAT/5x048fM/nFl4fzAc
mQIhAOF/a9o3EIsDKEmUl+Z1OaOiUxDF3kqWSmALEsmvDhwXAiEAw8ljV5RO/rUp
Zu2YMDFq3MKpyyMgBIJ8CxmGRc6gCmMCIGRQzkcmhfqBrhOFwkmozrqIBRIKJIjj
8TRm2LXWZZ2DAiAqVO7PztdNpynugUy4jtbGKKjBrTSNBRGA7OHlUgm0dQIhALQq
6oGU29Vxlvt3k0vmiRKU4AVfLyNXIGtcWcNG46h/
-----END RSA PRIVATE KEY-----"""
self.privkey = pkg_resources.resource_string(
__name__, 'testdata/rsa256_key.pem')
self.nonce = '\xec\xd6\xf2oYH\xeb\x13\xd5#q\xe0\xdd\xa2\x92\xa9'
self.b64nonce = '7Nbyb1lI6xPVI3Hg3aKSqQ'

View file

@ -0,0 +1,198 @@
"""Tests for letsencrypt.client.crypto_util."""
import datetime
import os
import pkg_resources
import unittest
import M2Crypto
RSA256_KEY = pkg_resources.resource_string(__name__, 'testdata/rsa256_key.pem')
RSA512_KEY = pkg_resources.resource_string(__name__, 'testdata/rsa512_key.pem')
class CreateSigTest(unittest.TestCase):
"""Tests for letsencrypt.client.crypto_util.create_sig."""
def setUp(self):
self.nonce = '\xec\xd6\xf2oYH\xeb\x13\xd5#q\xe0\xdd\xa2\x92\xa9'
self.b64nonce = '7Nbyb1lI6xPVI3Hg3aKSqQ'
self.signature = {
'nonce': self.b64nonce,
'alg': 'RS256',
'jwk': {
'kty': 'RSA',
'e': 'AQAB',
'n': 'rHVztFHtH92ucFJD_N_HW9AsdRsUuHUBBBDlHwNlRd3fp5'
'80rv2-6QWE30cWgdmJS86ObRz6lUTor4R0T-3C5Q',
},
'sig': 'SUPYKucUnhlTt8_sMxLiigOYdf_wlOLXPI-o7aRLTsOquVjDd6r'
'AX9AFJHk-bCMQPJbSzXKjG6H1IWbvxjS2Ew',
}
def _call(self, *args, **kwargs):
from letsencrypt.client.crypto_util import create_sig
return create_sig(*args, **kwargs)
def test_it(self):
self.assertEqual(
self._call('message', RSA256_KEY, self.nonce), self.signature)
def test_random_nonce(self):
signature = self._call('message', RSA256_KEY)
signature.pop('sig')
signature.pop('nonce')
del self.signature['sig']
del self.signature['nonce']
self.assertEqual(signature, self.signature)
class MakeCSRTest(unittest.TestCase):
"""Tests for letsencrypt.client.crypto_util.make_csr."""
def test_single_domain(self):
from letsencrypt.client.crypto_util import make_csr
pem, der = make_csr(RSA256_KEY, ['example.com'])
self.assertEqual(pem, pkg_resources.resource_string(
__name__, 'testdata/csr.pem'))
self.assertEqual(der, pkg_resources.resource_string(
__name__, 'testdata/csr.der'))
def test_san(self):
from letsencrypt.client.crypto_util import make_csr
pem, der = make_csr(RSA256_KEY, ['example.com', 'www.example.com'])
self.assertEqual(pem, pkg_resources.resource_string(
__name__, 'testdata/csr-san.pem'))
self.assertEqual(der, pkg_resources.resource_string(
__name__, 'testdata/csr-san.der'))
class ValidCSRTest(unittest.TestCase):
"""Tests for letsencrypt.client.crypto_util.valid_csr."""
def _call(self, csr):
from letsencrypt.client.crypto_util import valid_csr
return valid_csr(csr)
def _call_testdata(self, name):
return self._call(pkg_resources.resource_string(
__name__, os.path.join('testdata', name)))
def test_valid_pem_true(self):
self.assertTrue(self._call_testdata('csr.pem'))
def test_valid_pem_san_true(self):
self.assertTrue(self._call_testdata('csr-san.pem'))
def test_valid_der_false(self):
self.assertFalse(self._call_testdata('csr.der'))
def test_valid_der_san_false(self):
self.assertFalse(self._call_testdata('csr-san.der'))
def test_empty_false(self):
self.assertFalse(self._call(''))
def test_random_false(self):
self.assertFalse(self._call('foo bar'))
class CSRMatchesPubkeyTest(unittest.TestCase):
"""Tests for letsencrypt.client.crypto_util.csr_matches_pubkey."""
def _call_testdata(self, name, privkey):
from letsencrypt.client.crypto_util import csr_matches_pubkey
return csr_matches_pubkey(pkg_resources.resource_string(
__name__, os.path.join('testdata', name)), privkey)
def test_valid_true(self):
self.assertTrue(self._call_testdata('csr.pem', RSA256_KEY))
def test_invalid_false(self):
self.assertFalse(self._call_testdata('csr.pem', RSA512_KEY))
class MakeKeyTest(unittest.TestCase):
"""Tests for letsencrypt.client.crypto_util.make_key."""
def test_it(self):
from letsencrypt.client.crypto_util import make_key
M2Crypto.RSA.load_key_string(make_key(1024))
class ValidPrivkeyTest(unittest.TestCase):
"""Tests for letsencrypt.client.crypto_util.valid_privkey."""
def _call(self, privkey):
from letsencrypt.client.crypto_util import valid_privkey
return valid_privkey(privkey)
def test_valid_true(self):
self.assertTrue(self._call(RSA256_KEY))
def test_empty_false(self):
self.assertFalse(self._call(''))
def test_random_false(self):
self.assertFalse(self._call('foo bar'))
class MakeSSCertTest(unittest.TestCase):
"""Tests for letsencrypt.client.crypto_util.make_ss_cert."""
def test_it(self):
from letsencrypt.client.crypto_util import make_ss_cert
make_ss_cert(RSA256_KEY, ['example.com', 'www.example.com'])
class GetCertInfoTest(unittest.TestCase):
"""Tests for letsencrypt.client.crypto_util.get_cert_info."""
def setUp(self):
self.cert_info = {
'not_before': datetime.datetime(
2014, 12, 11, 22, 34, 45, tzinfo=M2Crypto.ASN1.UTC),
'not_after': datetime.datetime(
2014, 12, 18, 22, 34, 45, tzinfo=M2Crypto.ASN1.UTC),
'subject': 'C=US, ST=Michigan, L=Ann Arbor, O=University '
'of Michigan and the EFF, CN=example.com',
'cn': 'example.com',
'issuer': 'C=US, ST=Michigan, L=Ann Arbor, O=University '
'of Michigan and the EFF, CN=example.com',
'serial': 1337L,
'pub_key': 'RSA 512',
}
def _call(self, name):
from letsencrypt.client.crypto_util import get_cert_info
self.assertEqual(get_cert_info(pkg_resources.resource_filename(
__name__, os.path.join('testdata', name))), self.cert_info)
def test_single_domain(self):
self.cert_info.update({
'san': '',
'fingerprint': '9F8CE01450D288467C3326AC0457E351939C72E',
})
self._call('cert.pem')
def test_san(self):
self.cert_info.update({
'san': 'DNS:example.com, DNS:www.example.com',
'fingerprint': '62F7110431B8E8F55905DBE5592518F9634AC50A',
})
self._call('cert-san.pem')
class B64CertToPEMTest(unittest.TestCase):
"""Tests for letsencrypt.client.crypto_util.b64_cert_to_pem."""
def test_it(self):
from letsencrypt.client.crypto_util import b64_cert_to_pem
self.assertEqual(
b64_cert_to_pem(pkg_resources.resource_string(
__name__, 'testdata/cert.b64jose')),
pkg_resources.resource_string(__name__, 'testdata/cert.pem'))
if __name__ == '__main__':
unittest.main()

View file

@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICFjCCAcCgAwIBAgICBTkwDQYJKoZIhvcNAQELBQAwdzELMAkGA1UEBhMCVVMx
ETAPBgNVBAgMCE1pY2hpZ2FuMRIwEAYDVQQHDAlBbm4gQXJib3IxKzApBgNVBAoM
IlVuaXZlcnNpdHkgb2YgTWljaGlnYW4gYW5kIHRoZSBFRkYxFDASBgNVBAMMC2V4
YW1wbGUuY29tMB4XDTE0MTIxMTIyMzQ0NVoXDTE0MTIxODIyMzQ0NVowdzELMAkG
A1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIwEAYDVQQHDAlBbm4gQXJib3Ix
KzApBgNVBAoMIlVuaXZlcnNpdHkgb2YgTWljaGlnYW4gYW5kIHRoZSBFRkYxFDAS
BgNVBAMMC2V4YW1wbGUuY29tMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKx1c7RR
7R/drnBSQ/zfx1vQLHUbFLh1AQQQ5R8DZUXd36efNK79vukFhN9HFoHZiUvOjm0c
+pVE6K+EdE/twuUCAwEAAaM2MDQwCQYDVR0TBAIwADAnBgNVHREEIDAeggtleGFt
cGxlLmNvbYIPd3d3LmV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA0EASuvNKFTF
nTJsvnSXn52f4BMZJJ2id/kW7+r+FJRm+L20gKQ1aqq8d3e/lzRUrv5SMf1TAOe7
RDjyGMKy5ZgM2w==
-----END CERTIFICATE-----

View file

@ -0,0 +1 @@
MIIB3jCCAYigAwIBAgICBTkwDQYJKoZIhvcNAQELBQAwdzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIwEAYDVQQHDAlBbm4gQXJib3IxKzApBgNVBAoMIlVuaXZlcnNpdHkgb2YgTWljaGlnYW4gYW5kIHRoZSBFRkYxFDASBgNVBAMMC2V4YW1wbGUuY29tMB4XDTE0MTIxMTIyMzQ0NVoXDTE0MTIxODIyMzQ0NVowdzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIwEAYDVQQHDAlBbm4gQXJib3IxKzApBgNVBAoMIlVuaXZlcnNpdHkgb2YgTWljaGlnYW4gYW5kIHRoZSBFRkYxFDASBgNVBAMMC2V4YW1wbGUuY29tMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKx1c7RR7R_drnBSQ_zfx1vQLHUbFLh1AQQQ5R8DZUXd36efNK79vukFhN9HFoHZiUvOjm0c-pVE6K-EdE_twuUCAwEAATANBgkqhkiG9w0BAQsFAANBAC24z0IdwIVKSlntksllvr6zJepBH5fMndfk3XJp10jT6VE-14KNtjh02a56GoraAvJAT5_H67E8GvJ_ocNnB_o

View file

@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE-----
MIIB3jCCAYigAwIBAgICBTkwDQYJKoZIhvcNAQELBQAwdzELMAkGA1UEBhMCVVMx
ETAPBgNVBAgMCE1pY2hpZ2FuMRIwEAYDVQQHDAlBbm4gQXJib3IxKzApBgNVBAoM
IlVuaXZlcnNpdHkgb2YgTWljaGlnYW4gYW5kIHRoZSBFRkYxFDASBgNVBAMMC2V4
YW1wbGUuY29tMB4XDTE0MTIxMTIyMzQ0NVoXDTE0MTIxODIyMzQ0NVowdzELMAkG
A1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIwEAYDVQQHDAlBbm4gQXJib3Ix
KzApBgNVBAoMIlVuaXZlcnNpdHkgb2YgTWljaGlnYW4gYW5kIHRoZSBFRkYxFDAS
BgNVBAMMC2V4YW1wbGUuY29tMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKx1c7RR
7R/drnBSQ/zfx1vQLHUbFLh1AQQQ5R8DZUXd36efNK79vukFhN9HFoHZiUvOjm0c
+pVE6K+EdE/twuUCAwEAATANBgkqhkiG9w0BAQsFAANBAC24z0IdwIVKSlntksll
vr6zJepBH5fMndfk3XJp10jT6VE+14KNtjh02a56GoraAvJAT5/H67E8GvJ/ocNn
B/o=
-----END CERTIFICATE-----

Binary file not shown.

View file

@ -0,0 +1,10 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIBbjCCARgCAQAweTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIw
EAYDVQQHDAlBbm4gQXJib3IxDDAKBgNVBAoMA0VGRjEfMB0GA1UECwwWVW5pdmVy
c2l0eSBvZiBNaWNoaWdhbjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wXDANBgkqhkiG
9w0BAQEFAANLADBIAkEArHVztFHtH92ucFJD/N/HW9AsdRsUuHUBBBDlHwNlRd3f
p580rv2+6QWE30cWgdmJS86ObRz6lUTor4R0T+3C5QIDAQABoDowOAYJKoZIhvcN
AQkOMSswKTAnBgNVHREEIDAeggtleGFtcGxlLmNvbYIPd3d3LmV4YW1wbGUuY29t
MA0GCSqGSIb3DQEBCwUAA0EAZGBM8J1rRs7onFgtc76mOeoT1c3v0ZsEmxQfb2Wy
tmReY6X1N4cs38D9VSow+VMRu2LWkKvzS7RUFSaTaeQz1A==
-----END CERTIFICATE REQUEST-----

Binary file not shown.

View file

@ -0,0 +1,10 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIBXTCCAQcCAQAweTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE1pY2hpZ2FuMRIw
EAYDVQQHDAlBbm4gQXJib3IxDDAKBgNVBAoMA0VGRjEfMB0GA1UECwwWVW5pdmVy
c2l0eSBvZiBNaWNoaWdhbjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wXDANBgkqhkiG
9w0BAQEFAANLADBIAkEArHVztFHtH92ucFJD/N/HW9AsdRsUuHUBBBDlHwNlRd3f
p580rv2+6QWE30cWgdmJS86ObRz6lUTor4R0T+3C5QIDAQABoCkwJwYJKoZIhvcN
AQkOMRowGDAWBgNVHREEDzANggtleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAANB
AHJH/O6BtC9aGzEVCMGOZ7z9iIRHWSzr9x/bOzn7hLwsbXPAgO1QxEwL+X+4g20G
n9XBE1N9W6HCIEut2d8wACg=
-----END CERTIFICATE REQUEST-----

View file

@ -0,0 +1,9 @@
-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBAKx1c7RR7R/drnBSQ/zfx1vQLHUbFLh1AQQQ5R8DZUXd36efNK79
vukFhN9HFoHZiUvOjm0c+pVE6K+EdE/twuUCAwEAAQJAMbrEnJCrQe8YqAbw1/Bn
elAzIamndfE3U8bTavf9sgFpS4HL83rhd6PDbvx81ucaJAT/5x048fM/nFl4fzAc
mQIhAOF/a9o3EIsDKEmUl+Z1OaOiUxDF3kqWSmALEsmvDhwXAiEAw8ljV5RO/rUp
Zu2YMDFq3MKpyyMgBIJ8CxmGRc6gCmMCIGRQzkcmhfqBrhOFwkmozrqIBRIKJIjj
8TRm2LXWZZ2DAiAqVO7PztdNpynugUy4jtbGKKjBrTSNBRGA7OHlUgm0dQIhALQq
6oGU29Vxlvt3k0vmiRKU4AVfLyNXIGtcWcNG46h/
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1,9 @@
-----BEGIN RSA PRIVATE KEY-----
MIIBOwIBAAJBAPS2EXFRNza/qpXnnBHF/CcFQ543htV+7nLAmrLrmTNHtPXJmLlM
8SJDIzv/ceAFXL110VzxFfi81lpH5E5c0TMCAwEAAQJBALmppYQ/JVARjWBcsEm/
1/bXBJ127YLv4gQIY5baL4r6IdEE33OXMTTmD9wf+ajuq1eaH0htHkwhOvREu0sz
bskCIQD/Cg+xhEVLcwK3pFp3afPIhj1IPFiL3Uy/nqyMZ6O/RQIhAPWiDBofp7Cp
J4dGZs+hkRySq/IOeeRJlNK1Pq64nToXAiBZ7+te1100YSd5KT051SRB94zO13EG
SZESFduVW8rz3QIgK+tLiqg6TYYRQUi/PUTAM4GuKNuZw828RGiPyqHLywUCIQCd
pkZrNphL/y0D7HSbPIfZzD90M2V8tUjlK0BTqk1bHA==
-----END RSA PRIVATE KEY-----