macOS: cannot verify public/private key with crypto op when keyUsage doesn't allow dataencipherment

This commit is contained in:
Martin Regen
2017-11-16 15:14:41 +01:00
parent e156a3c3da
commit 5de112d59b
3 changed files with 112 additions and 76 deletions
@@ -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
{
@@ -697,7 +697,7 @@ public class CertificateFactory
/// </summary>
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();
}
}
/// <summary>
/// Verify the signature of a self signed certificate.
/// </summary>
@@ -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<X509KeyUsageExtension>())
{
allFlags |= ext.KeyUsages;
}
return allFlags;
}
/// <summary>
/// Verify RSA key pair of two certificates.
/// </summary>
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
/// <summary>
@@ -962,10 +1003,10 @@ public class CertificateFactory
///
/// </summary>
private static List<GeneralName> CreateSubjectAlternateNameDomains(IList<String> domainNames)
{
{
// subject alternate name
List<GeneralName> generalNames = new List<GeneralName>();
for (int i = 0; i<domainNames.Count; i++)
for (int i = 0; i < domainNames.Count; i++)
{
int domainType = GeneralName.OtherName;
switch (Uri.CheckHostName(domainNames[i]))
@@ -1103,8 +1144,8 @@ public class CertificateFactory
/// Get the certificate by issuer and serial number.
/// </summary>
private static async Task<X509Certificate2> 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;
}
/// <summary>
/// Verify RSA key pair of two certificates.
/// </summary>
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
@@ -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;
}
}