Я пытаюсь создать сертификат, используя dll BouncyCastle.Crypto, который затем используется для аутентификации SslStream в качестве сервера в процессе службы Windows, который выполняется под учетной записью локальной системы.
Однако, когда я получаю вызов SslStream.AuthenticateAsServer (сертификат), он генерирует исключение Win32 с сообщением об ошибке «Учетные данные, предоставленные для пакета, не были распознаны».
Здесь есть несколько вопросов об этом сообщении об ошибке, но, похоже, ни один из них не описывает и не решает мою конкретную проблему.
В надежде, что кто-то сможет предложить некоторую помощь, я включил код, который я использую для создания и установки сертификата:
// First create a certificate using the BouncyCastle classes
BigInteger serialNumber = BigInteger.ProbablePrime(120, new Random());
AsymmetricCipherKeyPair keyPair = GenerateKeyPair();
X509V1CertificateGenerator generator = new X509V1CertificateGenerator();
generator.SetSerialNumber(serialNumber);
generator.SetIssuerDN(new X509Name("CN=My Issuer"));
generator.SetNotBefore(DateTime.Today);
generator.SetNotAfter(DateTime.Today.AddYears(100));
generator.SetSubjectDN(new X509Name("CN=My Issuer"));
generator.SetPublicKey(keyPair.Public);
generator.SetSignatureAlgorithm("SHA1WITHRSA");
Org.BouncyCastle.X509.X509Certificate cert = generator.Generate(
keyPair.Private, SecureRandom.GetInstance("SHA1PRNG"));
// Ok, now we have a BouncyCastle certificate, we need to convert it to the
// System.Security.Cryptography class, by writing it out to disk and reloading
X509Certificate2 dotNetCert;
string tempStorePassword = "Password01"; // In real life I'd use a random password
FileInfo tempStoreFile = new FileInfo(Path.GetTempFileName());
try
{
Pkcs12Store newStore = new Pkcs12Store();
X509CertificateEntry entry = new X509CertificateEntry(cert);
newStore.SetCertificateEntry(Environment.MachineName, entry);
newStore.SetKeyEntry(
Environment.MachineName,
new AsymmetricKeyEntry(keyPair.Private),
new [] { entry });
using (FileStream s = tempStoreFile.Create())
{
newStore.Save(s,
tempStorePassword.ToCharArray(),
new SecureRandom(new CryptoApiRandomGenerator()));
}
// Reload the certificate from disk
dotNetCert = new X509Certificate2(tempStoreFile.FullName, tempStorePassword);
}
finally
{
tempStoreFile.Delete();
}
// Now install it into the required certificate stores
X509Store targetStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
targetStore.Open(OpenFlags.ReadWrite);
targetStore.Add(dotNetCert);
targetStore.Close();
Хорошо, теперь я создал и установил сертификат. Затем я настраиваю свою службу Windows для использования этого сертификата, предоставляя ему отпечаток сформированного сертификата. Затем я использую сертификат следующим образом:
// First load the certificate
X509Certificate2 certificate = null;
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
foreach (X509Certificate2 certInStore in store.Certificates)
{
if (certInStore.Thumbprint == "...value not shown...")
{
certificate = certInStore;
break;
}
}
SslStream sslStream = new SslStream(new NetworkStream(socket, false), false);
// Now this line throws a Win32Exception
// "The credentials supplied to the package were not recognized"
sslStream.AuthenticateAsServer(certificate);
Кто-нибудь знает, в чем может быть проблема?
У меня не возникает проблемы, если я устанавливаю сертификат, созданный с помощью 'makecert', но он не подходит для производственных сертификатов.
Я также пытался создать отдельный сертификат CA x509v1, а затем сертификат x509v3 для проверки подлинности сервера, но я получаю ту же ошибку, поэтому я удалил ее в примере кода для простоты.