Calculate message body digest from incoming bytes to avoid any json conversion issues

master
Bob Mottram 2019-08-16 18:19:23 +01:00
parent ffde81d909
commit 1b1810ff8a
4 changed files with 31 additions and 22 deletions

View File

@ -383,7 +383,7 @@ class PubServer(BaseHTTPRequestHandler):
self.server.projectVersion)
return True
def _updateInboxQueue(self,nickname: str,messageJson: {}) -> int:
def _updateInboxQueue(self,nickname: str,messageJson: {},messageBytes: str) -> int:
"""Update the inbox queue
"""
# Check if the queue is full
@ -410,11 +410,12 @@ class PubServer(BaseHTTPRequestHandler):
# save the json for later queue processing
queueFilename = \
savePostToInboxQueue(self.server.baseDir, \
self.server.httpPrefix, \
nickname, \
self.server.domainFull, \
savePostToInboxQueue(self.server.baseDir,
self.server.httpPrefix,
nickname,
self.server.domainFull,
messageJson,
messageBytes.decode('utf-8'),
headersDict,
self.path,
self.server.debug)
@ -2750,7 +2751,7 @@ class PubServer(BaseHTTPRequestHandler):
else:
self.postToNickname=pathUsersSection.split('/')[0]
if self.postToNickname:
queueStatus=self._updateInboxQueue(self.postToNickname,messageJson)
queueStatus=self._updateInboxQueue(self.postToNickname,messageJson,messageBytes)
if queueStatus==0:
self.send_response(200)
self.end_headers()
@ -2771,7 +2772,7 @@ class PubServer(BaseHTTPRequestHandler):
else:
if self.path == '/sharedInbox' or self.path == '/inbox':
print('DEBUG: POST to shared inbox')
queueStatus=self._updateInboxQueue('inbox',messageJson)
queueStatus=self._updateInboxQueue('inbox',messageJson,messageBytes)
if queueStatus==0:
self.send_response(200)
self.end_headers()

View File

@ -19,12 +19,16 @@ import json
from time import gmtime, strftime
from pprint import pprint
def messageContentDigest(messageBodyJsonStr: str) -> str:
return base64.b64encode(SHA256.new(messageBodyJsonStr.encode()).digest()).decode('utf-8')
def signPostHeaders(dateStr: str,privateKeyPem: str, \
nickname: str, \
domain: str,port: int, \
toDomain: str,toPort: int, \
path: str, \
httpPrefix: str, messageBodyJson: {}) -> str:
httpPrefix: str, \
messageBodyJson: {}) -> str:
"""Returns a raw signature string that can be plugged into a header and
used to verify the authenticity of an HTTP transmission.
"""
@ -45,8 +49,7 @@ def signPostHeaders(dateStr: str,privateKeyPem: str, \
headers = {'(request-target)': f'post {path}','host': toDomain,'date': dateStr,'content-type': 'application/json'}
else:
messageBodyJsonStr=json.dumps(messageBodyJson)
bodyDigest = \
base64.b64encode(SHA256.new(messageBodyJsonStr.encode()).digest()).decode('utf-8')
bodyDigest=messageContentDigest(messageBodyJsonStr)
headers = {'(request-target)': f'post {path}','host': toDomain,'date': dateStr,'digest': f'SHA-256={bodyDigest}','content-type': 'application/activity+json'}
privateKeyPem = RSA.import_key(privateKeyPem)
#headers.update({
@ -101,8 +104,7 @@ def createSignedHeader(privateKeyPem: str,nickname: str, \
path,httpPrefix,None)
else:
messageBodyJsonStr=json.dumps(messageBodyJson)
bodyDigest = \
base64.b64encode(SHA256.new(messageBodyJsonStr.encode()).digest()).decode('utf-8')
bodyDigest=messageContentDigest(messageBodyJsonStr)
print('***************************Send (request-target): post '+path)
print('***************************Send host: '+headerDomain)
print('***************************Send date: '+dateStr)
@ -120,6 +122,7 @@ def createSignedHeader(privateKeyPem: str,nickname: str, \
def verifyPostHeaders(httpPrefix: str,publicKeyPem: str,headers: dict, \
path: str,GETmethod: bool, \
messageBodyDigest: str, \
messageBodyJsonStr: str) -> bool:
"""Returns true or false depending on if the key that we plugged in here
validates against the headers, method, and path.
@ -153,8 +156,10 @@ def verifyPostHeaders(httpPrefix: str,publicKeyPem: str,headers: dict, \
f'(request-target): {method.lower()} {path}')
print('***************************Verify (request-target): '+method.lower()+' '+path)
elif signedHeader == 'digest':
bodyDigest = \
base64.b64encode(SHA256.new(messageBodyJsonStr.strip().encode()).digest()).decode('utf-8')
if messageBodyDigest:
bodyDigest=messageBodyDigest
else:
bodyDigest = messageContentDigest(messageBodyJsonStr)
signedHeaderList.append(f'digest: SHA-256={bodyDigest}')
print('***************************Verify digest: SHA-256='+bodyDigest)
print('***************************Verify messageBodyJsonStr: '+messageBodyJsonStr)

View File

@ -41,6 +41,7 @@ from like import undoLikesCollectionEntry
from blocking import isBlocked
from filters import isFiltered
from announce import updateAnnounceCollection
from httpsig import messageContentDigest
def validInbox(baseDir: str,nickname: str,domain: str) -> bool:
"""Checks whether files were correctly saved to the inbox
@ -165,7 +166,7 @@ def validPublishedDate(published) -> bool:
return False
return True
def savePostToInboxQueue(baseDir: str,httpPrefix: str,nickname: str, domain: str,postJsonObject: {},httpHeaders: {},postPath: str,debug: bool) -> str:
def savePostToInboxQueue(baseDir: str,httpPrefix: str,nickname: str, domain: str,postJsonObject: {},messageBytes: str,httpHeaders: {},postPath: str,debug: bool) -> str:
"""Saves the give json to the inbox queue for the person
keyId specifies the actor sending the post
"""
@ -241,6 +242,7 @@ def savePostToInboxQueue(baseDir: str,httpPrefix: str,nickname: str, domain: str
'httpHeaders': httpHeaders,
'path': postPath,
'post': postJsonObject,
'digest': messageContentDigest(messageBytes),
'filename': filename,
'destination': destination
}
@ -1156,6 +1158,7 @@ def runInboxQueue(projectVersion: str, \
pubKey, \
queueJson['httpHeaders'], \
queueJson['path'],False, \
queueJson['digest'], \
json.dumps(queueJson['post'])):
if debug:
print('DEBUG: Header signature check failed')

View File

@ -111,14 +111,14 @@ def testHttpsigBase(withDigest):
boxpath, httpPrefix, messageBodyJson)
headers['signature'] = signatureHeader
assert verifyPostHeaders(httpPrefix, publicKeyPem, headers, \
boxpath,False, \
assert verifyPostHeaders(httpPrefix,publicKeyPem,headers, \
boxpath,False,None, \
messageBodyJsonStr)
assert verifyPostHeaders(httpPrefix, publicKeyPem, headers, \
'/parambulator'+boxpath,False, \
assert verifyPostHeaders(httpPrefix,publicKeyPem,headers, \
'/parambulator'+boxpath,False,None, \
messageBodyJsonStr) == False
assert verifyPostHeaders(httpPrefix, publicKeyPem, headers, \
boxpath,True, \
assert verifyPostHeaders(httpPrefix,publicKeyPem,headers, \
boxpath,True,None, \
messageBodyJsonStr) == False
if not withDigest:
# fake domain
@ -130,7 +130,7 @@ def testHttpsigBase(withDigest):
headers = {'host': domain,'date': dateStr,'digest': f'SHA-256={bodyDigest}','content-type': contentType}
headers['signature'] = signatureHeader
assert verifyPostHeaders(httpPrefix,publicKeyPem,headers, \
boxpath,True, \
boxpath,True,None, \
messageBodyJsonStr) == False
os.chdir(baseDir)
shutil.rmtree(path)