def sign(cls, payload, key, alg, include_jwk=True, protect=frozenset(), **kwargs): """Sign. :param key: Key for signature. :type key: :class:`acme.jose.jwk.JWK` """ assert isinstance(key, alg.kty) header_params = kwargs header_params['alg'] = alg if include_jwk: header_params['jwk'] = key.public_key() assert set(header_params).issubset(cls.header_cls._fields) assert protect.issubset(cls.header_cls._fields) protected_params = {} for header in protect: protected_params[header] = header_params.pop(header) if protected_params: # pylint: disable=star-args protected = cls.header_cls(**protected_params).json_dumps() else: protected = '' header = cls.header_cls(**header_params) # pylint: disable=star-args signature = alg.sign(key.key, b64.b64encode(protected) + '.' + b64.b64encode(payload)) return cls(protected=protected, header=header, signature=signature)
def to_compact(self): """Compact serialization.""" assert len(self.signatures) == 1 assert 'alg' not in self.signature.header.not_omitted() # ... it must be in protected return '{0}.{1}.{2}'.format(b64.b64encode(self.signature.protected), b64.b64encode(self.payload), b64.b64encode(self.signature.signature))
def to_compact(self): """Compact serialization.""" assert len(self.signatures) == 1 assert 'alg' not in self.signature.header.not_omitted() # ... it must be in protected return '{0}.{1}.{2}'.format( b64.b64encode(self.signature.protected), b64.b64encode(self.payload), b64.b64encode(self.signature.signature))
def verify(self, payload, key=None): """Verify. :param key: Key used for verification. :type key: :class:`acme.jose.jwk.JWK` """ key = self.combined.find_key() if key is None else key return self.combined.alg.verify( key=key.key, sig=self.signature, msg=(b64.b64encode(self.protected) + '.' + b64.b64encode(payload)))
def verify(self, payload, key=None): """Verify. :param key: Key used for verification. :type key: :class:`acme.jose.jwk.JWK` """ key = self.combined.find_key() if key is None else key return self.combined.alg.verify(key=key.key, sig=self.signature, msg=(b64.b64encode(self.protected) + '.' + b64.b64encode(payload)))
def test_json_flat(self): jobj_to = { 'signature': b64.b64encode(self.mixed.signature.signature), 'payload': b64.b64encode('foo'), 'header': self.mixed.signature.header, 'protected': b64.b64encode(self.mixed.signature.protected), } jobj_from = jobj_to.copy() jobj_from['header'] = jobj_from['header'].to_json() self.assertEqual(self.mixed.to_partial_json(flat=True), jobj_to) from acme.jose.jws import JWS self.assertEqual(self.mixed, JWS.from_json(jobj_from))
def to_compact(self): """Compact serialization. :rtype: bytes """ assert len(self.signatures) == 1 assert 'alg' not in self.signature.header.not_omitted() # ... it must be in protected return (b64.b64encode(self.signature.protected.encode('utf-8')) + b'.' + b64.b64encode(self.payload) + b'.' + b64.b64encode(self.signature.signature))
def to_compact(self): """Compact serialization. :rtype: bytes """ assert len(self.signatures) == 1 assert 'alg' not in self.signature.header.not_omitted() # ... it must be in protected return ( b64.b64encode(self.signature.protected.encode('utf-8')) + b'.' + b64.b64encode(self.payload) + b'.' + b64.b64encode(self.signature.signature))
def encode_cert(cert): """Encode certificate as JOSE Base-64 DER. :param cert: Certificate. :type cert: :class:`acme.jose.util.ComparableX509` """ return b64.b64encode(cert.as_der())
def _encode_param(cls, data): def _leading_zeros(arg): if len(arg) % 2: return '0' + arg return arg return b64.b64encode(binascii.unhexlify( _leading_zeros(hex(data)[2:].rstrip('L'))))
def _perform_tlssni01_challenge(self, achall): tls_help = self._get_tls_sni_help(achall) response = tls_help._setup_challenge_cert(achall) json_data = OrderedDict() json_data[FIELD_CMD] = COMMAND_PERFORM json_data[FIELD_TYPE] = achall.chall.typ json_data[FIELD_DOMAIN] = achall.domain json_data[FIELD_TOKEN] = b64.b64encode(achall.chall.token) json_data[FIELD_Z_DOMAIN] = achall.response( achall.account_key).z_domain json_data[FIELD_VALIDATION] = json_data[FIELD_Z_DOMAIN] json_data[FIELD_CERT_PATH] = tls_help.get_cert_path(achall) json_data[FIELD_KEY_PATH] = tls_help.get_key_path(achall) json_data[FIELD_PORT] = str(self.config.tls_sni_01_port) json_data[FIELD_KEY_AUTH] = response.key_authorization json_data[FIELD_CERT_PEM] = None json_data[FIELD_KEY_PEM] = None try: with open(json_data[FIELD_CERT_PATH], 'r') as fh: json_data[FIELD_CERT_PEM] = fh.read() except: pass try: with open(json_data[FIELD_KEY_PATH], 'r') as fh: json_data[FIELD_KEY_PEM] = fh.read() except: pass if self._is_text_mode(): self._notify_and_wait( self._get_message(achall).format( domain=json_data[FIELD_DOMAIN], z_domain=json_data[FIELD_Z_DOMAIN], cert_path=json_data[FIELD_CERT_PATH], key_path=json_data[FIELD_KEY_PATH], port=json_data[FIELD_PORT])) elif self._is_json_mode(): self._json_out_and_wait(json_data) elif self._is_handler_mode(): self._json_out(json_data, True) if self._call_handler( "perform", **(self._get_json_to_kwargs(json_data))) is None: raise errors.PluginError( "Error in calling the handler to do the perform (challenge) stage" ) else: raise errors.PluginError("Unknown plugin mode selected") if not response.simple_verify(achall.chall, achall.domain, achall.account_key.public_key(), None): logger.warning("Self-verify of challenge failed.") return response
def encode_cert(cert): """Encode certificate as JOSE Base-64 DER. :param cert: Certificate. :type cert: :class:`acme.jose.util.ComparableX509` """ return b64.b64encode(OpenSSL.crypto.dump_certificate( OpenSSL.crypto.FILETYPE_ASN1, cert))
def encode_b64jose(data): """Encode JOSE Base-64 field. :param bytes data: :rtype: `unicode` """ # b64encode produces ASCII characters only return b64.b64encode(data).decode('ascii')
def test_json_not_flat(self): jobj_to = { 'signatures': (self.mixed.signature, ), 'payload': b64.b64encode('foo'), } jobj_from = jobj_to.copy() jobj_from['signatures'] = [jobj_to['signatures'][0].to_json()] self.assertEqual(self.mixed.to_partial_json(flat=False), jobj_to) from acme.jose.jws import JWS self.assertEqual(self.mixed, JWS.from_json(jobj_from))
def test_json_not_flat(self): jobj_to = { 'signatures': (self.mixed.signature,), 'payload': b64.b64encode('foo'), } jobj_from = jobj_to.copy() jobj_from['signatures'] = [jobj_to['signatures'][0].to_json()] self.assertEqual(self.mixed.to_partial_json(flat=False), jobj_to) from acme.jose.jws import JWS self.assertEqual(self.mixed, JWS.from_json(jobj_from))
def to_partial_json(self, flat=True): # pylint: disable=arguments-differ assert self.signatures payload = b64.b64encode(self.payload) if flat and len(self.signatures) == 1: ret = self.signatures[0].to_partial_json() ret['payload'] = payload return ret else: return { 'payload': payload, 'signatures': self.signatures, }
def sign(cls, payload, key, alg, include_jwk=True, protect=frozenset(), **kwargs): """Sign. :param key: Key for signature. :type key: :class:`acme.jose.jwk.JWK` """ assert isinstance(key, alg.kty) header_params = kwargs header_params['alg'] = alg if include_jwk: header_params['jwk'] = key.public() assert set(header_params).issubset(cls.header_cls._fields) assert protect.issubset(cls.header_cls._fields) protected_params = {} for header in protect: protected_params[header] = header_params.pop(header) if protected_params: # pylint: disable=star-args protected = cls.header_cls(**protected_params).json_dumps() else: protected = '' header = cls.header_cls(**header_params) # pylint: disable=star-args signature = alg.sign( key.key, b64.b64encode(protected) + '.' + b64.b64encode(payload)) return cls(protected=protected, header=header, signature=signature)
def _perform_dns01_challenge(self, achall): response, validation = achall.response_and_validation() json_data = OrderedDict() json_data[FIELD_CMD] = COMMAND_PERFORM json_data[FIELD_TYPE] = achall.chall.typ json_data[FIELD_DOMAIN] = achall.domain json_data[FIELD_TOKEN] = b64.b64encode(achall.chall.token) json_data[FIELD_VALIDATION] = validation json_data[FIELD_TXT_DOMAIN] = achall.validation_domain_name( achall.domain) json_data[FIELD_KEY_AUTH] = response.key_authorization json_data = self._json_sanitize_dict(json_data) if not self.conf("test-mode"): if self._is_text_mode(): self._notify_and_wait( self._get_message(achall).format( validation=json_data[FIELD_VALIDATION], domain=json_data[FIELD_DOMAIN], response=response)) elif self._is_json_mode(): self._json_out_and_wait(json_data) elif self._is_handler_mode(): self._json_out(json_data, True) if self._call_handler( "perform", **(self._get_json_to_kwargs(json_data))) is None: raise errors.PluginError( "Error in calling the handler to do the perform (challenge) stage" ) else: raise errors.PluginError("Unknown plugin mode selected") try: verification_status = response.simple_verify( achall.chall, achall.domain, achall.account_key.public_key()) except acme_errors.DependencyError: logger.warning("Self verification requires optional " "dependency `dnspython` to be installed.") else: if not verification_status: logger.warning("Self-verify of challenge failed.") return response
def _get_cleanup_json(self, achall): response, validation = achall.response_and_validation() cur_record = OrderedDict() cur_record[FIELD_CMD] = COMMAND_CLEANUP cur_record[FIELD_TYPE] = achall.chall.typ if isinstance(achall.chall, challenges.HTTP01): pass elif isinstance(achall.chall, challenges.DNS01): pass cur_record[FIELD_STATUS] = None cur_record[FIELD_DOMAIN] = achall.domain cur_record[FIELD_TOKEN] = b64.b64encode(achall.chall.token) if type(cur_record[FIELD_TOKEN]) == bytes: cur_record[FIELD_TOKEN] = cur_record[FIELD_TOKEN].decode('UTF-8') cur_record[FIELD_VALIDATION] = validation if isinstance( validation, basestring) else '' cur_record[FIELD_KEY_AUTH] = response.key_authorization.decode( 'UTF-8') if isinstance(response.key_authorization, bytes) else response.key_authorization cur_record[FIELD_VALIDATED] = None cur_record[FIELD_ERROR] = None if achall.status is not None: try: cur_record[FIELD_STATUS] = achall.status.name except: pass if achall.error is not None: try: cur_record[FIELD_ERROR] = str(achall.error) except: cur_record[FIELD_ERROR] = 'ERROR' if achall.validated is not None: try: cur_record[FIELD_VALIDATED] = str(achall.validated) except: cur_record[FIELD_VALIDATED] = 'ERROR' return cur_record
def _call(cls, data): from acme.jose.b64 import b64encode return b64encode(data)
def _msg(cls, protected, payload): return (b64.b64encode(protected.encode('utf-8')) + b'.' + b64.b64encode(payload))
def encode_csr(csr): """Encode CSR as JOSE Base-64 DER.""" return b64.b64encode(OpenSSL.crypto.dump_certificate_request( OpenSSL.crypto.FILETYPE_ASN1, csr))
def _perform_http01_challenge(self, achall): # same path for each challenge response would be easier for # users, but will not work if multiple domains point at the # same server: default command doesn't support virtual hosts response, validation = achall.response_and_validation() port = (response.port if self.config.http01_port is None else int( self.config.http01_port)) command = self.CMD_TEMPLATE.format( root=self._root, achall=achall, response=response, validation=pipes.quote(validation), encoded_token=achall.chall.encode("token"), port=port) json_data = OrderedDict() json_data[FIELD_CMD] = COMMAND_PERFORM json_data[FIELD_TYPE] = achall.chall.typ json_data[FIELD_DOMAIN] = achall.domain json_data[FIELD_TOKEN] = b64.b64encode(achall.chall.token) json_data[FIELD_VALIDATION] = validation json_data[FIELD_URI] = achall.chall.uri(achall.domain) json_data['command'] = command json_data[FIELD_KEY_AUTH] = response.key_authorization json_data = self._json_sanitize_dict(json_data) if self.conf("test-mode"): logger.debug("Test mode. Executing the manual command: %s", command) # sh shipped with OS X does't support echo -n, but supports printf try: self._httpd = subprocess.Popen( command, # don't care about setting stdout and stderr, # we're in test mode anyway shell=True, executable=None, # "preexec_fn" is UNIX specific, but so is "command" preexec_fn=os.setsid) except OSError as error: # ValueError should not happen! logger.debug("Couldn't execute manual command: %s", error, exc_info=True) return False logger.debug("Manual command running as PID %s.", self._httpd.pid) # give it some time to bootstrap, before we try to verify # (cert generation in case of simpleHttpS might take time) self._test_mode_busy_wait(port) if self._httpd.poll() is not None: raise errors.Error("Couldn't execute manual command") else: if self._is_text_mode(): self._notify_and_wait( self._get_message(achall).format(validation=validation, response=response, uri=achall.chall.uri( achall.domain), command=command)) elif self._is_json_mode(): self._json_out_and_wait(json_data) elif self._is_handler_mode(): self._json_out(json_data, True) if self._call_handler( "perform", **(self._get_json_to_kwargs(json_data))) is None: raise errors.PluginError( "Error in calling the handler to do the perform (challenge) stage" ) else: raise errors.PluginError("Unknown plugin mode selected") if not response.simple_verify(achall.chall, achall.domain, achall.account_key.public_key(), self.config.http01_port): logger.warning("Self-verify of challenge failed.") return response