public void SignPdf(GenericViewModel vm)
{
bool isAppendMode = true;
string dest = #"{exportedpdf}";
string source = #"{originalpdf}";
int certificationLevel = 3;
ICipherParameters pk = _certificate.GeneratePrivateKey(vm.NDISType, 2048);
System.Security.Cryptography.X509Certificates.X509Certificate cert = new System.Security.Cryptography.X509Certificates.X509Certificate(#"{certificate}");
Org.BouncyCastle.X509.X509Certificate bcCert = new X509CertificateParser().ReadCertificate(cert.GetRawCertData());
Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[1] { bcCert };
PdfReader reader = new PdfReader(source);
StampingProperties properties = new StampingProperties();
if (isAppendMode)
{
properties.UseAppendMode();
}
var outdoc = new FileStream(dest, FileMode.Create);
PdfSigner signer = new PdfSigner(reader, outdoc, properties);
var doc = signer.GetDocument();
signer.SetFieldName("Signature Field 2"); //existing signature field
signer.SetCertificationLevel(certificationLevel);
byte[] imageBytes = Convert.FromBase64String(vm.Assessor.AssessorSignature);
ImageData imageData = ImageDataFactory.Create(imageBytes);
PdfSignatureAppearance sigAppearance = signer.GetSignatureAppearance();
sigAppearance.SetSignatureGraphic(imageData);
sigAppearance.SetRenderingMode(RenderingMode.GRAPHIC);
PdfAcroForm.GetAcroForm(doc, false)
.GetField("Signature Field 2")
.SetVisibility(PdfFormField.VISIBLE);
IExternalSignature pks = new PrivateKeySignature(pk, "SHA-512");
signer.SignDetached(pks, chain, null, null, null, 0, PdfSigner.CryptoStandard.CMS);
outdoc.Close();
reader.Close();
}
existing pdf signature field
signed pdf
Since I am new to iText, I am looking to sign the pdf with a graphical signature appearance... I tried changing the rendering mode to the other options but nothing seemed to work, all options are not setting anything in the required signature field..
So we have this C# code that uses the itext7 library to sign pdf's:
public static void SignPDFDocument(string src, string dest, string thumbprint)
{
GetStoreCertificates("MY", StoreLocation.CurrentUser);
cert = GetCertificateFromCollection(thumbprint);
var privateKey = Org.BouncyCastle.Security //I think this part needs "exportable" cert
.DotNetUtilities
.GetKeyPair(cert.GetRSAPrivateKey())
.Private;
var boucyCertParsed = new Org.BouncyCastle.X509
.X509CertificateParser()
.ReadCertificate(cert.GetRawCertData());
Org.BouncyCastle.X509
.X509Certificate[] bouncyCert = { boucyCertParsed };
PdfReader reader = new PdfReader(src);
StampingProperties stampProp = new StampingProperties();
stampProp.PreserveEncryption();
PdfSigner signer = new PdfSigner(
reader,
new FileStream(dest, FileMode.Create),
stampProp);
string digestAlgorithm = DigestAlgorithms.SHA256;
IExternalSignature signature = new PrivateKeySignature(privateKey, digestAlgorithm);
signer.SignDetached(signature, bouncyCert, null, null, null, 0, CryptoStandard.CADES);
reader.Close();
}
The only problem I have with this, is that the user, needs to have the certificate installed and marked as exportable for this to work. Is there any workaround?
I am trying to sign a Hash of PDF Document that i receive from server. But it is showing "At Least one signature is invalid" in Adobe Reader. Can anybody suggest what is wrong in following code. Right now im just try implemented a code in one project with separated class.
CODE
prepareHashToken.cs
public class prepareHashToken
{
public const string OUT_DIR = #"C:\Document\Doc1";
private class MyExternalSignatureContainer : IExternalSignatureContainer
{
protected byte[] sig;
protected ICollection<X509Certificate> chain;
public MyExternalSignatureContainer(byte[] sig, ICollection<X509Certificate> chain)
{
this.sig = sig;
this.chain = chain;
}
public byte[] Sign(Stream data)
{
return sig;
}
}
public byte[] EmptySignature(string src, string dest, IList<X509Certificate> chain)
{
PdfReader reader = new PdfReader(src);
FileStream os = new FileStream(dest, FileMode.Create);
PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0');
PdfSignatureAppearance appearance = stamper.SignatureAppearance;
AcroFields acro = reader.AcroFields;
List<string> sig_name = acro.GetSignatureNames();
string field = "signature_" + (sig_name.Count + 1);
Console.WriteLine("field : " + field);
appearance.SetVisibleSignature(new Rectangle(36, 748, 144, 780), 1, field);
appearance.Certificate = chain[0];
IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
MakeSignature.SignExternalContainer(appearance, external, 8192);
Stream inp = appearance.GetRangeStream();
Sha256Digest digest = new Sha256Digest();
byte[] hash = DigestAlgorithms.Digest(inp, "SHA256");
return hash;
}
public string createHash(string base64X509, string SRC, string TEMP)
{
Directory.CreateDirectory(OUT_DIR);
byte[] xx = Convert.FromBase64String(base64X509);
X509.X509Certificate2 x509 = new X509.X509Certificate2(xx);
X509Certificate m = DotNetUtilities.FromX509Certificate(x509);
IList<X509Certificate> chain = new List<X509Certificate>();
chain.Add(m);
prepareHashToken app = new prepareHashToken();
byte[] hh = app.EmptySignature(SRC, TEMP, chain);
string hashString = Convert.ToBase64String(hh);
return hashString;
}
}
SignHashToken.cs
public PDFInfo SignPDF(List<string> Hash64, string pinNumber)
{
using (Session session = slot.OpenSession(false))
{
session.Login(CKU.CKU_USER, pin);
List<ObjectAttribute> privateKeyAttributes = new List<ObjectAttribute>();
privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY));
privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_RSA));
List<ObjectHandle> foundPrivateKeys = session.FindAllObjects(privateKeyAttributes);
ObjectHandle privateKeyHandle = foundPrivateKeys[0];
var mechanisms = new Mechanism(CKM.CKM_SHA256_RSA_PKCS);
byte[] sourceData = Convert.FromBase64String(item);
byte[] signature = session.Sign(mechanisms, privateKeyHandle, sourceData);
result = Convert.ToBase64String(signature);
}
}
embedSignatureToken.cs
public class embedSignatureToken
{
public const string OUT_DIR = #"C:\Document\Doc1";
private class MyExternalSignatureContainer : IExternalSignatureContainer
{
protected byte[] sig;
protected ICollection<X509Certificate> chain;
public MyExternalSignatureContainer(byte[] sig, ICollection<X509Certificate> chain)
{
this.sig = sig;
this.chain = chain;
}
public byte[] Sign(Stream data)
{
return sig;
}
public void ModifySigningDictionary(PdfDictionary signDic) {}
}
public void CreateSignature(string src, string dest, byte[] hash, IList<X509Certificate> chain)
{
try
{
PdfReader reader = new PdfReader(src);
AcroFields acro = reader.AcroFields;
List<string> sig_name = acro.GetSignatureNames();
string field = "signature_" + (sig_name.Count);
FileStream os = new FileStream(dest, FileMode.Create);
IExternalSignatureContainer external = new MyExternalSignatureContainer(hash,chain);
MakeSignature.SignDeferred(reader, field, os, external);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
public void embedSigned(string base64X509, string hash64, string pin, string SRC, string TEMP, string DEST)
{
Directory.CreateDirectory(OUT_DIR);
byte[] xx = Convert.FromBase64String(base64X509);
X509.X509Certificate2 x509 = new X509.X509Certificate2(xx);
X509Certificate m = DotNetUtilities.FromX509Certificate(x509);
IList<X509Certificate> chain = new List<X509Certificate>();
chain.Add(m);
embedSignatureToken app = new embedSignatureToken();
byte[] hh = Convert.FromBase64String(hash64);
app.CreateSignature(TEMP, DEST, hh, chain);
}
}
Base64 of pre-sign and sign
Here i put a signed PDF
UPDATE
SignHashToken.cs
byte[] xx = Convert.FromBase64String(CD.CertData);
X509Certificate2 x509 = new X509Certificate2(xx);
X509Certificate m = DotNetUtilities.FromX509Certificate(x509);
IList<X509Certificate> chain = new List<X509Certificate>();
chain.Add(m);
byte[] hash = Convert.FromBase64String(item);
PrivateKeySignature signature = new PrivateKeySignature(/*Asymmetric key */, "SHA256");
string hashAlgorithm = signature.GetHashAlgorithm();
PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, false);
DateTime signingTime = DateTime.Now;
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null, CryptoStandard.CMS);
byte[] extSignature = signature.Sign(sh);
sgn.SetExternalDigest(extSignature, null, signature.GetEncryptionAlgorithm());
byte[] encod = sgn.GetEncodedPKCS7(hash, tsaClient, null, null, CryptoStandard.CMS);
result = Convert.ToBase64String(encod);
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.