Last active
March 11, 2019 06:16
-
-
Save alex-t0/f446ccb5ca5e8936b778 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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