From bfa1a53836a8287d0245163cc14e4b5787ffb45c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mali=C5=A1a=20Vu=C4=8Dini=C4=87?= Date: Thu, 26 Jul 2018 15:05:11 +0200 Subject: [PATCH 1/2] COAP-41: Return a tuple of (code, options, payload) to the client as part of the response --- bin/test_client.py | 7 +++++-- coap/coap.py | 6 +++--- tests/func/test_BADREQUEST.py | 2 +- tests/func/test_INTERNALSERVERERROR.py | 2 +- tests/func/test_METHODNOTALLOWED.py | 2 +- tests/func/test_NOTFOUND.py | 2 +- tests/func/test_UNAUTHORIZED.py | 4 ++-- tests/func/test_multiple_CON.py | 4 ++-- tests/func/test_multiple_NON.py | 4 ++-- tests/func/test_single_CON.py | 4 ++-- tests/func/test_single_NON.py | 4 ++-- tests/func/test_timeout_CON.py | 2 +- tests/func/test_timeout_NON.py | 2 +- 13 files changed, 24 insertions(+), 21 deletions(-) diff --git a/bin/test_client.py b/bin/test_client.py index 0164861..7f3d91c 100644 --- a/bin/test_client.py +++ b/bin/test_client.py @@ -9,6 +9,7 @@ from coap import coap from coap import coapOption as o from coap import coapObjectSecurity as oscoap +from coap import coapUtils as u import logging_setup @@ -26,13 +27,15 @@ try: # retrieve value of 'test' resource - p = c.GET('coap://[{0}]/test'.format(SERVER_IP), + (respCode, respOptions, respPayload) = c.GET('coap://[{0}]/test'.format(SERVER_IP), confirmable=True, options=[objectSecurity]) print '=====' - print ''.join([chr(b) for b in p]) + print ''.join([chr(b) for b in respPayload]) + print binascii.hexlify(u.buf2str(respPayload)) print '=====' + except Exception as err: print err diff --git a/coap/coap.py b/coap/coap.py index 57884ee..ad29563 100644 --- a/coap/coap.py +++ b/coap/coap.py @@ -76,7 +76,7 @@ def GET(self,uri,confirmable=True,options=[]): options = options, ) log.debug('response: {0}'.format(response)) - return response['payload'] + return (response['code'], response['options'], response['payload']) def PUT(self,uri,confirmable=True,options=[],payload=None): response = self._transmit( @@ -87,7 +87,7 @@ def PUT(self,uri,confirmable=True,options=[],payload=None): payload = payload ) log.debug('response: {0}'.format(response)) - return response['payload'] + return (response['code'], response['options'], response['payload']) def POST(self,uri,confirmable=True,options=[],payload=None): response = self._transmit( @@ -98,7 +98,7 @@ def POST(self,uri,confirmable=True,options=[],payload=None): payload = payload ) log.debug('response: {0}'.format(response)) - return response['payload'] + return (response['code'], response['options'], response['payload']) def DELETE(self,uri,confirmable=True,options=[]): self._transmit( diff --git a/tests/func/test_BADREQUEST.py b/tests/func/test_BADREQUEST.py index d48cee2..7da409b 100644 --- a/tests/func/test_BADREQUEST.py +++ b/tests/func/test_BADREQUEST.py @@ -43,7 +43,7 @@ def test_BADREQUEST(logFixture, snoopyDispatcher, twoEndPoints, confirmableFixtu clientOptions = [o.ObjectSecurity(context=clientContext)] with pytest.raises(e.coapRcBadRequest): - reply = coap2.GET( + (respCode, respOptions, respPayload) = coap2.GET( uri='coap://[{0}]:{1}/{2}/'.format(IPADDRESS1, d.DEFAULT_UDP_PORT, RESOURCE), confirmable=confirmableFixture, options=clientOptions diff --git a/tests/func/test_INTERNALSERVERERROR.py b/tests/func/test_INTERNALSERVERERROR.py index 91d931b..004a8a2 100644 --- a/tests/func/test_INTERNALSERVERERROR.py +++ b/tests/func/test_INTERNALSERVERERROR.py @@ -71,7 +71,7 @@ def test_GET(logFixture,snoopyDispatcher,twoEndPoints): # have coap2 do a get with pytest.raises(e.coapRcInternalServerError): - reply = coap2.GET( + (respCode, respOptions, respPayload) = coap2.GET( uri = 'coap://[{0}]:{1}/{2}/'.format(IPADDRESS1,d.DEFAULT_UDP_PORT,'buggy'), confirmable = True, options=clientOptions diff --git a/tests/func/test_METHODNOTALLOWED.py b/tests/func/test_METHODNOTALLOWED.py index d038b4d..785b0c1 100644 --- a/tests/func/test_METHODNOTALLOWED.py +++ b/tests/func/test_METHODNOTALLOWED.py @@ -40,7 +40,7 @@ def test_METHODNOTALLOWED(logFixture,snoopyDispatcher,twoEndPoints,confirmableFi # have coap2 do a post with pytest.raises(e.coapRcMethodNotAllowed): - reply = coap2.POST( + (respCode, respOptions, respPayload) = coap2.POST( uri = 'coap://[{0}]:{1}/{2}/'.format(IPADDRESS1,d.DEFAULT_UDP_PORT,RESOURCE), confirmable = confirmableFixture, options=options diff --git a/tests/func/test_NOTFOUND.py b/tests/func/test_NOTFOUND.py index 09c9567..5a08c08 100644 --- a/tests/func/test_NOTFOUND.py +++ b/tests/func/test_NOTFOUND.py @@ -41,7 +41,7 @@ def test_NOTFOUND(logFixture,snoopyDispatcher,twoEndPoints,confirmableFixture): # have coap2 do a get with pytest.raises(e.coapRcNotFound): - reply = coap2.GET( + (respCode, respOptions, respPayload) = coap2.GET( uri = 'coap://[{0}]:{1}/{2}/'.format(IPADDRESS1,d.DEFAULT_UDP_PORT,RESOURCE_INVALID), confirmable = confirmableFixture, options=options, diff --git a/tests/func/test_UNAUTHORIZED.py b/tests/func/test_UNAUTHORIZED.py index 716a8fd..9e5bbd8 100644 --- a/tests/func/test_UNAUTHORIZED.py +++ b/tests/func/test_UNAUTHORIZED.py @@ -36,7 +36,7 @@ def test_UNAUTHORIZED_1(logFixture,snoopyDispatcher,twoEndPoints,confirmableFixt if securityEnabled: # have coap2 do a get without including an Object-Security option with pytest.raises(e.coapRcUnauthorized): - reply = coap2.GET( + (respCode, respOptions, respPayload) = coap2.GET( uri = 'coap://[{0}]:{1}/{2}/'.format(IPADDRESS1,d.DEFAULT_UDP_PORT,RESOURCE), confirmable = confirmableFixture, options=[] @@ -61,7 +61,7 @@ def test_UNAUTHORIZED_2(logFixture, snoopyDispatcher, twoEndPoints, confirmableF clientOptions = [o.ObjectSecurity(context=clientContext)] with pytest.raises(e.coapRcUnauthorized): - reply = coap2.GET( + (respCode, respOptions, respPayload) = coap2.GET( uri='coap://[{0}]:{1}/{2}/'.format(IPADDRESS1, d.DEFAULT_UDP_PORT, RESOURCE), confirmable=confirmableFixture, options=clientOptions diff --git a/tests/func/test_multiple_CON.py b/tests/func/test_multiple_CON.py index 66da71f..74ecae2 100644 --- a/tests/func/test_multiple_CON.py +++ b/tests/func/test_multiple_CON.py @@ -36,10 +36,10 @@ def test_GET(logFixture,snoopyDispatcher,twoEndPoints): # have coap2 do a get for _ in range(20): - reply = coap2.GET( + (respCode, respOptions, respPayload) = coap2.GET( uri = 'coap://[{0}]:{1}/{2}/'.format(IPADDRESS1,d.DEFAULT_UDP_PORT,RESOURCE), confirmable = False, options=options ) - assert reply==DUMMYVAL + assert respPayload==DUMMYVAL diff --git a/tests/func/test_multiple_NON.py b/tests/func/test_multiple_NON.py index 8c5a469..fe2e00f 100644 --- a/tests/func/test_multiple_NON.py +++ b/tests/func/test_multiple_NON.py @@ -35,9 +35,9 @@ def test_GET(logFixture,snoopyDispatcher,twoEndPoints): # have coap2 do a get for _ in range(20): - reply = coap2.GET( + (respCode, respOptions, respPayload) = coap2.GET( uri = 'coap://[{0}]:{1}/{2}/'.format(IPADDRESS1,d.DEFAULT_UDP_PORT,RESOURCE), confirmable = False, options = options ) - assert reply==DUMMYVAL + assert respPayload==DUMMYVAL diff --git a/tests/func/test_single_CON.py b/tests/func/test_single_CON.py index 4e49492..1d5e9de 100644 --- a/tests/func/test_single_CON.py +++ b/tests/func/test_single_CON.py @@ -33,10 +33,10 @@ def test_GET(logFixture,snoopyDispatcher,twoEndPoints): options = [o.ObjectSecurity(context=context)] # have coap2 do a get - reply = coap2.GET( + (respCode, respOptions, respPayload) = coap2.GET( uri='coap://[{0}]:{1}/{2}/'.format(IPADDRESS1, d.DEFAULT_UDP_PORT, RESOURCE), confirmable=False, options=options ) - assert reply == DUMMYVAL + assert respPayload == DUMMYVAL diff --git a/tests/func/test_single_NON.py b/tests/func/test_single_NON.py index aeb5e32..a6b05df 100644 --- a/tests/func/test_single_NON.py +++ b/tests/func/test_single_NON.py @@ -34,10 +34,10 @@ def test_GET(logFixture,snoopyDispatcher,twoEndPoints): options = [o.ObjectSecurity(context=context)] # have coap2 do a get - reply = coap2.GET( + (respCode, respOptions, respPayload) = coap2.GET( uri = 'coap://[{0}]:{1}/{2}/'.format(IPADDRESS1,d.DEFAULT_UDP_PORT,RESOURCE), confirmable = False, options=options, ) - assert reply==DUMMYVAL + assert respPayload==DUMMYVAL diff --git a/tests/func/test_timeout_CON.py b/tests/func/test_timeout_CON.py index 0b6264b..941a5d9 100644 --- a/tests/func/test_timeout_CON.py +++ b/tests/func/test_timeout_CON.py @@ -46,7 +46,7 @@ def test_GET(logFixture,snoopyDispatcher,twoEndPoints): # have coap2 do a get with pytest.raises(e.coapTimeout): - reply = coap2.GET( + (respCode, respOptions, respPayload) = coap2.GET( uri = 'coap://[{0}]:{1}/{2}/'.format(IPADDRESS_INVALID,d.DEFAULT_UDP_PORT,RESOURCE), confirmable = True, options=options, diff --git a/tests/func/test_timeout_NON.py b/tests/func/test_timeout_NON.py index be6cb08..4820aee 100644 --- a/tests/func/test_timeout_NON.py +++ b/tests/func/test_timeout_NON.py @@ -46,7 +46,7 @@ def test_GET(logFixture,snoopyDispatcher,twoEndPoints): # have coap2 do a get with pytest.raises(e.coapTimeout): - reply = coap2.GET( + (respCode, respOptions, respPayload) = coap2.GET( uri = 'coap://[{0}]:{1}/{2}/'.format(IPADDRESS_INVALID,d.DEFAULT_UDP_PORT,RESOURCE), confirmable = False, options=options From dd90fbbb7027edca1624104f6a15184aea143a78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mali=C5=A1a=20Vu=C4=8Dini=C4=87?= Date: Thu, 26 Jul 2018 15:53:37 +0200 Subject: [PATCH 2/2] COAP-42: Make hkdfDeriveParameter a public method --- coap/coapObjectSecurity.py | 59 ++++++++++++++------------------------ 1 file changed, 21 insertions(+), 38 deletions(-) diff --git a/coap/coapObjectSecurity.py b/coap/coapObjectSecurity.py index df44cf1..ddeccd2 100644 --- a/coap/coapObjectSecurity.py +++ b/coap/coapObjectSecurity.py @@ -345,7 +345,7 @@ class AES_CCM_16_64_128(CCMAlgorithm): class SecurityContext: REPLAY_WINDOW_SIZE = 64 - def __init__(self, masterSecret, senderID, recipientID, aeadAlgorithm = AES_CCM_64_64_128(), masterSalt = '', hashFunction = hashlib.sha256): + def __init__(self, masterSecret='', senderID='', recipientID='', aeadAlgorithm=AES_CCM_64_64_128(), masterSalt='', hashFunction=hashlib.sha256): # Common context self.aeadAlgorithm = aeadAlgorithm @@ -355,43 +355,27 @@ def __init__(self, masterSecret, senderID, recipientID, aeadAlgorithm = AES_CCM_ # Sender context self.senderID = senderID - self.senderKey = self._hkdfDeriveParameter(self.hashFunction, - self.masterSecret, - self.masterSalt, - self.senderID, - self.aeadAlgorithm.value, - 'Key', - self.aeadAlgorithm.keyLength - ) - - self.senderIV = self._hkdfDeriveParameter(self.hashFunction, - self.masterSecret, - self.masterSalt, - self.senderID, - self.aeadAlgorithm.value, - 'IV', - self.aeadAlgorithm.ivLength + self.senderKey = self.hkdfDeriveParameter(self.senderID, + 'Key', + self.aeadAlgorithm.keyLength ) + + self.senderIV = self.hkdfDeriveParameter(self.senderID, + 'IV', + self.aeadAlgorithm.ivLength + ) self.sequenceNumber = 0 # Recipient context self.recipientID = recipientID - self.recipientKey = self._hkdfDeriveParameter(self.hashFunction, - self.masterSecret, - self.masterSalt, - self.recipientID, - self.aeadAlgorithm.value, - 'Key', - self.aeadAlgorithm.keyLength + self.recipientKey = self.hkdfDeriveParameter(self.recipientID, + 'Key', + self.aeadAlgorithm.keyLength + ) + self.recipientIV = self.hkdfDeriveParameter(self.recipientID, + 'IV', + self.aeadAlgorithm.ivLength ) - self.recipientIV = self._hkdfDeriveParameter(self.hashFunction, - self.masterSecret, - self.masterSalt, - self.recipientID, - self.aeadAlgorithm.value, - 'IV', - self.aeadAlgorithm.ivLength - ) self.replayWindow = [0] # ======================== public ========================================== @@ -423,19 +407,18 @@ def replayWindowUpdate(self, sequenceNumber): self.replayWindow += [sequenceNumber] - # ======================== private ========================================== - - def _hkdfDeriveParameter(self, hashFunction, masterSecret, masterSalt, id, algorithm, type, length): + def hkdfDeriveParameter(self, id='', type='', length=16): info = cbor.dumps([ id, - algorithm, + self.aeadAlgorithm.value, unicode(type), # encode as text string length ]) - extract = hkdf.hkdf_extract(salt=masterSalt, input_key_material=masterSecret, hash=hashFunction) - expand = hkdf.hkdf_expand(pseudo_random_key=extract, info=info, length=length, hash=hashFunction) + extract = hkdf.hkdf_extract(salt=self.masterSalt, input_key_material=self.masterSecret, hash=self.hashFunction) + expand = hkdf.hkdf_expand(pseudo_random_key=extract, info=info, length=length, hash=self.hashFunction) return expand + # ======================== private ==========================================