# coding: utf-8 from __future__ import unicode_literals, division, absolute_import, print_function import unittest import sys import os from asn1crypto import pem, util from .unittest_data import data_decorator, data from ._unittest_compat import patch patch() if sys.version_info < (3,): byte_cls = str num_cls = long # noqa else: byte_cls = bytes num_cls = int tests_root = os.path.dirname(__file__) fixtures_dir = os.path.join(tests_root, 'fixtures') @data_decorator class PEMTests(unittest.TestCase): @staticmethod def detect_files(): return ( ( 'keys/test-der.crt', False ), ( 'keys/test-inter-der.crt', False ), ( 'keys/test-third-der.crt', False ), ( 'keys/test.crt', True ), ( 'keys/test-inter.crt', True ), ( 'keys/test-third.crt', True ), ) @data('detect_files') def detect(self, relative_path, is_pem): with open(os.path.join(fixtures_dir, relative_path), 'rb') as f: byte_string = f.read() self.assertEqual(is_pem, pem.detect(byte_string)) @staticmethod def unarmor_armor_files(): return ( ( 'keys/test.crt', 'keys/test-der.crt', 'CERTIFICATE', {} ), ( 'keys/test-inter.crt', 'keys/test-inter-der.crt', 'CERTIFICATE', {} ), ( 'keys/test-third.crt', 'keys/test-third-der.crt', 'CERTIFICATE', {} ), ( 'keys/test-pkcs8.key', 'keys/test-pkcs8-der.key', 'PRIVATE KEY', {} ), ( 'test-third.csr', 'test-third-der.csr', 'CERTIFICATE REQUEST', {} ), ( 'keys/test-aes128.key', 'keys/test-aes128-der.key', 'RSA PRIVATE KEY', util.OrderedDict([ ('Proc-Type', '4,ENCRYPTED'), ('DEK-Info', 'AES-128-CBC,01F6EE04516C912788B11BD7377626C2') ]) ), ) @data('unarmor_armor_files') def unarmor(self, relative_path, expected_bytes_filename, expected_type_name, expected_headers): with open(os.path.join(fixtures_dir, relative_path), 'rb') as f: byte_string = f.read() type_name, headers, decoded_bytes = pem.unarmor(byte_string) self.assertEqual(expected_type_name, type_name) self.assertEqual(expected_headers, headers) with open(os.path.join(fixtures_dir, expected_bytes_filename), 'rb') as f: expected_bytes = f.read() self.assertEqual(expected_bytes, decoded_bytes) def test_unarmor_multiple(self): data = self.unarmor_armor_files() input_data = b'' der_data = [] for pem_file, der_file in ((data[0][0], data[0][1]), (data[1][0], data[1][1])): with open(os.path.join(fixtures_dir, pem_file), 'rb') as f: input_data += f.read() + b'\n' with open(os.path.join(fixtures_dir, der_file), 'rb') as f: der_data.append(f.read()) i = 0 for name, headers, der_bytes in pem.unarmor(input_data, True): self.assertEqual('CERTIFICATE', name) self.assertEqual({}, headers) self.assertEqual(der_data[i], der_bytes) i += 1 self.assertEqual(2, i) @data('unarmor_armor_files') def armor(self, expected_bytes_filename, relative_path, type_name, headers): with open(os.path.join(fixtures_dir, relative_path), 'rb') as f: byte_string = f.read() encoded_bytes = pem.armor(type_name, byte_string, headers=headers) with open(os.path.join(fixtures_dir, expected_bytes_filename), 'rb') as f: expected_bytes = f.read() # In case a user on Windows has CRLF translation on in Git. # Ran into this with the GitHub Actions Windows environments. expected_bytes = expected_bytes.replace(b'\r\n', b'\n') self.assertEqual(expected_bytes, encoded_bytes) def test_armor_wrong_type(self): with self.assertRaisesRegex(TypeError, 'type_name must be a unicode string'): pem.armor(b'CERTIFICATE', b'') def test_armor_wrong_type2(self): with self.assertRaisesRegex(TypeError, 'der_bytes must be a byte string'): pem.armor('CERTIFICATE', '') def test_detect_wrong_type(self): with self.assertRaisesRegex(TypeError, 'byte_string must be a byte string'): pem.detect('CERTIFICATE')