Skip to content

Instantly share code, notes, and snippets.

@alex-t0
Last active March 11, 2019 06:16
Show Gist options
  • Save alex-t0/f446ccb5ca5e8936b778 to your computer and use it in GitHub Desktop.
Save alex-t0/f446ccb5ca5e8936b778 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
using iTextSharp.text.pdf.security;
using NUnit.Framework;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.X509;
namespace itextsharp.tests.iTextSharp.text.signature
{
[TestFixture]
public class ClientSignatureTest
{
public const string KEYSTORE = @"..\..\resources\text\pdf\signature\ds-ks\ot.pfx";
public const string KEYSTORE_PUB = @"..\..\resources\text\pdf\signature\ds-ks\ot_pub.cer";
// public const String KEYSTORE = @"..\..\resources\text\pdf\signature\ds-ks\cert2.pfx";
public const string PASSWORD = "password";
// public const String Src = @"..\..\resources\text\pdf\signature\xfa.pdf";
public const string Src =
@"D:\projectsgit\iTextSharp\src\extras\itextsharp.tests\resources\text\pdf\signature\grusho.pdf";
public const string Dst =
@"D:\projectsgit\iTextSharp\src\extras\itextsharp.tests\resources\text\pdf\signature\grusho.signed.pdf";
public const string Dst2 =
@"D:\projectsgit\iTextSharp\src\extras\itextsharp.tests\resources\text\pdf\signature\grusho.signed2.pdf";
public const string CmpDir = @"..\..\resources\text\pdf\signature\ds-ks\";
public const string DestDir = @"signatures\ds-ks\";
public const string HashAlg = "SHA1";
public const string SignAlg = "SHA-1withRSA";
private class SignatureDTO
{
public byte[] AuthenticatedAttributeBytes { get; set; }
public byte[] Hash { get; set; }
public PdfSignatureAppearance SignatureAppearance { get; set; }
public PdfPKCS7 Sign { get; set; }
public DateTime Now { get; set; }
public Stream Stream { get; set; }
}
private AsymmetricKeyEntry LoadCertificateChainFromKeyStorage()
{
MemoryStream ks = new MemoryStream();
using (FileStream reader = new FileStream(KEYSTORE, FileMode.Open))
{
byte[] buffer = new byte[reader.Length];
reader.Read(buffer, 0, (int)reader.Length);
ks.Write(buffer, 0, buffer.Length);
ks.Position = 0;
}
Pkcs12Store store = new Pkcs12Store(ks, PASSWORD.ToCharArray());
String alias = "";
List<X509Certificate> chain = new List<X509Certificate>();
// searching for private key
foreach (string al in store.Aliases)
{
if (store.IsKeyEntry(al) && store.GetKey(al).Key.IsPrivate)
{
alias = al;
break;
}
}
foreach (X509CertificateEntry c in store.GetCertificateChain(alias)) // may be return too
chain.Add(c.Certificate);
AsymmetricKeyEntry pk = store.GetKey(alias);
return pk;
//return chain;
}
[Test]
public void SignTest()
{
SignatureDTO result = ServerSidePrepare();
byte[] signedData = ClientSideSign(result.AuthenticatedAttributeBytes);
SaveSignedDocumentOnServer(result, signedData);
}
private SignatureDTO ServerSidePrepare()
{
// get public key chain
X509Certificate cert = new X509CertificateParser().ReadCertificate(
File.ReadAllBytes(KEYSTORE_PUB)); // сервер у нас и так имеет публичный ключ пользователя
PdfReader reader = new PdfReader(Src); // считаем что файл перед подписью есть на сервере
// MemoryStream ms = new MemoryStream();
// var ms = File.Create(Dst);
FileStream os = new FileStream(Dst, FileMode.Create);
PdfStamper stamper = PdfStamper.CreateSignature(reader, os, '\0');
PdfSignatureAppearance sap = stamper.SignatureAppearance;
sap.Reason = "reason";
sap.Location = "location";
sap.Certificate = cert;
sap.SetVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
dic.Reason = sap.Reason;
dic.Location = sap.Location;
dic.Contact = sap.Contact;
// dic.Date = new PdfDate(sap.SignDate);
dic.Date = new PdfDate(new DateTime(2015, 7, 26, 17, 5, 25));
sap.CryptoDictionary = dic;
Dictionary<PdfName, int> exc = new Dictionary<PdfName, int>
{
{ PdfName.CONTENTS, 8192 * 2 + 2 }
// не подписываемые данные (исключения). Зависит от того, внедрены ли CRL и ответы OCSP в документе.
// PdfName.CONTENTS здесь должен быть обязательно
};
sap.PreClose(exc);
var sgn = new PdfPKCS7(null, new[] { cert }, HashAlg, false);
Stream data = sap.GetRangeStream();
// byte[] hash = DigestAlgorithms.Digest(data, externalDigest.getMessageDigest("SHA256"));
byte[] messageHash = DigestAlgorithms.Digest(data, HashAlg); // hash calculated. Sending it to client.
var now = DateTime.Now;
return new SignatureDTO
{
Hash = messageHash,
AuthenticatedAttributeBytes = sgn.getAuthenticatedAttributeBytes(messageHash, now, null, null, CryptoStandard.CMS),
Now = now,
SignatureAppearance = sap,
Sign = sgn,
Stream = os
};
}
private byte[] ClientSideSign(byte[] hash)
{
AsymmetricKeyEntry pk = LoadCertificateChainFromKeyStorage();
// we sign the hash received from the server
ISigner sig = SignerUtilities.GetSigner(SignAlg);
sig.Init(true, pk.Key);
sig.BlockUpdate(hash, 0, hash.Length);
return sig.GenerateSignature();
}
private void SaveSignedDocumentOnServer(SignatureDTO result, byte[] signature)
{
result.Sign.SetExternalDigest(signature, null, "RSA");
byte[] encodedSig = result.Sign.GetEncodedPKCS7(result.Hash, result.Now, null, null, null, CryptoStandard.CMS);
byte[] paddedSig = new byte[8192];
Array.Copy(encodedSig, 0, paddedSig, 0, encodedSig.Length);
PdfDictionary pdfDic = new PdfDictionary();
pdfDic.Put(PdfName.CONTENTS, new PdfString(paddedSig).SetHexWriting(true));
result.SignatureAppearance.Close(pdfDic); // use try/catch in real app
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment