I am loading a certificate from string like this:
public static void Test()
{
byte[] arrayCertificate;
arrayCertificate = Convert.FromBase64String("CERT_STRING");
X509Certificate2 clientCertificateFromXml = new X509Certificate2(arrayCertificate);
Console.Write(clientCertificateFromXml);
Console.ReadKey();
}
But this certificate doesn't have a "Subject Unique Identifier"
Take a look at this:
http://en.wikipedia.org/wiki/X.509 (The part of Structure of a certificate)
And I want to know how can I read that value from my .NET code (I looked that I can get SerialNumber, Thumbprints and others but there is no Subject UID anywhere).
Also, I will really appreciate If anyone can share an openssl command to include this UID for the certificate :-) (pfx one)
And I want to know how can I read that value from my .NET code
IIRC this is not exposed in the .NET BCL, either from X509Certificate or the newer (better but still incomplete) X509Certificate2.
But you can use Mono.Security assembly (or just the code you want from it), from the Mono project. It's open source, MIT.X11 licensed and it includes it's own X509Certificate.
This version expose just about everything in X.509 certificates, including a SubjectUniqueIdentifier property.
I will really appreciate If anyone can share an openssl command to include this UID for the certificate
I do not recall for openssl... but you can use the X509CertificateBuilder from Mono.Security to create your own certificates. See Mono's makecert tool source code for an example.
Disclaimer: I wrote the code :-)
Related
Here is my code.
X509Certificate pXCert = new X509Certificate2(#"keyStore.p12", "password");
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)pXCert.PrivateKey;
string id = CryptoConfig.MapNameToOID("SHA256");
return csp.SignData(File.ReadAllBytes(filePath), id);
On the last line I'm getting the exception:
System.Security.Cryptography.CryptographicException "Invalid algorithm specified."
What am I doing wrong?
UPDATE:
id = 2.16.840.1.101.3.4.2.1
For dot net framework 4.7.0 or higher is not taking the sha1 so configure the below in application start. it's worked fine for me.
AppContext.SetSwitch("Switch.System.Security.Cryptography.Xml.UseInsecureHashAlgorithms", true);
AppContext.SetSwitch("Switch.System.Security.Cryptography.Pkcs.UseInsecureHashAlgorithms", true);
There is no issue with .NET code or the CSP code you provided.
Your problem is that CSP just doesn’t support SHA 256. You can get further information here
You might have come here while you are migrating your application from .NET Framework 4.7 and earlier versions to 4.7.1 or later versions.
If you are getting the exception System.Security.Cryptography.CryptographicException: Invalid algorithm specified., the reason is that default SignedXML and SignedXMS algorithms changed to SHA256 for applications that target the .NET Framework 4.7.1 and later versions (from Microsoft .NET migration guide)
In that guide you'll also find the solution:
For applications that target the .NET Framework 4.7.1 and later versions, if the use of SHA256 is undesirable, you can restore the default to SHA1 by adding the following configuration switch to the runtime section of your app config file:
<AppContextSwitchOverrides value="Switch.System.Security.Cryptography.Xml.UseInsecureHashAlgorithms=true;
Switch.System.Security.Cryptography.Pkcs.UseInsecureHashAlgorithms=true" />
But this may not always work, especially for web applications, as you can read in this blog post, fortunately along with the answer as well. It is only necessary to add some lines in the Application_Start
protected void Application_Start(object sender, EventArgs e)
{
[...]
AppContext.SetSwitch("Switch.System.Security.Cryptography.Xml.UseInsecureHashAlgorithms", true);
AppContext.SetSwitch("Switch.System.Security.Cryptography.Pkcs.UseInsecureHashAlgorithms", true);
}
Note that I use SHA512 but SHA256 will work with the below examples:
"Invalid algorithm specified" Took me forever to figure out and I tried practically everything.
Step 1 - the certificate has to be SHA512 and use a CSP (Cryptographic Service Provider) that is SHA512 Capable. Here is a list of CSPs and their capabilities. If you look for SHA512 you'll find the "Microsoft Enhanced RSA and AES Cryptographic Provider". By default generating certificates don't use this (at least in Windows) so you have to specify it when you create the certificate.
If you create the certificate with openssl, you can use the option -CSP below to set the correct CSP that will make it work. If you have an existing pfx, you can convert it to a PEM file with openssl, and then back to a pfx to add the option.
Create private key and certificate - this step will ask you questions, state, region etc etc.
openssl req -x509 -nodes -sha512 -newkey rsa:2048 -keyout 512key.pem -out 512cert.pem -days 3650
Create PFX file to import into your certificate store using the Microsoft Enhanced RSA and AES Cryptographic Provider:
openssl pkcs12 –export –in 512cert.pem –inkey 512key.pem –CSP “Microsoft Enhanced RSA and AES Cryptographic Provider” –out 512pfx.pfx
Step 2 : Props to Gonzalo Gallotti for posting the link to the piece of code that helped me. I commented up my code to show what each step is doing. NOTE: this code won't work without a properly generated certificate as described in step 1
public void GetCertificate() {
// Get the Machine Cert Store
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
string alg = CryptoConfig.MapNameToOID("SHA512");
// Open the cert store
store.Open(OpenFlags.ReadWrite);
// Loop through each certificate within the store
foreach (X509Certificate2 myCert in store.Certificates)
{
// Get the certificate we are looking for
if (myCert.IssuerName.Name.Contains("CN=YourSite"))
{
// Check if the certificate has a private key
if (myCert.HasPrivateKey)
{
// Get your custom signature as a string
string mySignature = GetSignatureString();
// Convert signature to byte array
byte[] originalData = Encoding.UTF8.GetBytes(mySignature);
// Create RSA provider from private key
RSACryptoServiceProvider rsaProvider = (RSACryptoServiceProvider)myCert.PrivateKey;
// Sign the signature with SHA512
byte[] signedSignature = signedSignature = rsaProvider.SignData(originalData, alg);
if (rsaProvider.VerifyData(originalData, alg, signedSignature))
{
// Signature is verified Do Stuff
}
else
{
throw new Exception("The data does not match the signature.");
}
}
}
}
}
Which CSP your certificate is using can be checked with certutil tool (on windows)
certutil yourCertificate.p12
Examples:
Microsoft Enhanced Cryptographic Provider v1.0 => throws error with C# 4.7 and above
Microsoft Enhanced RSA and AES Cryptographic Provider => works
Having a similar issue but just resolved it. If you are not using X509 but just the plain RSACryptoServiceProvider to get the keys, then only SHA1 is supported.
You can set the AppContext switches in a web config via appSettings:
<appSettings>
<add key="AppContext.SetSwitch:Switch.System.Security.Cryptography.Xml.UseInsecureHashAlgorithms" value="true" />
<add key="AppContext.SetSwitch:Switch.System.Security.Cryptography.Pkcs.UseInsecureHashAlgorithms" value="true" />
</appSettings>
I fixed the issue by upgrading my dependencies.
Instead of relying on the GAC version I was previously using for years, I switched to the latest NuGet packages (v16.8.0) of:
Microsoft.Build.Tasks.Core
Microsoft.Build.Utilities.Core
Microsoft.Build.Framework
This fixed this issue for us.
I need to decode the encryptedToken with private key file .p12..
For private key, I already assign in X509Certificate2 and calling with
RSA privateKey = _x509private.GetRSAPrivateKey();
I am not using
RSACryptoServiceProvider privateKey = _x509private.PublicKey.Key as RSACryptoServiceProvider;
because that function is already deprecated.
But when I want to use this function to decode the encryptedToken
string plainToken = Jose.JWT.Decode(encryptedToken, privateKey);
What I expected as output is token that I will verify token with public key. But, Unfortunately I get the error message of
Algorithm 'AesGcm' is not supported on this platform.
I was thinking the error message was arise because I didn't use RSACryptoServiceProvider as Private key.
I already search how to convert RSA to RSACryptoServiceProvider, but can't find anything...
I also considering not using the Jose.JWT.Decode(), but no luck...
Is there anyone that can help me?
PS: I am using .NET6 and Visual Studio Mac 2019 V.8
As bartonjs said in this comment, it only affects macOS.
.NET on macOS can’t use Apple’s AES-GCM implementation and requires OpenSSL to be installed to provide the algorithm. How to use .Net Core with Openssl3 on Mac OS? may help.
I'm currently trying to create a chat based on the SslStream class.
I was going through that msdn link: click here
I realized that I need to get an X509Certificate to establish that task. But I really don't know how can I get one? I know that there are ones who cost money, but there aren't free ones available?
P.S: I'm coming here after doing some search in google about that subject but haven't found any helpfull infomation.
So my question is: Where can I get an x509 certificate?
Thank you.
You can create certificates with the makecert tool.
Or, if your're only interested in encrypting the traffic, without signing it, and you control the client and the server, just use a CryptoStream.
You can generate your own, and sign it yourself, using openssl, though keep in mind if the client tries to verify it, and by client I usually mean the browser, since this is their most common use, though not the only one, they won't be able to.
I know that there are ones who cost money, but there aren't free ones available?
Basically what you are paying for is for a CA, certificate authority to sign it, as such when clients go and verify who you are with with CA it'll pass.
openssl: http://www.openssl.org/
This is the command I ussually use openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.pem
server.pem is your certificate and server.key is your private key.
Giving that you probably already have .NET SDK installed maybe makecert is a better/eassier approach since you would need to build openssl.
Stil I went to their docs and I couldn't find how to set the key size, though apparently the default is 1028 and I think using RSA , but I did find this:
makecert -pe -ss MY -$ individual -n "CN=your name here" -len 2048 -r
from MakeCert - Is it possible to change the key size? to http://www.mazecomputer.com/sxs/help/shared.htm
openssl supports many types not just RSA but maybe you don't need them.
These guys http://www.cacert.org/ have been giving away free certificates for years.
Read through this for clarity. You can sign your public key using Symantec's Verisign service. It is definitely not cheap. For testing, you can make your own certificate using a dummy CA.
Here is my code.
X509Certificate pXCert = new X509Certificate2(#"keyStore.p12", "password");
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)pXCert.PrivateKey;
string id = CryptoConfig.MapNameToOID("SHA256");
return csp.SignData(File.ReadAllBytes(filePath), id);
On the last line I'm getting the exception:
System.Security.Cryptography.CryptographicException "Invalid algorithm specified."
What am I doing wrong?
UPDATE:
id = 2.16.840.1.101.3.4.2.1
For dot net framework 4.7.0 or higher is not taking the sha1 so configure the below in application start. it's worked fine for me.
AppContext.SetSwitch("Switch.System.Security.Cryptography.Xml.UseInsecureHashAlgorithms", true);
AppContext.SetSwitch("Switch.System.Security.Cryptography.Pkcs.UseInsecureHashAlgorithms", true);
There is no issue with .NET code or the CSP code you provided.
Your problem is that CSP just doesn’t support SHA 256. You can get further information here
You might have come here while you are migrating your application from .NET Framework 4.7 and earlier versions to 4.7.1 or later versions.
If you are getting the exception System.Security.Cryptography.CryptographicException: Invalid algorithm specified., the reason is that default SignedXML and SignedXMS algorithms changed to SHA256 for applications that target the .NET Framework 4.7.1 and later versions (from Microsoft .NET migration guide)
In that guide you'll also find the solution:
For applications that target the .NET Framework 4.7.1 and later versions, if the use of SHA256 is undesirable, you can restore the default to SHA1 by adding the following configuration switch to the runtime section of your app config file:
<AppContextSwitchOverrides value="Switch.System.Security.Cryptography.Xml.UseInsecureHashAlgorithms=true;
Switch.System.Security.Cryptography.Pkcs.UseInsecureHashAlgorithms=true" />
But this may not always work, especially for web applications, as you can read in this blog post, fortunately along with the answer as well. It is only necessary to add some lines in the Application_Start
protected void Application_Start(object sender, EventArgs e)
{
[...]
AppContext.SetSwitch("Switch.System.Security.Cryptography.Xml.UseInsecureHashAlgorithms", true);
AppContext.SetSwitch("Switch.System.Security.Cryptography.Pkcs.UseInsecureHashAlgorithms", true);
}
Note that I use SHA512 but SHA256 will work with the below examples:
"Invalid algorithm specified" Took me forever to figure out and I tried practically everything.
Step 1 - the certificate has to be SHA512 and use a CSP (Cryptographic Service Provider) that is SHA512 Capable. Here is a list of CSPs and their capabilities. If you look for SHA512 you'll find the "Microsoft Enhanced RSA and AES Cryptographic Provider". By default generating certificates don't use this (at least in Windows) so you have to specify it when you create the certificate.
If you create the certificate with openssl, you can use the option -CSP below to set the correct CSP that will make it work. If you have an existing pfx, you can convert it to a PEM file with openssl, and then back to a pfx to add the option.
Create private key and certificate - this step will ask you questions, state, region etc etc.
openssl req -x509 -nodes -sha512 -newkey rsa:2048 -keyout 512key.pem -out 512cert.pem -days 3650
Create PFX file to import into your certificate store using the Microsoft Enhanced RSA and AES Cryptographic Provider:
openssl pkcs12 –export –in 512cert.pem –inkey 512key.pem –CSP “Microsoft Enhanced RSA and AES Cryptographic Provider” –out 512pfx.pfx
Step 2 : Props to Gonzalo Gallotti for posting the link to the piece of code that helped me. I commented up my code to show what each step is doing. NOTE: this code won't work without a properly generated certificate as described in step 1
public void GetCertificate() {
// Get the Machine Cert Store
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
string alg = CryptoConfig.MapNameToOID("SHA512");
// Open the cert store
store.Open(OpenFlags.ReadWrite);
// Loop through each certificate within the store
foreach (X509Certificate2 myCert in store.Certificates)
{
// Get the certificate we are looking for
if (myCert.IssuerName.Name.Contains("CN=YourSite"))
{
// Check if the certificate has a private key
if (myCert.HasPrivateKey)
{
// Get your custom signature as a string
string mySignature = GetSignatureString();
// Convert signature to byte array
byte[] originalData = Encoding.UTF8.GetBytes(mySignature);
// Create RSA provider from private key
RSACryptoServiceProvider rsaProvider = (RSACryptoServiceProvider)myCert.PrivateKey;
// Sign the signature with SHA512
byte[] signedSignature = signedSignature = rsaProvider.SignData(originalData, alg);
if (rsaProvider.VerifyData(originalData, alg, signedSignature))
{
// Signature is verified Do Stuff
}
else
{
throw new Exception("The data does not match the signature.");
}
}
}
}
}
Which CSP your certificate is using can be checked with certutil tool (on windows)
certutil yourCertificate.p12
Examples:
Microsoft Enhanced Cryptographic Provider v1.0 => throws error with C# 4.7 and above
Microsoft Enhanced RSA and AES Cryptographic Provider => works
Having a similar issue but just resolved it. If you are not using X509 but just the plain RSACryptoServiceProvider to get the keys, then only SHA1 is supported.
You can set the AppContext switches in a web config via appSettings:
<appSettings>
<add key="AppContext.SetSwitch:Switch.System.Security.Cryptography.Xml.UseInsecureHashAlgorithms" value="true" />
<add key="AppContext.SetSwitch:Switch.System.Security.Cryptography.Pkcs.UseInsecureHashAlgorithms" value="true" />
</appSettings>
I fixed the issue by upgrading my dependencies.
Instead of relying on the GAC version I was previously using for years, I switched to the latest NuGet packages (v16.8.0) of:
Microsoft.Build.Tasks.Core
Microsoft.Build.Utilities.Core
Microsoft.Build.Framework
This fixed this issue for us.
I believe I have a foundational understanding of the X509Certificate and have created certificates and private keys for my Development environment. Getting more acquainted now with the X509Certificate Class and other relevant permissions also.
So in the process, I decided to test a certificate after having installed it on my system. Then using the following code, I attempted to validate the check process for certification authentication:
const string x509Cert = #"\PathToMyCertificate\LMC.cer";
var cert = new X509Certificate(x509Cert);
var pmc = new PublisherMembershipCondition(cert);
if(pmc.Check(Assembly.GetCallingAssembly().Evidence))
{
Console.WriteLine("Assembly belongs to publisher");
}
Of course as expected, the inner block of code doesn't execute. So then I figured to simply sign my assembly using the certificate key, but "simply" wasn't as simple as I'd anticipated.
I used the following code in effort of assigning the certificate to my applications Evidence:
var publisher = new Publisher(X509Certificate.CreateFromCertFile(x509Cert));
var evidence = Assembly.GetCallingAssembly().Evidence;
evidence.AddHost(publisher);
// Create an identity permission based on publisher evidence.
var x509Permission = (PublisherIdentityPermission)publisher.CreateIdentityPermission(evidence);
x509Permission.Demand();
But this didn't seem to work either. Next, I checked the properties of my project to see if there was any way to sign it there using the X509Certificate key but nothing. The only option I see that comes close is to sign with Click Once manifests; but the "Select from file" option is looking for a .pfx extension. So I think maybe this method only works to support certificates generated by Click-Once?
Per BOL, "If you have a key file or certificate in another format, store it in the Windows certificate store and select the certificate is described in the previous procedure." I installed my X509Certificate in the Trusted Root Certificate Authorities store. Wouldn't that be a Windows certificate store? Because nothing shows up in the Certificate Store window.
Searching online resources didn't yield much either unless I am using the wrong combination of keywords. Now I could create another X509Certificate and key ensuring that the extension of the key is .pfx but I wanted to make certain that I am on the right course of resolve before spinning my wheels for nothing and I don't believe that would be the answer.
So, can a .NET assembly be signed using an X509Certificate? If so, what documentation is available to assist in performing this task?
Publisher* classes are associated with Authenticode(tm).
Look for the command-line tools:
* signcode (or signtool)
* chktrust
for how you can sign any .exe, .dll (and .cab, .ocx) using a valid code-signing certificate. A google search on Authenticode or "code-signing certificate" can also be helpful.
The question is what you want to do. There exist .NET signing (using RSA keypair) used for strong-naming the assemblies, and there exists Authenticode which lets you sign any file in PE format including assemblies in DLL files. Note, that Authenticode is not .NET-specific and knows nothing about .NET. It signs PE structure.
As said by poupou, for Authenticode signing (using X.509 certificates suitable for Code Signing) you can use SignTool.exe tool. .NET will verify the signature when it loads the assembly, but in some cases such verification can take extra seconds (if the OS performs CRL and OCSP checking of certificates in the chain), slowing down assembly loading.
So you need to choose the right tool and define what you want to achieve (signing is a method, not a goal).