From d9cda147828c48350f130232e00a7c173483255b Mon Sep 17 00:00:00 2001 From: Bob Mottram Date: Wed, 8 Sep 2021 11:05:45 +0100 Subject: [PATCH] Signing GET requests --- httpsig.py | 22 ++++++++++++++++------ session.py | 6 +----- utils.py | 8 ++++++++ 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/httpsig.py b/httpsig.py index 96fc2d338..cd3819ef8 100644 --- a/httpsig.py +++ b/httpsig.py @@ -24,6 +24,7 @@ from time import gmtime, strftime import datetime from utils import getFullDomain from utils import getSHA256 +from utils import getSHA512 from utils import localActorUrl @@ -49,11 +50,12 @@ def signPostHeaders(dateStr: str, privateKeyPem: str, if not dateStr: dateStr = strftime("%a, %d %b %Y %H:%M:%S %Z", gmtime()) - if nickname != domain: - keyID = localActorUrl(httpPrefix, nickname, domain) + '#main-key' + if nickname != domain and nickname.lower() != 'actor': + keyID = localActorUrl(httpPrefix, nickname, domain) else: # instance actor - keyID = httpPrefix + '://' + domain + '/actor#main-key' + keyID = httpPrefix + '://' + domain + '/actor' + keyID += '#main-key' if not messageBodyJsonStr: headers = { '(request-target)': f'get {path}', @@ -82,7 +84,8 @@ def signPostHeaders(dateStr: str, privateKeyPem: str, signedHeaderText = '' for headerKey in signedHeaderKeys: signedHeaderText += f'{headerKey}: {headers[headerKey]}\n' - signedHeaderText = signedHeaderText.strip() + # strip the trailing linefeed + signedHeaderText = signedHeaderText.rstrip('\n') # signedHeaderText.encode('ascii') matches headerDigest = getSHA256(signedHeaderText.encode('ascii')) # print('headerDigest2: ' + str(headerDigest)) @@ -159,11 +162,18 @@ def signPostHeadersNew(dateStr: str, privateKeyPem: str, for headerKey in signedHeaderKeys: signedHeaderText += f'{headerKey}: {headers[headerKey]}\n' signedHeaderText = signedHeaderText.strip() - headerDigest = getSHA256(signedHeaderText.encode('ascii')) # Sign the digest. Potentially other signing algorithms can be added here. signature = '' - if algorithm == 'rsa-sha256': + if algorithm == 'rsa-sha512': + headerDigest = getSHA512(signedHeaderText.encode('ascii')) + rawSignature = key.sign(headerDigest, + padding.PKCS1v15(), + hazutils.Prehashed(hashes.SHA512())) + signature = base64.b64encode(rawSignature).decode('ascii') + else: + # default sha256 + headerDigest = getSHA256(signedHeaderText.encode('ascii')) rawSignature = key.sign(headerDigest, padding.PKCS1v15(), hazutils.Prehashed(hashes.SHA256())) diff --git a/session.py b/session.py index f7cdfe899..474f83bf0 100644 --- a/session.py +++ b/session.py @@ -175,11 +175,8 @@ def _getJsonSigned(session, url: str, domainFull: str, sessionHeaders: {}, toPort = 443 else: toPort = 80 - # instance actor - nickname = domain # if debug: - print('Signed GET nickname: ' + nickname) print('Signed GET domain: ' + domain + ' ' + str(port)) print('Signed GET toDomain: ' + toDomain + ' ' + str(toPort)) print('Signed GET url: ' + url) @@ -191,7 +188,7 @@ def _getJsonSigned(session, url: str, domainFull: str, sessionHeaders: {}, else: path = '/actor' signatureHeaderJson = \ - createSignedHeader(signingPrivateKeyPem, nickname, domain, port, + createSignedHeader(signingPrivateKeyPem, 'actor', domain, port, toDomain, toPort, path, httpPrefix, withDigest, messageStr) print('Signed GET signatureHeaderJson ' + str(signatureHeaderJson)) @@ -201,7 +198,6 @@ def _getJsonSigned(session, url: str, domainFull: str, sessionHeaders: {}, sessionHeaders[key.title()] = value if sessionHeaders.get(key.lower()): del sessionHeaders[key.lower()] - sessionHeaders['Content-Length'] = '0' print('Signed GET sessionHeaders ' + str(sessionHeaders)) return _getJsonRequest(session, url, domainFull, sessionHeaders, diff --git a/utils.py b/utils.py index 5dc621815..592ef0c25 100644 --- a/utils.py +++ b/utils.py @@ -147,6 +147,14 @@ def getSHA256(msg: str): return digest.finalize() +def getSHA512(msg: str): + """Returns a SHA512 hash of the given string + """ + digest = hashes.Hash(hashes.SHA512(), backend=default_backend()) + digest.update(msg) + return digest.finalize() + + def _localNetworkHost(host: str) -> bool: """Returns true if the given host is on the local network """