From 032bc6ade7170d89fad736550c47d6904099f0aa Mon Sep 17 00:00:00 2001 From: Martin Regen Date: Thu, 21 Dec 2017 15:41:46 +0100 Subject: [PATCH] remove all dispose from RSA objects to work around mono bug --- .../Certificates/CertificateFactory.cs | 70 ++-- .../Certificates/CertificateValidator.cs | 8 +- .../Security/Certificates/RsaUtils.cs | 267 ++++++------- .../Stack/Tcp/UaSCBinaryChannel.Asymmetric.cs | 352 +++++++++--------- .../Stack/Tcp/UaSCBinaryChannel.Rsa.cs | 271 ++++++-------- 5 files changed, 433 insertions(+), 535 deletions(-) diff --git a/Stack/Opc.Ua.Core/Security/Certificates/CertificateFactory.cs b/Stack/Opc.Ua.Core/Security/Certificates/CertificateFactory.cs index 9e4d0867f7..f5b5e05e60 100644 --- a/Stack/Opc.Ua.Core/Security/Certificates/CertificateFactory.cs +++ b/Stack/Opc.Ua.Core/Security/Certificates/CertificateFactory.cs @@ -836,24 +836,20 @@ public class CertificateFactory try { // verify the public and private key match - using (RSA rsaPrivateKey = certWithPrivateKey.GetRSAPrivateKey()) + RSA rsaPrivateKey = certWithPrivateKey.GetRSAPrivateKey(); + RSA rsaPublicKey = certWithPublicKey.GetRSAPublicKey(); + X509KeyUsageFlags keyUsage = GetKeyUsage(certWithPublicKey); + if ((keyUsage & X509KeyUsageFlags.DataEncipherment) != 0) { - using (RSA rsaPublicKey = certWithPublicKey.GetRSAPublicKey()) - { - X509KeyUsageFlags keyUsage = GetKeyUsage(certWithPublicKey); - if ((keyUsage & X509KeyUsageFlags.DataEncipherment) != 0) - { - result = VerifyRSAKeyPairCrypt(rsaPublicKey, rsaPrivateKey); - } - else if ((keyUsage & X509KeyUsageFlags.DigitalSignature) != 0) - { - result = VerifyRSAKeyPairSign(rsaPublicKey, rsaPrivateKey); - } - else - { - throw new CryptographicException("Don't know how to verify the public/private key pair."); - } - } + result = VerifyRSAKeyPairCrypt(rsaPublicKey, rsaPrivateKey); + } + else if ((keyUsage & X509KeyUsageFlags.DigitalSignature) != 0) + { + result = VerifyRSAKeyPairSign(rsaPublicKey, rsaPrivateKey); + } + else + { + throw new CryptographicException("Don't know how to verify the public/private key pair."); } } catch (Exception e) @@ -1050,14 +1046,12 @@ public class CertificateFactory /// private static RsaKeyParameters GetPublicKeyParameter(X509Certificate2 certificate) { - using (RSA rsa = certificate.GetRSAPublicKey()) - { - RSAParameters rsaParams = rsa.ExportParameters(false); - return new RsaKeyParameters( - false, - new BigInteger(1, rsaParams.Modulus), - new BigInteger(1, rsaParams.Exponent)); - } + RSA rsa = certificate.GetRSAPublicKey(); + RSAParameters rsaParams = rsa.ExportParameters(false); + return new RsaKeyParameters( + false, + new BigInteger(1, rsaParams.Modulus), + new BigInteger(1, rsaParams.Exponent)); } /// @@ -1067,20 +1061,18 @@ public class CertificateFactory private static RsaPrivateCrtKeyParameters GetPrivateKeyParameter(X509Certificate2 certificate) { // try to get signing/private key from certificate passed in - using (RSA rsa = certificate.GetRSAPrivateKey()) - { - RSAParameters rsaParams = rsa.ExportParameters(true); - RsaPrivateCrtKeyParameters keyParams = new RsaPrivateCrtKeyParameters( - new BigInteger(1, rsaParams.Modulus), - new BigInteger(1, rsaParams.Exponent), - new BigInteger(1, rsaParams.D), - new BigInteger(1, rsaParams.P), - new BigInteger(1, rsaParams.Q), - new BigInteger(1, rsaParams.DP), - new BigInteger(1, rsaParams.DQ), - new BigInteger(1, rsaParams.InverseQ)); - return keyParams; - } + RSA rsa = certificate.GetRSAPrivateKey(); + RSAParameters rsaParams = rsa.ExportParameters(true); + RsaPrivateCrtKeyParameters keyParams = new RsaPrivateCrtKeyParameters( + new BigInteger(1, rsaParams.Modulus), + new BigInteger(1, rsaParams.Exponent), + new BigInteger(1, rsaParams.D), + new BigInteger(1, rsaParams.P), + new BigInteger(1, rsaParams.Q), + new BigInteger(1, rsaParams.DP), + new BigInteger(1, rsaParams.DQ), + new BigInteger(1, rsaParams.InverseQ)); + return keyParams; } /// diff --git a/Stack/Opc.Ua.Core/Security/Certificates/CertificateValidator.cs b/Stack/Opc.Ua.Core/Security/Certificates/CertificateValidator.cs index 471eabc6c0..5575bb2b87 100644 --- a/Stack/Opc.Ua.Core/Security/Certificates/CertificateValidator.cs +++ b/Stack/Opc.Ua.Core/Security/Certificates/CertificateValidator.cs @@ -709,12 +709,10 @@ namespace Opc.Ua throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "SHA1 signed certificates are not trusted"); } - using (RSA rsa = certificate.GetRSAPublicKey()) + RSA rsa = certificate.GetRSAPublicKey(); + if (rsa.KeySize < m_minimumCertificateKeySize) { - if (rsa.KeySize < m_minimumCertificateKeySize) - { - throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Certificate doesn't meet minimum key length requirement"); - } + throw new ServiceResultException(StatusCodes.BadSecurityChecksFailed, "Certificate doesn't meet minimum key length requirement"); } CertificateIdentifier trustedCertificate = await GetTrustedCertificate(certificate); diff --git a/Stack/Opc.Ua.Core/Security/Certificates/RsaUtils.cs b/Stack/Opc.Ua.Core/Security/Certificates/RsaUtils.cs index 29e506bf10..088d3ca9a8 100644 --- a/Stack/Opc.Ua.Core/Security/Certificates/RsaUtils.cs +++ b/Stack/Opc.Ua.Core/Security/Certificates/RsaUtils.cs @@ -28,10 +28,8 @@ namespace Opc.Ua /// public static int GetPlainTextBlockSize(X509Certificate2 encryptingCertificate, bool useOaep) { - using (RSA rsa = encryptingCertificate.GetRSAPublicKey()) - { - return GetPlainTextBlockSize(rsa, useOaep); - } + RSA rsa = encryptingCertificate.GetRSAPublicKey(); + return GetPlainTextBlockSize(rsa, useOaep); } /// @@ -58,30 +56,20 @@ namespace Opc.Ua /// public static int GetCipherTextBlockSize(X509Certificate2 encryptingCertificate, bool useOaep) { - using (RSA rsa = encryptingCertificate.GetRSAPublicKey()) - { - if (rsa != null) - { - return rsa.KeySize / 8; - } - } - return -1; + RSA rsa = encryptingCertificate.GetRSAPublicKey(); + return GetCipherTextBlockSize(rsa, useOaep); } /// - /// Returns the length of a RSA PKCS#1 v1.5 signature of a digest. + /// Return the ciphertext block size for RSA OAEP encryption. /// - public static int RsaPkcs15_GetSignatureLength(X509Certificate2 signingCertificate) + public static int GetCipherTextBlockSize(RSA rsa, bool useOaep) { - using (RSA rsa = signingCertificate.GetRSAPublicKey()) + if (rsa != null) { - if (rsa == null) - { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); - } - return rsa.KeySize / 8; } + return -1; } /// @@ -92,17 +80,14 @@ namespace Opc.Ua X509Certificate2 signingCertificate) { // extract the private key. - using (RSA rsa = signingCertificate.GetRSAPrivateKey()) + RSA rsa = signingCertificate.GetRSAPrivateKey(); + if (rsa == null) { - - if (rsa == null) - { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); - } - - // create the signature. - return rsa.SignData(dataToSign.Array, dataToSign.Offset, dataToSign.Count, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); } + + // create the signature. + return rsa.SignData(dataToSign.Array, dataToSign.Offset, dataToSign.Count, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); } /// @@ -113,17 +98,14 @@ namespace Opc.Ua X509Certificate2 signingCertificate) { // extract the private key. - using (RSA rsa = signingCertificate.GetRSAPrivateKey()) + RSA rsa = signingCertificate.GetRSAPrivateKey(); + if (rsa == null) { - - if (rsa == null) - { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); - } - - // create the signature. - return rsa.SignData(dataToSign.Array, dataToSign.Offset, dataToSign.Count, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); } + + // create the signature. + return rsa.SignData(dataToSign.Array, dataToSign.Offset, dataToSign.Count, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); } /// @@ -134,18 +116,15 @@ namespace Opc.Ua byte[] signature, X509Certificate2 signingCertificate) { - // extract the private key. - using (RSA rsa = signingCertificate.GetRSAPublicKey()) + // extract the public key. + RSA rsa = signingCertificate.GetRSAPublicKey(); + if (rsa == null) { - - if (rsa == null) - { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); - } - - // verify signature. - return rsa.VerifyData(dataToVerify.Array, dataToVerify.Offset, dataToVerify.Count, signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); } + + // verify signature. + return rsa.VerifyData(dataToVerify.Array, dataToVerify.Offset, dataToVerify.Count, signature, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); } /// @@ -157,17 +136,14 @@ namespace Opc.Ua X509Certificate2 signingCertificate) { // extract the private key. - using (RSA rsa = signingCertificate.GetRSAPublicKey()) + RSA rsa = signingCertificate.GetRSAPublicKey(); + if (rsa == null) { - - if (rsa == null) - { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); - } - - // verify signature. - return rsa.VerifyData(dataToVerify.Array, dataToVerify.Offset, dataToVerify.Count, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); } + + // verify signature. + return rsa.VerifyData(dataToVerify.Array, dataToVerify.Offset, dataToVerify.Count, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); } /// @@ -178,10 +154,16 @@ namespace Opc.Ua X509Certificate2 encryptingCertificate, bool useOaep) { - int plaintextBlockSize = GetPlainTextBlockSize(encryptingCertificate, useOaep); + RSA rsa = encryptingCertificate.GetRSAPublicKey(); + if (rsa == null) + { + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); + } + + int plaintextBlockSize = GetPlainTextBlockSize(rsa, useOaep); int blockCount = ((dataToEncrypt.Length + 4) / plaintextBlockSize) + 1; int plainTextSize = blockCount * plaintextBlockSize; - int cipherTextSize = blockCount * GetCipherTextBlockSize(encryptingCertificate, useOaep); + int cipherTextSize = blockCount * GetCipherTextBlockSize(rsa, useOaep); byte[] plainText = new byte[plainTextSize]; @@ -195,7 +177,7 @@ namespace Opc.Ua Array.Copy(dataToEncrypt, 0, plainText, 4, dataToEncrypt.Length); byte[] buffer = new byte[cipherTextSize]; - ArraySegment cipherText = Encrypt(new ArraySegment(plainText), encryptingCertificate, useOaep, new ArraySegment(buffer)); + ArraySegment cipherText = Encrypt(new ArraySegment(plainText), rsa, useOaep, new ArraySegment(buffer)); System.Diagnostics.Debug.Assert(cipherText.Count == buffer.Length); return buffer; @@ -206,61 +188,51 @@ namespace Opc.Ua /// public static ArraySegment Encrypt( ArraySegment dataToEncrypt, - X509Certificate2 encryptingCertificate, + RSA rsa, bool useOaep, ArraySegment outputBuffer) { - // get the encrypting key. - using (RSA rsa = encryptingCertificate.GetRSAPublicKey()) + int inputBlockSize = GetPlainTextBlockSize(rsa, useOaep); + int outputBlockSize = GetCipherTextBlockSize(rsa, useOaep); + + // verify the input data is the correct block size. + if (dataToEncrypt.Count % inputBlockSize != 0) + { + Utils.Trace("Message is not an integral multiple of the block size. Length = {0}, BlockSize = {1}.", dataToEncrypt.Count, inputBlockSize); + } + + byte[] encryptedBuffer = outputBuffer.Array; + + using (MemoryStream ostrm = new MemoryStream( + encryptedBuffer, + outputBuffer.Offset, + outputBuffer.Count)) { - if (rsa == null) + // encrypt body. + byte[] input = new byte[inputBlockSize]; + + for (int ii = dataToEncrypt.Offset; ii < dataToEncrypt.Offset + dataToEncrypt.Count; ii += inputBlockSize) { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); - } - - int inputBlockSize = GetPlainTextBlockSize(encryptingCertificate, useOaep); - int outputBlockSize = rsa.KeySize / 8; - - // verify the input data is the correct block size. - if (dataToEncrypt.Count % inputBlockSize != 0) - { - Utils.Trace("Message is not an integral multiple of the block size. Length = {0}, BlockSize = {1}.", dataToEncrypt.Count, inputBlockSize); - } - - byte[] encryptedBuffer = outputBuffer.Array; - - using (MemoryStream ostrm = new MemoryStream( - encryptedBuffer, - outputBuffer.Offset, - outputBuffer.Count)) - { - - // encrypt body. - byte[] input = new byte[inputBlockSize]; - - for (int ii = dataToEncrypt.Offset; ii < dataToEncrypt.Offset + dataToEncrypt.Count; ii += inputBlockSize) + Array.Copy(dataToEncrypt.Array, ii, input, 0, input.Length); + if (useOaep == true) { - Array.Copy(dataToEncrypt.Array, ii, input, 0, input.Length); - if (useOaep == true) - { - byte[] cipherText = rsa.Encrypt(input, RSAEncryptionPadding.OaepSHA1); - ostrm.Write(cipherText, 0, cipherText.Length); - } - else - { - byte[] cipherText = rsa.Encrypt(input, RSAEncryptionPadding.Pkcs1); - ostrm.Write(cipherText, 0, cipherText.Length); - } + byte[] cipherText = rsa.Encrypt(input, RSAEncryptionPadding.OaepSHA1); + ostrm.Write(cipherText, 0, cipherText.Length); + } + else + { + byte[] cipherText = rsa.Encrypt(input, RSAEncryptionPadding.Pkcs1); + ostrm.Write(cipherText, 0, cipherText.Length); } } - - // return buffer - return new ArraySegment( - encryptedBuffer, - outputBuffer.Offset, - (dataToEncrypt.Count / inputBlockSize) * outputBlockSize); } + + // return buffer + return new ArraySegment( + encryptedBuffer, + outputBuffer.Offset, + (dataToEncrypt.Count / inputBlockSize) * outputBlockSize); } /// @@ -271,11 +243,17 @@ namespace Opc.Ua X509Certificate2 encryptingCertificate, bool useOaep) { - int plainTextSize = dataToDecrypt.Count / GetCipherTextBlockSize(encryptingCertificate, useOaep); + RSA rsa = encryptingCertificate.GetRSAPrivateKey(); + if (rsa == null) + { + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); + } + + int plainTextSize = dataToDecrypt.Count / GetCipherTextBlockSize(rsa, useOaep); plainTextSize *= GetPlainTextBlockSize(encryptingCertificate, useOaep); byte[] buffer = new byte[plainTextSize]; - ArraySegment plainText = Decrypt(dataToDecrypt, encryptingCertificate, useOaep, new ArraySegment(buffer)); + ArraySegment plainText = Decrypt(dataToDecrypt, rsa, useOaep, new ArraySegment(buffer)); System.Diagnostics.Debug.Assert(plainText.Count == buffer.Length); // decode length. @@ -297,57 +275,48 @@ namespace Opc.Ua /// public static ArraySegment Decrypt( ArraySegment dataToDecrypt, - X509Certificate2 encryptingCertificate, + RSA rsa, bool useOaep, ArraySegment outputBuffer) { - // get the encrypting key. - using (RSA rsa = encryptingCertificate.GetRSAPrivateKey()) + int inputBlockSize = GetCipherTextBlockSize(rsa, useOaep); + int outputBlockSize = GetPlainTextBlockSize(rsa, useOaep); + + // verify the input data is the correct block size. + if (dataToDecrypt.Count % inputBlockSize != 0) { - if (rsa == null) + Utils.Trace("Message is not an integral multiple of the block size. Length = {0}, BlockSize = {1}.", dataToDecrypt.Count, inputBlockSize); + } + + byte[] decryptedBuffer = outputBuffer.Array; + + using (MemoryStream ostrm = new MemoryStream( + decryptedBuffer, + outputBuffer.Offset, + outputBuffer.Count)) + { + + // decrypt body. + byte[] input = new byte[inputBlockSize]; + + for (int ii = dataToDecrypt.Offset; ii < dataToDecrypt.Offset + dataToDecrypt.Count; ii += inputBlockSize) { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); - } - - int inputBlockSize = rsa.KeySize / 8; - int outputBlockSize = GetPlainTextBlockSize(encryptingCertificate, useOaep); - - // verify the input data is the correct block size. - if (dataToDecrypt.Count % inputBlockSize != 0) - { - Utils.Trace("Message is not an integral multiple of the block size. Length = {0}, BlockSize = {1}.", dataToDecrypt.Count, inputBlockSize); - } - - byte[] decryptedBuffer = outputBuffer.Array; - - using (MemoryStream ostrm = new MemoryStream( - decryptedBuffer, - outputBuffer.Offset, - outputBuffer.Count)) - { - - // decrypt body. - byte[] input = new byte[inputBlockSize]; - - for (int ii = dataToDecrypt.Offset; ii < dataToDecrypt.Offset + dataToDecrypt.Count; ii += inputBlockSize) + Array.Copy(dataToDecrypt.Array, ii, input, 0, input.Length); + if (useOaep == true) { - Array.Copy(dataToDecrypt.Array, ii, input, 0, input.Length); - if (useOaep == true) - { - byte[] plainText = rsa.Decrypt(input, RSAEncryptionPadding.OaepSHA1); - ostrm.Write(plainText, 0, plainText.Length); - } - else - { - byte[] plainText = rsa.Decrypt(input, RSAEncryptionPadding.Pkcs1); - ostrm.Write(plainText, 0, plainText.Length); - } + byte[] plainText = rsa.Decrypt(input, RSAEncryptionPadding.OaepSHA1); + ostrm.Write(plainText, 0, plainText.Length); + } + else + { + byte[] plainText = rsa.Decrypt(input, RSAEncryptionPadding.Pkcs1); + ostrm.Write(plainText, 0, plainText.Length); } } - - // return buffers. - return new ArraySegment(decryptedBuffer, outputBuffer.Offset, (dataToDecrypt.Count / inputBlockSize) * outputBlockSize); } + + // return buffers. + return new ArraySegment(decryptedBuffer, outputBuffer.Offset, (dataToDecrypt.Count / inputBlockSize) * outputBlockSize); } #endregion } diff --git a/Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.Asymmetric.cs b/Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.Asymmetric.cs index e248a2661a..8d5dac16a1 100644 --- a/Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.Asymmetric.cs +++ b/Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.Asymmetric.cs @@ -29,8 +29,8 @@ namespace Opc.Ua.Bindings /// public EndpointDescription EndpointDescription { - get - { + get + { lock (DataLock) { return m_selectedEndpoint; @@ -55,7 +55,7 @@ namespace Opc.Ua.Bindings { get { return m_serverCertificate; } } - + /// /// The security mode used with the channel. /// @@ -63,7 +63,7 @@ namespace Opc.Ua.Bindings { get { return m_securityMode; } } - + /// /// The security policy used with the channel. /// @@ -71,24 +71,24 @@ namespace Opc.Ua.Bindings { get { return m_securityPolicyUri; } } - + /// /// Whether the channel is restricted to discovery operations. /// protected bool DiscoveryOnly { - get - { - return m_discoveryOnly; + get + { + return m_discoveryOnly; } } - + /// /// The certificate for the client. /// protected X509Certificate2 ClientCertificate { - get { return m_clientCertificate; } + get { return m_clientCertificate; } set { m_clientCertificate = value; } } @@ -116,7 +116,7 @@ namespace Opc.Ua.Bindings return null; } - StringBuilder builder = new StringBuilder(thumbprint.Length*2); + StringBuilder builder = new StringBuilder(thumbprint.Length * 2); for (int ii = 0; ii < thumbprint.Length; ii++) { @@ -136,27 +136,27 @@ namespace Opc.Ua.Bindings return null; } - byte[] bytes = new byte[thumbprint.Length/2]; + byte[] bytes = new byte[thumbprint.Length / 2]; - for (int ii = 0; ii < thumbprint.Length-1; ii += 2) + for (int ii = 0; ii < thumbprint.Length - 1; ii += 2) { - bytes[ii/2] = Convert.ToByte(thumbprint.Substring(ii, 2), 16); + bytes[ii / 2] = Convert.ToByte(thumbprint.Substring(ii, 2), 16); } return bytes; } - + /// /// Compares two certificates. /// protected static void CompareCertificates(X509Certificate2 expected, X509Certificate2 actual, bool allowNull) { bool equal = true; - + if (expected == null) { equal = actual == null; - + // accept everything if no expected certificate and nulls are allowed. if (allowNull) { @@ -175,7 +175,7 @@ namespace Opc.Ua.Bindings if (!equal) { throw ServiceResultException.Create( - StatusCodes.BadCertificateInvalid, + StatusCodes.BadCertificateInvalid, "Certificate mismatch. Expecting '{0}'/{1},. Received '{2}'/{3}.", (expected != null) ? expected.Subject : "(null)", (expected != null) ? expected.Thumbprint : "(null)", @@ -183,9 +183,9 @@ namespace Opc.Ua.Bindings (actual != null) ? actual.Thumbprint : "(null)"); } } -#endregion + #endregion -#region Asymmetric Cryptography Functions + #region Asymmetric Cryptography Functions /// /// Returns the length of the symmetric encryption key. /// @@ -194,21 +194,21 @@ namespace Opc.Ua.Bindings switch (SecurityPolicyUri) { case SecurityPolicies.Basic128Rsa15: - { - return 16; - } + { + return 16; + } case SecurityPolicies.Basic256: case SecurityPolicies.Basic256Sha256: - { - return 32; - } + { + return 32; + } default: case SecurityPolicies.None: - { - return 0; - } + { + return 0; + } } } @@ -237,7 +237,7 @@ namespace Opc.Ua.Bindings return true; } } - + return false; } @@ -251,19 +251,19 @@ namespace Opc.Ua.Bindings case SecurityPolicies.Basic256: case SecurityPolicies.Basic256Sha256: { - return Rsa_GetPlainTextBlockSize(receiverCertificate, true); + return RsaUtils.GetPlainTextBlockSize(receiverCertificate, true); } case SecurityPolicies.Basic128Rsa15: { - return Rsa_GetPlainTextBlockSize(receiverCertificate, false); + return RsaUtils.GetPlainTextBlockSize(receiverCertificate, false); } default: case SecurityPolicies.None: - { - return 1; - } + { + return 1; + } } } @@ -277,19 +277,19 @@ namespace Opc.Ua.Bindings case SecurityPolicies.Basic256: case SecurityPolicies.Basic256Sha256: { - return Rsa_GetCipherTextBlockSize(receiverCertificate, true); + return RsaUtils.GetCipherTextBlockSize(receiverCertificate, true); } case SecurityPolicies.Basic128Rsa15: { - return Rsa_GetCipherTextBlockSize(receiverCertificate, false); + return RsaUtils.GetCipherTextBlockSize(receiverCertificate, false); } default: case SecurityPolicies.None: - { - return 1; - } + { + return 1; + } } } @@ -297,9 +297,9 @@ namespace Opc.Ua.Bindings /// Calculates the size of the asymmetric security header. /// protected int GetAsymmetricHeaderSize( - string securityPolicyUri, + string securityPolicyUri, X509Certificate2 senderCertificate) - { + { int headerSize = 0; headerSize += TcpMessageLimits.BaseHeaderSize; @@ -322,7 +322,7 @@ namespace Opc.Ua.Bindings if (headerSize >= SendBufferSize - TcpMessageLimits.SequenceHeaderSize - GetAsymmetricSignatureSize(senderCertificate) - 1) { throw ServiceResultException.Create( - StatusCodes.BadInternalError, + StatusCodes.BadInternalError, "AsymmetricSecurityHeader is {0} bytes which is too large for the send buffer size of {1} bytes.", headerSize, SendBufferSize); @@ -366,7 +366,7 @@ namespace Opc.Ua.Bindings return headerSize; } - + /// /// Calculates the size of the footer with an asymmetric signature. /// @@ -377,15 +377,15 @@ namespace Opc.Ua.Bindings case SecurityPolicies.Basic128Rsa15: case SecurityPolicies.Basic256: case SecurityPolicies.Basic256Sha256: - { - return RsaPkcs15_GetSignatureLength(senderCertificate); - } + { + return RsaUtils.GetSignatureLength(senderCertificate); + } default: case SecurityPolicies.None: - { - return 0; - } + { + return 0; + } } } @@ -393,12 +393,12 @@ namespace Opc.Ua.Bindings /// Writes the asymmetric security header to the buffer. /// protected void WriteAsymmetricMessageHeader( - BinaryEncoder encoder, - uint messageType, - uint secureChannelId, - string securityPolicyUri, - X509Certificate2 senderCertificate, - X509Certificate2 receiverCertificate) + BinaryEncoder encoder, + uint messageType, + uint secureChannelId, + string securityPolicyUri, + X509Certificate2 senderCertificate, + X509Certificate2 receiverCertificate) { int start = encoder.Position; @@ -417,11 +417,11 @@ namespace Opc.Ua.Bindings encoder.WriteByteString(null, null); encoder.WriteByteString(null, null); } - + if (encoder.Position - start > SendBufferSize) { throw ServiceResultException.Create( - StatusCodes.BadInternalError, + StatusCodes.BadInternalError, "AsymmetricSecurityHeader is {0} bytes which is too large for the send buffer size of {1} bytes.", encoder.Position - start, SendBufferSize); @@ -455,12 +455,12 @@ namespace Opc.Ua.Bindings /// Sends a OpenSecureChannel response. /// protected BufferCollection WriteAsymmetricMessage( - uint messageType, - uint requestId, - X509Certificate2 senderCertificate, - X509Certificate2 receiverCertificate, + uint messageType, + uint requestId, + X509Certificate2 senderCertificate, + X509Certificate2 receiverCertificate, ArraySegment messageBody) - { + { bool success = false; BufferCollection chunksToSend = new BufferCollection(); @@ -470,7 +470,7 @@ namespace Opc.Ua.Bindings { int headerSize = GetAsymmetricHeaderSize(SecurityPolicyUri, senderCertificate); int signatureSize = GetAsymmetricSignatureSize(senderCertificate); - + BinaryEncoder encoder = new BinaryEncoder(buffer, 0, SendBufferSize, Quotas.MessageContext); WriteAsymmetricMessageHeader( @@ -480,16 +480,16 @@ namespace Opc.Ua.Bindings SecurityPolicyUri, senderCertificate, receiverCertificate); - + // save the header. ArraySegment header = new ArraySegment(buffer, 0, headerSize); - + // calculate the space available. int plainTextBlockSize = GetPlainTextBlockSize(receiverCertificate); int cipherTextBlockSize = GetCipherTextBlockSize(receiverCertificate); int maxCipherTextSize = SendBufferSize - headerSize; - int maxCipherBlocks = maxCipherTextSize/cipherTextBlockSize; - int maxPlainTextSize = maxCipherBlocks*plainTextBlockSize; + int maxCipherBlocks = maxCipherTextSize / cipherTextBlockSize; + int maxPlainTextSize = maxCipherBlocks * plainTextBlockSize; int maxPayloadSize = maxPlainTextSize - signatureSize - 1 - TcpMessageLimits.SequenceHeaderSize; int bytesToWrite = messageBody.Count; @@ -512,11 +512,11 @@ namespace Opc.Ua.Bindings } // write the message body. - encoder.WriteRawBytes(messageBody.Array, messageBody.Offset+startOfBytes, payloadSize); + encoder.WriteRawBytes(messageBody.Array, messageBody.Offset + startOfBytes, payloadSize); // calculate the amount of plain text to encrypt. int plainTextSize = encoder.Position - headerSize + signatureSize; - + // calculate the padding. int padding = 0; @@ -566,28 +566,28 @@ namespace Opc.Ua.Bindings } // calculate the number of block to encrypt. - int encryptedBlocks = plainTextSize/plainTextBlockSize; + int encryptedBlocks = plainTextSize / plainTextBlockSize; // calculate the size of the encrypted data. - int cipherTextSize = encryptedBlocks*cipherTextBlockSize; - + int cipherTextSize = encryptedBlocks * cipherTextBlockSize; + // put the message size after encryption into the header. UpdateMessageSize(buffer, 0, cipherTextSize + headerSize); // write the signature. byte[] signature = Sign(new ArraySegment(buffer, 0, encoder.Position), senderCertificate); - + if (signature != null) { encoder.WriteRawBytes(signature, 0, signature.Length); } - + int messageSize = encoder.Close(); // encrypt the data. ArraySegment encryptedBuffer = Encrypt( - new ArraySegment(buffer, headerSize, messageSize-headerSize), - header, + new ArraySegment(buffer, headerSize, messageSize - headerSize), + header, receiverCertificate); // check for math errors due to code bugs. @@ -621,7 +621,7 @@ namespace Opc.Ua.Bindings } finally { - BufferManager.ReturnBuffer(buffer, "WriteAsymmetricMessage"); + BufferManager.ReturnBuffer(buffer, "WriteAsymmetricMessage"); if (!success) { @@ -635,12 +635,12 @@ namespace Opc.Ua.Bindings /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "messageType"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals", MessageId = "messageSize")] protected void ReadAsymmetricMessageHeader( - BinaryDecoder decoder, - X509Certificate2 receiverCertificate, - out uint secureChannelId, + BinaryDecoder decoder, + X509Certificate2 receiverCertificate, + out uint secureChannelId, out X509Certificate2 senderCertificate, - out string securityPolicyUri) - { + out string securityPolicyUri) + { senderCertificate = null; uint messageType = decoder.ReadUInt32(null); @@ -660,11 +660,11 @@ namespace Opc.Ua.Bindings catch (Exception e) { throw ServiceResultException.Create( - StatusCodes.BadSecurityChecksFailed, + StatusCodes.BadSecurityChecksFailed, e, "The asymmetric security header could not be parsed."); } - + // verify sender certificate. if (certificateData != null && certificateData.Length > 0) { @@ -714,7 +714,7 @@ namespace Opc.Ua.Bindings /// protected void ReviseSecurityMode(bool firstCall, MessageSecurityMode requestedMode) { - bool supported = false; + bool supported = false; // server may support multiple security modes - check if the one the client used is supported. if (firstCall && !m_discoveryOnly) @@ -723,7 +723,7 @@ namespace Opc.Ua.Bindings { if (endpoint.SecurityMode == requestedMode) { - if (requestedMode == MessageSecurityMode.None || + if (requestedMode == MessageSecurityMode.None || endpoint.SecurityPolicyUri == m_securityPolicyUri) { m_securityMode = endpoint.SecurityMode; @@ -740,7 +740,7 @@ namespace Opc.Ua.Bindings throw ServiceResultException.Create(StatusCodes.BadSecurityModeRejected, "Security mode is not acceptable to the server."); } } - + /// /// Sets to endpoint according to the endpoint url. /// @@ -780,15 +780,15 @@ namespace Opc.Ua.Bindings /// Processes an OpenSecureChannel request message. /// protected ArraySegment ReadAsymmetricMessage( - ArraySegment buffer, - X509Certificate2 receiverCertificate, - out uint channelId, + ArraySegment buffer, + X509Certificate2 receiverCertificate, + out uint channelId, out X509Certificate2 senderCertificate, - out uint requestId, - out uint sequenceNumber) - { + out uint requestId, + out uint sequenceNumber) + { BinaryDecoder decoder = new BinaryDecoder(buffer.Array, buffer.Offset, buffer.Count, Quotas.MessageContext); - + string securityPolicyUri = null; // parse the security header. @@ -804,7 +804,7 @@ namespace Opc.Ua.Bindings { Quotas.CertificateValidator.Validate(senderCertificate); } - + // check if this is the first open secure channel request. if (!m_uninitialized) { @@ -819,25 +819,25 @@ namespace Opc.Ua.Bindings if (m_endpoints != null) { foreach (EndpointDescription endpoint in m_endpoints) - { + { // There may be multiple endpoints with the same securityPolicyUri. // Just choose the first one that matches. This choice will be re-examined // When the OpenSecureChannel request body is processed. if (endpoint.SecurityPolicyUri == securityPolicyUri || (securityPolicyUri == SecurityPolicies.None && endpoint.SecurityMode == MessageSecurityMode.None)) { - m_securityMode = endpoint.SecurityMode; + m_securityMode = endpoint.SecurityMode; m_securityPolicyUri = securityPolicyUri; - m_discoveryOnly = false; - m_uninitialized = false; - m_selectedEndpoint = endpoint; - + m_discoveryOnly = false; + m_uninitialized = false; + m_selectedEndpoint = endpoint; + // recalculate the key sizes. CalculateSymmetricKeySizes(); break; } } } - + // allow a discovery only channel with no security if policy not suppported if (m_uninitialized) { @@ -846,11 +846,11 @@ namespace Opc.Ua.Bindings throw ServiceResultException.Create(StatusCodes.BadSecurityPolicyRejected, "The security policy is not supported."); } - m_securityMode = MessageSecurityMode.None; + m_securityMode = MessageSecurityMode.None; m_securityPolicyUri = SecurityPolicies.None; - m_discoveryOnly = true; - m_uninitialized = false; - m_selectedEndpoint = null; + m_discoveryOnly = true; + m_uninitialized = false; + m_selectedEndpoint = null; } } @@ -861,7 +861,7 @@ namespace Opc.Ua.Bindings new ArraySegment(buffer.Array, buffer.Offset + headerSize, buffer.Count - headerSize), new ArraySegment(buffer.Array, buffer.Offset, headerSize), receiverCertificate); - + // extract signature. int signatureSize = GetAsymmetricSignatureSize(senderCertificate); @@ -869,14 +869,14 @@ namespace Opc.Ua.Bindings for (int ii = 0; ii < signatureSize; ii++) { - signature[ii] = plainText.Array[plainText.Offset+plainText.Count-signatureSize+ii]; + signature[ii] = plainText.Array[plainText.Offset + plainText.Count - signatureSize + ii]; } - + // verify the signature. - ArraySegment dataToVerify = new ArraySegment(plainText.Array, plainText.Offset, plainText.Count-signatureSize); - + ArraySegment dataToVerify = new ArraySegment(plainText.Array, plainText.Offset, plainText.Count - signatureSize); + if (!Verify(dataToVerify, signature, senderCertificate)) - { + { Utils.Trace("Could not verify signature on message."); throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "Could not verify the signature on the message."); } @@ -920,11 +920,11 @@ namespace Opc.Ua.Bindings // decode message. decoder = new BinaryDecoder( - plainText.Array, - plainText.Offset + headerSize, - plainText.Count - headerSize, + plainText.Array, + plainText.Offset + headerSize, + plainText.Count - headerSize, Quotas.MessageContext); - + sequenceNumber = decoder.ReadUInt32(null); requestId = decoder.ReadUInt32(null); @@ -932,12 +932,12 @@ namespace Opc.Ua.Bindings decoder.Close(); Utils.Trace("Security Policy: {0}", SecurityPolicyUri); - Utils.Trace("Sender Certificate: {0}", (senderCertificate != null)?senderCertificate.Subject:"(none)"); + Utils.Trace("Sender Certificate: {0}", (senderCertificate != null) ? senderCertificate.Subject : "(none)"); // return the body. return new ArraySegment( - plainText.Array, - plainText.Offset + headerSize, + plainText.Array, + plainText.Offset + headerSize, plainText.Count - headerSize - signatureSize - paddingCount); } @@ -950,26 +950,26 @@ namespace Opc.Ua.Bindings /// protected byte[] Sign( ArraySegment dataToSign, - X509Certificate2 senderCertificate) + X509Certificate2 senderCertificate) { switch (SecurityPolicyUri) { default: case SecurityPolicies.None: - { - return null; - } + { + return null; + } case SecurityPolicies.Basic256: case SecurityPolicies.Basic128Rsa15: - { - return RsaPkcs15_Sign(dataToSign, senderCertificate, HashAlgorithmName.SHA1); - } + { + return RsaPkcs15_Sign(dataToSign, senderCertificate, HashAlgorithmName.SHA1); + } case SecurityPolicies.Basic256Sha256: - { - return RsaPkcs15_Sign(dataToSign, senderCertificate, HashAlgorithmName.SHA256); - } + { + return RsaPkcs15_Sign(dataToSign, senderCertificate, HashAlgorithmName.SHA256); + } } } @@ -983,32 +983,32 @@ namespace Opc.Ua.Bindings /// protected bool Verify( ArraySegment dataToVerify, - byte[] signature, - X509Certificate2 senderCertificate) - { + byte[] signature, + X509Certificate2 senderCertificate) + { // verify signature. switch (SecurityPolicyUri) { case SecurityPolicies.None: - { - return true; - } + { + return true; + } case SecurityPolicies.Basic128Rsa15: case SecurityPolicies.Basic256: - { - return RsaPkcs15_Verify(dataToVerify, signature, senderCertificate, HashAlgorithmName.SHA1); - } + { + return RsaPkcs15_Verify(dataToVerify, signature, senderCertificate, HashAlgorithmName.SHA1); + } case SecurityPolicies.Basic256Sha256: - { - return RsaPkcs15_Verify(dataToVerify, signature, senderCertificate, HashAlgorithmName.SHA256); - } + { + return RsaPkcs15_Verify(dataToVerify, signature, senderCertificate, HashAlgorithmName.SHA256); + } default: - { - return false; - } + { + return false; + } } } @@ -1023,30 +1023,30 @@ namespace Opc.Ua.Bindings protected ArraySegment Encrypt( ArraySegment dataToEncrypt, ArraySegment headerToCopy, - X509Certificate2 receiverCertificate) - { + X509Certificate2 receiverCertificate) + { switch (SecurityPolicyUri) { default: case SecurityPolicies.None: - { - byte[] encryptedBuffer = BufferManager.TakeBuffer(SendBufferSize, "Encrypt"); + { + byte[] encryptedBuffer = BufferManager.TakeBuffer(SendBufferSize, "Encrypt"); - Array.Copy(headerToCopy.Array, headerToCopy.Offset, encryptedBuffer, 0, headerToCopy.Count); - Array.Copy(dataToEncrypt.Array, dataToEncrypt.Offset, encryptedBuffer, headerToCopy.Count, dataToEncrypt.Count); + Array.Copy(headerToCopy.Array, headerToCopy.Offset, encryptedBuffer, 0, headerToCopy.Count); + Array.Copy(dataToEncrypt.Array, dataToEncrypt.Offset, encryptedBuffer, headerToCopy.Count, dataToEncrypt.Count); - return new ArraySegment(encryptedBuffer, 0, dataToEncrypt.Count+headerToCopy.Count); - } + return new ArraySegment(encryptedBuffer, 0, dataToEncrypt.Count + headerToCopy.Count); + } case SecurityPolicies.Basic256: case SecurityPolicies.Basic256Sha256: - { - return Rsa_Encrypt(dataToEncrypt, headerToCopy, receiverCertificate, true); - } + { + return Rsa_Encrypt(dataToEncrypt, headerToCopy, receiverCertificate, true); + } case SecurityPolicies.Basic128Rsa15: - { - return Rsa_Encrypt(dataToEncrypt, headerToCopy, receiverCertificate, false); - } + { + return Rsa_Encrypt(dataToEncrypt, headerToCopy, receiverCertificate, false); + } } } @@ -1060,43 +1060,43 @@ namespace Opc.Ua.Bindings protected ArraySegment Decrypt( ArraySegment dataToDecrypt, ArraySegment headerToCopy, - X509Certificate2 receiverCertificate) + X509Certificate2 receiverCertificate) { switch (SecurityPolicyUri) { default: case SecurityPolicies.None: - { - byte[] decryptedBuffer = BufferManager.TakeBuffer(SendBufferSize, "Decrypt"); + { + byte[] decryptedBuffer = BufferManager.TakeBuffer(SendBufferSize, "Decrypt"); - Array.Copy(headerToCopy.Array, headerToCopy.Offset, decryptedBuffer, 0, headerToCopy.Count); - Array.Copy(dataToDecrypt.Array, dataToDecrypt.Offset, decryptedBuffer, headerToCopy.Count, dataToDecrypt.Count); + Array.Copy(headerToCopy.Array, headerToCopy.Offset, decryptedBuffer, 0, headerToCopy.Count); + Array.Copy(dataToDecrypt.Array, dataToDecrypt.Offset, decryptedBuffer, headerToCopy.Count, dataToDecrypt.Count); - return new ArraySegment(decryptedBuffer, 0, dataToDecrypt.Count+headerToCopy.Count); - } + return new ArraySegment(decryptedBuffer, 0, dataToDecrypt.Count + headerToCopy.Count); + } case SecurityPolicies.Basic256: case SecurityPolicies.Basic256Sha256: - { - return Rsa_Decrypt(dataToDecrypt, headerToCopy, receiverCertificate, true); - } + { + return Rsa_Decrypt(dataToDecrypt, headerToCopy, receiverCertificate, true); + } case SecurityPolicies.Basic128Rsa15: - { - return Rsa_Decrypt(dataToDecrypt, headerToCopy, receiverCertificate, false); - } + { + return Rsa_Decrypt(dataToDecrypt, headerToCopy, receiverCertificate, false); + } } } -#endregion + #endregion -#region Private Fields + #region Private Fields private EndpointDescriptionCollection m_endpoints; private MessageSecurityMode m_securityMode; private string m_securityPolicyUri; private bool m_discoveryOnly; private EndpointDescription m_selectedEndpoint; - private X509Certificate2 m_serverCertificate; + private X509Certificate2 m_serverCertificate; private X509Certificate2 m_clientCertificate; private bool m_uninitialized; -#endregion + #endregion } } diff --git a/Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.Rsa.cs b/Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.Rsa.cs index cecb7c73d1..b62e7d6424 100644 --- a/Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.Rsa.cs +++ b/Stack/Opc.Ua.Core/Stack/Tcp/UaSCBinaryChannel.Rsa.cs @@ -23,57 +23,6 @@ namespace Opc.Ua.Bindings /// public partial class UaSCUaBinaryChannel { - /// - /// Return the plaintext block size for RSA OAEP encryption. - /// - protected static int Rsa_GetPlainTextBlockSize(X509Certificate2 encryptingCertificate, bool useOaep) - { - using (RSA rsa = encryptingCertificate.GetRSAPublicKey()) - { - if (rsa != null) - { - if (useOaep) - { - return rsa.KeySize / 8 - 42; - } - else - { - return rsa.KeySize / 8 - 11; - } - } - } - return -1; - } - - /// - /// Return the ciphertext block size for RSA OAEP encryption. - /// - protected static int Rsa_GetCipherTextBlockSize(X509Certificate2 encryptingCertificate, bool useOaep) - { - using (RSA rsa = encryptingCertificate.GetRSAPublicKey()) - { - if (rsa != null) - { - return rsa.KeySize / 8; - } - } - return -1; - } - - /// - /// Returns the length of a RSA PKCS#1 v1.5 signature. - /// - private static int RsaPkcs15_GetSignatureLength(X509Certificate2 signingCertificate) - { - using (RSA rsa = signingCertificate.GetRSAPublicKey()) - { - if (rsa == null) - { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); - } - return rsa.KeySize / 8; - } - } /// /// Creates an RSA PKCS#1 v1.5 signature of a hash algorithm for the stream. @@ -84,16 +33,14 @@ namespace Opc.Ua.Bindings HashAlgorithmName algorithm) { // extract the private key. - using (RSA rsa = signingCertificate.GetRSAPrivateKey()) + RSA rsa = signingCertificate.GetRSAPrivateKey(); + if (rsa == null) { - if (rsa == null) - { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); - } - - // create the signature. - return rsa.SignData(dataToSign.Array, dataToSign.Offset, dataToSign.Count, algorithm, RSASignaturePadding.Pkcs1); + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); } + + // create the signature. + return rsa.SignData(dataToSign.Array, dataToSign.Offset, dataToSign.Count, algorithm, RSASignaturePadding.Pkcs1); } @@ -102,35 +49,32 @@ namespace Opc.Ua.Bindings /// private static bool RsaPkcs15_Verify( ArraySegment dataToVerify, - byte[] signature, - X509Certificate2 signingCertificate, + byte[] signature, + X509Certificate2 signingCertificate, HashAlgorithmName algorithm) { // extract the public key. - using (RSA rsa = signingCertificate.GetRSAPublicKey()) + RSA rsa = signingCertificate.GetRSAPublicKey(); + if (rsa == null) { + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); + } - if (rsa == null) - { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); - } + // verify signature. + if (!rsa.VerifyData(dataToVerify.Array, dataToVerify.Offset, dataToVerify.Count, signature, algorithm, RSASignaturePadding.Pkcs1)) + { + string messageType = new UTF8Encoding().GetString(dataToVerify.Array, dataToVerify.Offset, 4); + int messageLength = BitConverter.ToInt32(dataToVerify.Array, dataToVerify.Offset + 4); + string actualSignature = Utils.ToHexString(signature); - // verify signature. - if (!rsa.VerifyData(dataToVerify.Array, dataToVerify.Offset, dataToVerify.Count, signature, algorithm, RSASignaturePadding.Pkcs1)) - { - string messageType = new UTF8Encoding().GetString(dataToVerify.Array, dataToVerify.Offset, 4); - int messageLength = BitConverter.ToInt32(dataToVerify.Array, dataToVerify.Offset + 4); - string actualSignature = Utils.ToHexString(signature); + Utils.Trace( + "Could not validate signature.\r\nCertificate={0}, MessageType={1}, Length={2}\r\nActualSignature={3}", + signingCertificate.Subject, + messageType, + messageLength, + actualSignature); - Utils.Trace( - "Could not validate signature.\r\nCertificate={0}, MessageType={1}, Length={2}\r\nActualSignature={3}", - signingCertificate.Subject, - messageType, - messageLength, - actualSignature); - - return false; - } + return false; } return true; } @@ -141,56 +85,54 @@ namespace Opc.Ua.Bindings private ArraySegment Rsa_Encrypt( ArraySegment dataToEncrypt, ArraySegment headerToCopy, - X509Certificate2 encryptingCertificate, - bool useOaep) + X509Certificate2 encryptingCertificate, + bool useOaep) { // get the encrypting key. - using (RSA rsa = encryptingCertificate.GetRSAPublicKey()) + RSA rsa = encryptingCertificate.GetRSAPublicKey(); + if (rsa == null) { - if (rsa == null) + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); + } + + int inputBlockSize = RsaUtils.GetPlainTextBlockSize(rsa, useOaep); + int outputBlockSize = RsaUtils.GetCipherTextBlockSize(rsa, useOaep); + + // verify the input data is the correct block size. + if (dataToEncrypt.Count % inputBlockSize != 0) + { + Utils.Trace("Message is not an integral multiple of the block size. Length = {0}, BlockSize = {1}.", dataToEncrypt.Count, inputBlockSize); + } + + byte[] encryptedBuffer = BufferManager.TakeBuffer(SendBufferSize, "Rsa_Encrypt"); + Array.Copy(headerToCopy.Array, headerToCopy.Offset, encryptedBuffer, 0, headerToCopy.Count); + + using (MemoryStream ostrm = new MemoryStream( + encryptedBuffer, + headerToCopy.Count, + encryptedBuffer.Length - headerToCopy.Count)) + { + + // encrypt body. + byte[] input = new byte[inputBlockSize]; + + for (int ii = dataToEncrypt.Offset; ii < dataToEncrypt.Offset + dataToEncrypt.Count; ii += inputBlockSize) { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No public key for certificate."); - } - - int inputBlockSize = Rsa_GetPlainTextBlockSize(encryptingCertificate, useOaep); - int outputBlockSize = rsa.KeySize / 8; - - // verify the input data is the correct block size. - if (dataToEncrypt.Count % inputBlockSize != 0) - { - Utils.Trace("Message is not an integral multiple of the block size. Length = {0}, BlockSize = {1}.", dataToEncrypt.Count, inputBlockSize); - } - - byte[] encryptedBuffer = BufferManager.TakeBuffer(SendBufferSize, "Rsa_Encrypt"); - Array.Copy(headerToCopy.Array, headerToCopy.Offset, encryptedBuffer, 0, headerToCopy.Count); - - using (MemoryStream ostrm = new MemoryStream( - encryptedBuffer, - headerToCopy.Count, - encryptedBuffer.Length - headerToCopy.Count)) - { - - // encrypt body. - byte[] input = new byte[inputBlockSize]; - - for (int ii = dataToEncrypt.Offset; ii < dataToEncrypt.Offset + dataToEncrypt.Count; ii += inputBlockSize) + Array.Copy(dataToEncrypt.Array, ii, input, 0, input.Length); + if (useOaep == true) { - Array.Copy(dataToEncrypt.Array, ii, input, 0, input.Length); - if (useOaep == true) - { - byte[] cipherText = rsa.Encrypt(input, RSAEncryptionPadding.OaepSHA1); - ostrm.Write(cipherText, 0, cipherText.Length); - } - else - { - byte[] cipherText = rsa.Encrypt(input, RSAEncryptionPadding.Pkcs1); - ostrm.Write(cipherText, 0, cipherText.Length); - } + byte[] cipherText = rsa.Encrypt(input, RSAEncryptionPadding.OaepSHA1); + ostrm.Write(cipherText, 0, cipherText.Length); + } + else + { + byte[] cipherText = rsa.Encrypt(input, RSAEncryptionPadding.Pkcs1); + ostrm.Write(cipherText, 0, cipherText.Length); } } - // return buffer - return new ArraySegment(encryptedBuffer, 0, (dataToEncrypt.Count / inputBlockSize) * outputBlockSize + headerToCopy.Count); } + // return buffer + return new ArraySegment(encryptedBuffer, 0, (dataToEncrypt.Count / inputBlockSize) * outputBlockSize + headerToCopy.Count); } /// @@ -199,58 +141,55 @@ namespace Opc.Ua.Bindings private ArraySegment Rsa_Decrypt( ArraySegment dataToDecrypt, ArraySegment headerToCopy, - X509Certificate2 encryptingCertificate, - bool useOaep) + X509Certificate2 encryptingCertificate, + bool useOaep) { // get the encrypting key. - using (RSA rsa = encryptingCertificate.GetRSAPrivateKey()) + RSA rsa = encryptingCertificate.GetRSAPrivateKey(); + if (rsa == null) + { + throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); + } + + int inputBlockSize = RsaUtils.GetCipherTextBlockSize(rsa, useOaep); + int outputBlockSize = RsaUtils.GetPlainTextBlockSize(rsa, useOaep); + + // verify the input data is the correct block size. + if (dataToDecrypt.Count % inputBlockSize != 0) + { + Utils.Trace("Message is not an integral multiple of the block size. Length = {0}, BlockSize = {1}.", dataToDecrypt.Count, inputBlockSize); + } + + byte[] decryptedBuffer = BufferManager.TakeBuffer(SendBufferSize, "Rsa_Decrypt"); + Array.Copy(headerToCopy.Array, headerToCopy.Offset, decryptedBuffer, 0, headerToCopy.Count); + + using (MemoryStream ostrm = new MemoryStream( + decryptedBuffer, + headerToCopy.Count, + decryptedBuffer.Length - headerToCopy.Count)) { - if (rsa == null) + // decrypt body. + byte[] input = new byte[inputBlockSize]; + + for (int ii = dataToDecrypt.Offset; ii < dataToDecrypt.Offset + dataToDecrypt.Count; ii += inputBlockSize) { - throw ServiceResultException.Create(StatusCodes.BadSecurityChecksFailed, "No private key for certificate."); - } - - int inputBlockSize = rsa.KeySize / 8; - int outputBlockSize = Rsa_GetPlainTextBlockSize(encryptingCertificate, useOaep); - - // verify the input data is the correct block size. - if (dataToDecrypt.Count % inputBlockSize != 0) - { - Utils.Trace("Message is not an integral multiple of the block size. Length = {0}, BlockSize = {1}.", dataToDecrypt.Count, inputBlockSize); - } - - byte[] decryptedBuffer = BufferManager.TakeBuffer(SendBufferSize, "Rsa_Decrypt"); - Array.Copy(headerToCopy.Array, headerToCopy.Offset, decryptedBuffer, 0, headerToCopy.Count); - - using (MemoryStream ostrm = new MemoryStream( - decryptedBuffer, - headerToCopy.Count, - decryptedBuffer.Length - headerToCopy.Count)) - { - - // decrypt body. - byte[] input = new byte[inputBlockSize]; - - for (int ii = dataToDecrypt.Offset; ii < dataToDecrypt.Offset + dataToDecrypt.Count; ii += inputBlockSize) + Array.Copy(dataToDecrypt.Array, ii, input, 0, input.Length); + if (useOaep == true) { - Array.Copy(dataToDecrypt.Array, ii, input, 0, input.Length); - if (useOaep == true) - { - byte[] plainText = rsa.Decrypt(input, RSAEncryptionPadding.OaepSHA1); - ostrm.Write(plainText, 0, plainText.Length); - } - else - { - byte[] plainText = rsa.Decrypt(input, RSAEncryptionPadding.Pkcs1); - ostrm.Write(plainText, 0, plainText.Length); - } + byte[] plainText = rsa.Decrypt(input, RSAEncryptionPadding.OaepSHA1); + ostrm.Write(plainText, 0, plainText.Length); + } + else + { + byte[] plainText = rsa.Decrypt(input, RSAEncryptionPadding.Pkcs1); + ostrm.Write(plainText, 0, plainText.Length); } } - - // return buffers. - return new ArraySegment(decryptedBuffer, 0, (dataToDecrypt.Count / inputBlockSize) * outputBlockSize + headerToCopy.Count); } + + // return buffers. + return new ArraySegment(decryptedBuffer, 0, (dataToDecrypt.Count / inputBlockSize) * outputBlockSize + headerToCopy.Count); } } }