I have a PDF document that needs to be both digitally signed and encrypted.
I am using ABCPDF and when I apply the digital signature to a document that is encrypted the signature gets invalidated.
The error that is provided by Adobe Acrobat Reader is: "There have been changes made to this document that invalidate the signature"
Source code:
using (Doc doc = new Doc())
{
doc.Read(pdfPath);
if (options.Encrypt)
{
doc.Encryption.Type = 4;
doc.Encryption.SetCryptMethods(CryptMethodType.AESV3);
doc.Encryption.Password = Encryption.Decrypt(options.UserPassword, PdfSecurityOptions.EncryptionPassword);
doc.Encryption.OwnerPassword = Encryption.Decrypt(options.OwnerPassword, PdfSecurityOptions.EncryptionPassword);
}
if (options.Sign)
{
byte[] bytes = Convert.FromBase64String(options.Certificate);
X509Certificate2 certificate = new X509Certificate2(bytes, Encryption.Decrypt(options.CertificatePassword, PdfSecurityOptions.EncryptionPassword), X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
PdfUtils.DigitallySign(
doc,
options.SignatureText,
options.Rectangle,
certificate
);
}
doc.Save(savePath);
}
I have tried:
Apply the encryption before the signing
Apply the encryption after the signing
Apply the encryption, save the document and then load and sign it
You can't perform a signature after another it's done; doing so, you will corrupt first signature.
To avoid this, you have to use incremental updates, each time a signature is done.
Check out Abcpdf Online documentation
http://www.websupergoo.com/helppdfnet/source/6-abcpdf.objects/signature/1-methods/commit.htm
I have tested your code, and the signature appears ok. I think that you have an issue in the way you're adding the field. I see you're using the Abcpdf example code. Maybe you need some changes on it. Can you provide a pdf sample?
Related
I am have digitally signed a pdf using digital token attached in pc using libarary itext sharp to append same, when i open same in adobe reader it shows revocation can not be performed and when i see details then it shows that one of the issuers certificate's revocation is not checked with error : error encountered while BER decoding.
path to my plain signed pdf: https://www.sendspace.com/file/vqgl53
As a solution i thought if i can add CRL information itself in document(my plain signed pdf) then i won't face this problem. So i added code mentioned in this ans : I want to sign a pdf document with ITextSharp and return ltv pdf enabled file
but I am getting exception on line : addLtvForChain(null, ocspClient, crlClient, getCrlHashKey(crlBytes));
IN SUBMETHOD getCrlHashKey ON FIRST LINE : X509Crl crl = new X509Crl(CertificateList.GetInstance(crlBytes));
Exception says :
Unknown object in GetInstance:
Org.BouncyCastle.Asn1.DerApplicationSpecific Parameter name: obj
Kindly suggest further.
Extending AdobeLtvEnabling
The cause of the exception is that for one certificate the associated CRL is base64 encoded which the AdobeLtvEnabling class does not expect (the expectation here is to retrieve a binary version, no decoding required).
You can extend the AdobeLtvEnabling as follows to also be able to handle base64 encoded CRLs: search the AdobeLtvEnabling method addLtvForChain and replace the CRL handling loop
Console.WriteLine(" with {0} CRLs\n", crl.Count);
foreach (byte[] crlBytes in crl)
{
validationData.crls.Add(crlBytes);
addLtvForChain(null, ocspClient, crlClient, getCrlHashKey(crlBytes));
}
with this:
Console.WriteLine(" with {0} CRLs\n", crl.Count);
foreach (byte[] crlBytes in crl)
{
PdfName hashKey = null;
byte[] bytes = null;
try
{
hashKey = getCrlHashKey(crlBytes);
bytes = crlBytes;
}
catch (Exception e)
{
Console.WriteLine(" CRL decoding exception, assuming Base64 encoding, trying to decode - {0}\n", e.Message);
bytes = Convert.FromBase64String(new String(Encoding.Default.GetChars(crlBytes)));
hashKey = getCrlHashKey(bytes);
}
validationData.crls.Add(bytes);
addLtvForChain(null, ocspClient, crlClient, hashKey);
}
Your signature, though
While revocation of the other non-root certificates in question now refers to embedded CRLs, for one certificate there still is an issue, the revocation tab for "SafeScrypt sub-CA for RCAI Class 2 2014 (SAFESCRYPTONLINE_15)" in Adobe Reader shows
CRL processing error
Issuer: cn=SafeScrypt CA 2014, houseIdentifier=II Floor, Tidel Park, street=No.4, Rajiv Gandhi Salai, Taramani, Chennai, st=Tamil Nadu, postalCode=600 113, ou=Certifying Authority, o=Sify Technologies Limited, c=IN
This update: 20180303183000Z
Next update: 20190303182959Z
CRL has expired or is not yet valid
Indeed, a CRL with a next update value of 20190303182959Z is expired and, therefore, cannot be used now for validation without appropriate POEs. So indeed, Adobe Reader ist completely correct in stating that based on that CRL (currently served by the PKI) it cannot determine non-Revocation.
But could it from other information? Well, there is an AIA attribute in the certificate for an OCSP responder that could alternatively be used. But an attempt to use it fails, http://ocsp.safescrypt.com currently accepts no requests. So this is no actual alternative.
All in all this makes the quality of service of this CA appear questionable. If this state continues, you might want to switch to a different CA.
I have a .xml file that has to be signed with digital certificate in format of PKCS#7 version 1.5 (RFC 2315) and DER (ITU-T Recommendation X.690
That .xml will be send to a govt. WebService that only accept the format I mentioned upwards.
What I'm able to do - thanks to this website is digitaly sign .xml with the .pfx file that I generated with Certificate Export Wizard explained below. The class that I'm using to sign is down on mentioned website or here.
From what I tried to understand so far I will need to sign the .xml with .pfx file according to X.690 standards but I'm only able to access this namespace:
using System.Security.Cryptography.X509Certificates;
which is obviously for X.509 format.
Note:
There are several things I'm confused about - to export the certificate into .pfx I'm using Internet Explorer - Certificate Export Wizard from there I'm able to:
Yes - export private keys - then it will be generated in PKCS#12 but .pfx
No - do not export private keys - Certificate according to standards Cryptographic Message Syntax Standard - PKCS#7 that I guess I need but I would receive .p7b file
I must say that I am a newbie in certificates and digital signatures so I'm not even sure if I'm correctly exporting the certificat and the second thing is how I can sign according to X.690 standards.
May I know how to sign according to X.690 format please?
Thank you everyone for your time and replies.
My code is following:
bool res = false;
try
{
byte[] certBytes = System.IO.File.ReadAllBytes(pvkPath);
X509Certificate2 cert = new X509Certificate2(certBytes, certPass);
XmlDocument doc = new XmlDocument();
doc.Load(xmlPath);
// sign the document with the private key of the certificate
XmlDsig.SignXml(doc, cert);
// save the document
doc.Save(xmlSavePath);
// verify that the document has a signature
bool hasSignature = XmlDsig.HasSignatureElement(doc);
return res = true;
}
catch (Exception)
{ return res; }
foDigital signature in PKCS#7/CMS format is blob that contains your XML data + signer's x509 public key certificate (.cer file) + Digital signature. The entire blob is encoded in ASN 1.0 format(X690). There may be variations in the blob due to the absence of original data or the signer certificate, This variation is called detached signatures.
Digital signature is generated when you sign your xml file with the signer's private key. This signature can be verified when you send your XML file + signer's public key (as X509 .cer file)+ digital signature to the party who are interested in verifying it.
PFX/p12 is a container that contains both the signer's private key and public key. You get this key pair from either your government or your government approved key custodians. You will then use this PFX to perform digital signature.
PKCS#7 is supported by cryptoAPI.
The above are the basics. This should allow you make your queries more clearly.
I want to read the signature from Usb token safenet (alladin etoken pro 72 k(Java)) and attach to pdf. I dont know how to do this. In previously they given an option to export .pfx file. Now they are giving an option to export .cer file. When i googled i get this code. When i run this code works it prompts the password of the token after enter the password i can able to verify the signature but i dont know how to attach the signature to the pdf. please guide me whether i am in correct direction or not. I am using c# language
private void btnGenpdfdigitalSignature_Click(object sender, EventArgs e)
{
try
{
// Cert myCert = null;
// Sign text
byte[] signature = Sign("Test", "Name of the signature person");
// Verify signature. Testcert.cer corresponds to "cn=my cert subject"
if (Verify("Test", signature,"jai.cer"))
{
}
else
{
Console.WriteLine("ERROR: Signature not valid!");
}
}
catch (Exception ex)
{
Console.WriteLine("EXCEPTION: " + ex.Message);
}
// Console.ReadKey();
}
static byte[] Sign(string text, string certSubject)
{
// Access Personal (MY) certificate store of current user
X509Store my = new X509Store(StoreName.My, StoreLocation.CurrentUser);
my.Open(OpenFlags.ReadOnly);
// Find the certificate we'll use to sign
RSACryptoServiceProvider csp = null;
foreach (X509Certificate2 cert in my.Certificates)
{
if (cert.Subject.Contains(certSubject))
{
// We found it.
// Get its associated CSP and private key
csp = (RSACryptoServiceProvider)cert.PrivateKey;
}
}
if (csp == null)
{
throw new Exception("No valid cert was found");
}
// Hash the data
SHA1Managed sha1 = new SHA1Managed();
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] data = encoding.GetBytes(text);
byte[] hash = sha1.ComputeHash(data);
// Sign the hash
return csp.SignHash(hash, CryptoConfig.MapNameToOID("Test"));
}
public bool Verify(string text, byte[] signature, string certPath)
{
// Load the certificate we'll use to verify the signature from a file
cert = new X509Certificate2(certPath);
// Note:
// If we want to use the client cert in an ASP.NET app, we may use something like this instead:
// X509Certificate2 cert = new X509Certificate2(Request.ClientCertificate.Certificate);
// Get its associated CSP and public key
RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert.PublicKey.Key;
// Hash the data
SHA1Managed sha1 = new SHA1Managed();
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] data = encoding.GetBytes(text);
byte[] hash = sha1.ComputeHash(data);
// Verify the signature with the hash
return csp.VerifyHash(hash, CryptoConfig.MapNameToOID("Test"), signature);
}
As it seems, you need to sign the PDF with the key stored on USB token.
First thing to figure out is what signing format to use. PDFs can be signed according to PDF specification (which includes digital signing), PAdES (extended PDF signing), or as a generic binary data using CMS/CAdES or even XMLDSig/XAdES.
Assuming you need to sign the PDF according to PDF specification, you most likely need to use some library such as our PDFBlackbox or iText (watch the license and pricing!).
Back to technical side -- .cer file that you mentioned contains only public part of the certificate, and the private key, used for signing, can not usually be extracted from the security device such as USB token. The PDF signing library must support calling the USB token via some programming interface (our PDFBlackbox supports both CryptoAPI and PKCS#11) to have it sign the hash of the data.
If you want to sign PDF with embedded signature you would most likely need to use PDF processing library such as iTextSharp which will embed the signature into the structure of PDF document. Bruno Lowagie from iText Software has written white paper called "Digital Signatures for PDF documents" which is a great source of information about digital signatures in PDF documents.
If you want to use your application also on platforms other than Windows then you should take a look at my Pkcs11Interop.PDF library that extends iTextSharp with the ability to digitally sign PDF document with the private key stored on almost any PKCS#11 compatible device (smartcard, HSM, etc.).
The great thing about iTextSharp and Pkcs11Interop.PDF libraries is they are available under the dual license model so if you are able to comply with the terms of AGPL license then you can use both libraries for free.
I'm writing a service where I pre-sign a pdf file with an empty container, take a hash of a byte range from the pdf file and send it to another service, that will allow a user to sign the hash using a mobile phone. I get back a certificate that I will inject into the signature container in the pre-signed pdf file.
Everything works so far, except that I want to have visible signatures in the document. The visible signatures require the certificate to get information from it (like who signed it and when) but it seems that I need to add the visible signature before I actually sign it.
My question is therefore, is it possible to change the appearance of the signature within the document after signing it? The visible signature image seems to be outside the signed byte range of the document.
I am pre-signing the file with a blank container:
IExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ETSI_CADES_DETACHED);
MakeSignature.SignExternalContainer(_sap, external, 8192 * 2);
Where _sap is the SignatureAppearance from a stamper initialized the following way:
PdfStamper stamper = PdfStamper.CreateSignature(reader, baos, '\0', null, true);
The returning a hash of the byterange from the SignatureAppearance:
Stream data = _sap.GetRangeStream();
_hash = DigestAlgorithms.Digest(data, DigestAlgorithms.SHA1);
_hashStr = Convert.ToBase64String(_hash);
return _hashStr;
And then when I get the certification I create a custom container:
IExternalSignatureContainer container = new CustomContainer(cert);
MakeSignature.SignDeferred(reader, _signatureFieldName, baos, container);
The custom container doesn't do anything except to return the cert in it's public byte[] Sign(Stream data) method.
The signing itself works, the digital signatures are valid but I just need to change the text of the visible signature itself. I would think that it's possible, since the visible signature doesn't actually have anything to do with the certificate itself, it's just a convenience to display the name from the certificate, especially with multiple signatures.
You were right when you wrote: it seems that I need to add the visible signature before I actually sign it. You were wrong when you wrote: I would think that it's possible.
The appearance of the signature consists of dictionaries and streams stored in the PDF document. These objects are part of the bytes that are hashed and subsequently signed. You can't change these bytes without breaking the signature.
I am working on a feature that needs me to digitally sign a short string in PHP, and verify the string's signature in C#.
I would really like to use openssl_sign in PHP, because of its simplicity, but all the information I can find on Google indicates that this will not work.
There are some external libraries that claim to do this well, however as this is a hobby project I would rather not purchase such a library.
So what are the alternatives here? Full interoperability between C# and PHP is required. Libraries besides OpenSSL can be used.
I've done something very similar using Bouncy Castle Crypto APIs. It appears PHP openssl_sign uses SHA1 by default. If you are using anything other than the default you'll need to change the algorithm parameter for GetSigner.
string base64pubkey = "<!-- BASE64 representation of your pubkey from open ssl -->";
RsaKeyParameters pubKey = PublicKeyFactory.CreateKey(Convert.FromBase64String(base64pubkey)) as RsaKeyParameters;
byte[] signature = Convert.FromBase64String("<!-- BASE64 representation of your sig -->");
byte[] message = Encoding.ASCII.GetBytes("Something that has been signed");
ISigner sig = SignerUtilities.GetSigner("SHA1WithRSAEncryption");
sig.Init(false, pubKey);
sig.BlockUpdate(message, 0, message.Length);
if (sig.VerifySignature(signature))
{
Console.WriteLine("all good!");
}
You may use to check the digital signature smth like this:
string publicKey = "some key";
// Verifying Step 1: Create the digital signature algorithm object
DSACryptoServiceProvider verifier = new DSACryptoServiceProvider();
// Verifying Step 2: Import the signature and public key.
verifier.FromXmlString(publicKey);
// Verifying Step 3: Store the data to be verified in a byte array
FileStream file = new FileStream(args[0], FileMode.Open, FileAccess.Read);
BinaryReader reader = new BinaryReader(file2);
byte[] data = reader.ReadBytes((int)file2.Length);
// Verifying Step 4: Call the VerifyData method
if (verifier.VerifyData(data, signature))
Console.WriteLine("Signature verified");
else
Console.WriteLine("Signature NOT verified");
reader.Close();
file.Close();
Is there a reason you need something as complex as SSL signing? Can't you just use a simple one-way hash like MD5/SHA-1 on the string? If all you're looking for is verification that the string wasn't tampered with, that should be sufficient.
So looking at this - this guy appears to have asymmetric signing and encrypting working between PHP and C#. Signing should not be a problem, SHA* and MD* are standard, and so it's very very unlikely that is going to not be compatible (although you should be looking at SHA256 as MD* and SHA1 are deprecated due to vulnerabilities)
We're missing some context as to why you need to sign it. You may not need to.
The important question is: what guarantees do you need from your data?
If all you need to do is verify the integrity of the data, a hash will do the job. If you need to verify where it's coming from, you need to sign it. If you need both, hash it, concatenate the payload with the hash, and sign the whole thing.
Regarding cross-platform libraries... you really should need to worry about it. A SHA1 is a SHA1 is a SHA1, no matter which library generated it. Same thing with generating and verifying digital signatures. Use what's easiest in PHP and use what's easiest in C#. If they're both set up correctly you shouldn't need to worry about it.