Example #1
0
    def get_cert_days(self, cert_filename=None, cert_content=None, now=None):
        '''
        Return the days the certificate in cert_filename remains valid and -1
        if the file was not found. If cert_filename contains more than one
        certificate, only the first one will be considered.

        If now is not specified, datetime.datetime.now() is used.
        '''
        if cert_filename is not None:
            cert_content = None
            if os.path.exists(cert_filename):
                cert_content = read_file(cert_filename)
        else:
            cert_content = to_bytes(cert_content)

        if cert_content is None:
            return -1

        try:
            cert = cryptography.x509.load_pem_x509_certificate(
                cert_content, _cryptography_backend)
        except Exception as e:
            if cert_filename is None:
                raise BackendException(
                    'Cannot parse certificate: {0}'.format(e))
            raise BackendException('Cannot parse certificate {0}: {1}'.format(
                cert_filename, e))

        if now is None:
            now = datetime.datetime.now()
        return (cert.not_valid_after - now).days
Example #2
0
 def create_mac_key(self, alg, key):
     '''Create a MAC key.'''
     if alg == 'HS256':
         hashalg = cryptography.hazmat.primitives.hashes.SHA256
         hashbytes = 32
     elif alg == 'HS384':
         hashalg = cryptography.hazmat.primitives.hashes.SHA384
         hashbytes = 48
     elif alg == 'HS512':
         hashalg = cryptography.hazmat.primitives.hashes.SHA512
         hashbytes = 64
     else:
         raise BackendException(
             'Unsupported MAC key algorithm for cryptography backend: {0}'.
             format(alg))
     key_bytes = base64.urlsafe_b64decode(key)
     if len(key_bytes) < hashbytes:
         raise BackendException(
             '{0} key must be at least {1} bytes long (after Base64 decoding)'
             .format(alg, hashbytes))
     return {
         'mac_obj':
         lambda: cryptography.hazmat.primitives.hmac.HMAC(
             key_bytes, hashalg(), _cryptography_backend),
         'type':
         'hmac',
         'alg':
         alg,
         'jwk': {
             'kty': 'oct',
             'k': key,
         },
     }
Example #3
0
 def create_mac_key(self, alg, key):
     '''Create a MAC key.'''
     if alg == 'HS256':
         hashalg = 'sha256'
         hashbytes = 32
     elif alg == 'HS384':
         hashalg = 'sha384'
         hashbytes = 48
     elif alg == 'HS512':
         hashalg = 'sha512'
         hashbytes = 64
     else:
         raise BackendException(
             'Unsupported MAC key algorithm for OpenSSL backend: {0}'.
             format(alg))
     key_bytes = base64.urlsafe_b64decode(key)
     if len(key_bytes) < hashbytes:
         raise BackendException(
             '{0} key must be at least {1} bytes long (after Base64 decoding)'
             .format(alg, hashbytes))
     return {
         'type': 'hmac',
         'alg': alg,
         'jwk': {
             'kty': 'oct',
             'k': key,
         },
         'hash': hashalg,
     }
Example #4
0
 def get_csr_identifiers(self, csr_filename=None, csr_content=None):
     '''
     Return a set of requested identifiers (CN and SANs) for the CSR.
     Each identifier is a pair (type, identifier), where type is either
     'dns' or 'ip'.
     '''
     identifiers = set([])
     if csr_content is None:
         csr_content = read_file(csr_filename)
     else:
         csr_content = to_bytes(csr_content)
     csr = cryptography.x509.load_pem_x509_csr(csr_content,
                                               _cryptography_backend)
     for sub in csr.subject:
         if sub.oid == cryptography.x509.oid.NameOID.COMMON_NAME:
             identifiers.add(('dns', sub.value))
     for extension in csr.extensions:
         if extension.oid == cryptography.x509.oid.ExtensionOID.SUBJECT_ALTERNATIVE_NAME:
             for name in extension.value:
                 if isinstance(name, cryptography.x509.DNSName):
                     identifiers.add(('dns', name.value))
                 elif isinstance(name, cryptography.x509.IPAddress):
                     identifiers.add(('ip', name.value.compressed))
                 else:
                     raise BackendException(
                         'Found unsupported SAN identifier {0}'.format(
                             name))
     return identifiers
Example #5
0
 def create_chain_matcher(self, criterium):
     '''
     Given a Criterium object, creates a ChainMatcher object.
     '''
     raise BackendException(
         'Alternate chain matching can only be used with the "cryptography" backend.'
     )
Example #6
0
    def get_cert_days(self, cert_filename=None, cert_content=None, now=None):
        '''
        Return the days the certificate in cert_filename remains valid and -1
        if the file was not found. If cert_filename contains more than one
        certificate, only the first one will be considered.

        If now is not specified, datetime.datetime.now() is used.
        '''
        filename = cert_filename
        data = None
        if cert_content is not None:
            filename = '-'
            data = cert_content.encode('utf-8')
            cert_filename_suffix = ''
        elif cert_filename is not None:
            if not os.path.exists(cert_filename):
                return -1
            cert_filename_suffix = ' in {0}'.format(cert_filename)
        else:
            return -1

        openssl_cert_cmd = [
            self.openssl_binary, "x509", "-in", filename, "-noout", "-text"
        ]
        dummy, out, dummy = self.module.run_command(
            openssl_cert_cmd,
            data=data,
            check_rc=True,
            binary_data=True,
            environ_update=_OPENSSL_ENVIRONMENT_UPDATE)
        try:
            not_after_str = re.search(
                r"\s+Not After\s*:\s+(.*)",
                to_text(out, errors='surrogate_or_strict')).group(1)
            not_after = datetime.datetime.strptime(not_after_str,
                                                   '%b %d %H:%M:%S %Y %Z')
        except AttributeError:
            raise BackendException(
                "No 'Not after' date found{0}".format(cert_filename_suffix))
        except ValueError:
            raise BackendException(
                "Failed to parse 'Not after' date{0}".format(
                    cert_filename_suffix))
        if now is None:
            now = datetime.datetime.now()
        return (not_after - now).days
Example #7
0
    def sign(self, payload64, protected64, key_data):
        sign_payload = "{0}.{1}".format(protected64, payload64).encode('utf8')
        if key_data['type'] == 'hmac':
            hex_key = to_native(
                binascii.hexlify(base64.urlsafe_b64decode(
                    key_data['jwk']['k'])))
            cmd_postfix = [
                "-mac", "hmac", "-macopt", "hexkey:{0}".format(hex_key),
                "-binary"
            ]
        else:
            cmd_postfix = ["-sign", key_data['key_file']]
        openssl_sign_cmd = [
            self.openssl_binary, "dgst", "-{0}".format(key_data['hash'])
        ] + cmd_postfix

        dummy, out, dummy = self.module.run_command(
            openssl_sign_cmd,
            data=sign_payload,
            check_rc=True,
            binary_data=True,
            environ_update=_OPENSSL_ENVIRONMENT_UPDATE)

        if key_data['type'] == 'ec':
            dummy, der_out, dummy = self.module.run_command(
                [self.openssl_binary, "asn1parse", "-inform", "DER"],
                data=out,
                binary_data=True,
                environ_update=_OPENSSL_ENVIRONMENT_UPDATE)
            expected_len = 2 * key_data['point_size']
            sig = re.findall(
                r"prim:\s+INTEGER\s+:([0-9A-F]{1,%s})\n" % expected_len,
                to_text(der_out, errors='surrogate_or_strict'))
            if len(sig) != 2:
                raise BackendException(
                    "failed to generate Elliptic Curve signature; cannot parse DER output: {0}"
                    .format(to_text(der_out, errors='surrogate_or_strict')))
            sig[0] = (expected_len - len(sig[0])) * '0' + sig[0]
            sig[1] = (expected_len - len(sig[1])) * '0' + sig[1]
            out = binascii.unhexlify(sig[0]) + binascii.unhexlify(sig[1])

        return {
            "protected": protected64,
            "payload": payload64,
            "signature": nopad_b64(to_bytes(out)),
        }
Example #8
0
    def get_csr_identifiers(self, csr_filename=None, csr_content=None):
        '''
        Return a set of requested identifiers (CN and SANs) for the CSR.
        Each identifier is a pair (type, identifier), where type is either
        'dns' or 'ip'.
        '''
        filename = csr_filename
        data = None
        if csr_content is not None:
            filename = '-'
            data = csr_content.encode('utf-8')

        openssl_csr_cmd = [
            self.openssl_binary, "req", "-in", filename, "-noout", "-text"
        ]
        dummy, out, dummy = self.module.run_command(
            openssl_csr_cmd,
            data=data,
            check_rc=True,
            binary_data=True,
            environ_update=_OPENSSL_ENVIRONMENT_UPDATE)

        identifiers = set([])
        common_name = re.search(r"Subject:.* CN\s?=\s?([^\s,;/]+)",
                                to_text(out, errors='surrogate_or_strict'))
        if common_name is not None:
            identifiers.add(('dns', common_name.group(1)))
        subject_alt_names = re.search(
            r"X509v3 Subject Alternative Name: (?:critical)?\n +([^\n]+)\n",
            to_text(out, errors='surrogate_or_strict'),
            re.MULTILINE | re.DOTALL)
        if subject_alt_names is not None:
            for san in subject_alt_names.group(1).split(", "):
                if san.lower().startswith("dns:"):
                    identifiers.add(('dns', san[4:]))
                elif san.lower().startswith("ip:"):
                    identifiers.add(('ip', self._normalize_ip(san[3:])))
                elif san.lower().startswith("ip address:"):
                    identifiers.add(('ip', self._normalize_ip(san[11:])))
                else:
                    raise BackendException(
                        'Found unsupported SAN identifier "{0}"'.format(san))
        return identifiers
 def get_cert_days(self, cert_filename=None, cert_content=None, now=None):
     raise BackendException('Not implemented in fake backend')
 def get_csr_identifiers(self, csr_filename=None, csr_content=None):
     raise BackendException('Not implemented in fake backend')
 def create_mac_key(self, alg, key):
     raise BackendException('Not implemented in fake backend')
 def sign(self, payload64, protected64, key_data):
     raise BackendException('Not implemented in fake backend')
 def parse_key(self, key_file=None, key_content=None, passphrase=None):
     raise BackendException('Not implemented in fake backend')
 def create_chain_matcher(self, criterium):
     raise BackendException('Not implemented in fake backend')