2021-02-04 16:30:32 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								__filename__ = "httpsig.py"
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-03 12:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								__author__ = "Bob Mottram"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								__credits__ = ['lamia']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								__license__ = "AGPL3+"
							 | 
						
					
						
							
								
									
										
										
										
											2024-12-22 23:37:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								__version__ = "1.6.0"
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-03 12:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								__maintainer__ = "Bob Mottram"
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-10 16:14:50 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								__email__ = "bob@libreserver.org"
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-03 12:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								__status__ = "Production"
							 | 
						
					
						
							
								
									
										
										
										
											2021-06-15 15:08:12 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								__module_group__ = "Security"
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2019-08-15 22:33:42 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								# see https://tools.ietf.org/html/draft-cavage-http-signatures-06
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-21 22:51:08 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								#
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								# This might change in future
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-22 18:30:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								# see https://tools.ietf.org/html/draft-ietf-httpbis-message-signatures
							 | 
						
					
						
							
								
									
										
										
										
											2019-08-15 22:33:42 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-04 16:30:32 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								from cryptography.hazmat.backends import default_backend
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								from cryptography.hazmat.primitives.serialization import load_pem_private_key
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								from cryptography.hazmat.primitives.serialization import load_pem_public_key
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								from cryptography.hazmat.primitives.asymmetric import padding
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								from cryptography.hazmat.primitives import hashes
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								from cryptography.hazmat.primitives.asymmetric import utils as hazutils
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								import base64
							 | 
						
					
						
							
								
									
										
										
										
											2019-08-15 09:08:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								from time import gmtime, strftime
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-26 12:45:03 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								from utils import get_full_domain
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-26 12:13:46 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								from utils import get_sha_256
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								from utils import get_sha_512
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-26 10:19:59 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								from utils import local_actor_url
							 | 
						
					
						
							
								
									
										
										
										
											2023-11-20 22:27:58 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								from utils import date_utcnow
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								from utils import date_epoch
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								from utils import date_from_string_format
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-04 16:30:32 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def message_content_digest(message_body_json_str: str,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                           digest_algorithm: str) -> str:
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-23 11:41:40 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    """Returns the digest for the message body
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    msg = message_body_json_str.encode('utf-8')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if digest_algorithm in ('rsa-sha512', 'rsa-pss-sha512'):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        hash_result = get_sha_512(msg)
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-23 11:41:40 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    else:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        hash_result = get_sha_256(msg)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return base64.b64encode(hash_result).decode('utf-8')
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-03 12:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2019-08-16 17:19:23 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def get_digest_prefix(digest_algorithm: str) -> str:
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-23 11:41:40 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    """Returns the prefix for the message body digest
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if digest_algorithm in ('rsa-sha512', 'rsa-pss-sha512'):
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-23 11:41:40 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return 'SHA-512'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return 'SHA-256'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def get_digest_algorithm_from_headers(http_headers: {}) -> str:
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-23 11:41:40 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    """Returns the digest algorithm from http headers
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    digest_str = None
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if http_headers.get('digest'):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        digest_str = http_headers['digest']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    elif http_headers.get('Digest'):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        digest_str = http_headers['Digest']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if digest_str:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if digest_str.startswith('SHA-512'):
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-23 11:41:40 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            return 'rsa-sha512'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return 'rsa-sha256'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def sign_post_headers(date_str: str, private_key_pem: str,
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                      nickname: str, domain: str, port: int,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                      to_domain: str, to_port: int,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                      path: str, http_prefix: str,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                      message_body_json_str: str,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                      content_type: str, algorithm: str,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                      digest_algorithm: str) -> str:
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """Returns a raw signature string that can be plugged into a header and
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    used to verify the authenticity of an HTTP transmission.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-26 12:45:03 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    domain = get_full_domain(domain, port)
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-01 09:31:02 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    to_domain = get_full_domain(to_domain, to_port)
							 | 
						
					
						
							
								
									
										
										
										
											2019-08-16 13:47:01 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if not date_str:
							 | 
						
					
						
							
								
									
										
										
										
											2022-11-24 23:26:15 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        date_str = strftime("%a, %d %b %Y %H:%M:%S %Z", gmtime())
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-08 10:05:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if nickname != domain and nickname.lower() != 'actor':
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        key_id = local_actor_url(http_prefix, nickname, domain)
							 | 
						
					
						
							
								
									
										
										
										
											2021-08-31 21:02:58 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    else:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # instance actor
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        key_id = http_prefix + '://' + domain + '/actor'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    key_id += '#main-key'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if not message_body_json_str:
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-03 12:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        headers = {
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-01 18:46:28 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            '(request-target)': f'get {path}',
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'host': to_domain,
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'date': date_str,
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-26 15:32:00 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'accept': content_type
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-03 12:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        body_digest = \
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            message_content_digest(message_body_json_str, digest_algorithm)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        digest_prefix = get_digest_prefix(digest_algorithm)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        content_length = len(message_body_json_str)
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-03 12:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        headers = {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            '(request-target)': f'post {path}',
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'host': to_domain,
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'date': date_str,
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'digest': f'{digest_prefix}={body_digest}',
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-03 12:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'content-type': 'application/activity+json',
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'content-length': str(content_length)
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-03 12:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    key = load_pem_private_key(private_key_pem.encode('utf-8'),
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-04 16:30:32 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                               None, backend=default_backend())
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-03 12:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    # headers.update({
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    #     '(request-target)': f'post {path}',
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # })
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # build a digest for signing
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    signed_header_keys = headers.keys()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    signed_header_text = ''
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    for header_key in signed_header_keys:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        signed_header_text += f'{header_key}: {headers[header_key]}\n'
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-08 10:05:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    # strip the trailing linefeed
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    signed_header_text = signed_header_text.rstrip('\n')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # signed_header_text.encode('ascii') matches
							 | 
						
					
						
							
								
									
										
										
										
											2023-01-18 10:18:48 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    try:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        sig_header_encoded = signed_header_text.encode('ascii')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    except UnicodeEncodeError:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        sig_header_encoded = signed_header_text
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        print('WARN: sign_post_headers unable to ascii encode ' +
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              signed_header_text)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    header_digest = get_sha_256(sig_header_encoded)
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    # print('header_digest2: ' + str(header_digest))
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # Sign the digest
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    raw_signature = key.sign(header_digest,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                             padding.PKCS1v15(),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                             hazutils.Prehashed(hashes.SHA256()))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    signature = base64.b64encode(raw_signature).decode('ascii')
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # Put it into a valid HTTP signature format
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    signature_dict = {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        'keyId': key_id,
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-23 11:41:40 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        'algorithm': algorithm,
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        'headers': ' '.join(signed_header_keys),
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        'signature': signature
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    signature_header = ','.join(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        [f'{k}="{v}"' for k, v in signature_dict.items()])
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return signature_header
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-03 12:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def sign_post_headers_new(date_str: str, private_key_pem: str,
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                          nickname: str,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                          domain: str, port: int,
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                          to_domain: str, to_port: int,
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                          path: str,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                          http_prefix: str,
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                          message_body_json_str: str,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                          algorithm: str, digest_algorithm: str,
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                          debug: bool) -> (str, str):
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 18:20:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    """Returns a raw signature strings that can be plugged into a header
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    as "Signature-Input" and "Signature"
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    used to verify the authenticity of an HTTP transmission.
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-22 18:30:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    See https://tools.ietf.org/html/draft-ietf-httpbis-message-signatures
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 18:20:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-26 12:45:03 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    domain = get_full_domain(domain, port)
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 18:20:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    to_domain = get_full_domain(to_domain, to_port)
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 18:20:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    time_format = "%a, %d %b %Y %H:%M:%S %Z"
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if not date_str:
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-26 13:17:46 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        curr_time = gmtime()
							 | 
						
					
						
							
								
									
										
										
										
											2022-11-24 23:26:15 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        date_str = strftime(time_format, curr_time)
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 18:20:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    else:
							 | 
						
					
						
							
								
									
										
										
										
											2023-11-20 22:27:58 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        curr_time = date_from_string_format(date_str, [time_format])
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    seconds_since_epoch = \
							 | 
						
					
						
							
								
									
										
										
										
											2023-11-20 22:27:58 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        int((curr_time - date_epoch()).total_seconds())
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    key_id = local_actor_url(http_prefix, nickname, domain) + '#main-key'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if not message_body_json_str:
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 18:20:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        headers = {
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-22 18:30:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            '@request-target': f'get {path}',
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            '@created': str(seconds_since_epoch),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'host': to_domain,
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'date': date_str
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 18:20:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        body_digest = message_content_digest(message_body_json_str,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                             digest_algorithm)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        digest_prefix = get_digest_prefix(digest_algorithm)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        content_length = len(message_body_json_str)
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 18:20:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        headers = {
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-22 18:30:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            '@request-target': f'post {path}',
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            '@created': str(seconds_since_epoch),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'host': to_domain,
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'date': date_str,
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'digest': f'{digest_prefix}={body_digest}',
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 18:20:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'content-type': 'application/activity+json',
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'content-length': str(content_length)
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 18:20:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    key = load_pem_private_key(private_key_pem.encode('utf-8'),
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 18:20:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                               None, backend=default_backend())
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # build a digest for signing
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    signed_header_keys = headers.keys()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    signed_header_text = ''
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    for header_key in signed_header_keys:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        signed_header_text += f'{header_key}: {headers[header_key]}\n'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    signed_header_text = signed_header_text.strip()
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 18:20:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-22 18:30:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if debug:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        print('\nsign_post_headers_new signed_header_text:\n' +
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              signed_header_text + '\nEND\n')
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-22 18:30:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 18:20:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    # Sign the digest. Potentially other signing algorithms can be added here.
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    signature = ''
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-08 10:05:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if algorithm == 'rsa-sha512':
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        header_digest = get_sha_512(signed_header_text.encode('ascii'))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        raw_signature = key.sign(header_digest,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                 padding.PKCS1v15(),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                 hazutils.Prehashed(hashes.SHA512()))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        signature = base64.b64encode(raw_signature).decode('ascii')
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-08 10:05:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    else:
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-18 14:04:45 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        # default rsa-sha256
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        header_digest = get_sha_256(signed_header_text.encode('ascii'))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        raw_signature = key.sign(header_digest,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                 padding.PKCS1v15(),
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                 hazutils.Prehashed(hashes.SHA256()))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        signature = base64.b64encode(raw_signature).decode('ascii')
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 18:20:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    sig_key = 'sig1'
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 18:20:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    # Put it into a valid HTTP signature format
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    signature_input_dict = {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        'keyId': key_id,
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 18:20:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    signature_index_header = '; '.join(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        [f'{k}="{v}"' for k, v in signature_input_dict.items()])
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    signature_index_header += '; alg=hs2019'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    signature_index_header += '; created=' + str(seconds_since_epoch)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    signature_index_header += \
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        '; ' + sig_key + '=(' + ', '.join(signed_header_keys) + ')'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    signature_dict = {
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        sig_key: signature
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 18:20:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    }
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    signature_header = '; '.join(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        [f'{k}=:{v}:' for k, v in signature_dict.items()])
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return signature_index_header, signature_header
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 18:20:33 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def create_signed_header(date_str: str, private_key_pem: str, nickname: str,
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                         domain: str, port: int,
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                         to_domain: str, to_port: int,
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                         path: str, http_prefix: str, with_digest: bool,
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                         message_body_json_str: str,
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                         content_type: str) -> {}:
							 | 
						
					
						
							
								
									
										
										
										
											2019-08-16 13:47:01 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    """Note that the domain is the destination, not the sender
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-23 11:41:40 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    algorithm = 'rsa-sha256'
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    digest_algorithm = 'rsa-sha256'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    header_domain = get_full_domain(to_domain, to_port)
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-01 09:31:02 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-15 10:44:44 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    # if no date is given then create one
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if not date_str:
							 | 
						
					
						
							
								
									
										
										
										
											2022-11-24 23:26:15 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        date_str = strftime("%a, %d %b %Y %H:%M:%S %Z", gmtime())
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-15 10:44:44 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # Content-Type or Accept header
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-26 15:32:00 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if not content_type:
							 | 
						
					
						
							
								
									
										
										
										
											2022-02-27 21:38:17 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        content_type = 'application/activity+json'
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-15 10:44:44 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if not with_digest:
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-03 12:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        headers = {
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-01 20:57:54 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            '(request-target)': f'get {path}',
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'host': header_domain,
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'date': date_str,
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-26 15:32:00 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'accept': content_type
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        signature_header = \
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            sign_post_headers(date_str, private_key_pem, nickname,
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                              domain, port, to_domain, to_port,
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                              path, http_prefix, None, content_type,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                              algorithm, None)
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-01 09:31:02 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    else:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        body_digest = message_content_digest(message_body_json_str,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                             digest_algorithm)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        digest_prefix = get_digest_prefix(digest_algorithm)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        content_length = len(message_body_json_str)
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-03 12:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        headers = {
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            '(request-target)': f'post {path}',
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'host': header_domain,
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'date': date_str,
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'digest': f'{digest_prefix}={body_digest}',
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            'content-length': str(content_length),
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-26 15:32:00 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            'content-type': content_type
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-22 20:36:19 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        signature_header = \
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            sign_post_headers(date_str, private_key_pem, nickname,
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                              domain, port,
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                              to_domain, to_port,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                              path, http_prefix, message_body_json_str,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                              content_type, algorithm, digest_algorithm)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    headers['signature'] = signature_header
							 | 
						
					
						
							
								
									
										
										
										
											2019-07-01 09:31:02 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return headers
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-03 12:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def _verify_recent_signature(signed_date_str: str) -> bool:
							 | 
						
					
						
							
								
									
										
										
										
											2019-08-23 11:31:46 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    """Checks whether the given time taken from the header is within
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    12 hours of the current time
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							
								
									
										
										
										
											2023-11-20 22:27:58 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    curr_date = date_utcnow()
							 | 
						
					
						
							
								
									
										
										
										
											2022-11-24 23:43:26 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    formats = ("%a, %d %b %Y %H:%M:%S %Z",
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								               "%a, %d %b %Y %H:%M:%S %z")
							 | 
						
					
						
							
								
									
										
										
										
											2023-11-20 22:27:58 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    signed_date = date_from_string_format(signed_date_str, formats)
							 | 
						
					
						
							
								
									
										
										
										
											2022-11-24 23:43:26 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if not signed_date:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return False
							 | 
						
					
						
							
								
									
										
										
										
											2023-11-20 22:27:58 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2023-02-21 13:26:17 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    time_diff_sec = (curr_date - signed_date).total_seconds()
							 | 
						
					
						
							
								
									
										
										
										
											2019-08-23 11:39:16 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    # 12 hours tollerance
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if time_diff_sec > 43200:
							 | 
						
					
						
							
								
									
										
										
										
											2023-02-21 11:35:10 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        print('WARN: Header signed too long ago: ' + signed_date_str + ' ' +
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              str(time_diff_sec / (60 * 60)) + ' hours')
							 | 
						
					
						
							
								
									
										
										
										
											2019-08-23 11:37:34 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return False
							 | 
						
					
						
							
								
									
										
										
										
											2023-02-21 13:26:17 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    # allow clocks to be off by a few mins
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if time_diff_sec < -480:
							 | 
						
					
						
							
								
									
										
										
										
											2023-02-21 11:35:10 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        print('WARN: Header signed in the future! ' + signed_date_str + ' ' +
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              str(time_diff_sec / (60 * 60)) + ' hours')
							 | 
						
					
						
							
								
									
										
										
										
											2019-08-23 11:30:37 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        return False
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return True
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-03 12:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								def verify_post_headers(http_prefix: str,
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                        public_key_pem: str, headers: dict,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                        path: str, get_method: bool,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                        message_body_digest: str,
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                        message_body_json_str: str, debug: bool,
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                        no_recency_check: bool = False) -> bool:
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """Returns true or false depending on if the key that we plugged in here
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    validates against the headers, method, and path.
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    public_key_pem - the public key from an rsa key pair
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    headers - should be a dictionary of request headers
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    path - the relative url that was requested from this site
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    get_method - GET or POST
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    message_body_json_str - the received request body (used for digest)
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							
								
									
										
										
										
											2019-08-23 11:20:20 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if get_method:
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-03 12:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        method = 'GET'
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else:
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-03 12:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        method = 'POST'
							 | 
						
					
						
							
								
									
										
										
										
											2019-11-12 15:03:17 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if debug:
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        print('DEBUG: verify_post_headers ' + method)
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        print('verify_post_headers public_key_pem: ' + str(public_key_pem))
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        print('verify_post_headers headers: ' + str(headers))
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        print('verify_post_headers message_body_json_str: ' +
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              str(message_body_json_str))
							 | 
						
					
						
							
								
									
										
										
										
											2020-03-22 21:16:02 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    pubkey = load_pem_public_key(public_key_pem.encode('utf-8'),
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-04 16:30:32 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                                 backend=default_backend())
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # Build a dictionary of the signature values
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-22 18:30:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if headers.get('Signature-Input') or headers.get('signature-input'):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if headers.get('Signature-Input'):
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            signature_header = headers['Signature-Input']
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-22 18:30:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        else:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            signature_header = headers['signature-input']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        field_sep2 = ','
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 14:03:24 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        # split the signature input into separate fields
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        signature_dict = {
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 14:03:24 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            k.strip(): v.strip()
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            for k, v in [i.split('=', 1) for i in signature_header.split(';')]
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 14:03:24 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        request_target_key = None
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        request_target_str = None
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        for key_str, value_str in signature_dict.items():
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if value_str.startswith('('):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                request_target_key = key_str
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                request_target_str = value_str[1:-1]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            elif value_str.startswith('"'):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                signature_dict[key_str] = value_str[1:-1]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if not request_target_key:
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 14:03:24 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            return False
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        signature_dict[request_target_key] = request_target_str
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 11:13:27 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    else:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        request_target_key = 'headers'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        signature_header = headers['signature']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        field_sep2 = ' '
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 14:03:24 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        # split the signature input into separate fields
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        signature_dict = {
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 14:03:24 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            k: v[1:-1]
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            for k, v in [i.split('=', 1) for i in signature_header.split(',')]
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 14:03:24 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        }
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-14 21:22:49 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if debug:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        print('signature_dict: ' + str(signature_dict))
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-14 21:22:49 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # Unpack the signed headers and set values based on current headers and
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # body (if a digest was included)
							 | 
						
					
						
							
								
									
										
										
										
											2024-12-23 17:45:20 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    signed_header_list: list[str] = []
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-01 14:42:43 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    algorithm = 'rsa-sha256'
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    digest_algorithm = 'rsa-sha256'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    for signed_header in signature_dict[request_target_key].split(field_sep2):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        signed_header = signed_header.strip()
							 | 
						
					
						
							
								
									
										
										
										
											2019-11-12 15:03:17 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if debug:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            print('DEBUG: verify_post_headers signed_header=' + signed_header)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if signed_header == '(request-target)':
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 11:13:27 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            # original Mastodon http signature
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            append_str = f'(request-target): {method.lower()} {path}'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            signed_header_list.append(append_str)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        elif '@request-target' in signed_header:
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 11:13:27 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            # https://tools.ietf.org/html/
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-22 18:30:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            # draft-ietf-httpbis-message-signatures
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            append_str = f'@request-target: {method.lower()} {path}'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            signed_header_list.append(append_str)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        elif '@created' in signed_header:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if signature_dict.get('created'):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                created_str = str(signature_dict['created'])
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                append_str = f'@created: {created_str}'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                signed_header_list.append(append_str)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        elif '@expires' in signed_header:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if signature_dict.get('expires'):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                expires_str = str(signature_dict['expires'])
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                append_str = f'@expires: {expires_str}'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                signed_header_list.append(append_str)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        elif '@method' in signed_header:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            append_str = f'@expires: {method}'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            signed_header_list.append(append_str)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        elif '@scheme' in signed_header:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            signed_header_list.append('@scheme: http')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        elif '@authority' in signed_header:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            authority_str = None
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if signature_dict.get('authority'):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                authority_str = str(signature_dict['authority'])
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            elif signature_dict.get('Authority'):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                authority_str = str(signature_dict['Authority'])
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if authority_str:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                append_str = f'@authority: {authority_str}'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                signed_header_list.append(append_str)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        elif signed_header == 'algorithm':
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if headers.get(signed_header):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                algorithm = headers[signed_header]
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-22 11:52:55 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                if debug:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    print('http signature algorithm: ' + algorithm)
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        elif signed_header == 'digest':
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if message_body_digest:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                body_digest = message_body_digest
							 | 
						
					
						
							
								
									
										
										
										
											2019-08-16 17:19:23 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            else:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                body_digest = \
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    message_content_digest(message_body_json_str,
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                                           digest_algorithm)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            signed_header_list.append(f'digest: SHA-256={body_digest}')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        elif signed_header == 'content-length':
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if headers.get(signed_header):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                append_str = f'content-length: {headers[signed_header]}'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                signed_header_list.append(append_str)
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-01 14:22:11 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            elif headers.get('Content-Length'):
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                content_length = headers['Content-Length']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                signed_header_list.append(f'content-length: {content_length}')
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-01 14:22:11 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            elif headers.get('Content-length'):
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                content_length = headers['Content-length']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                append_str = f'content-length: {content_length}'
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                signed_header_list.append(append_str)
							 | 
						
					
						
							
								
									
										
										
										
											2019-11-12 17:16:34 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            else:
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-01 14:22:11 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                if debug:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    print('DEBUG: verify_post_headers ' + signed_header +
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-01 14:22:11 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                          ' not found in ' + str(headers))
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        else:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            if headers.get(signed_header):
							 | 
						
					
						
							
								
									
										
										
										
											2022-05-30 21:41:18 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                if signed_header == 'date' and not no_recency_check:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    if not _verify_recent_signature(headers[signed_header]):
							 | 
						
					
						
							
								
									
										
										
										
											2019-11-12 15:03:17 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                        if debug:
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-03 12:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                            print('DEBUG: ' +
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                                  'verify_post_headers date is not recent ' +
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                                  headers[signed_header])
							 | 
						
					
						
							
								
									
										
										
										
											2019-08-23 11:30:37 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                        return False
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                signed_header_list.append(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    f'{signed_header}: {headers[signed_header]}')
							 | 
						
					
						
							
								
									
										
										
										
											2019-08-15 21:34:25 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            else:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                if '-' in signed_header:
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-14 12:09:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    # capitalise with dashes
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    # my-header becomes My-Header
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    header_parts = signed_header.split('-')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    signed_header_cap = None
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    for part in header_parts:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                        if signed_header_cap:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                            signed_header_cap += '-' + part.capitalize()
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-14 12:09:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                        else:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                            signed_header_cap = part.capitalize()
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-14 11:53:13 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                else:
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-14 12:09:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    # header becomes Header
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    signed_header_cap = signed_header.capitalize()
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-14 12:09:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                if debug:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    print('signed_header_cap: ' + signed_header_cap)
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-14 12:09:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                # if this is the date header then check it is recent
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                if signed_header_cap == 'Date':
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    signed_hdr_cap = headers[signed_header_cap]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    if not _verify_recent_signature(signed_hdr_cap):
							 | 
						
					
						
							
								
									
										
										
										
											2019-11-12 15:03:17 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                        if debug:
							 | 
						
					
						
							
								
									
										
										
										
											2020-04-03 12:05:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                            print('DEBUG: ' +
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                                  'verify_post_headers date is not recent ' +
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                                  headers[signed_header])
							 | 
						
					
						
							
								
									
										
										
										
											2019-08-23 11:30:37 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                        return False
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-14 12:09:56 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                # add the capitalised header
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                if headers.get(signed_header_cap):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    signed_header_list.append(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                        f'{signed_header}: {headers[signed_header_cap]}')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                elif '-' in signed_header:
							 | 
						
					
						
							
								
									
										
										
										
											2021-03-14 18:34:30 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    # my-header becomes My-header
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								                    signed_header_cap = signed_header.capitalize()
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    if headers.get(signed_header_cap):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                        signed_header_list.append(
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                            f'{signed_header}: {headers[signed_header_cap]}')
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # Now we have our header data digest
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    signed_header_text = '\n'.join(signed_header_list)
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-14 21:22:49 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if debug:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        print('\nverify_post_headers signed_header_text:\n' +
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								              signed_header_text + '\nEND\n')
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # Get the signature, verify with public key, return result
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-22 18:30:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if (headers.get('Signature-Input') and headers.get('Signature')) or \
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								       (headers.get('signature-input') and headers.get('signature')):
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 11:13:27 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        # https://tools.ietf.org/html/
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-22 18:30:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        # draft-ietf-httpbis-message-signatures
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if headers.get('Signature'):
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            headers_sig = headers['Signature']
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-22 18:30:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        else:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            headers_sig = headers['signature']
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 11:13:27 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        # remove sig1=:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if request_target_key + '=:' in headers_sig:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            headers_sig = headers_sig.split(request_target_key + '=:')[1]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            headers_sig = headers_sig[:len(headers_sig)-1]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        signature = base64.b64decode(headers_sig)
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-22 11:13:27 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    else:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # Original Mastodon signature
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        headers_sig = signature_dict['signature']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        signature = base64.b64decode(headers_sig)
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-22 18:30:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if debug:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        print('signature: ' + algorithm + ' ' + headers_sig)
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-22 11:52:55 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    # log unusual signing algorithms
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if signature_dict.get('alg'):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        print('http signature algorithm: ' + signature_dict['alg'])
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-22 11:52:55 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-01 14:42:43 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    # If extra signing algorithms need to be added then do it here
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if not signature_dict.get('alg'):
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-22 11:52:55 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        alg = hazutils.Prehashed(hashes.SHA256())
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    elif (signature_dict['alg'] == 'rsa-sha256' or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          signature_dict['alg'] == 'rsa-v1_5-sha256' or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          signature_dict['alg'] == 'hs2019'):
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-22 11:52:55 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        alg = hazutils.Prehashed(hashes.SHA256())
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    elif (signature_dict['alg'] == 'rsa-sha512' or
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								          signature_dict['alg'] == 'rsa-pss-sha512'):
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-22 11:52:55 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        alg = hazutils.Prehashed(hashes.SHA512())
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    else:
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-01 14:42:43 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        alg = hazutils.Prehashed(hashes.SHA256())
							 | 
						
					
						
							
								
									
										
										
										
											2021-11-22 11:52:55 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    if digest_algorithm == 'rsa-sha256':
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        header_digest = get_sha_256(signed_header_text.encode('ascii'))
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    elif digest_algorithm == 'rsa-sha512':
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        header_digest = get_sha_512(signed_header_text.encode('ascii'))
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-01 14:42:43 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    else:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        print('Unknown http digest algorithm: ' + digest_algorithm)
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        header_digest = ''
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    padding_str = padding.PKCS1v15()
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-01 14:42:43 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    try:
							 | 
						
					
						
							
								
									
										
										
										
											2022-01-02 15:41:05 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        pubkey.verify(signature, header_digest, padding_str, alg)
							 | 
						
					
						
							
								
									
										
										
										
											2019-06-28 18:55:29 +00:00
										 
									 
								 
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return True
							 | 
						
					
						
							
								
									
										
										
										
											2021-02-04 16:30:32 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    except BaseException:
							 | 
						
					
						
							
								
									
										
										
										
											2019-11-12 15:03:17 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								        if debug:
							 | 
						
					
						
							
								
									
										
										
										
											2021-12-29 21:55:09 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								            print('EX: verify_post_headers pkcs1_15 verify failure')
							 | 
						
					
						
							
								
									
										
										
										
											2021-09-14 21:22:49 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								    return False
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-29 14:38:23 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def getheader_signature_input(headers: {}):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """There are different versions of http signatures with
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    different header styles
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if headers.get('Signature-Input'):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # https://tools.ietf.org/html/
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # draft-ietf-httpbis-message-signatures-01
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return headers['Signature-Input']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if headers.get('signature-input'):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return headers['signature-input']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if headers.get('signature'):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        # Ye olde Masto http sig
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return headers['signature']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return None
							 | 
						
					
						
							
								
									
										
										
										
											2024-01-31 22:23:57 +00:00
										 
									 
								 
							 | 
							
								
									
										
									
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								def signed_get_key_id(headers: {}, debug: bool) -> str:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """Returns the actor from the signed GET key_id
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    """
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    signature = None
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if headers.get('signature'):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        signature = headers['signature']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    elif headers.get('Signature'):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        signature = headers['Signature']
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # check that the headers are signed
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    if not signature:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if debug:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            print('AUTH: secure mode actor, ' +
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                  'GET has no signature in headers')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        return None
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    # get the key_id, which is typically the instance actor
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    key_id = None
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    signature_params = signature.split(',')
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    for signature_item in signature_params:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								        if signature_item.startswith('keyId='):
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								            if '"' in signature_item:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                key_id = signature_item.split('"')[1]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                # remove #/main-key or #main-key
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                if '#' in key_id:
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                    key_id = key_id.split('#')[0]
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								                return key_id
							 | 
						
					
						
							| 
								
							 | 
							
								
							 | 
							
								
							 | 
							
							
								    return None
							 |