def to_binary(self): security = struct_to_binary(self.SecurityHeader) encrypted_part = struct_to_binary(self.SequenceHeader) + self.Body encrypted_part += self.security_policy.padding(len(encrypted_part)) self.MessageHeader.body_size = len(security) + self.encrypted_size(len(encrypted_part)) header = header_to_binary(self.MessageHeader) encrypted_part += self.security_policy.signature(header + security + encrypted_part) return header + security + self.security_policy.encrypt(encrypted_part)
def test_custom_structs_array(self): xmlpath = "tests/example.bsd" c = StructGenerator() c.make_model_from_file(xmlpath) c.save_to_file("tests/structures.py") import structures as s # test with default values v = s.ArrayValueDataType() data = struct_to_binary(v) v2 = struct_from_binary(s.ArrayValueDataType, ua.utils.Buffer(data)) # set some values v = s.ArrayValueDataType() v.SbyteValue = [1] v.ByteValue = [2] v.Int16Value = [3] v.UInt16Value = [4] v.Int32Value = [5] v.UInt32Value = [6] v.Int64Value = [7] v.UInt64Value = [8] v.FloatValue = [9.0] v.DoubleValue = [10.0] v.StringValue = ["elleven"] v.DateTimeValue = [datetime.utcnow()] #self.GuidValue = uuid.uudib"14" v.ByteStringValue = [b"fifteen", b"sixteen"] v.XmlElementValue = [ua.XmlElement("<toto>titi</toto>")] v.NodeIdValue = [ ua.NodeId.from_string("ns=4;i=9999"), ua.NodeId.from_string("i=6") ] #self.ExpandedNodeIdValue = #self.QualifiedNameValue = #self.LocalizedTextValue = #self.StatusCodeValue = #self.VariantValue = #self.EnumerationValue = #self.StructureValue = #self.Number = #self.Integer = #self.UInteger = data = struct_to_binary(v) v2 = struct_from_binary(s.ArrayValueDataType, ua.utils.Buffer(data)) self.assertEqual(v.NodeIdValue, v2.NodeIdValue) print(v2.NodeIdValue)
def send_response(self, requesthandle, algohdr, seqhdr, response, msgtype=ua.MessageType.SecureMessage): with self._socketlock: response.ResponseHeader.RequestHandle = requesthandle data = self._connection.message_to_binary( struct_to_binary(response), message_type=msgtype, request_id=seqhdr.RequestId, algohdr=algohdr) self.socket.write(data)
def from_header_and_body(security_policy, header, buf): assert len(buf) >= header.body_size, 'Full body expected here' data = buf.copy(header.body_size) buf.skip(header.body_size) if header.MessageType in (ua.MessageType.SecureMessage, ua.MessageType.SecureClose): security_header = struct_from_binary(ua.SymmetricAlgorithmHeader, data) crypto = security_policy.symmetric_cryptography elif header.MessageType == ua.MessageType.SecureOpen: security_header = struct_from_binary(ua.AsymmetricAlgorithmHeader, data) crypto = security_policy.asymmetric_cryptography else: raise ua.UaError("Unsupported message type: {0}".format( header.MessageType)) obj = MessageChunk(crypto) obj.MessageHeader = header obj.SecurityHeader = security_header decrypted = crypto.decrypt(data.read(len(data))) signature_size = crypto.vsignature_size() if signature_size > 0: signature = decrypted[-signature_size:] decrypted = decrypted[:-signature_size] crypto.verify( header_to_binary(obj.MessageHeader) + struct_to_binary(obj.SecurityHeader) + decrypted, signature) data = ua.utils.Buffer(crypto.remove_padding(decrypted)) obj.SequenceHeader = struct_from_binary(ua.SequenceHeader, data) obj.Body = data.read(len(data)) return obj
def from_header_and_body(security_policy, header, buf): assert len(buf) >= header.body_size, 'Full body expected here' data = buf.copy(header.body_size) buf.skip(header.body_size) if header.MessageType in (ua.MessageType.SecureMessage, ua.MessageType.SecureClose): security_header = struct_from_binary(ua.SymmetricAlgorithmHeader, data) crypto = security_policy.symmetric_cryptography elif header.MessageType == ua.MessageType.SecureOpen: security_header = struct_from_binary(ua.AsymmetricAlgorithmHeader, data) crypto = security_policy.asymmetric_cryptography else: raise ua.UaError("Unsupported message type: {0}".format(header.MessageType)) obj = MessageChunk(crypto) obj.MessageHeader = header obj.SecurityHeader = security_header decrypted = crypto.decrypt(data.read(len(data))) signature_size = crypto.vsignature_size() if signature_size > 0: signature = decrypted[-signature_size:] decrypted = decrypted[:-signature_size] crypto.verify(header_to_binary(obj.MessageHeader) + struct_to_binary(obj.SecurityHeader) + decrypted, signature) data = ua.utils.Buffer(crypto.remove_padding(decrypted)) obj.SequenceHeader = struct_from_binary(ua.SequenceHeader, data) obj.Body = data.read(len(data)) return obj
def get_request(client): """ Assemble an OpenSecureChannelRequest for the specified client :param client: client object containing the channel parameters :return: binary OpenSecureChannelRequest """ params = ua.OpenSecureChannelParameters() params.ClientProtocolVersion = 0 params.RequestType = ua.SecurityTokenRequestType.Issue params.SecurityMode = client.security_policy.Mode params.RequestedLifetime = client.secure_channel_timeout nonce = utils.create_nonce(client.security_policy.symmetric_key_size) params.ClientNonce = nonce request = ua.OpenSecureChannelRequest() request.Parameters = params request.RequestHeader = client.uaclient._uasocket._create_request_header() try: binreq = struct_to_binary(request) except Exception: # reset request handle if any error # see self._create_request_header client.uaclient._uasocket._request_handle -= 1 raise return binreq
def _send_request(self, request, callback=None, timeout=1000, message_type=ua.MessageType.SecureMessage): """ send request to server, lower-level method timeout is the timeout written in ua header returns future """ with self._lock: request.RequestHeader = self._create_request_header(timeout) self.logger.debug("Sending: %s", request) try: binreq = struct_to_binary(request) except Exception: # reset reqeust handle if any error # see self._create_request_header self._request_handle -= 1 raise self._request_id += 1 future = Future() if callback: future.add_done_callback(callback) self._callbackmap[self._request_id] = future # Change to the new security token if the connection has been renewed. if self._connection.next_security_token.TokenId != 0: self._connection.revolve_tokens() msg = self._connection.message_to_binary( binreq, message_type=message_type, request_id=self._request_id) self._socket.write(msg) return future
def test_custom_structs_array(self): xmlpath = "tests/example.bsd" c = StructGenerator() c.make_model_from_file(xmlpath) c.save_to_file("tests/structures.py") import structures as s # test with default values v = s.ArrayValueDataType() data = struct_to_binary(v) v2 = struct_from_binary(s.ArrayValueDataType, ua.utils.Buffer(data)) # set some values v = s.ArrayValueDataType() v.SbyteValue = [1] v.ByteValue = [2] v.Int16Value = [3] v.UInt16Value = [4] v.Int32Value = [5] v.UInt32Value = [6] v.Int64Value = [7] v.UInt64Value = [8] v.FloatValue = [9.0] v.DoubleValue = [10.0] v.StringValue = ["elleven"] v.DateTimeValue = [datetime.utcnow()] #self.GuidValue = uuid.uudib"14" v.ByteStringValue = [b"fifteen", b"sixteen"] v.XmlElementValue = [ua.XmlElement("<toto>titi</toto>")] v.NodeIdValue = [ua.NodeId.from_string("ns=4;i=9999"), ua.NodeId.from_string("i=6")] #self.ExpandedNodeIdValue = #self.QualifiedNameValue = #self.LocalizedTextValue = #self.StatusCodeValue = #self.VariantValue = #self.EnumerationValue = #self.StructureValue = #self.Number = #self.Integer = #self.UInteger = data = struct_to_binary(v) v2 = struct_from_binary(s.ArrayValueDataType, ua.utils.Buffer(data)) self.assertEqual(v.NodeIdValue, v2.NodeIdValue) print(v2.NodeIdValue)
def test_text(self): t1 = ua.LocalizedText('Root') t2 = ua.LocalizedText('Root') t3 = ua.LocalizedText('root') self.assertEqual(t1, t2) self.assertNotEqual(t1, t3) t4 = struct_from_binary(ua.LocalizedText, ua.utils.Buffer(struct_to_binary(t1))) self.assertEqual(t1, t4)
def test_custom_structs(self): xmlpath = "tests/example.bsd" c = StructGenerator() c.make_model_from_file(xmlpath) c.save_to_file("tests/structures.py") import structures as s # test with default values v = s.ScalarValueDataType() data = struct_to_binary(v) v2 = struct_from_binary(s.ScalarValueDataType, ua.utils.Buffer(data)) # set some values v = s.ScalarValueDataType() v.SbyteValue = 1 v.ByteValue = 2 v.Int16Value = 3 v.UInt16Value = 4 v.Int32Value = 5 v.UInt32Value = 6 v.Int64Value = 7 v.UInt64Value = 8 v.FloatValue = 9.0 v.DoubleValue = 10.0 v.StringValue = "elleven" v.DateTimeValue = datetime.utcnow() #self.GuidValue = uuid.uudib"14" v.ByteStringValue = b"fifteen" v.XmlElementValue = ua.XmlElement("<toto>titi</toto>") v.NodeIdValue = ua.NodeId.from_string("ns=4;i=9999") #self.ExpandedNodeIdValue = #self.QualifiedNameValue = #self.LocalizedTextValue = #self.StatusCodeValue = #self.VariantValue = #self.EnumerationValue = #self.StructureValue = #self.Number = #self.Integer = #self.UInteger = data = struct_to_binary(v) v2 = struct_from_binary(s.ScalarValueDataType, ua.utils.Buffer(data)) self.assertEqual(v.NodeIdValue, v2.NodeIdValue)
def test_string_to_val_xml_element(self): string = "<p> titi toto </p>" obj = ua.XmlElement(string) self.assertEqual(string_to_val(string, ua.VariantType.XmlElement), obj) self.assertEqual(val_to_string(obj), string) b = struct_to_binary(obj) obj2 = struct_from_binary(ua.XmlElement, ua.utils.Buffer(b)) self.assertEqual(obj, obj2)
def test_binary_struct_example(self): # Example test so that we can manually control the object that gets # generated and see how it gets serialized/deserialized original = ObjectWithOptionalFields() serialized = struct_to_binary(original) deserialized = struct_from_binary(ObjectWithOptionalFields, ua.utils.Buffer(serialized)) self.assertEqual(len(original.ua_switches), len(deserialized.ua_switches)) self.assertEqual(len(original.ua_types), len(deserialized.ua_types)) for field, _ in original.ua_types: self.assertEqual(getattr(original, field), getattr(deserialized, field))
def test_status_code_to_string(self): # serialize a status code and deserialize it, name and doc resolution should work just fine statuscode = ua.StatusCode(ua.StatusCodes.BadNotConnected) statuscode2 = struct_from_binary(ua.StatusCode, io.BytesIO(struct_to_binary(ua.StatusCode(ua.StatusCodes.BadNotConnected)))) self.assertEqual(statuscode, statuscode2) self.assertEqual(statuscode.value, statuscode2.value) # properties that are not serialized should still translate properly self.assertEqual(statuscode.name, statuscode2.name) self.assertEqual(statuscode.doc, statuscode2.doc)
def to_binary(chunk, cert, padding=None, ciphertext_manipulator=None): """ Convert chunk to binary :param chunk: chunk to convert :param cert: server certificate to use for ciphertext manipulation :param padding: padding function :param ciphertext_manipulator: manipulation function for the ciphertext :return: bytes to send to the server """ security = struct_to_binary(chunk.SecurityHeader) encrypted_part = struct_to_binary(chunk.SequenceHeader) + chunk.Body encrypted_part += chunk.security_policy.padding(len(encrypted_part)) chunk.MessageHeader.body_size = len(security) + chunk.encrypted_size( len(encrypted_part)) header = header_to_binary(chunk.MessageHeader) signature = chunk.security_policy.signature(header + security + encrypted_part) encrypted_part += signature # if no padding is given, use the default PKCS #1 v1.5 padding if not padding: plaintext = paddings.pad_pkcs1v15(encrypted_part) else: plaintext = padding(encrypted_part) # extract modulus and exponent from the server certificate N = cert.public_key().public_numbers().n e = cert.public_key().public_numbers().e modulus_bits = int(math.ceil(math.log(N, 2))) modulus_bytes = (modulus_bits + 7) // 8 plaintext_bytes = int.from_bytes(plaintext, byteorder='big') ciphertext = int(gmpy2.powmod(plaintext_bytes, e, N)).to_bytes(modulus_bytes, byteorder="big") if ciphertext_manipulator: ciphertext = ciphertext_manipulator(ciphertext) return header + security + ciphertext
def test_custom_struct_with_optional_fields(self): xmlpath = "custom_extension_with_optional_fields.xml" c = StructGenerator() c.make_model_from_file(xmlpath) for m in c.model: if type(m) in (Struct, EnumType): m.typeid = self._generate_node_id() c.save_to_file("custom_extension_with_optional_fields.py", register=True) import como_structures as s for name, obj in inspect.getmembers(sys.modules[s.__name__], predicate=inspect.isclass): if name.startswith('__') or obj in (datetime,) or isinstance(obj, EnumMeta): continue with self.subTest(name=name): original = obj() serialized = struct_to_binary(original) deserialized = struct_from_binary(obj, ua.utils.Buffer(serialized)) self.assertCustomStructEqual(original, deserialized)
def _send_request(self, request, callback=None, timeout=1000, message_type=ua.MessageType.SecureMessage): """ send request to server, lower-level method timeout is the timeout written in ua header returns future """ with self._lock: request.RequestHeader = self._create_request_header(timeout) self.logger.debug("Sending: %s", request) try: binreq = struct_to_binary(request) except Exception: # reset reqeust handle if any error # see self._create_request_header self._request_handle -= 1 raise self._request_id += 1 future = Future() if callback: future.add_done_callback(callback) self._callbackmap[self._request_id] = future msg = self._connection.message_to_binary(binreq, message_type=message_type, request_id=self._request_id) self._socket.write(msg) return future
def error_message_to_binary(message): header = ua.Header(ua.MessageType.Error, ua.ChunkType.Single) body = struct_to_binary(message) header.body_size = len(body) return header_to_binary(header) + body