diff --git a/salt/modules/x509.py b/salt/modules/x509.py index 153ba0ebe6..73da9530cf 100644 --- a/salt/modules/x509.py +++ b/salt/modules/x509.py @@ -131,6 +131,10 @@ def _new_extension(name, value, critical=0, issuer=None, _pyfree=1): raise salt.exceptions.SaltInvocationError( 'value must be precomputed hash') + # ensure name and value are bytes + name = salt.utils.stringutils.to_bytes(name) + value = salt.utils.stringutils.to_bytes(value) + try: ctx = M2Crypto.m2.x509v3_set_nconf() _fix_ctx(ctx, issuer) @@ -316,7 +320,7 @@ def _text_or_file(input_): ''' if os.path.isfile(input_): with salt.utils.files.fopen(input_) as fp_: - return salt.utils.stringutils.to_unicode(fp_.read()) + return salt.utils.stringutils.to_bytes(fp_.read()) else: return input_ @@ -493,7 +497,7 @@ def get_pem_entry(text, pem_type=None): ret += pem_body[i:i + 64] + '\n' ret += pem_footer + '\n' - return ret + return ret.encode('ascii') def get_pem_entries(glob_path): diff --git a/salt/states/x509.py b/salt/states/x509.py index e8ba08905b..b2de03d281 100644 --- a/salt/states/x509.py +++ b/salt/states/x509.py @@ -310,7 +310,7 @@ def private_key_managed(name, ret = __states__['file.managed'](**file_args) if ret['changes'] and new_key: - ret['changes'] = 'New private key generated' + ret['changes'] = {'new': 'New private key generated'} return ret diff --git a/tests/unit/modules/test_x509.py b/tests/unit/modules/test_x509.py index edafe4ff44..a56cc4a9da 100644 --- a/tests/unit/modules/test_x509.py +++ b/tests/unit/modules/test_x509.py @@ -34,6 +34,12 @@ from tests.support.mock import ( from salt.modules import x509 +try: + import M2Crypto # pylint: disable=unused-import + HAS_M2CRYPTO = True +except ImportError: + HAS_M2CRYPTO = False + @skipIf(NO_MOCK, NO_MOCK_REASON) @skipIf(not bool(pytest), False) @@ -65,3 +71,96 @@ class X509TestCase(TestCase, LoaderModuleMockMixin): assert x509.log.trace.call_args[0][0] == "Missing attribute '%s'. Error: %s" assert x509.log.trace.call_args[0][1] == list(subj.nid.keys())[0] assert isinstance(x509.log.trace.call_args[0][2], TypeError) + + @skipIf(not HAS_M2CRYPTO, 'Skipping, M2Crypt is unavailble') + def test_get_pem_entry(self): + ''' + Test private function _parse_subject(subject) it handles a missing fields + :return: + ''' + ca_key = '''-----BEGIN RSA PRIVATE KEY----- +MIICWwIBAAKBgQCjdjbgL4kQ8Lu73xeRRM1q3C3K3ptfCLpyfw38LRnymxaoJ6ls +pNSx2dU1uJ89YKFlYLo1QcEk4rJ2fdIjarV0kuNCY3rC8jYUp9BpAU5Z6p9HKeT1 +2rTPH81JyjbQDR5PyfCyzYOQtpwpB4zIUUK/Go7tTm409xGKbbUFugJNgQIDAQAB +AoGAF24we34U1ZrMLifSRv5nu3OIFNZHyx2DLDpOFOGaII5edwgIXwxZeIzS5Ppr +yO568/8jcdLVDqZ4EkgCwRTgoXRq3a1GLHGFmBdDNvWjSTTMLoozuM0t2zjRmIsH +hUd7tnai9Lf1Bp5HlBEhBU2gZWk+SXqLvxXe74/+BDAj7gECQQDRw1OPsrgTvs3R +3MNwX6W8+iBYMTGjn6f/6rvEzUs/k6rwJluV7n8ISNUIAxoPy5g5vEYK6Ln/Ttc7 +u0K1KNlRAkEAx34qcxjuswavL3biNGE+8LpDJnJx1jaNWoH+ObuzYCCVMusdT2gy +kKuq9ytTDgXd2qwZpIDNmscvReFy10glMQJAXebMz3U4Bk7SIHJtYy7OKQzn0dMj +35WnRV81c2Jbnzhhu2PQeAvt/i1sgEuzLQL9QEtSJ6wLJ4mJvImV0TdaIQJAAYyk +TcKK0A8kOy0kMp3yvDHmJZ1L7wr7bBGIZPBlQ0Ddh8i1sJExm1gJ+uN2QKyg/XrK +tDFf52zWnCdVGgDwcQJALW/WcbSEK+JVV6KDJYpwCzWpKIKpBI0F6fdCr1G7Xcwj +c9bcgp7D7xD+TxWWNj4CSXEccJgGr91StV+gFg4ARQ== +-----END RSA PRIVATE KEY----- +''' + + ret = x509.get_pem_entry(ca_key) + self.assertEqual(ret, ca_key) + + @skipIf(not HAS_M2CRYPTO, 'Skipping, M2Crypt is unavailble') + def test_get_private_key_size(self): + ''' + Test private function _parse_subject(subject) it handles a missing fields + :return: + ''' + ca_key = ''' +-----BEGIN RSA PRIVATE KEY----- +MIICWwIBAAKBgQCjdjbgL4kQ8Lu73xeRRM1q3C3K3ptfCLpyfw38LRnymxaoJ6ls +pNSx2dU1uJ89YKFlYLo1QcEk4rJ2fdIjarV0kuNCY3rC8jYUp9BpAU5Z6p9HKeT1 +2rTPH81JyjbQDR5PyfCyzYOQtpwpB4zIUUK/Go7tTm409xGKbbUFugJNgQIDAQAB +AoGAF24we34U1ZrMLifSRv5nu3OIFNZHyx2DLDpOFOGaII5edwgIXwxZeIzS5Ppr +yO568/8jcdLVDqZ4EkgCwRTgoXRq3a1GLHGFmBdDNvWjSTTMLoozuM0t2zjRmIsH +hUd7tnai9Lf1Bp5HlBEhBU2gZWk+SXqLvxXe74/+BDAj7gECQQDRw1OPsrgTvs3R +3MNwX6W8+iBYMTGjn6f/6rvEzUs/k6rwJluV7n8ISNUIAxoPy5g5vEYK6Ln/Ttc7 +u0K1KNlRAkEAx34qcxjuswavL3biNGE+8LpDJnJx1jaNWoH+ObuzYCCVMusdT2gy +kKuq9ytTDgXd2qwZpIDNmscvReFy10glMQJAXebMz3U4Bk7SIHJtYy7OKQzn0dMj +35WnRV81c2Jbnzhhu2PQeAvt/i1sgEuzLQL9QEtSJ6wLJ4mJvImV0TdaIQJAAYyk +TcKK0A8kOy0kMp3yvDHmJZ1L7wr7bBGIZPBlQ0Ddh8i1sJExm1gJ+uN2QKyg/XrK +tDFf52zWnCdVGgDwcQJALW/WcbSEK+JVV6KDJYpwCzWpKIKpBI0F6fdCr1G7Xcwj +c9bcgp7D7xD+TxWWNj4CSXEccJgGr91StV+gFg4ARQ== +-----END RSA PRIVATE KEY----- +''' + + ret = x509.get_private_key_size(ca_key) + self.assertEqual(ret, 1024) + + @skipIf(not HAS_M2CRYPTO, 'Skipping, M2Crypt is unavailble') + def test_create_certificate(self): + ''' + Test private function _parse_subject(subject) it handles a missing fields + :return: + ''' + ca_key = ''' +-----BEGIN RSA PRIVATE KEY----- +MIICWwIBAAKBgQCjdjbgL4kQ8Lu73xeRRM1q3C3K3ptfCLpyfw38LRnymxaoJ6ls +pNSx2dU1uJ89YKFlYLo1QcEk4rJ2fdIjarV0kuNCY3rC8jYUp9BpAU5Z6p9HKeT1 +2rTPH81JyjbQDR5PyfCyzYOQtpwpB4zIUUK/Go7tTm409xGKbbUFugJNgQIDAQAB +AoGAF24we34U1ZrMLifSRv5nu3OIFNZHyx2DLDpOFOGaII5edwgIXwxZeIzS5Ppr +yO568/8jcdLVDqZ4EkgCwRTgoXRq3a1GLHGFmBdDNvWjSTTMLoozuM0t2zjRmIsH +hUd7tnai9Lf1Bp5HlBEhBU2gZWk+SXqLvxXe74/+BDAj7gECQQDRw1OPsrgTvs3R +3MNwX6W8+iBYMTGjn6f/6rvEzUs/k6rwJluV7n8ISNUIAxoPy5g5vEYK6Ln/Ttc7 +u0K1KNlRAkEAx34qcxjuswavL3biNGE+8LpDJnJx1jaNWoH+ObuzYCCVMusdT2gy +kKuq9ytTDgXd2qwZpIDNmscvReFy10glMQJAXebMz3U4Bk7SIHJtYy7OKQzn0dMj +35WnRV81c2Jbnzhhu2PQeAvt/i1sgEuzLQL9QEtSJ6wLJ4mJvImV0TdaIQJAAYyk +TcKK0A8kOy0kMp3yvDHmJZ1L7wr7bBGIZPBlQ0Ddh8i1sJExm1gJ+uN2QKyg/XrK +tDFf52zWnCdVGgDwcQJALW/WcbSEK+JVV6KDJYpwCzWpKIKpBI0F6fdCr1G7Xcwj +c9bcgp7D7xD+TxWWNj4CSXEccJgGr91StV+gFg4ARQ== +-----END RSA PRIVATE KEY----- +''' + + ret = x509.create_certificate(text=True, + signing_private_key=ca_key, + CN='Redacted Root CA', + O='Redacted', + C='BE', + ST='Antwerp', + L='Local Town', + Email='certadm@example.org', + basicConstraints="critical CA:true", + keyUsage="critical cRLSign, keyCertSign", + subjectKeyIdentifier='hash', + authorityKeyIdentifier='keyid,issuer:always', + days_valid=3650, + days_remaining=0) + self.assertIn('BEGIN CERTIFICATE', ret)