remove all dispose from RSA objects to work around mono bug

This commit is contained in:
Martin Regen
2017-12-21 15:41:46 +01:00
parent 2e4d719a19
commit 032bc6ade7
5 changed files with 433 additions and 535 deletions
@@ -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
/// </summary>
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));
}
/// <summary>
@@ -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;
}
/// <summary>
@@ -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);
@@ -28,10 +28,8 @@ namespace Opc.Ua
/// </summary>
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);
}
/// <summary>
@@ -58,30 +56,20 @@ namespace Opc.Ua
/// </summary>
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);
}
/// <summary>
/// Returns the length of a RSA PKCS#1 v1.5 signature of a digest.
/// Return the ciphertext block size for RSA OAEP encryption.
/// </summary>
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;
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -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<byte> cipherText = Encrypt(new ArraySegment<byte>(plainText), encryptingCertificate, useOaep, new ArraySegment<byte>(buffer));
ArraySegment<byte> cipherText = Encrypt(new ArraySegment<byte>(plainText), rsa, useOaep, new ArraySegment<byte>(buffer));
System.Diagnostics.Debug.Assert(cipherText.Count == buffer.Length);
return buffer;
@@ -206,61 +188,51 @@ namespace Opc.Ua
/// </summary>
public static ArraySegment<byte> Encrypt(
ArraySegment<byte> dataToEncrypt,
X509Certificate2 encryptingCertificate,
RSA rsa,
bool useOaep,
ArraySegment<byte> 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<byte>(
encryptedBuffer,
outputBuffer.Offset,
(dataToEncrypt.Count / inputBlockSize) * outputBlockSize);
}
// return buffer
return new ArraySegment<byte>(
encryptedBuffer,
outputBuffer.Offset,
(dataToEncrypt.Count / inputBlockSize) * outputBlockSize);
}
/// <summary>
@@ -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<byte> plainText = Decrypt(dataToDecrypt, encryptingCertificate, useOaep, new ArraySegment<byte>(buffer));
ArraySegment<byte> plainText = Decrypt(dataToDecrypt, rsa, useOaep, new ArraySegment<byte>(buffer));
System.Diagnostics.Debug.Assert(plainText.Count == buffer.Length);
// decode length.
@@ -297,57 +275,48 @@ namespace Opc.Ua
/// </summary>
public static ArraySegment<byte> Decrypt(
ArraySegment<byte> dataToDecrypt,
X509Certificate2 encryptingCertificate,
RSA rsa,
bool useOaep,
ArraySegment<byte> 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<byte>(decryptedBuffer, outputBuffer.Offset, (dataToDecrypt.Count / inputBlockSize) * outputBlockSize);
}
// return buffers.
return new ArraySegment<byte>(decryptedBuffer, outputBuffer.Offset, (dataToDecrypt.Count / inputBlockSize) * outputBlockSize);
}
#endregion
}
@@ -29,8 +29,8 @@ namespace Opc.Ua.Bindings
/// </summary>
public EndpointDescription EndpointDescription
{
get
{
get
{
lock (DataLock)
{
return m_selectedEndpoint;
@@ -55,7 +55,7 @@ namespace Opc.Ua.Bindings
{
get { return m_serverCertificate; }
}
/// <summary>
/// The security mode used with the channel.
/// </summary>
@@ -63,7 +63,7 @@ namespace Opc.Ua.Bindings
{
get { return m_securityMode; }
}
/// <summary>
/// The security policy used with the channel.
/// </summary>
@@ -71,24 +71,24 @@ namespace Opc.Ua.Bindings
{
get { return m_securityPolicyUri; }
}
/// <summary>
/// Whether the channel is restricted to discovery operations.
/// </summary>
protected bool DiscoveryOnly
{
get
{
return m_discoveryOnly;
get
{
return m_discoveryOnly;
}
}
/// <summary>
/// The certificate for the client.
/// </summary>
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;
}
/// <summary>
/// Compares two certificates.
/// </summary>
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
/// <summary>
/// Returns the length of the symmetric encryption key.
/// </summary>
@@ -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.
/// </summary>
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;
}
/// <summary>
/// Calculates the size of the footer with an asymmetric signature.
/// </summary>
@@ -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.
/// </summary>
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.
/// </summary>
protected BufferCollection WriteAsymmetricMessage(
uint messageType,
uint requestId,
X509Certificate2 senderCertificate,
X509Certificate2 receiverCertificate,
uint messageType,
uint requestId,
X509Certificate2 senderCertificate,
X509Certificate2 receiverCertificate,
ArraySegment<byte> 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<byte> header = new ArraySegment<byte>(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<byte>(buffer, 0, encoder.Position), senderCertificate);
if (signature != null)
{
encoder.WriteRawBytes(signature, 0, signature.Length);
}
int messageSize = encoder.Close();
// encrypt the data.
ArraySegment<byte> encryptedBuffer = Encrypt(
new ArraySegment<byte>(buffer, headerSize, messageSize-headerSize),
header,
new ArraySegment<byte>(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
/// </summary>
[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
/// </summary>
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.");
}
}
/// <summary>
/// Sets to endpoint according to the endpoint url.
/// </summary>
@@ -780,15 +780,15 @@ namespace Opc.Ua.Bindings
/// Processes an OpenSecureChannel request message.
/// </summary>
protected ArraySegment<byte> ReadAsymmetricMessage(
ArraySegment<byte> buffer,
X509Certificate2 receiverCertificate,
out uint channelId,
ArraySegment<byte> 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<byte>(buffer.Array, buffer.Offset + headerSize, buffer.Count - headerSize),
new ArraySegment<byte>(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<byte> dataToVerify = new ArraySegment<byte>(plainText.Array, plainText.Offset, plainText.Count-signatureSize);
ArraySegment<byte> dataToVerify = new ArraySegment<byte>(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<byte>(
plainText.Array,
plainText.Offset + headerSize,
plainText.Array,
plainText.Offset + headerSize,
plainText.Count - headerSize - signatureSize - paddingCount);
}
@@ -950,26 +950,26 @@ namespace Opc.Ua.Bindings
/// </remarks>
protected byte[] Sign(
ArraySegment<byte> 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
/// </remarks>
protected bool Verify(
ArraySegment<byte> 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<byte> Encrypt(
ArraySegment<byte> dataToEncrypt,
ArraySegment<byte> 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<byte>(encryptedBuffer, 0, dataToEncrypt.Count+headerToCopy.Count);
}
return new ArraySegment<byte>(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<byte> Decrypt(
ArraySegment<byte> dataToDecrypt,
ArraySegment<byte> 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<byte>(decryptedBuffer, 0, dataToDecrypt.Count+headerToCopy.Count);
}
return new ArraySegment<byte>(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
}
}
@@ -23,57 +23,6 @@ namespace Opc.Ua.Bindings
/// </summary>
public partial class UaSCUaBinaryChannel
{
/// <summary>
/// Return the plaintext block size for RSA OAEP encryption.
/// </summary>
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;
}
/// <summary>
/// Return the ciphertext block size for RSA OAEP encryption.
/// </summary>
protected static int Rsa_GetCipherTextBlockSize(X509Certificate2 encryptingCertificate, bool useOaep)
{
using (RSA rsa = encryptingCertificate.GetRSAPublicKey())
{
if (rsa != null)
{
return rsa.KeySize / 8;
}
}
return -1;
}
/// <summary>
/// Returns the length of a RSA PKCS#1 v1.5 signature.
/// </summary>
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;
}
}
/// <summary>
/// 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
/// </summary>
private static bool RsaPkcs15_Verify(
ArraySegment<byte> 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<byte> Rsa_Encrypt(
ArraySegment<byte> dataToEncrypt,
ArraySegment<byte> 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<byte>(encryptedBuffer, 0, (dataToEncrypt.Count / inputBlockSize) * outputBlockSize + headerToCopy.Count);
}
// return buffer
return new ArraySegment<byte>(encryptedBuffer, 0, (dataToEncrypt.Count / inputBlockSize) * outputBlockSize + headerToCopy.Count);
}
/// <summary>
@@ -199,58 +141,55 @@ namespace Opc.Ua.Bindings
private ArraySegment<byte> Rsa_Decrypt(
ArraySegment<byte> dataToDecrypt,
ArraySegment<byte> 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<byte>(decryptedBuffer, 0, (dataToDecrypt.Count / inputBlockSize) * outputBlockSize + headerToCopy.Count);
}
// return buffers.
return new ArraySegment<byte>(decryptedBuffer, 0, (dataToDecrypt.Count / inputBlockSize) * outputBlockSize + headerToCopy.Count);
}
}
}