I am trying to get a certificate signature using CMS/Pkcs, it keeps prompting me a PIN code. How to disable this pin code pop-up or include it within the code (Note it is a fixed pin and it does not change)
Encoding utf8 = Encoding.UTF8;
byte[] bytes = utf8.GetBytes(serializedJson);
Pkcs11InteropFactories factories = new Pkcs11InteropFactories();
using (IPkcs11Library library = factories.Pkcs11LibraryFactory.LoadPkcs11Library(factories, this.DllLibPath, AppType.MultiThreaded))
{
ISlot slot = ((IEnumerable<ISlot>)library.GetSlotList(SlotsType.WithTokenPresent)).FirstOrDefault<ISlot>();
if (slot == null)
{
str = "No slots found";
}
else
{
ITokenInfo tokenInfo = slot.GetTokenInfo();
ISlotInfo slotInfo = slot.GetSlotInfo();
using (ISession session = slot.OpenSession(SessionType.ReadWrite))
{
session.Login(CKU.CKU_USER, utf8.GetBytes(this.TokenPin));
List<IObjectAttribute> list1 = new List<IObjectAttribute>();
list1.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_CERTIFICATE));
list1.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_TOKEN, true));
list1.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CERTIFICATE_TYPE, CKC.CKC_X_509));
if (((IEnumerable<IObjectHandle>)session.FindAllObjects(list1)).FirstOrDefault<IObjectHandle>() == null)
{
str = "Certificate not found";
}
else
{
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.MaxAllowed);
X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindByIssuerName, "Egypt Trust Sealing CA", true);
if (certificates.Count == 0)
{
str = "no device detected";
}
else
{
X509Certificate2 certificate = certificates[0];
store.Close();
SignedCms cms = new SignedCms(new ContentInfo(new Oid("1.2.840.113549.1.7.5"), bytes), true);
EssCertIDv2 dv = new EssCertIDv2(new Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier(new DerObjectIdentifier("1.2.840.113549.1.9.16.2.47")), this.HashBytes(certificate.RawData));
EssCertIDv2[] certs = new EssCertIDv2[] { dv };
SigningCertificateV2 ev = new SigningCertificateV2(certs);
CmsSigner signer = new CmsSigner(certificate)
{
DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1"),
SignedAttributes = {
new Pkcs9SigningTime(DateTime.UtcNow),
new AsnEncodedData(new Oid("1.2.840.113549.1.9.16.2.47"), ev.GetEncoded())
}
};
cms.ComputeSignature(signer);
Thank you in advance.
Related
I have a program with .net 4.7 and we used a CMSSign class, it fail when try to compute sign, actually we convert the class from .Net Core and private property missed, the below code is from .net core
CmsSigner signer = new CmsSigner(xcert);
signer.PrivateKey = privateKey; // missed in .net 4.7
and here full code from from 4.7 and it's not working as expected :
Pkcs11InteropFactories factories = new Pkcs11InteropFactories();
using (var lib = factories.Pkcs11LibraryFactory.LoadPkcs11Library(factories, dllPath, AppType.MultiThreaded))
{
ISlot slot = lib.GetSlotList(SlotsType.WithTokenPresent).First();
if (slot is null)
{
return "No slots found";
}
ITokenInfo tokenInfo = slot.GetTokenInfo();
using (ISession session = slot.OpenSession(SessionType.ReadOnly))
{
session.Login(CKU.CKU_USER, Encoding.UTF8.GetBytes("123456"));
List<IObjectAttribute> certificateSearchAttributes = new List<IObjectAttribute>
{
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_CERTIFICATE),
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_TOKEN, true),
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CERTIFICATE_TYPE, CKC.CKC_X_509)
};
IObjectHandle certificate = session.FindAllObjects(certificateSearchAttributes).FirstOrDefault();
if (certificate is null)
{
return "Certificate not found";
}
var attributeValues = session.GetAttributeValue(certificate, new List<CKA>
{
CKA.CKA_VALUE
});
var searchAttribute = new List<IObjectAttribute>()
{
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY),
session.Factories.ObjectAttributeFactory.Create(CKA.CKA_KEY_TYPE, CKK.CKK_RSA)
};
IObjectHandle privateKeyHandler = session.FindAllObjects(searchAttribute).FirstOrDefault();
var xcert = new X509Certificate2(attributeValues[0].GetValueAsByteArray());
RSA privateKey = new TokenRSA(xcert, session, slot, privateKeyHandler);
string serializedDocument = "Text To sign";
byte[] data = Encoding.UTF8.GetBytes(serializedDocument);
ContentInfo content = new ContentInfo(new Oid("1.2.840.113549.1.7.5"), data);
SignedCms cms = new SignedCms(content, detached: true);
CmsSigner signer = new CmsSigner(xcert);
EssCertIDv2 bouncyCertificate = new EssCertIDv2(new Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier(new DerObjectIdentifier("1.2.840.113549.1.9.16.2.47")), HashBytes(xcert.RawData));
SigningCertificateV2 signerCertificateV2 = new SigningCertificateV2(new EssCertIDv2[1] { bouncyCertificate });
signer.DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1");
signer.SignedAttributes.Add(new Pkcs9SigningTime(DateTime.UtcNow));
signer.SignedAttributes.Add(new AsnEncodedData(new Oid("1.2.840.113549.1.9.16.2.47"), signerCertificateV2.GetEncoded()));
cms.ComputeSignature(signer);
byte[] output = cms.Encode();
return Convert.ToBase64String(output, Base64FormattingOptions.None);
}
}
The .NET Framework version of CmsSigner only works when the certificate object is already coupled to its private key (cert.HasPrivateKey is true).
On .NET Framework 4.7 that pretty well requires putting the cert and private key together in a PFX, or having already had them associated in a cert that's in a cert store.
If privateKey is already just assigned something like cert.GetRSAPrivateKey() then you shouldn't need to assign signer.PrivateKey.
I am using NuGet package (Install-Package BouncyCastle.Crypto.dll).
I am generating the X509 certificate as follows.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Security.Cryptography;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Operators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.X509.Extension;
using X509Certificate = Org.BouncyCastle.X509.X509Certificate;
namespace ConsoleApplication1
{
public class Program
{
static void Main()
{
var applicationId = ((GuidAttribute)typeof(Program).Assembly.GetCustomAttributes(typeof(GuidAttribute), true)[0]).Value;
var certSubjectName = "CN=CapIbmSignalRServer";
CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator();
SecureRandom random = new SecureRandom(randomGenerator);
AsymmetricCipherKeyPair asymetricKey = GenerateCACertificate(certSubjectName);
ISignatureFactory factory = new Asn1SignatureFactory("SHA512WITHRSA", asymetricKey.Private, random);
X509V1CertificateGenerator dsafdsafa = new X509V1CertificateGenerator();
dsafdsafa.SetSerialNumber(BigInteger.ProbablePrime(256, random));
dsafdsafa.SetIssuerDN(new X509Name(certSubjectName));
dsafdsafa.SetSubjectDN(new X509Name(certSubjectName));
dsafdsafa.SetNotAfter(DateTime.Now.AddYears(5));
dsafdsafa.SetNotBefore(DateTime.Now.AddYears(-1));
dsafdsafa.SetPublicKey(asymetricKey.Public);
System.Security.Cryptography.X509Certificates.X509Certificate asdsad = DotNetUtilities.ToX509Certificate(dsafdsafa.Generate(factory));
X509Certificate2 x509Certificate2 = new X509Certificate2(asdsad.Export(X509ContentType.Cert), (string)null, X509KeyStorageFlags.MachineKeySet
| X509KeyStorageFlags.PersistKeySet
| X509KeyStorageFlags.Exportable);
X509Store store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(x509Certificate2);
Console.WriteLine(ExecuteCommand($"netsh http add sslcert ipport=0.0.0.0:4443 certhash={x509Certificate2.Thumbprint} appid={{{applicationId}}}"));
Console.ReadKey();
}
public static string ExecuteCommand(string action)
{
StringBuilder stringBuilder = new StringBuilder();
using (Process process = new Process
{
StartInfo = new ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Normal,
FileName = "cmd.exe",
UseShellExecute = false,
RedirectStandardOutput = true,
Arguments = "/c " + action
}
})
{
process.Start();
while (!process.StandardOutput.EndOfStream)
{
stringBuilder.AppendLine(process.StandardOutput.ReadLine());
}
process.Close();
}
return stringBuilder.ToString();
}
}
}
Unfortunately, every time i try to bind to the port I get the error.
SSL Certificate Add Failure Error: 1312
A specified logon session does not exist. It may already have been terminated.
Am I generating the X509 certificate incorrectly?
Bouncy Castle's X509V3CertificateGenerator.SetSignatureAlgorithm marked obsolete. What do I do?
Please use the answer posted in the above question
Solved it woot!. In addition, I added to the answer a bit as well demonstrating how to make a CA and then make a certificate from that CA then bind it a a port for self hosted solution.
static void Main()
{
Console.WriteLine(ExecuteCommand("netsh http delete sslcert ipport=0.0.0.0:4443"));
var applicationId = ((GuidAttribute)typeof(Program).Assembly.GetCustomAttributes(typeof(GuidAttribute), true)[0]).Value;
var certSubjectName = "TEST";
var sslCert = ExecuteCommand("netsh http show sslcert 0.0.0.0:4443");
Console.WriteLine(sslCert);
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
if (sslCert.IndexOf(applicationId, StringComparison.OrdinalIgnoreCase) >= 0)
{
Console.WriteLine("This implies we can start running.");
Console.WriteLine(ExecuteCommand("netsh http delete sslcert ipport=0.0.0.0:4443"));
//store.Remove(certs.First(x => x.Subject.Contains(certSubjectName)));
}
AsymmetricKeyParameter myCAprivateKey = null;
Console.WriteLine("Creating CA");
X509Certificate2 certificateAuthorityCertificate = CreateCertificateAuthorityCertificate("CN=" + certSubjectName + "CA", ref myCAprivateKey);
Console.WriteLine("Adding CA to Store");
AddCertificateToSpecifiedStore(certificateAuthorityCertificate, StoreName.Root, StoreLocation.LocalMachine);
Console.WriteLine("Creating certificate based on CA");
X509Certificate2 certificate = CreateSelfSignedCertificateBasedOnCertificateAuthorityPrivateKey("CN=" + certSubjectName, "CN=" + certSubjectName + "CA", myCAprivateKey);
Console.WriteLine("Adding certificate to Store");
AddCertificateToSpecifiedStore(certificate, StoreName.My, StoreLocation.LocalMachine);
Console.WriteLine(ExecuteCommand($"netsh http add sslcert ipport=0.0.0.0:4443 certhash={certificate.Thumbprint} appid={{{applicationId}}}"));
// Check to see if our cert exists
// If the cert does not exist create it then bind it to the port
// If the cert does exist then check the port it is bound to
// If the port and thumbprint match and applicationId match continue
// Else throw exception
// See here for more netsh commands https://msdn.microsoft.com/en-us/library/ms733791(v=vs.110).aspx
Console.ReadKey();
}
public static X509Certificate2 CreateSelfSignedCertificateBasedOnCertificateAuthorityPrivateKey(string subjectName, string issuerName, AsymmetricKeyParameter issuerPrivKey)
{
const int keyStrength = 2048;
// Generating Random Numbers
CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator();
SecureRandom random = new SecureRandom(randomGenerator);
ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA512WITHRSA", issuerPrivKey, random);
// The Certificate Generator
X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();
certificateGenerator.AddExtension(X509Extensions.ExtendedKeyUsage, true, new ExtendedKeyUsage((new ArrayList() { new DerObjectIdentifier("1.3.6.1.5.5.7.3.1") })));
// Serial Number
BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
certificateGenerator.SetSerialNumber(serialNumber);
// Signature Algorithm
//const string signatureAlgorithm = "SHA512WITHRSA";
//certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm);
// Issuer and Subject Name
X509Name subjectDN = new X509Name(subjectName);
X509Name issuerDN = new X509Name(issuerName);
certificateGenerator.SetIssuerDN(issuerDN);
certificateGenerator.SetSubjectDN(subjectDN);
// Valid For
DateTime notBefore = DateTime.Now.AddYears(-1);
DateTime notAfter = notBefore.AddYears(8);
certificateGenerator.SetNotBefore(notBefore);
certificateGenerator.SetNotAfter(notAfter);
// Subject Public Key
AsymmetricCipherKeyPair subjectKeyPair;
var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
var keyPairGenerator = new RsaKeyPairGenerator();
keyPairGenerator.Init(keyGenerationParameters);
subjectKeyPair = keyPairGenerator.GenerateKeyPair();
certificateGenerator.SetPublicKey(subjectKeyPair.Public);
// Generating the Certificate
AsymmetricCipherKeyPair issuerKeyPair = subjectKeyPair;
// selfsign certificate
X509Certificate certificate = certificateGenerator.Generate(signatureFactory);
// correcponding private key
PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);
// merge into X509Certificate2
X509Certificate2 x509 = new X509Certificate2(certificate.GetEncoded());
Asn1Sequence seq = (Asn1Sequence)Asn1Object.FromByteArray(info.ParsePrivateKey().GetDerEncoded());
if (seq.Count != 9)
{
//throw new PemException("malformed sequence in RSA private key");
}
RsaPrivateKeyStructure rsa = RsaPrivateKeyStructure.GetInstance(seq); //new RsaPrivateKeyStructure(seq);
RsaPrivateCrtKeyParameters rsaparams = new RsaPrivateCrtKeyParameters(
rsa.Modulus, rsa.PublicExponent, rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, rsa.Exponent2, rsa.Coefficient);
x509.PrivateKey = DotNetUtilities.ToRSA(rsaparams);
return x509;
}
public static X509Certificate2 CreateCertificateAuthorityCertificate(string subjectName, ref AsymmetricKeyParameter CaPrivateKey)
{
const int keyStrength = 2048;
// Generating Random Numbers
CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator();
SecureRandom random = new SecureRandom(randomGenerator);
// The Certificate Generator
X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();
// Serial Number
BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
certificateGenerator.SetSerialNumber(serialNumber);
// Signature Algorithm
//const string signatureAlgorithm = "SHA256WithRSA";
//certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm);
// Issuer and Subject Name
X509Name subjectDN = new X509Name(subjectName);
X509Name issuerDN = subjectDN;
certificateGenerator.SetIssuerDN(issuerDN);
certificateGenerator.SetSubjectDN(subjectDN);
// Valid For
DateTime notBefore = DateTime.Now.AddYears(-1);
DateTime notAfter = notBefore.AddYears(8);
certificateGenerator.SetNotBefore(notBefore);
certificateGenerator.SetNotAfter(notAfter);
// Subject Public Key
AsymmetricCipherKeyPair subjectKeyPair;
KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
RsaKeyPairGenerator keyPairGenerator = new RsaKeyPairGenerator();
keyPairGenerator.Init(keyGenerationParameters);
subjectKeyPair = keyPairGenerator.GenerateKeyPair();
certificateGenerator.SetPublicKey(subjectKeyPair.Public);
// Generating the Certificate
AsymmetricCipherKeyPair issuerKeyPair = subjectKeyPair;
ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA512WITHRSA", issuerKeyPair.Private, random);
// selfsign certificate
X509Certificate certificate = certificateGenerator.Generate(signatureFactory);
X509Certificate2 x509 = new X509Certificate2(certificate.GetEncoded());
CaPrivateKey = issuerKeyPair.Private;
return x509;
//return issuerKeyPair.Private;
}
public static bool AddCertificateToSpecifiedStore(X509Certificate2 cert, StoreName st, StoreLocation sl)
{
bool bRet = false;
try
{
X509Store store = new X509Store(st, sl);
store.Open(OpenFlags.ReadWrite);
store.Add(cert);
store.Close();
}
catch
{
Console.WriteLine("An error occured");
}
return bRet;
}
public static string ExecuteCommand(string action)
{
StringBuilder stringBuilder = new StringBuilder();
using (Process process = new Process
{
StartInfo = new ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Normal,
FileName = "cmd.exe",
UseShellExecute = false,
RedirectStandardOutput = true,
Arguments = "/c " + action
}
})
{
Console.WriteLine("Executing Command:");
Console.WriteLine(action);
process.Start();
while (!process.StandardOutput.EndOfStream)
{
stringBuilder.AppendLine(process.StandardOutput.ReadLine());
}
process.Close();
}
return stringBuilder.ToString();
}
I have a function that signing an XML file with a X509Certificate2 certificate. My problem is that the signature is inserted as SHA-1 and SHA-256 instead. What did I do wrong in my code?
CmsSigner cms = new CmsSigner(oCert);
//if apply this row receive unknow error!
//cms.DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1");
ContentInfo ci = new ContentInfo(File.ReadAllBytes(cFileXml));
SignedCms cmssigned = new SignedCms(ci);
cmssigned.ComputeSignature(cms);
byte[] encodedmessage = cmssigned.Encode();
File.WriteAllBytes(cFile + ".p7m", encodedmessage);
I say to myself. This is the simply solution:
string PIN = Leo.LeggiFirmacert();
System.Security.SecureString SecurePIN = new System.Security.SecureString();
foreach (char ch in PIN)
{ SecurePIN.AppendChar(ch); }
var rsa = (RSACryptoServiceProvider)cert.PrivateKey;
string ContinerName = rsa.CspKeyContainerInfo.KeyContainerName;
string CspName = rsa.CspKeyContainerInfo.ProviderName;
int CspType = rsa.CspKeyContainerInfo.ProviderType;
CspParameters csp = new CspParameters(CspType, CspName, ContinerName, new System.Security.AccessControl.CryptoKeySecurity(), SecurePIN);
SHA256Managed hashSha256 = new SHA256Managed();
byte[] certHash = hashSha256.ComputeHash(cert.RawData);
EssCertIDv2 essCert1 = new EssCertIDv2(new Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier("2.16.840.1.101.3.4.2.1"), certHash);
SigningCertificateV2 scv2 = new SigningCertificateV2(new EssCertIDv2[] { essCert1 });
Org.BouncyCastle.Asn1.Cms.Attribute CertHAttribute = new Org.BouncyCastle.Asn1.Cms.Attribute(Org.BouncyCastle.Asn1.Pkcs.PkcsObjectIdentifiers.IdAASigningCertificateV2, new DerSet(scv2));
Asn1EncodableVector v = new Asn1EncodableVector();
v.Add(CertHAttribute);
Org.BouncyCastle.Asn1.Cms.AttributeTable AT = new Org.BouncyCastle.Asn1.Cms.AttributeTable(v);
CmsSignedDataGenWithRsaCsp cms = new CmsSignedDataGenWithRsaCsp();
Org.BouncyCastle.Crypto.AsymmetricKeyParameter keyParameter = null;
Org.BouncyCastle.X509.X509Certificate certCopy = DotNetUtilities.FromX509Certificate(cert);
cms.MyAddSigner(rsa, certCopy, keyParameter, "1.2.840.113549.1.1.1", "2.16.840.1.101.3.4.2.1", AT, null);
ArrayList certList = new ArrayList();
certList.Add(certCopy);
Org.BouncyCastle.X509.Store.X509CollectionStoreParameters PP = new Org.BouncyCastle.X509.Store.X509CollectionStoreParameters(certList);
Org.BouncyCastle.X509.Store.IX509Store st1 = Org.BouncyCastle.X509.Store.X509StoreFactory.Create("CERTIFICATE/COLLECTION", PP);
cms.AddCertificates(st1);
FileInfo File__1 = new FileInfo(NomeFile);
CmsProcessableFile file__2 = new CmsProcessableFile(File__1);
CmsSignedData Firmato = cms.Generate(file__2, true);
byte[] Encoded = Firmato.GetEncoded();
RisFirma = "";
return Encoded;
I'm new to iTextSharp (and StackOverFlow). I'm trying to sign a PDF in C# using external USB token. I try using the follow code I've digged from the internet.
Org.BouncyCastle.X509.X509CertificateParser cp = new Org.BouncyCastle.X509.X509CertificateParser();
//Get Sertifiacte
X509Certificate2 certClient = null;
X509Store st = new X509Store(StoreName.My, StoreLocation.CurrentUser);
st.Open(OpenFlags.MaxAllowed);
X509Certificate2Collection collection = X509Certificate2UI.SelectFromCollection(st.Certificates, "Please choose certificate:", "", X509SelectionFlag.SingleSelection);
if (collection.Count > 0){
certClient = collection[0];
}
st.Close();
//Get Cert Chain
IList<Org.BouncyCastle.X509.X509Certificate> chain = new List<Org.BouncyCastle.X509.X509Certificate>();
X509Chain x509chain = new X509Chain();
x509chain.Build(certClient );
foreach (X509ChainElement x509ChainElement in x509chain.ChainElements){
chain.Add(DotNetUtilities.FromX509Certificate(x509ChainElement.Certificate));
}
PdfReader reader = new PdfReader(sourceDocument);
FileStream resStream = new FileStream(resultDocument, FileMode.Create, FileAccess.ReadWrite);
PdfStamper stamper = PdfStamper.CreateSignature(reader, resStream , '\0', null, true);
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
appearance.Reason = reason;
appearance.Location = location;
appearance.SetVisibleSignature(new iTextSharp.text.Rectangle(20, 10, 170, 60), 1, "Signed");
X509Certificate2Signature es = new X509Certificate2Signature(certClient, "SHA-1");
MakeSignature.SignDetached(appearance, es, chain, null, null, null, 0, CryptoStandard.CMS);
The problem is that I receive an exception:
System.Security.Cryptography.CryptographicException was unhandled
Message=Invalid type specified.
Source=mscorlib
StackTrace:
at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
at System.Security.Cryptography.Utils._GetKeyParameter(SafeKeyHandle hKey, UInt32 paramID)
at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle& safeProvHandle, SafeKeyHandle& safeKeyHandle)
at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize)
at System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()
at iTextSharp.text.pdf.security.X509Certificate2Signature..ctor(X509Certificate2 certificate, String hashAlgorithm)
at WindowsFormsApplication1.PDFSignerHelper.signPdfFile(String sourceDocument, String resultDocument, X509Certificate2 certClient, String reason, String location)
InnerException:
This approach works fine for us (iTextSharp 5.3.3). We use smart-card and USB-token (vendor - www.author.kiev.ua):
X509Store store = new X509Store(StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection sel = X509Certificate2UI.SelectFromCollection(store.Certificates, null, null, X509SelectionFlag.SingleSelection);
X509Certificate2 cert = sel[0];
Org.BouncyCastle.X509.X509CertificateParser cp = new Org.BouncyCastle.X509.X509CertificateParser();
Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] {
cp.ReadCertificate(cert.RawData)};
IExternalSignature externalSignature = new X509Certificate2Signature(cert, "SHA-1");
PdfReader pdfReader = new PdfReader(pathToBasePdf);
signedPdf = new FileStream(pathToBasePdf, FileMode.Create);
pdfStamper = PdfStamper.CreateSignature(pdfReader, signedPdf, '\0');
PdfSignatureAppearance signatureAppearance = pdfStamper.SignatureAppearance;
signatureAppearance.SignatureGraphic = Image.GetInstance(pathToSignatureImage);
signatureAppearance.SetVisibleSignature(new Rectangle(100, 100, 250, 150), pdfReader.NumberOfPages, "Signature");
signatureAppearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.GRAPHIC_AND_DESCRIPTION;
MakeSignature.SignDetached(signatureAppearance, externalSignature, chain, null, null, null, 0, CryptoStandard.CMS);
I have made a c# project that can sign a PDF from the windows store, SmartCard or a Pfx/P12 file
Maybe it can be useful for you
using System;
using System.Windows.Forms;
using System.IO;
using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.security;
namespace SignPdf
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private SecureString GetSecurePin(string PinCode)
{
SecureString pwd = new SecureString();
foreach (var c in PinCode.ToCharArray()) pwd.AppendChar(c);
return pwd;
}
private void button1_Click(object sender, EventArgs e)
{
//Sign from SmartCard
//note : ProviderName and KeyContainerName can be found with the dos command : CertUtil -ScInfo
string ProviderName = textBox2.Text;
string KeyContainerName = textBox3.Text;
string PinCode = textBox4.Text;
if (PinCode != "")
{
//if pin code is set then no windows form will popup to ask it
SecureString pwd = GetSecurePin(PinCode);
CspParameters csp = new CspParameters(1,
ProviderName,
KeyContainerName,
new System.Security.AccessControl.CryptoKeySecurity(),
pwd);
try
{
RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider(csp);
// the pin code will be cached for next access to the smart card
}
catch (Exception ex)
{
MessageBox.Show("Crypto error: " + ex.Message);
return;
}
}
X509Store store = new X509Store(StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
X509Certificate2 cert = null;
if ((ProviderName == "") || (KeyContainerName == ""))
{
MessageBox.Show("You must set Provider Name and Key Container Name");
return;
}
foreach (X509Certificate2 cert2 in store.Certificates)
{
if (cert2.HasPrivateKey)
{
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert2.PrivateKey;
if (rsa == null) continue; // not smart card cert again
if (rsa.CspKeyContainerInfo.HardwareDevice) // sure - smartcard
{
if ((rsa.CspKeyContainerInfo.KeyContainerName == KeyContainerName) && (rsa.CspKeyContainerInfo.ProviderName == ProviderName))
{
//we find it
cert = cert2;
break;
}
}
}
}
if (cert == null)
{
MessageBox.Show("Certificate not found");
return;
}
SignWithThisCert(cert);
}
private void button2_Click(object sender, EventArgs e)
{
//Sign with certificate selection in the windows certificate store
X509Store store = new X509Store(StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
X509Certificate2 cert = null;
//manually chose the certificate in the store
X509Certificate2Collection sel = X509Certificate2UI.SelectFromCollection(store.Certificates, null, null, X509SelectionFlag.SingleSelection);
if (sel.Count > 0)
cert = sel[0];
else
{
MessageBox.Show("Certificate not found");
return;
}
SignWithThisCert(cert);
}
private void button3_Click(object sender, EventArgs e)
{
//Sign from certificate in a pfx or a p12 file
string PfxFileName = textBox5.Text;
string PfxPassword = textBox6.Text;
X509Certificate2 cert = new X509Certificate2(PfxFileName, PfxPassword);
SignWithThisCert(cert);
}
private void SignWithThisCert(X509Certificate2 cert)
{
string SourcePdfFileName = textBox1.Text;
string DestPdfFileName = textBox1.Text + "-Signed.pdf";
Org.BouncyCastle.X509.X509CertificateParser cp = new Org.BouncyCastle.X509.X509CertificateParser();
Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] { cp.ReadCertificate(cert.RawData) };
IExternalSignature externalSignature = new X509Certificate2Signature(cert, "SHA-1");
PdfReader pdfReader = new PdfReader(SourcePdfFileName);
FileStream signedPdf = new FileStream(DestPdfFileName, FileMode.Create); //the output pdf file
PdfStamper pdfStamper = PdfStamper.CreateSignature(pdfReader, signedPdf, '\0');
PdfSignatureAppearance signatureAppearance = pdfStamper.SignatureAppearance;
//here set signatureAppearance at your will
signatureAppearance.Reason = "Because I can";
signatureAppearance.Location = "My location";
signatureAppearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.DESCRIPTION;
MakeSignature.SignDetached(signatureAppearance, externalSignature, chain, null, null, null, 0, CryptoStandard.CMS);
//MakeSignature.SignDetached(signatureAppearance, externalSignature, chain, null, null, null, 0, CryptoStandard.CADES);
MessageBox.Show("Done");
}
}
}
The same code as above but uses a certificate file instead of store to sign a PDF document on the last page.
X509Certificate2 cert = new X509Certificate2("C:\\mycert.p12");
Org.BouncyCastle.X509.X509CertificateParser cp = new Org.BouncyCastle.X509.X509CertificateParser();
Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] {
cp.ReadCertificate(cert.RawData)};
IExternalSignature externalSignature = new X509Certificate2Signature(cert, "SHA-1");
PdfReader pdfReader = new PdfReader("C:\\multi-page-pdf.pdf");
var signedPdf = new FileStream("C:\\multi-page-pdf-signed.pdf", FileMode.Create);
var pdfStamper = PdfStamper.CreateSignature(pdfReader, signedPdf, '\0');
PdfSignatureAppearance signatureAppearance = pdfStamper.SignatureAppearance;
signatureAppearance.SignatureGraphic = Image.GetInstance("C:\\logo.png");
signatureAppearance.Reason = "Because I can";
signatureAppearance.Location = "My location";
signatureAppearance.SetVisibleSignature(new Rectangle(100, 100, 250, 150), pdfReader.NumberOfPages, "Signature");
signatureAppearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.GRAPHIC_AND_DESCRIPTION;
MakeSignature.SignDetached(signatureAppearance, externalSignature, chain, null, null, null, 0, CryptoStandard.CMS);
Copy, paste, import needed libraries and go work on something else.
I'm trying to build a self hosted service that uses WebAPI with SSL and I need to be able to self-generate SSL certificates to use. I want to be able to do this all from C#. I've been playing with BouncyCastle.
I need to generate 2 certificates, a root and a site certificate. Then I need to install them in Windows in their correct places.
I can't figure out how to make my second certificate reference my root ca. Everything I've tried just gets me an untrusted certificate error. Any help would be appreciated.
This is what I do (I'm using DSA, but if you are using RSA, just change the key generation).
public void IssueClientFromCA()
{
// get CA
string caCn = "MyCA CommonName";
Stream caCertFile = File.OpenRead(string.Format(#"{0}\{1}", _certificatesDir, "MyCAFile.pfx"));
char[] caPass = "passwordForThePfx".ToCharArray();
Pkcs12Store store = new Pkcs12StoreBuilder().Build();
store.Load(caCertFile, caPass);
var caCert = store.GetCertificate(caCn).Certificate;
var caPrivKey = store.GetKey(caCn).Key;
var clientCert = CertIssuer.GenerateDsaCertificateAsPkcs12(
"My Client FriendlyName",
"My Client SubjectName",
"GT",
new DateTime(2011,9,19),
new DateTime(2014,9,18),
"PFXPASS",
caCert,
caPrivKey);
var saveAS = string.Format(#"{0}\{1}", _certificatesDir, "clientCertFile.pfx");
File.WriteAllBytes(saveAS, clientCert);
}
public static byte[] GenerateDsaCertificateAsPkcs12(
string friendlyName,
string subjectName,
string country,
DateTime validStartDate,
DateTime validEndDate,
string password,
Org.BouncyCastle.X509.X509Certificate caCert,
AsymmetricKeyParameter caPrivateKey)
{
var keys = GenerateDsaKeys();
#region build certificate
var certGen = new X509V3CertificateGenerator();
// build name attributes
var nameOids = new ArrayList();
nameOids.Add(Org.BouncyCastle.Asn1.X509.X509Name.CN);
nameOids.Add(X509Name.O);
nameOids.Add(X509Name.C);
var nameValues = new ArrayList();
nameValues.Add(friendlyName);
nameValues.Add(subjectName);
nameValues.Add(country);
var subjectDN = new X509Name(nameOids, nameValues);
// certificate fields
certGen.SetSerialNumber(BigInteger.ValueOf(1));
certGen.SetIssuerDN(caCert.SubjectDN);
certGen.SetNotBefore(validStartDate);
certGen.SetNotAfter(validEndDate);
certGen.SetSubjectDN(subjectDN);
certGen.SetPublicKey(keys.Public);
certGen.SetSignatureAlgorithm("SHA1withDSA");
// extended information
certGen.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(caCert.GetPublicKey()));
certGen.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifierStructure(keys.Public));
#endregion
// generate x509 certificate
var cert = certGen.Generate(caPrivateKey);
//ert.Verify(caCert.GetPublicKey());
var chain = new Dictionary<string, Org.BouncyCastle.X509.X509Certificate>();
//chain.Add("CertiFirmas CA", caCert);
var caCn = caCert.SubjectDN.GetValues(X509Name.CN)[0].ToString();
chain.Add(caCn, caCert);
// store the file
return GeneratePkcs12(keys, cert, friendlyName, password, chain);
}
private static byte[] GeneratePkcs12(AsymmetricCipherKeyPair keys, Org.BouncyCastle.X509.X509Certificate cert, string friendlyName, string password,
Dictionary<string, Org.BouncyCastle.X509.X509Certificate> chain)
{
var chainCerts = new List<X509CertificateEntry>();
// Create the PKCS12 store
Pkcs12Store store = new Pkcs12StoreBuilder().Build();
// Add a Certificate entry
X509CertificateEntry certEntry = new X509CertificateEntry(cert);
store.SetCertificateEntry(friendlyName, certEntry); // use DN as the Alias.
//chainCerts.Add(certEntry);
// Add chain entries
var additionalCertsAsBytes = new List<byte[]>();
if (chain != null && chain.Count > 0)
{
foreach (var additionalCert in chain)
{
additionalCertsAsBytes.Add(additionalCert.Value.GetEncoded());
}
}
if (chain != null && chain.Count > 0)
{
var addicionalCertsAsX09Chain = BuildCertificateChainBC(cert.GetEncoded(), additionalCertsAsBytes);
foreach (var addCertAsX09 in addicionalCertsAsX09Chain)
{
chainCerts.Add(new X509CertificateEntry(addCertAsX09));
}
}
// Add a key entry
AsymmetricKeyEntry keyEntry = new AsymmetricKeyEntry(keys.Private);
// no chain
store.SetKeyEntry(friendlyName, keyEntry, new X509CertificateEntry[] { certEntry });
using (var memoryStream = new MemoryStream())
{
store.Save(memoryStream, password.ToCharArray(), new SecureRandom());
return memoryStream.ToArray();
}
}
Some missing methods:
static IEnumerable<Org.BouncyCastle.X509.X509Certificate> BuildCertificateChainBC(byte[] primary, IEnumerable<byte[]> additional)
{
X509CertificateParser parser = new X509CertificateParser();
PkixCertPathBuilder builder = new PkixCertPathBuilder();
// Separate root from itermediate
var intermediateCerts = new List<Org.BouncyCastle.X509.X509Certificate>();
HashSet rootCerts = new HashSet();
foreach (byte[] cert in additional)
{
var x509Cert = parser.ReadCertificate(cert);
// Separate root and subordinate certificates
if (x509Cert.IssuerDN.Equivalent(x509Cert.SubjectDN))
rootCerts.Add(new TrustAnchor(x509Cert, null));
else
intermediateCerts.Add(x509Cert);
}
// Create chain for this certificate
X509CertStoreSelector holder = new X509CertStoreSelector();
holder.Certificate = parser.ReadCertificate(primary);
// WITHOUT THIS LINE BUILDER CANNOT BEGIN BUILDING THE CHAIN
intermediateCerts.Add(holder.Certificate);
PkixBuilderParameters builderParams = new PkixBuilderParameters(rootCerts, holder);
builderParams.IsRevocationEnabled = false;
X509CollectionStoreParameters intermediateStoreParameters =
new X509CollectionStoreParameters(intermediateCerts);
builderParams.AddStore(X509StoreFactory.Create(
"Certificate/Collection", intermediateStoreParameters));
PkixCertPathBuilderResult result = builder.Build(builderParams);
return result.CertPath.Certificates.Cast<Org.BouncyCastle.X509.X509Certificate>();
}
private static AsymmetricCipherKeyPair GenerateDsaKeys()
{
DSACryptoServiceProvider DSA = new DSACryptoServiceProvider();
var dsaParams = DSA.ExportParameters(true);
AsymmetricCipherKeyPair keys = DotNetUtilities.GetDsaKeyPair(dsaParams);
return keys;
}
Also: you have to install you CA certificate into the Trusted CAs store in the client machine, as well as the client certificate (it could be in the Personal or ThirdParty store).