Loading a self-signed P12 cert file in C# - c#

Working with certs is all still new to me.
I am trying to load a p12 cert file (I think is is called a self signed cert) for use with a channel factory. This is a C# program in VS2010 and a WFC service reference. Below are the methods I have tried and the errors I am receiving. The last bit of code is VB.net code, which runs without error. I think this indicates that the path and password to the p12 file are correct.
//Create the binding and channel
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
binding.Security.Message.NegotiateServiceCredential = false;
binding.Security.Message.EstablishSecurityContext = false;
EndpointAddress serviceAddress = new EndpointAddress("http://myendpoint");
ChannelFactory<ServiceName> channelFactory = null;
channelFactory = new ChannelFactory<ServiceName>(binding, serviceAddress);
//try to add the cert - Error: Object reference not set to an instance of the object. I've tried all available X509KeyStorageFlags
channelFactory.Credentials.ClientCertificate.Certificate.Import(#c:\path\to\file\fw.mycert.com.p12", "password", X509KeyStorageFlags.PersistKeySet);
//try to add the cert - Error: The specified network password is not correct. I've tried all available X509KeyStorageFlags
//rawCertificateData does contain 2000+ bytes
X509Certificate2 certificate = new X509Certificate2();
byte[] rawCertificateData = File.ReadAllBytes(#"c:\path\to\file\fw.mycert.com.p12");
channelFactory.Credentials.ClientCertificate.Certificate.Import(rawCertificateData, "password", X509KeyStorageFlags.DefaultKeySet);
//This works in vb.net with the same path and password
Dim cert As New X509Certificate2("c:\path\to\file\fw.mycert.com.p12", "password")
request.ClientCertificates.Add(cert)

Related

How to use client certificate for HTTPs requests in UWP app

I'm writing an app that needs to make some HTTPs requests that use a client certificate. However, I can't find any documents on how to install the certificate and then load it for use. I know that you can use the certificate by making a HttpBaseProtocolFilter and adding a certificate but how do you load the certificate for use here? And if you have a .pfx file with your client certificate, how do you install it with your package?
Thanks in advance!
For what it's worth, I ended up figuring this out using a mix of the Portable.BouncyCastle NuGet package and some UWP APIs. Some sample (pseudo-ish) code for what I did is below:
// Asymmetric key pair
RsaKeyPairGenerator keyPairGenerator = new RsaKeyPairGenerator();
keyPairGenerator.Init(
new KeyGenerationParameters(
new SecureRandom(new CryptoApiRandomGenerator()), 2048));
AsymmetricCipherKeyPair keyPair = keyPairGenerator.GenerateKeyPair();
// Create certificate
X509V3CertificateGenerator generator = new X509V3CertificateGenerator();
generator.SetSubjectDN("foo");
generator.SetIssuerDN("foo");
generator.SetSerialNumber(new BigInteger("12345").Abs());
generator.SetNotBefore(DateTime.UtcNow);
generator.SetNotAfter(DateTime.UtcNow + TimeSpan.FromYears(1));
generator.SetPublicKey(keyPair.Public);
BouncyCastleX509Certificate certificate =
generator.Generate(
new Asn1SignatureFactory("SHA1WithRSA", keyPair.Private));
// Create PKCS12 certificate bytes.
Pkcs12Store store = new Pkcs12Store();
X509CertificateEntry certificateEntry = new X509CertificateEntry(certificate);
string friendlyName = "Friendly Name";
string password = "password";
store.SetCertificateEntry(friendlyName, certificateEntry);
store.SetKeyEntry(
friendlyName,
new AsymmetricKeyEntry(keyPair.Private),
new X509CertificateEntry[] { certificateEntry });
string pfxData;
using (MemoryStream memoryStream = new MemoryStream(512))
{
store.Save(memoryStream, password.ToCharArray(), this.SecureRandom);
pfxData = CryptographicBuffer.EncodeToBase64String(memoryStream.ToArray().AsBuffer());
}
// Add the certificate to the cert store
await CertificateEnrollmentManager.ImportPfxDataAsync(
pfxData,
password,
ExportOption.NotExportable,
KeyProtectionLevel.NoConsent,
InstallOptions.DeleteExpired,
friendlyName);
// Read the UWP cert from the cert store
Certificate uwpCertificate =
(await CertificateStores.FindAllAsync(
new CertificateQuery { FriendlyName = friendlyName }))[0];
// Create the UWP HTTP client.
HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter();
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName);
filter.ClientCertificate = uwpCertificate;
HttpClient httpClient = new HttpClient(filter);
// Profit!

How to add PFX installed certificate to Windows.Web.Http.HttpClient

i have manually installed pfx extention certificate to my machine . How to get and pass in Windows.Web.Http.HttpClient
i tried following way but no luck
var myFilter = new HttpBaseProtocolFilter();
CertificateQuery certQuery = new Windows.Security.Cryptography.Certificates.CertificateQuery();
certQuery.FriendlyName = "TEST"; // This is the friendly name of the certificate that was just installed.
IReadOnlyList<Certificate> certificates = await Windows.Security.Cryptography.Certificates.CertificateStores.FindAllAsync(certQuery);
var client = new HttpClient(certificates[0]);
Can someone help me on this how to add manually installed certificate in httpclient ?
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certs = store.Certificates.Find(
X509FindType.FindByIssuerName, "TEST", false);
//Change FindType to your liking, it doesn't support FriendlyName,
//maybe use your method?
WebRequestHandler handler = new WebRequestHandler();
X509Certificate2 certificate = GetMyX509Certificate();
handler.ClientCertificates.Add(certificate);
HttpClient client = new HttpClient(handler);
There you have it. Maybe use your certificate for the Add method but I don't know if they're compatible.

How to set X509 SubjectAltName (SAN) using Mono.Security?

Chrome 58 deprecates self-signed certificates that omit the Subject Alternative Name (SAN). I use Mono.Security.X509 X509CertificateBuilder() to create a certificate for a Windows OWIN service on 'localhost' that enables the browser to communicate with a TWAIN scanner. The certificate currently only sets the Common Name so it is insufficient for Chrome 58.
What is the correct way to create a self-signed certificate that enables Chrome to communicate with the OWIN service on localhost, using Mono.Security.X509?
RSA subjectKey = new RSACryptoServiceProvider(2048);
X509CertificateBuilder cb = new X509CertificateBuilder(3);
cb.SerialNumber = GenerateSerialNumber();
cb.IssuerName = "CN=localhost";
cb.NotBefore = notBefore;
cb.NotAfter = notAfter;
cb.SubjectName = "CN=localhost";
cb.SubjectPublicKey = subjectKey;
cb.Hash = "SHA256";
byte[] rawcert = cb.Sign(subjectKey);
PKCS12 p12 = new PKCS12();
p12.Password = password;
Hashtable attributes = GetAttributes();
p12.AddCertificate(new X509Certificate(rawcert), attributes);
p12.AddPkcs8ShroudedKeyBag(subjectKey, attributes);
return p12.GetBytes();
var san = new SubjectAltNameExtension(new string[0], new string[1] { "localhost" }, new string[0], new string[0]);
cb.Extensions.Add(san);
I tested this in Jexus Manager,
https://github.com/jexuswebserver/JexusManager/blob/master/JexusManager.Features.Certificates/SelfCertificateDialog.cs

Generating passbook pass signature file in C#

App is about generating passes (Passbook App in Iphone) through C#.
I have downloaded Pass certificate and AppleWWDRCA certificate.
To generate pass I am able to generate pass.json and manifest.json.
But when I generate a PKCS 7 detached signature file using signing certificates and manifest.json it is not getting recognized by Passbook app in iphone.
I generated detached signature file using openssl in MAC and that is working fine and getting installed in Passbook.
I have downloaded pass certificate and AppleWWDRCA certificate
Can anyone help me in step by step procedure of creating signature file in c# and methods to be used
I have stored both the certificates in local folder not in windows local store. I have tried in windows local store before but it was not working.
below is the method used for signature,
X509Certificate2 card = GetCertificate(); //Fetches the pass certificate
X509Certificate2 appleCA = GetAppleCertificate(); //Fetches the AppleWWDRCA certificate
byte[] manifestbytes = Encoding.ASCII.GetBytes(manifest);
ContentInfo contentinfo = new ContentInfo(manifestbytes);
SignedCms signedCms = new SignedCms(contentinfo, true);
var signer = new CmsSigner(SubjectIdentifierType.IssuerAndSerialNumber,card);
signer.Certificates.Add(new X509Certificate2(appleCA));
signer.IncludeOption = X509IncludeOption.WholeChain;
signer.SignedAttributes.Add(new Pkcs9SigningTime());
signedCms.ComputeSignature(signer);
signatureFile = signedCms.Encode();
return signatureFile;
I have created an open source C# library for generating these passes.
https://github.com/tomasmcguinness/dotnet-passbook
This is the code I use perform the signing of the files (it uses BouncyCastle)
// Load your pass type identifier certificate
X509Certificate2 card = GetCertificate(request);
Org.BouncyCastle.X509.X509Certificate cert = DotNetUtilities.FromX509Certificate(card);
Org.BouncyCastle.Crypto.AsymmetricKeyParameter privateKey = DotNetUtilities.GetKeyPair(card.PrivateKey).Private;
// Load the Apple certificate
X509Certificate2 appleCA = GetAppleCertificate(request);
X509.X509Certificate appleCert = DotNetUtilities.FromX509Certificate(appleCA);
ArrayList intermediateCerts = new ArrayList();
intermediateCerts.Add(appleCert);
intermediateCerts.Add(cert);
Org.BouncyCastle.X509.Store.X509CollectionStoreParameters PP = new Org.BouncyCastle.X509.Store.X509CollectionStoreParameters(intermediateCerts);
Org.BouncyCastle.X509.Store.IX509Store st1 = Org.BouncyCastle.X509.Store.X509StoreFactory.Create("CERTIFICATE/COLLECTION", PP);
CmsSignedDataGenerator generator = new CmsSignedDataGenerator();
generator.AddSigner(privateKey, cert, CmsSignedDataGenerator.DigestSha1);
generator.AddCertificates(st1);
CmsProcessable content = new CmsProcessableByteArray(manifestFile);
CmsSignedData signedData = generator.Generate(content, false);
signatureFile = signedData.GetEncoded();
I hope this helps.

Signing X509 Certs w/BouncyCastle - invalid digital signature [duplicate]

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.

Categories

Resources