Ejemplo n.º 1
0
def parseMessage(message):

    returnVal = {}

    # header
    if len(message) < 4:
        raise e.messageFormatError(
            'message too short, {0} bytes: no space for header'.format(
                len(message)))
    returnVal['version'] = (message[0] >> 6) & 0x03
    if returnVal['version'] != d.COAP_VERSION:
        raise e.messageFormatError('invalid CoAP version {0}'.format(
            returnVal['version']))
    returnVal['type'] = (message[0] >> 4) & 0x03
    if returnVal['type'] not in d.TYPE_ALL:
        raise e.messageFormatError('invalid message type {0}'.format(
            returnVal['type']))
    TKL = message[0] & 0x0f
    if TKL > 8:
        raise e.messageFormatError('TKL too large {0}'.format(TKL))
    returnVal['code'] = message[1]
    returnVal['messageId'] = u.buf2int(message[2:4])
    message = message[4:]

    # token
    if len(message) < TKL:
        raise e.messageFormatError(
            'message too short, {0} bytes: no space for token'.format(
                len(message)))
    if TKL:
        returnVal['token'] = u.buf2int(message[:TKL])
        message = message[TKL:]
    else:
        returnVal['token'] = None

    # outer options and payload/ciphertext
    (returnVal['options'], payload) = decodeOptionsAndPayload(message)

    # if object security option is present decode the value in order to be able to decrypt the message
    objectSecurity = oscoap.objectSecurityOptionLookUp(returnVal['options'])
    if objectSecurity:
        oscoapDict = oscoap.parseObjectSecurity(
            objectSecurity.getPayloadBytes(), payload)
        objectSecurity.setKid(oscoapDict['kid'])
        returnVal.update(oscoapDict)
    else:
        returnVal['payload'] = payload

    log.debug('parsed message: {0}'.format(returnVal))

    return returnVal
Ejemplo n.º 2
0
def parseMessage(message):

    returnVal = {}

    # header
    if len(message) < 4:
        raise e.messageFormatError(
            'message to short, {0} bytes: not space for header'.format(
                len(message)))
    returnVal['version'] = (message[0] >> 6) & 0x03
    if returnVal['version'] != d.COAP_VERSION:
        raise e.messageFormatError('invalid CoAP version {0}'.format(
            returnVal['version']))
    returnVal['type'] = (message[0] >> 4) & 0x03
    if returnVal['type'] not in d.TYPE_ALL:
        raise e.messageFormatError('invalid message type {0}'.format(
            returnVal['type']))
    TKL = message[0] & 0x0f
    if TKL > 8:
        raise e.messageFormatError('TKL too large {0}'.format(TKL))
    returnVal['code'] = message[1]
    returnVal['messageId'] = u.buf2int(message[2:4])
    message = message[4:]

    # token
    if len(message) < TKL:
        raise e.messageFormatError(
            'message to short, {0} bytes: not space for token'.format(
                len(message)))
    returnVal['token'] = u.buf2int(message[:TKL])
    message = message[TKL:]

    # options
    returnVal['options'] = []
    currentOptionNumber = 0
    while True:
        (option, message) = o.parseOption(message, currentOptionNumber)
        if not option:
            break
        returnVal['options'] += [option]
        currentOptionNumber = option.optionNumber

    # payload
    returnVal['payload'] = message

    log.debug('parsed message: {0}'.format(returnVal))

    return returnVal
Ejemplo n.º 3
0
def parseMessage(message):

    returnVal = {}
    print "received message {0}".format(",".join(str(c) for c in message))
    # header
    if len(message) < 4:
        raise e.messageFormatError("message to short, {0} bytes: not space for header".format(len(message)))
    returnVal["version"] = (message[0] >> 6) & 0x03
    if returnVal["version"] != d.COAP_VERSION:
        raise e.messageFormatError("invalid CoAP version {0}".format(returnVal["version"]))
    returnVal["type"] = (message[0] >> 4) & 0x03
    if returnVal["type"] not in d.TYPE_ALL:
        raise e.messageFormatError("invalid message type {0}".format(returnVal["type"]))
    TKL = message[0] & 0x0F
    if TKL > 8:
        raise e.messageFormatError("TKL too large {0}".format(TKL))
    returnVal["code"] = message[1]
    returnVal["messageId"] = u.buf2int(message[2:4])
    message = message[4:]

    # token
    if len(message) < TKL:
        raise e.messageFormatError("message to short, {0} bytes: not space for token".format(len(message)))
    returnVal["token"] = u.buf2int(message[:TKL])
    message = message[TKL:]

    # options
    returnVal["options"] = []
    currentOptionNumber = 0
    while True:
        (option, message) = o.parseOption(message, currentOptionNumber)
        if not option:
            break
        returnVal["options"] += [option]
        currentOptionNumber = option.optionNumber

    # payload
    returnVal["payload"] = message

    log.debug("parsed message: {0}".format(returnVal))

    return returnVal
Ejemplo n.º 4
0
def parseObjectSecurity(optionValue, payload):
    if optionValue and payload:
        raise e.messageFormatError('invalid oscoap message, both payload and value are set.')
    elif optionValue:
        buffer = optionValue
    elif payload:
        buffer = payload
    else:
        raise e.messageFormatError('invalid oscoap message. no value or payload found.')

    returnVal = {}

    # decode first byte
    pivsz = (buffer[0] >> 0) & 0x07
    k = (buffer[0] >> 3) & 0x01
    reserved = (buffer[0] >> 4) & 0x0f

    if reserved:
        raise e.messageFormatError('invalid oscoap message. reserved bits set.')

    buffer = buffer[1:]

    returnVal['partialIV'] = []
    if pivsz:
        returnVal['partialIV'] = buffer[:pivsz]
        buffer = buffer[pivsz:]

    returnVal['kid'] = []
    if k:
        kidLength = buffer[0]
        buffer = buffer[1:]
        returnVal['kid'] = buffer[:kidLength]
        buffer = buffer[kidLength:]

    returnVal['ciphertext'] = buffer

    return returnVal
Ejemplo n.º 5
0
def parseOption(message,previousOptionNumber):
    '''
    \brief Extract an option from the beginning of a message.
    
    \param[in] message              A list of bytes.
    \param[in] previousOptionNumber The option number from the previous option
        in the message; set to 0 if this is the first option.
    
    \return A tuple with the following elements:
        - element 0 is the option that was extracted. If no option was found
          (end of the options or end of the packet), None is returned.
        - element 1 is the message without the option.
    '''
    
    log.debug(
        'parseOption message={0} previousOptionNumber={1}'.format(
            u.formatBuf(message),
            previousOptionNumber,
        )
    )
    
    #==== detect end of packet
    if len(message)==0:
        message = message[1:]
        return (None,message)
    
    #==== detect payload marker
    if message[0]==d.COAP_PAYLOAD_MARKER:
        message = message[1:]
        return (None,message)
    
    #==== parse option
    
    # header
    optionDelta  = (message[0]>>4)&0x0f
    optionLength = (message[0]>>0)&0x0f
    message = message[1:]
    
    # optionDelta
    if   optionDelta<=12:
        pass
    elif optionDelta==13:
        if len(message)<1:
            raise e.messageFormatError('message to short, {0} bytes: not space for 1B optionDelta'.format(len(message)))
        optionDelta = u.buf2int(message[0])+13
        message = message[1:]
    elif optionDelta==14:
        if len(message)<2:
            raise e.messageFormatError('message to short, {0} bytes: not space for 2B optionDelta'.format(len(message)))
        optionDelta = u.buf2int(message[0:1])+269
        message = message[2:]
    else:
        raise e.messageFormatError('invalid optionDelta={0}'.format(optionDelta))
    
    log.debug('optionDelta   = {0}'.format(optionDelta))
    
    # optionLength
    if   optionLength<=12:
        pass
    elif optionLength==13:
        if len(message)<1:
            raise e.messageFormatError('message to short, {0} bytes: not space for 1B optionLength'.format(len(message)))
        optionLength = u.buf2int(message[0])+13
        message = message[1:]
    elif optionLength==14:
        if len(message)<2:
            raise e.messageFormatError('message to short, {0} bytes: not space for 2B optionLength'.format(len(message)))
        optionLength = u.buf2int(message[0:1])+269
        message = message[2:]
    else:
        raise e.messageFormatError('invalid optionLength={0}'.format(optionLength))
    
    log.debug('optionLength  = {0}'.format(optionLength))
    
    # optionValue
    if len(message)<optionLength:
        raise e.messageFormatError('message to short, {0} bytes: not space for optionValue'.format(len(message)))
    optionValue = message[:optionLength]
    message = message[optionLength:]
    
    log.debug('optionValue   = {0}'.format(u.formatBuf(optionValue)))
    
    #===== create option
    optionNumber = previousOptionNumber+optionDelta
    
    log.debug('optionNumber  = {0}'.format(optionNumber))
    
    if optionNumber not in d.OPTION_NUM_ALL:
        raise e.messageFormatError('invalid option number {0} (0x{0:x})'.format(optionNumber))
    
    if   optionNumber==d.OPTION_NUM_URIPATH:
        option = UriPath(path=''.join([chr(b) for b in optionValue]))
    elif optionNumber==d.OPTION_NUM_CONTENTFORMAT:
        option = ContentFormat(cformat=optionValue)
    elif optionNumber==d.OPTION_NUM_BLOCK2:
        option = Block2(rawbytes=optionValue)
    else:
        raise NotImplementedError('option {0} not implemented'.format(optionNumber))
    
    return (option,message)
Ejemplo n.º 6
0
def parseOption(message, previousOptionNumber):
    '''
    \brief Extract an option from the beginning of a message.
    
    \param[in] message              A list of bytes.
    \param[in] previousOptionNumber The option number from the previous option
        in the message; set to 0 if this is the first option.
    
    \return A tuple with the following elements:
        - element 0 is the option that was extracted. If no option was found
          (end of the options or end of the packet), None is returned.
        - element 1 is the message without the option.
    '''

    log.debug('parseOption message={0} previousOptionNumber={1}'.format(
        u.formatBuf(message),
        previousOptionNumber,
    ))

    #==== detect end of packet
    if len(message) == 0:
        message = message[1:]
        return (None, message)

    #==== detect payload marker
    if message[0] == d.COAP_PAYLOAD_MARKER:
        message = message[1:]
        return (None, message)

    #==== parse option

    # header
    optionDelta = (message[0] >> 4) & 0x0f
    optionLength = (message[0] >> 0) & 0x0f
    message = message[1:]

    # optionDelta
    if optionDelta <= 12:
        pass
    elif optionDelta == 13:
        if len(message) < 1:
            raise e.messageFormatError(
                'message too short, {0} bytes: no space for 1B optionDelta'.
                format(len(message)))
        optionDelta = u.buf2int(message[0:1]) + 13
        message = message[1:]
    elif optionDelta == 14:
        if len(message) < 2:
            raise e.messageFormatError(
                'message too short, {0} bytes: no space for 2B optionDelta'.
                format(len(message)))
        optionDelta = u.buf2int(message[0:2]) + 269
        message = message[2:]
    else:
        raise e.messageFormatError(
            'invalid optionDelta={0}'.format(optionDelta))

    log.debug('optionDelta   = {0}'.format(optionDelta))

    # optionLength
    if optionLength <= 12:
        pass
    elif optionLength == 13:
        if len(message) < 1:
            raise e.messageFormatError(
                'message too short, {0} bytes: no space for 1B optionLength'.
                format(len(message)))
        optionLength = u.buf2int(message[0:1]) + 13
        message = message[1:]
    elif optionLength == 14:
        if len(message) < 2:
            raise e.messageFormatError(
                'message too short, {0} bytes: no space for 2B optionLength'.
                format(len(message)))
        optionLength = u.buf2int(message[0:2]) + 269
        message = message[2:]
    else:
        raise e.messageFormatError(
            'invalid optionLength={0}'.format(optionLength))

    log.debug('optionLength  = {0}'.format(optionLength))

    # optionValue
    if len(message) < optionLength:
        raise e.messageFormatError(
            'message too short, {0} bytes: no space for optionValue'.format(
                len(message)))
    optionValue = message[:optionLength]
    message = message[optionLength:]

    log.debug('optionValue   = {0}'.format(u.formatBuf(optionValue)))

    #===== create option
    optionNumber = previousOptionNumber + optionDelta

    log.debug('optionNumber  = {0}'.format(optionNumber))

    if optionNumber not in d.OPTION_NUM_ALL:
        raise e.messageFormatError(
            'invalid option number {0} (0x{0:x})'.format(optionNumber))

    if optionNumber == d.OPTION_NUM_URIHOST:
        option = UriHost(host=''.join([chr(b) for b in optionValue]))
    elif optionNumber == d.OPTION_NUM_URIPATH:
        option = UriPath(path=''.join([chr(b) for b in optionValue]))
    elif optionNumber == d.OPTION_NUM_CONTENTFORMAT:
        option = ContentFormat(cformat=optionValue)
    elif optionNumber == d.OPTION_NUM_BLOCK2:
        option = Block2(rawbytes=optionValue)
    elif optionNumber == d.OPTION_NUM_OBJECT_SECURITY:
        option = ObjectSecurity(payload=optionValue)
    elif optionNumber == d.OPTION_NUM_PROXYSCHEME:
        option = ProxyScheme(scheme=''.join([chr(b) for b in optionValue]))
    elif optionNumber == d.OPTION_NUM_STATELESSPROXY:
        option = StatelessProxy(value=optionValue)
    else:
        raise NotImplementedError(
            'option {0} not implemented'.format(optionNumber))

    return (option, message)
Ejemplo n.º 7
0
def unprotectMessage(context, version, code, options = [], ciphertext = [], partialIV=None):
    '''
    \brief A function which verifies and decrypts the incoming CoAP message using OSCOAP.

    This function verifies the incoming CoAP message determined by input parameters according to
    draft-ietf-core-object-security-03.
    \param[in] Security context to use to verify+decrypt the outgoing message.
    \param[in] version CoAP version field of the incoming message.
    \param[in] code CoAP code field of the incoming message.
    \param[in] options A list of 'outer' options that are not encrypted.
    \param[in] ciphertext Ciphertext of the incoming CoAP message.
    \param[in] partialIV In case of request, partialIV corresponds to the one parsed from the message. In case
     of response, it corresponds to the appropriate partialIV used in request. Expected string of length given
     by the context algorithm.

    \return A tuple with the following elements:
        - element 0 is the list of inner (encrypted) CoAP options.
        - element 1 is the decrypted payload.
    '''
    assert objectSecurityOptionLookUp(options)

    (optionsClassE, optionsClassI, optionsClassU) = _splitOptions(options)

    if optionsClassE:
        raise e.messageFormatError('invalid oscoap message. E-class option present in the outer message')

    if _isRequest(code):
        requestKid = context.recipientID
        if not context.replayWindowLookup(u.buf2int(u.str2buf(partialIV))):
            raise e.oscoapError('Replay protection failed')
    else:
        requestKid = context.senderID

    requestSeq = partialIV.lstrip('\0')

    aad = _constructAAD(version,
                        code,
                        u.buf2str(m.encodeOptions(optionsClassI)),
                        context.aeadAlgorithm.value,
                        requestKid,
                        requestSeq)

    # construct nonce
    if _isRequest(code): # verifying request
        nonce = u.xorStrings(context.recipientIV, partialIV)
    else: # verifying response
        nonce = u.xorStrings(u.flipFirstBit(context.recipientIV), partialIV)

    try:
        plaintext = context.aeadAlgorithm.authenticateAndDecrypt(
            aad=aad,
            ciphertext=u.buf2str(ciphertext),
            key=context.recipientKey,
            nonce=nonce)
    except e.oscoapError:
        raise

    if _isRequest(code):
        context.replayWindowUpdate(u.buf2int(u.str2buf(partialIV)))

    # returns a tuple (innerOptions, payload)
    return m.decodeOptionsAndPayload(u.str2buf(plaintext))
Ejemplo n.º 8
0
def parseOption(message, previousOptionNumber):
    '''
    \brief Extract an option from the beginning of a message.
    
    \param[in] message              A list of bytes.
    \param[in] previousOptionNumber The option number from the previous option
        in the message; set to 0 if this is the first option.
    
    \return A tuple with the following elements:
        - element 0 is the option that was extracted. If no option was found
          (end of the options or end of the packet), None is returned.
        - element 1 is the message without the option.
    '''

    log.debug('parseOption message={0} previousOptionNumber={1}'.format(
        u.formatBuf(message),
        previousOptionNumber,
    ))

    #==== detect end of packet
    if len(message) == 0:
        message = message[1:]
        return (None, message)

    #==== detect payload marker
    if message[0] == d.COAP_PAYLOAD_MARKER:
        message = message[1:]
        return (None, message)

    #==== parse option

    # header
    optionDelta = (message[0] >> 4) & 0x0f
    optionLength = (message[0] >> 0) & 0x0f
    message = message[1:]

    # optionDelta
    if optionDelta <= 12:
        pass
    elif optionDelta == 13:
        if len(message) < 1:
            raise e.messageFormatError(
                'message to short, {0} bytes: not space for 1B optionDelta'.
                format(len(message)))
        optionDelta = u.buf2int(messsage[0]) + 13
        message = message[1:]
    elif optionDelta == 14:
        if len(message) < 2:
            raise e.messageFormatError(
                'message to short, {0} bytes: not space for 2B optionDelta'.
                format(len(message)))
        optionDelta = u.buf2int(messsage[0:1]) + 269
        message = message[2:]
    else:
        raise e.messageFormatError(
            'invalid optionDelta={0}'.format(optionDelta))

    log.debug('optionDelta={0}'.format(optionDelta))

    # optionLength
    if optionLength <= 12:
        pass
    elif optionLength == 13:
        if len(message) < 1:
            raise e.messageFormatError(
                'message to short, {0} bytes: not space for 1B optionLength'.
                format(len(message)))
        optionLength = u.buf2int(messsage[0]) + 13
        message = message[1:]
    elif optionLength == 14:
        if len(message) < 2:
            raise e.messageFormatError(
                'message to short, {0} bytes: not space for 2B optionLength'.
                format(len(message)))
        optionLength = u.buf2int(messsage[0:1]) + 269
        message = message[2:]
    else:
        raise e.messageFormatError(
            'invalid optionLength={0}'.format(optionLength))

    log.debug('optionLength={0}'.format(optionLength))

    # optionValue
    if len(message) < optionLength:
        raise e.messageFormatError(
            'message to short, {0} bytes: not space for optionValue'.format(
                len(message)))
    optionValue = message[:optionLength]
    message = message[optionLength:]

    log.debug('optionValue={0}'.format(u.formatBuf(optionValue)))

    #===== create option
    optionNumber = previousOptionNumber + optionDelta
    if optionNumber not in d.OPTION_NUM_ALL:
        raise e.messageFormatError(
            'invalid option number {0}'.format(optionNumber))

    if optionNumber == d.OPTION_NUM_URIPATH:
        option = UriPath(path=''.join([chr(b) for b in optionValue]))
    else:
        raise NotImplementedError()

    return (option, message)