i have 1x X509Certificate2 with a Publickey (x509certificate_1)
Now i created a new X509Certificate2 and try to Verify it.
Org.BouncyCastle.X509.X509Certificate x509certificate_11 = DotNetUtilities.FromX509Certificate(x509certificate_1);
Org.BouncyCastle.X509.X509Certificate x509certificate_22 = DotNetUtilities.FromX509Certificate(x509certificate_2);
x509certificate_22.Verify(x509certificate_11.GetPublicKey());
ERROR: Public key presented not for certificate signature
Can somebody explain me, how to verify my x509certificate_2 to x509certificate_1?
Related
I have taken a certificate:
X509Certificate2 x509 = store.Certificates.Find(X509FindType.FindBySubjectName, "CNGTestCert", false)[0];
and now I want to get the providertype parameter. But I cant do x509.PrivateKey.
In result of this I used var key = x509.GetRSAPrivateKey();. How can I get out of this key the ProviderType to decide the KeyNumber (looks like here: referencesource.microsoft.com). Or is there a easier way to test the private key for key function (key was created for signature or exchange)?
I found a way to check CNG certificate for exchangeable. If I read the private key of certificate by var privateKey = (cngCert.GetRSAPrivateKey() as RSACng).Key;, did I get the KeyUsage. The "KeyAgreement" flag marks the certificate for usage of secret agreement generation and key exchange.
var privateKey = (cngCert.GetRSAPrivateKey() as RSACng).Key;
if(privateKey.KeyUsage.HasFlag(CngKeyUsages.KeyAgreement))
{
//is for KeyExchange
}
How to sign a string with x509 cert private key using RS256 Algorithm in c#?
I'm using the following code but it showing "Value was invalid." for the prKey1.SignData() method.
X509Certificate2 cert = new X509Certificate2();
cert.Import(certFileServerPath, certPassword, X509KeyStorageFlags.Exportable);
RSACryptoServiceProvider prKey = (RSACryptoServiceProvider)cert.PrivateKey;
RSACryptoServiceProvider prKey1 = new RSACryptoServiceProvider();
prKey1 .ImportParameters(prKey.ExportParameters(true));
byte[] data = Encoding.UTF8.GetBytes(inputData);
byte[] signature = prKey1.SignData(data, "SHA256withRSA");
output = Convert.ToBase64String(signature);
Hope to get some help on this.
Thank you
I'm setting up a server under my own root CA to generate SSL certificates on the fly under .NET Core.
I'm able to generate self-signed certificates using the CertificateRequest class. However, these certs obviously aren't trusted by clients with my own root CA. I'm using the CertificateRequest.CreateSelfSigned() method to do this. I cannot use my root CA to sign these new certs, however. Using the CertificateRequest.Create() method will generate my new cert, but it will not provide a private key.
public static X509Certificate2 CreateSelfSignedCertificate(string domain)
{
SubjectAlternativeNameBuilder sanBuilder = new SubjectAlternativeNameBuilder();
sanBuilder.AddDnsName(domain);
X500DistinguishedName distinguishedName = new X500DistinguishedName($"CN=On-The-Fly Generated Cert");
using (RSA rsa = RSA.Create(2048))
{
var request = new CertificateRequest(distinguishedName, rsa, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
request.CertificateExtensions.Add(
new X509KeyUsageExtension(X509KeyUsageFlags.DataEncipherment | X509KeyUsageFlags.KeyEncipherment | X509KeyUsageFlags.DigitalSignature, false));
request.CertificateExtensions.Add(
new X509EnhancedKeyUsageExtension(
new OidCollection { new Oid("1.3.6.1.5.5.7.3.1") }, false));
request.CertificateExtensions.Add(sanBuilder.Build());
var ca = new X509Certificate2(File.ReadAllBytes(#"E:\testing_ca_certificate.pfx"), "password"); //Open my root CA cert, generated in OpenSSL
//Generates a cert, but does not provide a private key.
var certificate = request.Create(ca, new DateTimeOffset(DateTime.UtcNow.AddDays(-1)), new DateTimeOffset(DateTime.UtcNow.AddDays(365)), new byte[] { 0, 1, 2, 3 });
//Generates a usable cert, but is not under my root CA
//var certificate = request.CreateSelfSigned(new DateTimeOffset(DateTime.UtcNow.AddDays(-1)), new DateTimeOffset(DateTime.UtcNow.AddDays(365)));
return new X509Certificate2(certificate.Export(X509ContentType.Pfx, "password"), "password", X509KeyStorageFlags.DefaultKeySet);
}
}
Using the CertificateRequest.Create() method, I get a valid cert without a private key. I should have this private key so I can encrypt SSL traffic.
Using the CertificateRequest.Create() method, I get a valid cert without a private key.
Real certificate authorities should not have the private key of the CA and the private key matching the certificate to be created in the same place at the same time. Aside from the fact that there is currently no way to decode a Certification Request (CSR), this method assumes it's being used with a public-only key provided to the CertificateRequest constructor.
Following the flow, the "expected" model is:
Client determines the need for a new certificate
Client generates public/private keypair
Client sends public key and other necessary information to CA (PKCS#10 CertificationRequest, or other means)
CA validates request
CA builds up the CertificateRequest object using the client public key
CA produces a certfificate with CertificateRequest.Create()
CA sends the certificate back to the client (cert.RawData)
Client instantiates X509Certificate2 instance (only has public key)
Client uses the CopyWithPrivateKey (extension) method to associate the private key to a new certificate object.
Client does whatever client wants now.
So, after
//Generates a cert, but does not provide a private key.
var certificate = request.Create(ca, new DateTimeOffset(DateTime.UtcNow.AddDays(-1)), new DateTimeOffset(DateTime.UtcNow.AddDays(365)), new byte[] { 0, 1, 2, 3 });
you should add
certificate = certificate.CopyWithPrivateKey(rsa);
(Though, really, you should have your certificate objects in using statements so they get disposed when no longer needed, in which case you'd need a second variable to hold the cert-with-key)
Given the certificate request was created using your rsa instance, you should be able to export the private key from it. RSA.ToXmlString() allows for exporting the key to a format that later that can be later imported using RSA.FromXmlString().
I was trying to get keypair for pkcs-7 signature an X509Certificate2 object from this code.
RSACryptoServiceProvider key = (RSACryptoServiceProvider)Cert.PrivateKey;
RSAParameters rsaparam = key.ExportParameters(true);
AsymmetricCipherKeyPair keypair = DotNetUtilities.GetRsaKeyPair(rsaparam);
This works fine if X509Certificate2 object is created using .pfx file like this
X509Certificate2 cert = new X509Certificate2(".pfx file path", "password");
it works fine.
but when the certificate is listed from certificate store like this
X509Certificate2 cert;
X509Store UserCertificateStore = new X509Store("My");
UserCertificateStore.Open(OpenFlags.ReadOnly);
var certificates = UserCertificateStore.Certificates;
foreach (var certificate in certificates)
{
if (certificate.Thumbprint==thumbprint)
{
cert=certificate;
break;
}
}
it throws an exception with the message - Key not valid for use in specified state.
after #Crypt32 answer tried using RSA method sign hash
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert.PrivateKey;
using (SHA256Managed sHA256 = new SHA256Managed())
{
byte[] hash = sHA256.ComputeHash(data);
return csp.SignHash(hash, CryptoConfig.MapNameToOID("SHA256"));
}
but the signature was not in PKCS#7 format
This is because BouncyCastle attempts to get raw key material (literally, export) from .NET object while actual key is not marked as exportable. In Windows systems, keys are stored in cryptographic service providers which control all key operations. When you need to perform a specific cryptographic operation, you are asking CSP to do a job and it does without having to expose key material to you. If the key was imported/generated in CSP as exportable, you can ask CSP to export key material. If this flag was not set, CSP won't give you the key.
I don't know how BouncyCastle works, but if it expects raw key material, then you need exportable private key in your certificate.
To answer the underlying question, "How do I make a PKCS#7 SignedData message signed with RSA+SHA-2-256?"
https://github.com/Microsoft/dotnet/blob/master/releases/net471/dotnet471-changes.md#bcl says that SHA-2-256 not only works in 4.7.1, but it's the default now:
Updated SignedXML and SignedCMS to use SHA256 as a default over SHA1. SHA1 may still be used by selected as a default by enabling a context switch. [397307, System.Security.dll, Bug]
On older frameworks it's possible via:
ContentInfo content = new ContentInfo(data);
SignedCms cms = new SignedCms(content);
CmsSigner signer = new CmsSigner(cert);
signer.DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1");
cms.ComputeSignature(signer);
return cms.Encode();
Where "2.16.840.1.101.3.4.2.1" is OID-ese for SHA-2-256.
This question already has an answer here:
Closed 11 years ago.
Possible Duplicate:
Generated signed X.509 client certificate is invalid (no certificate chain to its CA)
I followed the example at:
http://www.bouncycastle.org/wiki/display/JA1/X.509+Public+Key+Certificate+and+Certification+Request+Generation
But the resulting signed client certificate has the following error when opened in windows:
"This file is invalid for use as the following: Security Certificate"
If I install it anyway and view it with certmgr, the certification path looks OK - I see my self-signed Certificate Authority (which is fine, no problems there) but the client cert has the following status:
"This certificate has an invalid digital signature."
If I call X509Certificate.Verify() it throws the following exception:
"Public key presented not for certificate signature"
Yet I'm using the same exact public key extracted from the Pkcs10CertificationRequest and when I called Verify() on that it's fine.
Any ideas? After days of struggling through this, I've got all the pieces working except this last one - and what's really confusing is that my self-signed CA cert is fine. There's just something going on with the client cert. Here's the entire block of code:
TextReader textReader = new StreamReader("certificaterequest.pkcs10");
PemReader pemReader = new PemReader(textReader);
Pkcs10CertificationRequest certificationRequest = (Pkcs10CertificationRequest)pemReader.ReadObject();
CertificationRequestInfo certificationRequestInfo = certificationRequest.GetCertificationRequestInfo();
SubjectPublicKeyInfo publicKeyInfo = certificationRequestInfo.SubjectPublicKeyInfo;
RsaPublicKeyStructure publicKeyStructure = RsaPublicKeyStructure.GetInstance(publicKeyInfo.GetPublicKey());
RsaKeyParameters publicKey = new RsaKeyParameters(false, publicKeyStructure.Modulus, publicKeyStructure.PublicExponent);
bool certIsOK = certificationRequest.Verify(publicKey);
// public key is OK here...
// get the server certificate
Org.BouncyCastle.X509.X509Certificate serverCertificate = DotNetUtilities.FromX509Certificate(System.Security.Cryptography.X509Certificates.X509Certificate.CreateFromCertFile("servermastercertificate.cer"));
// get the server private key
byte[] privateKeyBytes = File.ReadAllBytes("serverprivate.key");
AsymmetricKeyParameter serverPrivateKey = PrivateKeyFactory.CreateKey(privateKeyBytes);
// generate the client certificate
X509V3CertificateGenerator generator = new X509V3CertificateGenerator();
generator.SetSerialNumber(BigInteger.ProbablePrime(120, new Random()));
generator.SetIssuerDN(serverCertificate.SubjectDN);
generator.SetNotBefore(DateTime.Now);
generator.SetNotAfter(DateTime.Now.AddYears(5));
generator.SetSubjectDN(certificationRequestInfo.Subject);
generator.SetPublicKey(publicKey);
generator.SetSignatureAlgorithm("SHA512withRSA");
generator.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(serverCertificate));
generator.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure(publicKey));
var newClientCert = generator.Generate(serverPrivateKey);
newClientCert.Verify(publicKey); // <-- this blows up
return DotNetUtilities.ToX509Certificate(newClientCert).Export(X509ContentType.Pkcs12, "user password");
I figured this out. If you call X509Certificate.Verify(publicKey) you have to pass the CA's public key, not the client's public key from the Pkcs10CertificationRequest.