diff --git a/SampleApplications/Samples/GDS/ClientTest/ClientTest.cs b/SampleApplications/Samples/GDS/ClientTest/ClientTest.cs
index 783d23e562..edc193b92a 100644
--- a/SampleApplications/Samples/GDS/ClientTest/ClientTest.cs
+++ b/SampleApplications/Samples/GDS/ClientTest/ClientTest.cs
@@ -31,13 +31,13 @@ using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Threading;
+using System.Security.Cryptography.X509Certificates;
using NUnit.Framework;
using Opc.Ua;
using Opc.Ua.Gds;
using Opc.Ua.Gds.Client;
using Opc.Ua.Gds.Test;
using Opc.Ua.Test;
-using System.Security.Cryptography.X509Certificates;
namespace NUnit.Opc.Ua.Gds.Test
{
diff --git a/Stack/Opc.Ua.Core/Security/Certificates/CertificateFactory.cs b/Stack/Opc.Ua.Core/Security/Certificates/CertificateFactory.cs
index 289de97480..2b383fa65b 100644
--- a/Stack/Opc.Ua.Core/Security/Certificates/CertificateFactory.cs
+++ b/Stack/Opc.Ua.Core/Security/Certificates/CertificateFactory.cs
@@ -697,7 +697,7 @@ public class CertificateFactory
///
public static X509Certificate2 CreateCertificateWithPEMPrivateKey(
X509Certificate2 certificate,
- byte [] pemDataBlob,
+ byte[] pemDataBlob,
string password = null)
{
AsymmetricKeyParameter privateKey = null;
@@ -727,7 +727,7 @@ public class CertificateFactory
AsymmetricCipherKeyPair keypair = pemObject as AsymmetricCipherKeyPair;
if (keypair != null)
- {
+ {
privateKey = keypair.Private;
break;
}
@@ -791,24 +791,6 @@ public class CertificateFactory
}
}
-
- private class Password
- : IPasswordFinder
- {
- private readonly char[] password;
-
- public Password(
- char[] word)
- {
- this.password = (char[])word.Clone();
- }
-
- public char[] GetPassword()
- {
- return (char[])password.Clone();
- }
- }
-
///
/// Verify the signature of a self signed certificate.
///
@@ -825,7 +807,66 @@ public class CertificateFactory
}
return true;
}
-#endregion
+
+ public static X509KeyUsageFlags GetKeyUsage(X509Certificate2 cert)
+ {
+ X509KeyUsageFlags allFlags = X509KeyUsageFlags.None;
+ foreach (X509KeyUsageExtension ext in cert.Extensions.OfType())
+ {
+ allFlags |= ext.KeyUsages;
+ }
+ return allFlags;
+ }
+
+ ///
+ /// Verify RSA key pair of two certificates.
+ ///
+ public static bool VerifyRSAKeyPair(
+ X509Certificate2 certWithPublicKey,
+ X509Certificate2 certWithPrivateKey,
+ bool throwOnError = false)
+ {
+ bool result = false;
+ try
+ {
+ // verify the public and private key match
+ using (RSA rsaPrivateKey = certWithPrivateKey.GetRSAPrivateKey())
+ {
+ 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.");
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ if (throwOnError)
+ {
+ throw e;
+ }
+ }
+ finally
+ {
+ if (!result && throwOnError)
+ {
+ throw new CryptographicException("The public/private key pair in the certficates do not match.");
+ }
+ }
+ return result;
+ }
+ #endregion
#region Private Methods
///
@@ -962,10 +1003,10 @@ public class CertificateFactory
///
///
private static List CreateSubjectAlternateNameDomains(IList domainNames)
- {
+ {
// subject alternate name
List generalNames = new List();
- for (int i = 0; i
private static async Task FindIssuerCABySerialNumberAsync(
- ICertificateStore store,
- string issuer,
+ ICertificateStore store,
+ string issuer,
string serialnumber)
{
X509Certificate2Collection certificates = await store.Enumerate();
@@ -1185,50 +1226,52 @@ public class CertificateFactory
return string.Empty;
}
- ///
- /// Verify RSA key pair of two certificates.
- ///
- private static bool VerifyRSAKeyPair(
- X509Certificate2 certWithPublicKey,
- X509Certificate2 certWithPrivateKey,
- bool throwOnError = false)
+
+ private static bool VerifyRSAKeyPairCrypt(
+ RSA rsaPublicKey,
+ RSA rsaPrivateKey)
{
- bool result = false;
- try
+ Opc.Ua.Test.RandomSource randomSource = new Opc.Ua.Test.RandomSource();
+ int blockSize = RsaUtils.GetPlainTextBlockSize(rsaPrivateKey, true);
+ byte[] testBlock = new byte[blockSize];
+ randomSource.NextBytes(testBlock, 0, blockSize);
+ byte[] encryptedBlock = rsaPublicKey.Encrypt(testBlock, RSAEncryptionPadding.OaepSHA1);
+ byte[] decryptedBlock = rsaPrivateKey.Decrypt(encryptedBlock, RSAEncryptionPadding.OaepSHA1);
+ if (decryptedBlock != null)
{
- // verify the public and private key match
- using (RSA rsaPrivateKey = certWithPrivateKey.GetRSAPrivateKey())
- {
- using (RSA rsaPublicKey = certWithPublicKey.GetRSAPublicKey())
- {
- Opc.Ua.Test.RandomSource randomSource = new Opc.Ua.Test.RandomSource();
- int blockSize = RsaUtils.GetPlainTextBlockSize(rsaPrivateKey, true);
- byte[] testBlock = new byte[blockSize];
- randomSource.NextBytes(testBlock, 0, blockSize);
- byte[] encryptedBlock = rsaPublicKey.Encrypt(testBlock, RSAEncryptionPadding.OaepSHA1);
- byte[] decryptedBlock = rsaPrivateKey.Decrypt(encryptedBlock, RSAEncryptionPadding.OaepSHA1);
- if (decryptedBlock != null)
- {
- result = Utils.IsEqual(testBlock, decryptedBlock);
- }
- }
- }
+ return Utils.IsEqual(testBlock, decryptedBlock);
}
- catch (Exception e)
+ return false;
+ }
+
+ private static bool VerifyRSAKeyPairSign(
+ RSA rsaPublicKey,
+ RSA rsaPrivateKey)
+ {
+ Opc.Ua.Test.RandomSource randomSource = new Opc.Ua.Test.RandomSource();
+ int blockSize = RsaUtils.GetPlainTextBlockSize(rsaPrivateKey, true);
+ byte[] testBlock = new byte[blockSize];
+ randomSource.NextBytes(testBlock, 0, blockSize);
+ byte[] signature = rsaPrivateKey.SignData(testBlock, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
+ return rsaPublicKey.VerifyData(testBlock, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pss);
+ }
+
+
+ private class Password
+ : IPasswordFinder
+ {
+ private readonly char[] password;
+
+ public Password(
+ char[] word)
{
- if (throwOnError)
- {
- throw e;
- }
+ this.password = (char[])word.Clone();
}
- finally
- {
- if (!result && throwOnError)
- {
- throw new CryptographicException("The public/private key pair in the certficates do not match.");
- }
+
+ public char[] GetPassword()
+ {
+ return (char[])password.Clone();
}
- return result;
}
#endregion
diff --git a/Stack/Opc.Ua.Core/Security/Certificates/DirectoryCertificateStore.cs b/Stack/Opc.Ua.Core/Security/Certificates/DirectoryCertificateStore.cs
index 499da901a4..ee4bdc05c7 100644
--- a/Stack/Opc.Ua.Core/Security/Certificates/DirectoryCertificateStore.cs
+++ b/Stack/Opc.Ua.Core/Security/Certificates/DirectoryCertificateStore.cs
@@ -310,7 +310,6 @@ namespace Opc.Ua
filePath.Append(fileRoot);
FileInfo privateKeyFile = new FileInfo(filePath.ToString() + ".pfx");
- RSA rsa = null;
password = password ?? String.Empty;
try
{
@@ -318,7 +317,10 @@ namespace Opc.Ua
privateKeyFile.FullName,
password,
X509KeyStorageFlags.Exportable | X509KeyStorageFlags.UserKeySet);
- rsa = certificate.GetRSAPrivateKey();
+ if (CertificateFactory.VerifyRSAKeyPair(certificate, certificate, true))
+ {
+ return certificate;
+ }
}
catch (Exception)
{
@@ -326,17 +328,8 @@ namespace Opc.Ua
privateKeyFile.FullName,
password,
X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);
- rsa = certificate.GetRSAPrivateKey();
- }
- if (rsa != null)
- {
- int inputBlockSize = RsaUtils.GetPlainTextBlockSize(rsa, true);
- byte[] bytes1 = rsa.Encrypt(new byte[inputBlockSize], RSAEncryptionPadding.OaepSHA1);
- byte[] bytes2 = rsa.Decrypt(bytes1, RSAEncryptionPadding.OaepSHA1);
- rsa.Dispose();
- if (bytes2 != null)
+ if (CertificateFactory.VerifyRSAKeyPair(certificate, certificate, true))
{
- // Utils.Trace(1, "RSA: {0}", certificate.Thumbprint);
return certificate;
}
}