Search code examples
pythonpython-unittestpython-mock

Error while trying to mock X509 certificate in python unit test


I have a function, the job of which is to read the private key and certificate from a shared drive.

def get_private_key():
    with open(config.CERTIFICATE_PATH + config.PRIVATE_KEY, 'rb') as key_file, \
             open(config.CERTIFICATE_PATH + config.PUBLIC_KEY, 'rb') as cert_file_string:
        private_key = serialization.load_pem_private_key(key_file.read(), password=None, backend=default_backend())
        cert = load_certificate(FILETYPE_PEM, cert_file_string.read())
    sha1_fingerprint = cert.digest("sha1")
    strkid = sha1_fingerprint.decode()
    kid = strkid.replace(':', '')

I'm trying to write a unit test for this where I won't have access to the shared drive, hence I'm trying to mock the certificate and the private key. Here's what I've tried so far.

@patch('OpenSSL.crypto.load_certificate')
@patch('cryptography.hazmat.primitives.serialization.load_pem_private_key')
@patch('builtins.open')
def test_get_private_key(self, mock_open, mock_load_pem_private_key, mock_load_certificate)
    mock_open.return_value = io.BytesIO('dummy'.encode('utf-8'))
    mock_load_pem_private_key.return_value = MagicMock(cryptography.hazmat.backends.openssl.rsa.RSAPrivateKey)
    mock_load_certificate.return_value = MagicMock(crypto.X509)
    self.assertEqual(get_private_key(), "dummyPvtKey")

But when I try to run this test I get an error on the line where I'm invoking the load_certificate function.

OpenSSL.crypto.Error: [('PEM routines', 'get_name', 'no start line')]

It would be great if someone could advise me on how to go about this, thanks in advance.


Solution

  • Explanation

    You've patched the wrong target for the following line

    @patch('OpenSSL.crypto.load_certificate')
    

    Since you've imported load_certificate() and used it in your module where get_private_key() is, let's call it foo.py since you didn't provide it your post. We want to patch the load_certificate() in foo.py not where it's defined which is OpenSSL.crypto.

    Solution

    Change the patch target to

    @patch('foo.load_certificate')
    

    Resources