This is an automated email from the ASF dual-hosted git repository. sruehl pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/plc4x.git
commit 7c21ea88ce2db4e36b4f9100c08d9eee521ed51e Author: Sebastian Rühl <sru...@apache.org> AuthorDate: Fri Jul 28 11:35:59 2023 +0200 feat(plc4go/opcua): work on encryption part --- plc4go/internal/opcua/CertificateGenerator.go | 150 +++++++++++++++++++++ plc4go/internal/opcua/CertificateKeyPair.go | 11 +- plc4go/internal/opcua/Configuration.go | 44 +++++- plc4go/internal/opcua/Driver.go | 4 +- plc4go/internal/opcua/EncryptionHandler.go | 184 ++++++++++++++++++++++++-- plc4go/internal/opcua/SecureChannel.go | 48 +++++-- 6 files changed, 406 insertions(+), 35 deletions(-) diff --git a/plc4go/internal/opcua/CertificateGenerator.go b/plc4go/internal/opcua/CertificateGenerator.go new file mode 100644 index 0000000000..63e7e534dd --- /dev/null +++ b/plc4go/internal/opcua/CertificateGenerator.go @@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package opcua + +import ( + "bytes" + "crypto/rand" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "math/big" + "net" + "time" + + "github.com/pkg/errors" +) + +func generateCertificate() (*CertificateKeyPair, error) { + // From: https://gist.github.com/shaneutt/5e1995295cff6721c89a71d13a71c251 + // set up our CA certificate + ca := &x509.Certificate{ + SerialNumber: big.NewInt(40), + Subject: pkix.Name{ + CommonName: "Apache PLC4X Driver Client", + Organization: []string{"Apache Software Foundation"}, + OrganizationalUnit: []string{"dev"}, + Locality: []string{""}, + Country: []string{"US"}, + Province: []string{""}, + }, + NotBefore: time.Now().Add(-24 * time.Hour), + NotAfter: time.Now().AddDate(25, 0, 0), + IsCA: true, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, + BasicConstraintsValid: true, + } + + // create our private and public key + caPrivateKey, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return nil, errors.Wrap(err, "error generating key") + } + + // create the CA + caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &caPrivateKey.PublicKey, caPrivateKey) + if err != nil { + return nil, errors.Wrap(err, "error creating certificate") + } + + // pem encode + caPEM := new(bytes.Buffer) + if err := pem.Encode(caPEM, &pem.Block{ + Type: "CERTIFICATE", + Bytes: caBytes, + }); err != nil { + return nil, errors.Wrap(err, "error pem encode") + } + + caPrivateKeyPEM := new(bytes.Buffer) + if err := pem.Encode(caPrivateKeyPEM, &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(caPrivateKey), + }); err != nil { + return nil, errors.Wrap(err, "error pem encode") + } + + // set up our server certificate + cert := &x509.Certificate{ + SerialNumber: big.NewInt(2019), + Subject: pkix.Name{ + Organization: []string{"Company, INC."}, + Country: []string{"US"}, + Province: []string{""}, + Locality: []string{"San Francisco"}, + StreetAddress: []string{"Golden Gate Bridge"}, + PostalCode: []string{"94016"}, + }, + IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1), net.IPv6loopback}, + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(10, 0, 0), + SubjectKeyId: []byte{1, 2, 3, 4, 6}, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + KeyUsage: x509.KeyUsageDigitalSignature, + } + + certPrivateKey, err := rsa.GenerateKey(rand.Reader, 4096) + if err != nil { + return nil, errors.Wrap(err, "error generating key") + } + + certBytes, err := x509.CreateCertificate(rand.Reader, cert, ca, &certPrivateKey.PublicKey, caPrivateKeyPEM) + if err != nil { + return nil, errors.Wrap(err, "error creating certificate") + } + + certPEM := new(bytes.Buffer) + if err := pem.Encode(certPEM, &pem.Block{ + Type: "CERTIFICATE", + Bytes: certBytes, + }); err != nil { + return nil, errors.Wrap(err, "error pem encode") + } + + certPrivKeyPEM := new(bytes.Buffer) + if err := pem.Encode(certPrivKeyPEM, &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(certPrivateKey), + }); err != nil { + return nil, errors.Wrap(err, "error pem encode") + } + + serverCert, err := tls.X509KeyPair(certPEM.Bytes(), certPrivKeyPEM.Bytes()) + if err != nil { + return nil, errors.Wrap(err, "error building keypair") + } + + serverTLSConf := &tls.Config{ + Certificates: []tls.Certificate{serverCert}, + } + _ = serverTLSConf + + certpool := x509.NewCertPool() + certpool.AppendCertsFromPEM(caPEM.Bytes()) + clientTLSConf := &tls.Config{ + RootCAs: certpool, + } + _ = clientTLSConf + + return NewCertificateKeyPair(caPrivateKey, cert), nil +} diff --git a/plc4go/internal/opcua/CertificateKeyPair.go b/plc4go/internal/opcua/CertificateKeyPair.go index c4bba2453d..68a7671052 100644 --- a/plc4go/internal/opcua/CertificateKeyPair.go +++ b/plc4go/internal/opcua/CertificateKeyPair.go @@ -20,17 +20,18 @@ package opcua import ( + "crypto/rsa" "crypto/sha1" "crypto/x509" ) type CertificateKeyPair struct { - keyPair x509.KeyUsage - certificate x509.Certificate + keyPair *rsa.PrivateKey + certificate *x509.Certificate thumbprint []byte } -func NewCertificateKeyPair(keyPair x509.KeyUsage, certificate x509.Certificate) *CertificateKeyPair { +func NewCertificateKeyPair(keyPair *rsa.PrivateKey, certificate *x509.Certificate) *CertificateKeyPair { thumbprint := sha1.Sum(certificate.Raw) return &CertificateKeyPair{ keyPair: keyPair, @@ -39,11 +40,11 @@ func NewCertificateKeyPair(keyPair x509.KeyUsage, certificate x509.Certificate) } } -func (p *CertificateKeyPair) getKeyPair() x509.KeyUsage { +func (p *CertificateKeyPair) getKeyPair() *rsa.PrivateKey { return p.keyPair } -func (p *CertificateKeyPair) getCertificate() x509.Certificate { +func (p *CertificateKeyPair) getCertificate() *x509.Certificate { return p.certificate } diff --git a/plc4go/internal/opcua/Configuration.go b/plc4go/internal/opcua/Configuration.go index 98d995fa38..850251ae50 100644 --- a/plc4go/internal/opcua/Configuration.go +++ b/plc4go/internal/opcua/Configuration.go @@ -20,11 +20,14 @@ package opcua import ( - readWriteModel "github.com/apache/plc4x/plc4go/protocols/opcua/readwrite/model" - "github.com/pkg/errors" + "os" + "path" "reflect" "strconv" + readWriteModel "github.com/apache/plc4x/plc4go/protocols/opcua/readwrite/model" + + "github.com/pkg/errors" "github.com/rs/zerolog" ) @@ -46,7 +49,9 @@ type Configuration struct { keyStoreFile string certDirectory string keyStorePassword string - ckp CertificateKeyPair + ckp *CertificateKeyPair + + log zerolog.Logger `ignore:"true"` } func ParseFromOptions(log zerolog.Logger, options map[string][]string) (Configuration, error) { @@ -74,13 +79,40 @@ func ParseFromOptions(log zerolog.Logger, options map[string][]string) (Configur } } } + configuration.log = log return configuration, nil } -func (c *Configuration) openKeyStore() { +func (c *Configuration) openKeyStore() error { c.isEncrypted = true - // TODO: load keystore yada yada - // TODO: NewCertificateKeyPair() + securityTempDir := path.Join(c.certDirectory, "security") + if _, err := os.Stat(securityTempDir); errors.Is(err, os.ErrNotExist) { + if err := os.Mkdir(securityTempDir, 700); err != nil { + return errors.New("Unable to create directory please confirm folder permissions on " + securityTempDir) + } + } + + serverKeyStore := path.Join(securityTempDir, c.keyStoreFile) + if _, err := os.Stat(securityTempDir); errors.Is(err, os.ErrNotExist) { + var err error + c.ckp, err = generateCertificate() + if err != nil { + return errors.Wrap(err, "error generating certificate") + } + c.log.Info().Str("serverKeyStore", serverKeyStore).Msg("Creating keystore") + // TODO: not sure how to do that in golang. Seems pkc12 can only decode for now + _ = os.WriteFile(serverKeyStore, []byte{0xA}, 0700) + } else { + c.log.Info().Str("serverKeyStore", serverKeyStore).Msg("Loading keystore") + serverKeyStoreContent, err := os.ReadFile(serverKeyStore) + if err != nil { + return errors.Wrap(err, "error reading "+serverKeyStore) + } + // TODO: here we can parse with "golang.org/x/crypto/pkcs12" Decode + _ = serverKeyStoreContent + } + + return nil } func createDefaultConfiguration() Configuration { diff --git a/plc4go/internal/opcua/Driver.go b/plc4go/internal/opcua/Driver.go index b29a73fe70..66e1d96513 100644 --- a/plc4go/internal/opcua/Driver.go +++ b/plc4go/internal/opcua/Driver.go @@ -123,7 +123,9 @@ func (m *Driver) GetConnectionWithContext(ctx context.Context, transportUrl url. configuration.endpoint = "opc." + transportCode + "://" + transportHost + ":" + transportPort + "" + transportEndpoint if configuration.securityPolicy != "" && configuration.securityPolicy != "None" { - configuration.openKeyStore() + if err := configuration.openKeyStore(); err != nil { + return m.reportError(errors.Wrap(err, "error opening key store")) + } } driverContext := NewDriverContext(configuration) diff --git a/plc4go/internal/opcua/EncryptionHandler.go b/plc4go/internal/opcua/EncryptionHandler.go index 4cb43c3de0..bdad7b63d1 100644 --- a/plc4go/internal/opcua/EncryptionHandler.go +++ b/plc4go/internal/opcua/EncryptionHandler.go @@ -20,34 +20,192 @@ package opcua import ( + "context" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" "crypto/x509" + "encoding/binary" + readWriteModel "github.com/apache/plc4x/plc4go/protocols/opcua/readwrite/model" + "github.com/apache/plc4x/plc4go/spi/utils" + + "github.com/pkg/errors" + "github.com/rs/zerolog" ) type EncryptionHandler struct { - // TODO: implement me + serverCertificate *x509.Certificate + clientCertificate *x509.Certificate + clientPrivateKey *rsa.PrivateKey + clientPublicKey crypto.PublicKey + securityPolicy string + + log zerolog.Logger +} + +func NewEncryptionHandler(log zerolog.Logger, ckp *CertificateKeyPair, senderCertificate []byte, securityPolicy string) *EncryptionHandler { + e := &EncryptionHandler{ + securityPolicy: securityPolicy, + log: log, + } + if ckp != nil { + e.clientPrivateKey = ckp.getKeyPair() + e.clientPublicKey = ckp.getKeyPair().Public() + e.clientCertificate = ckp.getCertificate() + } + if senderCertificate != nil { + var err error + e.serverCertificate, err = e.getCertificateX509(senderCertificate) + if err != nil { + e.log.Error().Err(err).Msg("error getting sender certificate") + } + } + return e +} + +func (h *EncryptionHandler) encodeMessage(ctx context.Context, pdu readWriteModel.MessagePDU, message []byte) ([]byte, error) { + const PREENCRYPTED_BLOCK_LENGTH = 190 + unencryptedLength := int(pdu.GetLengthInBytes(ctx)) + openRequestLength := len(message) + positionFirstBlock := unencryptedLength - openRequestLength - 8 + paddingSize := PREENCRYPTED_BLOCK_LENGTH - ((openRequestLength + 256 + 1 + 8) % PREENCRYPTED_BLOCK_LENGTH) + preEncryptedLength := openRequestLength + 256 + 1 + 8 + paddingSize + if preEncryptedLength%PREENCRYPTED_BLOCK_LENGTH != 0 { + return nil, errors.Errorf("Pre encrypted block length %d isn't a multiple of the block size", preEncryptedLength) + } + numberOfBlocks := preEncryptedLength / PREENCRYPTED_BLOCK_LENGTH + encryptedLength := numberOfBlocks*256 + positionFirstBlock + buf := utils.NewWriteBufferByteBased(utils.WithByteOrderForByteBasedBuffer(binary.LittleEndian)) + if err := readWriteModel.NewOpcuaAPU(pdu, false).SerializeWithWriteBuffer(ctx, buf); err != nil { + return nil, errors.Wrap(err, "error serializing") + } + paddingByte := byte(paddingSize) + if err := buf.WriteByte("", paddingByte); err != nil { + return nil, errors.Wrap(err, "error writing byte") + } + for i := 0; i < paddingSize; i++ { + if err := buf.WriteByte("", paddingByte); err != nil { + return nil, errors.Wrap(err, "error writing byte") + } + } + //Writing Message Length + { + if err := buf.WriteInt32("", 32, int32(encryptedLength)); err != nil { + return nil, errors.Wrap(err, "error writing int32") + } + allBytes := buf.GetBytes() + encryptedLengthBytes := allBytes[len(allBytes)-4:] + allBytes = allBytes[:len(allBytes)-4] + allBytes = append(allBytes[:4], append(encryptedLengthBytes, allBytes[8:]...)...) + buf = utils.NewWriteBufferByteBased(utils.WithByteOrderForByteBasedBuffer(binary.LittleEndian)) + if err := buf.WriteByteArray("", allBytes); err != nil { + return nil, errors.Wrap(err, "error writing back bytes") + } + } + + signature, err := h.sign(buf.GetBytes()[:unencryptedLength+paddingSize+1]) + if err != nil { + return nil, errors.Wrap(err, "error signing") + } + //Write the signature to the end of the buffer + for _, b := range signature { + if err := buf.WriteByte("", b); err != nil { + return nil, errors.Wrap(err, "error writing byte") + } + } + //buf.SetPos(uint16(positionFirstBlock))// TODO: check if we need to move the position at all + if err := h.encryptBlock(buf, buf.GetBytes()[positionFirstBlock:positionFirstBlock+preEncryptedLength]); err != nil { + return nil, errors.Wrap(err, "error encrypting block") + } + return buf.GetBytes(), nil +} + +func (h *EncryptionHandler) decodeMessage(ctx context.Context, pdu readWriteModel.OpcuaAPU) (readWriteModel.OpcuaAPU, error) { + h.log.Info().Msgf("Decoding Message with Security policy %s", h.securityPolicy) + switch h.securityPolicy { + case "None": + return pdu, nil + case "Basic256Sha256": + var message []byte + switch pduMessage := pdu.GetMessage().(type) { + case readWriteModel.OpcuaOpenResponseExactly: + message = pduMessage.GetMessage() + case readWriteModel.OpcuaMessageResponseExactly: + message = pduMessage.GetMessage() + default: + return pdu, nil + } + encryptedLength := int(pdu.GetLengthInBytes(ctx)) + encryptedMessageLength := len(message) + 8 + headerLength := encryptedLength - encryptedMessageLength + buf := utils.NewWriteBufferByteBased(utils.WithByteOrderForByteBasedBuffer(binary.LittleEndian)) + if err := pdu.SerializeWithWriteBuffer(ctx, buf); err != nil { + return nil, errors.Wrap(err, "error serializing") + } + allBytes := buf.GetBytes() + data := allBytes[headerLength:encryptedLength] + buf = utils.NewWriteBufferByteBased(utils.WithByteOrderForByteBasedBuffer(binary.LittleEndian)) + if err := buf.WriteByteArray("", allBytes[:headerLength-1]); err != nil { + return nil, errors.Wrap(err, "error serializing") + } + if err := h.decryptBlock(buf, data); err != nil { + return nil, errors.Wrap(err, "error decrypting") + } + { + if err := buf.WriteInt32("", 32, int32(encryptedLength)); err != nil { + return nil, errors.Wrap(err, "error writing int32") + } + encryptedLengthBytes := allBytes[len(allBytes)-4:] + allBytes = allBytes[:len(allBytes)-4] + allBytes = append(allBytes[:4], append(encryptedLengthBytes, allBytes[8:]...)...) + buf = utils.NewWriteBufferByteBased(utils.WithByteOrderForByteBasedBuffer(binary.LittleEndian)) + if err := buf.WriteByteArray("", allBytes); err != nil { + return nil, errors.Wrap(err, "error writing back bytes") + } + } + + readBuffer := utils.NewReadBufferByteBased(buf.GetBytes(), utils.WithByteOrderForReadBufferByteBased(binary.LittleEndian)) + return readWriteModel.OpcuaAPUParseWithBuffer(ctx, readBuffer, true) + } + return pdu, nil } -func NewEncryptionHandler(any, []byte, string) *EncryptionHandler { - return &EncryptionHandler{} +func (h *EncryptionHandler) decryptBlock(buf utils.WriteBufferByteBased, data []byte) error { + oaep, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, h.clientPrivateKey, data, nil) + if err != nil { + return errors.Wrap(err, "error DecryptOAEP") + } + return buf.WriteByteArray("", oaep) } -func (h *EncryptionHandler) encodeMessage(messageRequest readWriteModel.MessagePDU, bytes []byte) []byte { - return nil +func (h *EncryptionHandler) getCertificateX509(senderCertificate []byte) (*x509.Certificate, error) { + return x509.ParseCertificate(senderCertificate) } -func (h *EncryptionHandler) decodeMessage(apu readWriteModel.OpcuaAPU) readWriteModel.OpcuaAPUExactly { - return nil +func (h *EncryptionHandler) setServerCertificate(serverCertificate *x509.Certificate) { + h.serverCertificate = serverCertificate } -func (h *EncryptionHandler) getCertificateX509(senderCertificate []byte) x509.Certificate { - return x509.Certificate{} +func (h *EncryptionHandler) encryptPassword(password []byte) ([]byte, error) { + publicKey := h.serverCertificate.PublicKey.(rsa.PublicKey) + encryptOAEP, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, &publicKey, password, nil) + if err != nil { + return nil, errors.Wrap(err, "error EncryptOAEP") + } + return encryptOAEP, nil } -func (h *EncryptionHandler) setServerCertificate(certificateX509 x509.Certificate) { - return +func (h *EncryptionHandler) encryptBlock(buf utils.WriteBufferByteBased, data []byte) error { + publicKey := h.serverCertificate.PublicKey.(rsa.PublicKey) + encryptOAEP, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, &publicKey, data, nil) + if err != nil { + return errors.Wrap(err, "error EncryptOAEP") + } + return buf.WriteByteArray("", encryptOAEP) } -func (h *EncryptionHandler) encryptPassword(password []byte) []byte { - return nil +func (h *EncryptionHandler) sign(data []byte) ([]byte, error) { + return h.clientPrivateKey.Sign(rand.Reader, data, crypto.SHA256) } diff --git a/plc4go/internal/opcua/SecureChannel.go b/plc4go/internal/opcua/SecureChannel.go index cda111c59b..b17a476790 100644 --- a/plc4go/internal/opcua/SecureChannel.go +++ b/plc4go/internal/opcua/SecureChannel.go @@ -146,14 +146,14 @@ func NewSecureChannel(log zerolog.Logger, ctx DriverContext, configuration Confi if configuration.securityPolicy == "Basic256Sha256" { //Sender Certificate gets populated during the 'discover' phase when encryption is enabled. s.senderCertificate = configuration.senderCertificate - s.encryptionHandler = NewEncryptionHandler(ckp, s.senderCertificate, configuration.securityPolicy) + s.encryptionHandler = NewEncryptionHandler(s.log, ckp, s.senderCertificate, configuration.securityPolicy) certificate := ckp.getCertificate() s.publicCertificate = readWriteModel.NewPascalByteString(int32(len(certificate.Raw)), certificate.Raw) s.isEncrypted = true s.thumbprint = configuration.thumbprint } else { - s.encryptionHandler = NewEncryptionHandler(ckp, s.senderCertificate, configuration.securityPolicy) + s.encryptionHandler = NewEncryptionHandler(s.log, ckp, s.senderCertificate, configuration.securityPolicy) s.publicCertificate = NULL_BYTE_STRING s.thumbprint = NULL_BYTE_STRING s.isEncrypted = false @@ -190,8 +190,12 @@ func (s *SecureChannel) submit(ctx context.Context, codec *MessageCodec, errorDi var apu readWriteModel.OpcuaAPU if s.isEncrypted { - var err error - apu, err = readWriteModel.OpcuaAPUParse(ctx, s.encryptionHandler.encodeMessage(messageRequest, buffer.GetBytes()), false) + message, err := s.encryptionHandler.encodeMessage(ctx, messageRequest, buffer.GetBytes()) + if err != nil { + errorDispatcher(err) + return + } + apu, err = readWriteModel.OpcuaAPUParse(ctx, message, false) if err != nil { errorDispatcher(err) return @@ -209,7 +213,12 @@ func (s *SecureChannel) submit(ctx context.Context, codec *MessageCodec, errorDi s.log.Debug().Type("type", message).Msg("Not relevant") return false } - opcuaAPU = s.encryptionHandler.decodeMessage(opcuaAPU) + if decodedOpcuaAPU, err := s.encryptionHandler.decodeMessage(ctx, opcuaAPU); err != nil { + s.log.Debug().Err(err).Msg("error decoding") + return false + } else { + opcuaAPU = decodedOpcuaAPU.(readWriteModel.OpcuaAPUExactly) + } messagePDU := opcuaAPU.GetMessage() opcuaResponse, ok := messagePDU.(readWriteModel.OpcuaMessageResponseExactly) if !ok { @@ -230,7 +239,7 @@ func (s *SecureChannel) submit(ctx context.Context, codec *MessageCodec, errorDi }, func(message spi.Message) error { opcuaAPU := message.(readWriteModel.OpcuaAPU) - opcuaAPU = s.encryptionHandler.decodeMessage(opcuaAPU) + opcuaAPU, _ = s.encryptionHandler.decodeMessage(ctx, opcuaAPU) messagePDU := opcuaAPU.GetMessage() opcuaResponse := messagePDU.(readWriteModel.OpcuaMessageResponse) if opcuaResponse.GetChunk() == (FINAL_CHUNK) { @@ -377,7 +386,12 @@ func (s *SecureChannel) onConnectOpenSecureChannel(ctx context.Context, codec *M var apu readWriteModel.OpcuaAPU if s.isEncrypted { - apu, err = readWriteModel.OpcuaAPUParse(ctx, s.encryptionHandler.encodeMessage(openRequest, buffer.GetBytes()), false) + message, err := s.encryptionHandler.encodeMessage(ctx, openRequest, buffer.GetBytes()) + if err != nil { + s.log.Debug().Err(err).Msg("error encoding") + return + } + apu, err = readWriteModel.OpcuaAPUParse(ctx, message, false) if err != nil { s.log.Debug().Err(err).Msg("error parsing") return @@ -554,7 +568,12 @@ func (s *SecureChannel) onConnectCreateSessionRequest(ctx context.Context, codec func (s *SecureChannel) onConnectActivateSessionRequest(ctx context.Context, codec *MessageCodec, opcuaMessageResponse readWriteModel.CreateSessionResponse, sessionResponse readWriteModel.CreateSessionResponse) { s.senderCertificate = sessionResponse.GetServerCertificate().GetStringValue() - s.encryptionHandler.setServerCertificate(s.encryptionHandler.getCertificateX509(s.senderCertificate)) + certificate, err := s.encryptionHandler.getCertificateX509(s.senderCertificate) + if err != nil { + s.log.Error().Err(err).Msg("error getting certificate") + return + } + s.encryptionHandler.setServerCertificate(certificate) s.senderNonce = sessionResponse.GetServerNonce().GetStringValue() endpoints := make([]string, 3) if address, err := url.Parse(s.configuration.host); err != nil { @@ -1297,7 +1316,12 @@ func (s *SecureChannel) keepAlive() { var apu readWriteModel.OpcuaAPU if s.isEncrypted { - apu, err = readWriteModel.OpcuaAPUParse(ctx, s.encryptionHandler.encodeMessage(openRequest, buffer.GetBytes()), false) + message, err := s.encryptionHandler.encodeMessage(ctx, openRequest, buffer.GetBytes()) + if err != nil { + s.log.Error().Err(err).Msg("error encoding") + return + } + apu, err = readWriteModel.OpcuaAPUParse(ctx, message, false) if err != nil { s.log.Error().Err(err).Msg("error parsing") return @@ -1507,7 +1531,11 @@ func (s *SecureChannel) getIdentityToken(tokenType readWriteModel.UserTokenType, encodeablePassword := make([]byte, 4+len(passwordBytes)+len(s.senderNonce)) n, err := encodeableBuffer.Read(encodeablePassword) s.log.Debug().Err(err).Int("n", n).Msg("read") - encryptedPassword := s.encryptionHandler.encryptPassword(encodeablePassword) + encryptedPassword, err := s.encryptionHandler.encryptPassword(encodeablePassword) + if err != nil { + s.log.Error().Err(err).Msg("error encrypting password") + return nil + } userNameIdentityToken := readWriteModel.NewUserNameIdentityToken( readWriteModel.NewPascalString(s.username), readWriteModel.NewPascalByteString(int32(len(encryptedPassword)), encryptedPassword),