C# X509Certificate2.PrivateKey threw exception "invalid provider type specified." - ssl-certificate

I have a trusted CA issued SSL certificate installed on Windows Server 2019. When the following code in ASP.NET MVC controller was run, it did retrieve the X509Certificate2, its HasProviateKey property was true. But when its PrivateKey property was accessed, it threw a CryptographicException: "invalid provider type specified."
X509Certificate2 certificate = null;
X509Store userCaStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
userCaStore.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certificatesInStore = userCaStore.Certificates;
X509Certificate2Collection findResult = certificatesInStore.Find(X509FindType.FindByThumbprint, "xyz...", true);
if (findResult.Count != 1)
throw new Exception("Certificate not found.");
certificate = findResult[0];
userCaStore.Close();
The reason I need to access the private key, was that the server needs to accept some long-lasting TCP socket connections, and I plan to use the SSL certificate's public/private key to do the typical handshake: the client generates a random AES key, and uses the public key to encrypt this AES key and sends it to the server. That is why I need to access the private key on the server side to decrypt the AES key.
How do I do it?

I figured it out, partly. It has to do with the type of cryptography of the SSL certificate. I tried the same code to retrieve another trusted CA issued certificate and the PrivateKey property did present itself as RsaCryptoServiceProvider. The other thing that must be done is to right-click the certificate in the certificate store (mmc.exe) and select "All tasks | Manage private keys", and make sure the identity used by your code is there in a ACL.

Related

How gRPC's NewClientTLSFromCert generates TLS credentials from public key?

The google.golang.org/grpc/credentials library has the following method.
// NewClientTLSFromCert constructs TLS credentials from the provided root
// certificate authority certificate(s) to validate server connections. If
// certificates to establish the identity of the client need to be included in
// the credentials (eg: for mTLS), use NewTLS instead, where a complete
// tls.Config can be specified.
// serverNameOverride is for testing only. If set to a non empty string,
// it will override the virtual host name of authority (e.g. :authority header
// field) in requests.
func NewClientTLSFromCert(cp *x509.CertPool, serverNameOverride string) TransportCredentials {
return NewTLS(&tls.Config{ServerName: serverNameOverride, RootCAs: cp})
}
I am confused about how it can generate TLS credentials from a public key (the certificate here).
How will this work? If I generate credentials from a public cert, why would it be accepted on the server side whose TLS cert has been signed with the private key of the TLS CA?
What exactly happens here and how is the connection secured over here?
Transport "credentials" in gRPC are fully responsible for the handshake with the client/server. That means they include configuration other than just "credentials" like private keys and other secrets. For TLS here, it includes the root trust certificates to use when verifying the server's certificate. You can think of it as just "TLS configuration."

WinRm - Cannot create a WinRM listener on HTTPS due to incorrect SSL certificate

I want to use WinRM with https transport. I've bought a Comodo certificate (the error states I cannot use a self-signed certificate) with the Subject matching my FQDN (Full computer name in System) of my Windows 10 computer (not domain joined):
CN = my.domain.net
OU = PositiveSSL
OU = Domain Control Validated
When trying to create a https listener with the following command:
WinRm quickconfig -transport:https
I get the error message:
Error number: -2144108267 0x80338115
Cannot create a WinRM listener on HTTPS because this machine does not have an appropriate certificate. To be used for SSL, a certificate must have a CN matching the hostname, be appropriate for Server Authentication, and not be expired, revoked, or self-signed.
I've installed (doubleclick the *.crt file) the certificate in several stores (local machine / personal and Trusted Root Certification Authorities) but WinRM fails to create the https listener. The http listener is working OK.
Some extra info: When using certreq to try to install the *.cer certificate, I get the error:
Element not found. 0x80070490 (WIN32: 1168 ERROR_NOT_FOUND)
How do I get WinRM working with https?
Here is how I solved this issue:
create a SSL CSR using DigiCert Certificate Utility for Windows from digicert.com
use the generate CSR to request a certificate. I used versio.nl but I'll guess there are a lot of CA's out there
Install the certificate by double clicking it
go to the certificate manager for user
rightclick the certificate (it should me in the personal store) and export it
- follow the wizard and be sure to export the private key
install the newly exported certificate (mark the key as exportable and include all extended properties) in the local computer certificate store
Open an console (cmd) with administrator privilidges and type:
winrm create winrm/config/Listener?Address=*+Transport=HTTPS 
#{Hostname="server.fqdn";CertificateThumbprint="YOURCERTIFICATETHUMPPRINT"}
This worked for me. Some things to check if it is not working:
is the certificate still valid (check the date range)
check if the certificate property 'Subject" has a CN value with the FQDN of your computer
check if the listener is installed (winrm e winrm/config/listener)
I took me a lot of hours to figure this out. I hope it will help some of you out there.
I also experienced this issue - the answer from RHAD was partially helpful, but I needed to use an entirely internally generated CA.
The problem was caused by the Key algorithm I had chosen. Using the same configuration, only changing the key it works:
Failed key: elliptic curve cryptography with the brainpoolP512t1 curve (in the certificate this showed as: Public Key Algorithm: id-ecPublicKey / ASN1 OID: brainpoolP512t1 )
Successful key: an RSA key: (in the certificate: RSA Public-Key: (4096 bit))
Hopefully this helps others with similar issues.

Self Signed Certificate: Can I trust the client being indeed the owner of the public key?

I am playing around with OpenSSL, and in my server code I have the following:
rc = SSL_get_verify_result(ssl);
printf("SSL_get_verify_result(): %i\n", rc);
cert = SSL_get_peer_certificate(ssl);
printf("SSL_get_peer_certificate(): %p\n", cert);
pkey = X509_get_pubkey(cert);
printf("X509_get_pubkey(): %p\n", pkey);
SSL_get_verify_result() returns X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN which is expected.
My question is, can I trust that the client is actually the owner of the pub key that I get using X509_get_pubkey() after SSL_get_verify_result() has failed with the above error.
In other words, can I perform authentication using this public key (assuming my server somehow has knowledge of this public key).
Thanks!
You can trust that the peer owns the private key of the certificate he supplies, because he also supplies a digital signature which is checked by SSL using the public key in the certificate. Only the owner of the private key can do that.
Whether you trust that the peer owns the identity expressed in the subject DN comes down to whether you trust the issuer, which in the case of a self-signed certificate is himself.
And whether that identity is authorised to communicate with your application is yet another question, which only your application can answer.

WCF client certificare not valid

I try to send a message to MSMQ using WCF. I want to use Transport security and sign messages. However, when I set clientcertificate credentials and try to send message, an error is being thrown: "An error occurred while sending to the queue: The user certificate is invalid. (-1072824276, 0xc00e002c)". Certificate is stored in LocalMachine\My location and has read only access set for ASPNET process.
Here are two common reasons a certificate is considered "invalid":
You don't have the private key associated with the certificate. If you don't have the private key, you need to re-install the cert with the private key, or get a new cert for which you do have the private key.
The certificate is issued by a certificate authority that is not trusted by your computer. If this is the problem, you need to install the issuing authority's certificate into your "Trusted Root Certificate Authority" store (there are security risks involved with doing this so make sure you read the pop-up warning that will come up when trying to do this).
View the certificate in the CertMgr.msc to see if its one of these issues. (Start > Run > CertMgr.msc > Personal > Certificates).

SSL error RemoteCertificateNameMismatch

I am using WCF for the client to access service. I am trying to access the endpoint with TLS (https). I have certificates with both private and public keys.
If I have the end point of the service to have the host name same as the certificate name ("Issued To"), then i am able to access the service from the client.
If the names of the "issued to" and end point domain name are different i get the error "Could not establish trust relationship for the SSL/TLS secure channel with authority". I have added the certificates to "Trusted Root", "Personal" and "trusted People". In my service i have used "PeerOrChainTrust".
Please let me know if anybody has any idea on this.
Thanks,
Jan
In that case, you need to define the trust policy for the server on client side,
Call SetCertPolicy once before you make any call to the services.
using System.Net;
using System.Security.Cryptography.X509Certificates;
public static void SetCertPolicy()
{
ServicePointManager.ServerCertificateValidationCallback += RemoteCertValidate;
}
private static bool RemoteCertValidate( object sender, X509Certificate cert, X509Chain chain,
SslPolicyErrors error )
{
// trust any cert!!!
return true;
}
I don't think you can override the check on whether the certificate name matches the server name.
Some agents allow you to manually override after the warnings, but unless WCF has a setting to disable certificate validation with all the dangers that brings. SSL is designed first and foremost for the client to be able to validate which server it is talking to, otherwise you will be open to all sorts of vulnerabilities (including man-in-the-middle and fake servers).