Exemplo n.º 1
0
    def _download_cert(self, url):
        '''
        Download and parse the certificate chain.
        https://tools.ietf.org/html/draft-ietf-acme-acme-12#section-7.4.2
        '''
        resp, info = fetch_url(
            self.module,
            url,
            headers={'Accept': 'application/pem-certificate-chain'})
        try:
            content = resp.read()
        except AttributeError:
            content = info.get('body')

        if not content or not info['content-type'].startswith(
                'application/pem-certificate-chain'):
            raise ModuleFailException(
                "Cannot download certificate chain from {0}: {1} (headers: {2})"
                .format(url, content, info))

        cert = None
        chain = []

        # Parse data
        lines = content.decode('utf-8').splitlines(True)
        current = []
        for line in lines:
            if line.strip():
                current.append(line)
            if line.startswith('-----END CERTIFICATE-----'):
                if cert is None:
                    cert = ''.join(current)
                else:
                    chain.append(''.join(current))
                current = []

        # Process link-up headers if there was no chain in reply
        if not chain and 'link' in info:
            link = info['link']
            parsed_link = re.match(r'<(.+)>;rel="(\w+)"', link)
            if parsed_link and parsed_link.group(2) == "up":
                chain_link = parsed_link.group(1)
                chain_result, chain_info = fetch_url(self.module,
                                                     chain_link,
                                                     method='GET')
                if chain_info['status'] in [200, 201]:
                    chain.append(self._der_to_pem(chain_result.read()))

        if cert is None or current:
            raise ModuleFailException(
                "Failed to parse certificate chain download from {0}: {1} (headers: {2})"
                .format(url, content, info))
        return {'cert': cert, 'chain': chain}
Exemplo n.º 2
0
    def _new_cert_v1(self):
        '''
        Create a new certificate based on the CSR (ACME v1 protocol).
        Return the certificate object as dict
        https://tools.ietf.org/html/draft-ietf-acme-acme-02#section-6.5
        '''
        csr = pem_to_der(self.csr)
        new_cert = {
            "resource": "new-cert",
            "csr": nopad_b64(csr),
        }
        result, info = self.account.send_signed_request(self.directory['new-cert'], new_cert)

        chain = []
        if 'link' in info:
            link = info['link']
            parsed_link = re.match(r'<(.+)>;rel="(\w+)"', link)
            if parsed_link and parsed_link.group(2) == "up":
                chain_link = parsed_link.group(1)
                chain_result, chain_info = fetch_url(self.module, chain_link, method='GET')
                if chain_info['status'] in [200, 201]:
                    chain = [self._der_to_pem(chain_result.read())]

        if info['status'] not in [200, 201]:
            raise ModuleFailException("Error new cert: CODE: {0} RESULT: {1}".format(info['status'], result))
        else:
            return {'cert': self._der_to_pem(result), 'uri': info['location'], 'chain': chain}
Exemplo n.º 3
0
    def finish_challenges(self):
        '''
        Verify challenges for all domains of the CSR.
        '''
        self.authorizations = {}

        # Step 1: obtain challenge information
        if self.version == 1:
            # For ACME v1, we attempt to create new authzs. Existing ones
            # will be returned instead.
            for domain in self.domains:
                new_auth = self._new_authz_v1(domain)
                self._add_or_update_auth(domain, new_auth)
        else:
            # For ACME v2, we obtain the order object by fetching the
            # order URI, and extract the information from there.
            resp, info = fetch_url(self.module, self.order_uri)
            try:
                result = resp.read()
            except AttributeError:
                result = info.get('body')

            if not result:
                raise ModuleFailException(
                    "Cannot download order from {0}: {1} (headers: {2})".
                    format(self.order_uri, result, info))

            if info['status'] not in [200]:
                raise ModuleFailException(
                    "Error on downloading order: CODE: {0} RESULT: {1}".format(
                        info['status'], result))

            result = self.module.from_json(result.decode('utf8'))
            for auth_uri in result['authorizations']:
                auth_data = simple_get(self.module, auth_uri)
                auth_data['uri'] = auth_uri
                domain = auth_data['identifier']['value']
                if auth_data.get('wildcard', False):
                    domain = '*.{0}'.format(domain)
                self.authorizations[domain] = auth_data

            self.finalize_uri = result['finalize']

        # Step 2: validate challenges
        for domain, auth in self.authorizations.items():
            if auth['status'] == 'pending':
                self._validate_challenges(domain, auth)