Esempio n. 1
0
def require_cryptography(obj):
    """
    Raise exception if cryptography module is not available.
    Call this function in constructors.
    """
    if not CRYPTOGRAPHY_AVAILABLE:
        raise UaError(
            "Can't use {0}, cryptography module is not installed".format(
                obj.__class__.__name__))
Esempio n. 2
0
    def _check_incoming_chunk(self, chunk):
        assert isinstance(
            chunk, MessageChunk), "Expected chunk, got: {}".format(chunk)
        if chunk.MessageHeader.MessageType != MessageType.SecureOpen:
            if chunk.MessageHeader.ChannelId != self.channel.SecurityToken.ChannelId:
                raise UaError("Wrong channel id {}, expected {}".format(
                    chunk.MessageHeader.ChannelId,
                    self.channel.SecurityToken.ChannelId))
            if chunk.SecurityHeader.TokenId != self.channel.SecurityToken.TokenId:
                if chunk.SecurityHeader.TokenId not in self._old_tokens:
                    raise UaError("Wrong token id {}, expected {}".format(
                        chunk.SecurityHeader.TokenId,
                        self.channel.SecurityToken.TokenId))
                else:
                    # Do some cleanup, spec says we can remove old tokens when new one are used
                    idx = self._old_tokens.index(chunk.SecurityHeader.TokenId)
                    if idx != 0:
                        self._old_tokens = self._old_tokens[idx:]
        if self._incoming_parts:
            if self._incoming_parts[
                    0].SequenceHeader.RequestId != chunk.SequenceHeader.RequestId:
                raise UaError("Wrong request id {}, expected {}".format(
                    chunk.SequenceHeader.RequestId,
                    self._incoming_parts[0].SequenceHeader.RequestId))

        # sequence number must be incremented or wrapped
        num = chunk.SequenceHeader.SequenceNumber
        if self._peer_sequence_number is not None:
            if num != self._peer_sequence_number + 1:
                wrap = (1 << 32) - 1024
                if num < 1024 and self._peer_sequence_number >= wrap:
                    # specs Part 6, 6.7.2
                    logger.debug("Sequence number wrapped: %d -> %d",
                                 self._peer_sequence_number, num)
                else:
                    raise UaError(
                        "Wrong sequence {} -> {} (server bug or replay attack)"
                        .format(self._peer_sequence_number, num))
        self._peer_sequence_number = num
Esempio n. 3
0
def encrypt_asymmetric(pubkey, data, policy_uri):
    """
    Encrypt data with pubkey using an asymmetric algorithm.
    The algorithm is selected by policy_uri.
    Returns a tuple (encrypted_data, algorithm_uri)
    """
    for cls in [SecurityPolicyBasic256Sha256, SecurityPolicyBasic256, SecurityPolicyBasic128Rsa15]:
        if policy_uri == cls.URI:
            return (cls.encrypt_asymmetric(pubkey, data),
                    cls.AsymmetricEncryptionURI)
    if not policy_uri or policy_uri == POLICY_NONE_URI:
        return (data, '')
    raise UaError("Unsupported security policy `{0}`".format(policy_uri))
Esempio n. 4
0
 def receive_from_socket(self, socket):
     """
     Convert binary stream to OPC UA TCP message (see OPC UA
     specs Part 6, 7.1: Hello, Acknowledge or ErrorMessage), or a Message
     object, or None (if intermediate chunk is received)
     """
     logger.debug("Waiting for header")
     header = Header.from_string(socket)
     logger.info("received header: %s", header)
     body = socket.read(header.body_size)
     if len(body) != header.body_size:
         raise UaError("{} bytes expected, {} available".format(
             header.body_size, len(body)))
     return self.receive_from_header_and_body(header, utils.Buffer(body))
Esempio n. 5
0
 def __init__(self,
              security_policy,
              body=b'',
              msg_type=MessageType.SecureMessage,
              chunk_type=ChunkType.Single):
     self.MessageHeader = Header(msg_type, chunk_type)
     if msg_type in (MessageType.SecureMessage, MessageType.SecureClose):
         self.SecurityHeader = SymmetricAlgorithmHeader()
     elif msg_type == MessageType.SecureOpen:
         self.SecurityHeader = AsymmetricAlgorithmHeader()
     else:
         raise UaError("Unsupported message type: {}".format(msg_type))
     self.SequenceHeader = SequenceHeader()
     self.Body = body
     self._security_policy = security_policy
Esempio n. 6
0
 def _receive(self, msg):
     self._check_incoming_chunk(msg)
     self._incoming_parts.append(msg)
     if msg.MessageHeader.ChunkType == ChunkType.Intermediate:
         return None
     if msg.MessageHeader.ChunkType == ChunkType.Abort:
         err = ErrorMessage.from_binary(utils.Buffer(msg.Body))
         logger.warning("Message %s aborted: %s", msg, err)
         # specs Part 6, 6.7.3 say that aborted message shall be ignored
         # and SecureChannel should not be closed
         self._incoming_parts = []
         return None
     elif msg.MessageHeader.ChunkType == ChunkType.Single:
         message = Message(self._incoming_parts)
         self._incoming_parts = []
         return message
     else:
         raise UaError("Unsupported chunk type: {}".format(msg))