“The credentials supplied to the package were not

2020-02-03 05:35发布

问题:

I'm trying to create a certificate using the BouncyCastle.Crypto dll, which is then used to authenticate a SslStream as the server in a Windows Service process, which runs under the Local System account.

However when I get to the SslStream.AuthenticateAsServer(certificate) call, it throws a Win32 exception with the error message "The credentials supplied to the package were not recognized".

There are several questions on here about this error message, but none of them seem to describe, or solve, my particular problem.

In the hope that someone may be able to offer some help, I include the code I am using to create and install the certificate:

// 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();

Ok, now I have created and installed the certificate. I then configure my Windows Service to use this certificate by supplying it with the generated certificate's thumbprint. I then use the certificate like this:

// 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);

Does anyone have any idea what the problem could be here?

I don't get the problem if I install a certificate created with 'makecert', but that isn't suitable for production certificates.

I've also tried creating a separate x509v1 CA certificate and then x509v3 certificate for server authentication, but I get the same error, so I removed this in the example code for simplicity.

回答1:

That particular error message rings a bell. I'll guess that either you did not store the private key with the certificate, or, the Windows service does not have access to the private key. To check this, open the Certificates MMC snap-in:

  1. Run mmc (e.g. from the Start menu)
  2. File menu > Add/Remove Snap-in
  3. Select "Certificates" in left pane and then click Add
  4. Select "Computer Account" (for LocalMachine) then click Next, and then Finish

Navigate to the certificate and double-click in the right pane. On the General tab that comes up, you should see a little key icon at the bottom, along with the text, "You have a private key that corresponds to this certificate." If not, that's the problem. The private key was not saved.

If the private key is present, click Ok to dismiss this dialog, and then right-click on the certificate in the right pane and select on the pop-up menu: All Tasks > Manage Private Keys. In that dialog, make sure that the Windows account that the service runs under has read access to the private key. If it doesn't, that's the problem.

Edit: Oops, you wrote that the service runs as Local System, so it must be a missing private key, if it is one of these two problems. I'll leave the key access check in my answer anyway, for anybody else that hits this and is not running as Local System.



回答2:

Sometime the problem happens when the application try to reach the certificate doesn't have enough privilege to access the certificate, the issue may resolve by running the application as administrator.



回答3:

Found this solution online but I can't find the source to give the credit.

Since I ran into the "The credentials supplied to the package were not recognized" problem with AuthenticateAsClient() (for client verification), I'd like to document how I solved it. It's a different method with the same end goal. Since it might be useful for AuthenticateAsServer(), figured why not.

Here I convert a BC Certificate to a .NET certificate. Add an extra step in converting it to a .NET X509Certificate2 to store it's PrivateKey property.

Org.BouncyCastle.X509.X509Certificate bcCert;

X509Certificate dotNetCert = DotNetUtilities.ToX509Certificate(bcCert);
X509Certificate2 dotNetCert2 = new X509Certificate2(dotNetCert);

Problem showed up when adding a BouncyCastle private key to a .NET private key. The X509 certificates converted fine but not the private keys. I converted the BC private key to RSACryptoServiceProvider using the provided DotNetUtilities. Unfortunately it looks like the conversion isn't complete. So I created another RSACryptoServiceProvider which I then initialized. Then I imported the private key into the one I created.

// Apparently, using DotNetUtilities to convert the private key is a little iffy. Have to do some init up front.
RSACryptoServiceProvider tempRcsp = (RSACryptoServiceProvider)DotNetUtilities.ToRSA((RsaPrivateCrtKeyParameters)ackp.Private);
RSACryptoServiceProvider rcsp = new RSACryptoServiceProvider(new CspParameters(1, "Microsoft Strong Cryptographic Provider", 
            new Guid().ToString(), 
            new CryptoKeySecurity(), null));

rcsp.ImportCspBlob(tempRcsp.ExportCspBlob(true));
dotNetCert2.PrivateKey = rcsp;

After that, I was able to save the X509Certificate2 object directly to the key store. I didn't need the actual file so I skipped that step.



回答4:

I've the same issue, tried everything from many posts, and google researching. But looks like I found fix. When I changed Identify from ApplicationPoolIdentity to LocalSystem everything start working perfectly.

May be will be helpful for someone.



回答5:

For me works on Windows Server 2012 R2 (.net 4.6.1) - "All Tasks > Manage Private Keys" and set access to Everyone (setting to IS_IUSRS was not enough)



回答6:

Previously, every time I have run into this issue, I have had to delete the cert out of my local machine cert store and re-import it. Then it all seems happy. I can't see how it could be a global permissions issue or invalid cert if simply re-importing it fixes the issue.

How I finally fixed it was using the winhttpcertcfg tool from the Windows Resource Kit to grant permission to the specific user that was using the cert.

The syntax would be:

"C:\Program Files (x86)\Windows Resource Kits\Tools\winhttpcertcfg" -i cert.p12 -c LOCAL_MACHINE\My -a UserWhoUsesTheCert -p passwordforp12


回答7:

I had the similar issue when calling a WCF REST service from .NET application where I need to attach the client certificate; All I had to do was provide access to the certificate in cert store[mmc console] to the "NETWORKSERVICE] off course my IIS Pool was default pool which indicates its using NETWORKService user account.

the mistake that I did was, I copied the cert from another store to Local Machine -> Personnel store where the certificate was protected with password. should import the certificate explicitly in required store.



回答8:

I don't recall this error but the certificate you're creating is not a valid to be used for SSL/TLS, including:

  • v1 (not v3) certificate;
  • missing extensions;
  • invalid CN;
  • ...

There are several RFC that talks about this, including RFC5246 on TLS (1.2).

Finally making your own certificates is not more suitable than using the ones made by makecert (but the last one can generate the minimum set to be usable for an SSL/TLS server certificate).

I strongly suggest you to buy, from a good known Certificate Authority (CA), a SSL/TLS certificate for production. That will get you a working certificate recognized by the most browsers and tools.