def _verified_content_type_from_id(content_type_id):
    # type: (int) -> ContentType
    """Load a message :class:`ContentType` for the specified content type ID.

    :param int content_type_id: Content type ID
    :return: Message content type
    :rtype: ContentType
    :raises UnknownIdentityError: if unknown content type ID is received
    """
    try:
        return ContentType(content_type_id)
    except ValueError as error:
        raise UnknownIdentityError("Unknown content type {}".format(content_type_id), error)
Example #2
0
def deserialize_header(stream):
    """Deserializes the header from a source stream

    :param stream: Source data stream
    :type stream: io.BytesIO
    :returns: Deserialized MessageHeader object
    :rtype: :class:`aws_encryption_sdk.structures.MessageHeader` and bytes
    :raises NotSupportedError: if unsupported data types are found
    :raises UnknownIdentityError: if unknown data types are found
    :raises SerializationError: if IV length does not match algorithm
    """
    _LOGGER.debug('Starting header deserialization')
    tee = io.BytesIO()
    tee_stream = TeeStream(stream, tee)
    version_id, message_type_id = unpack_values('>BB', tee_stream)
    try:
        message_type = ObjectType(message_type_id)
    except ValueError as error:
        raise NotSupportedError(
            'Unsupported type {} discovered in data stream'.format(
                message_type_id), error)
    try:
        version = SerializationVersion(version_id)
    except ValueError as error:
        raise NotSupportedError('Unsupported version {}'.format(version_id),
                                error)
    header = {'version': version, 'type': message_type}

    algorithm_id, message_id, ser_encryption_context_length = unpack_values(
        '>H16sH', tee_stream)

    try:
        alg = Algorithm.get_by_id(algorithm_id)
    except KeyError as error:
        raise UnknownIdentityError('Unknown algorithm {}'.format(algorithm_id),
                                   error)
    if not alg.allowed:
        raise NotSupportedError('Unsupported algorithm: {}'.format(alg))
    header['algorithm'] = alg
    header['message_id'] = message_id

    header['encryption_context'] = deserialize_encryption_context(
        tee_stream.read(ser_encryption_context_length))
    (encrypted_data_key_count, ) = unpack_values('>H', tee_stream)

    encrypted_data_keys = set([])
    for _ in range(encrypted_data_key_count):
        (key_provider_length, ) = unpack_values('>H', tee_stream)
        (key_provider_identifier, ) = unpack_values(
            '>{}s'.format(key_provider_length), tee_stream)
        (key_provider_information_length, ) = unpack_values('>H', tee_stream)
        (key_provider_information, ) = unpack_values(
            '>{}s'.format(key_provider_information_length), tee_stream)
        (encrypted_data_key_length, ) = unpack_values('>H', tee_stream)
        encrypted_data_key = tee_stream.read(encrypted_data_key_length)
        encrypted_data_keys.add(
            EncryptedDataKey(key_provider=MasterKeyInfo(
                provider_id=to_str(key_provider_identifier),
                key_info=key_provider_information),
                             encrypted_data_key=encrypted_data_key))
    header['encrypted_data_keys'] = encrypted_data_keys

    (content_type_id, ) = unpack_values('>B', tee_stream)
    try:
        content_type = ContentType(content_type_id)
    except ValueError as error:
        raise UnknownIdentityError(
            'Unknown content type {}'.format(content_type_id), error)
    header['content_type'] = content_type

    (content_aad_length, ) = unpack_values('>I', tee_stream)
    if content_aad_length != 0:
        raise SerializationError(
            'Content AAD length field is currently unused, its value must be always 0'
        )
    header['content_aad_length'] = 0

    (iv_length, ) = unpack_values('>B', tee_stream)
    if iv_length != alg.iv_len:
        raise SerializationError(
            'Specified IV length ({length}) does not match algorithm IV length ({alg})'
            .format(length=iv_length, alg=alg))
    header['header_iv_length'] = iv_length

    (frame_length, ) = unpack_values('>I', tee_stream)
    if content_type == ContentType.FRAMED_DATA and frame_length > MAX_FRAME_SIZE:
        raise SerializationError(
            'Specified frame length larger than allowed maximum: {found} > {max}'
            .format(found=frame_length, max=MAX_FRAME_SIZE))
    elif content_type == ContentType.NO_FRAMING and frame_length != 0:
        raise SerializationError(
            'Non-zero frame length found for non-framed message')
    header['frame_length'] = frame_length

    return MessageHeader(**header), tee.getvalue()