Подписание PDF через iText sharp с использованием хэша и подписи из внешнего веб-сервиса - PullRequest
0 голосов
/ 18 февраля 2019

Я пытаюсь подписать PDF через внешний веб-сервис.Веб-служба получает хеш-код в формате SHA-256, а после подписания служба возвращает подпись с шестнадцатеричным дайджестом.

В данный момент я застрял, пытаясь использовать библиотеку iText 7 (c #), пытаясь подписать документ значениями подписи.Мне удалось подписать pdf-документ с помощью itext с использованием локального самоподписанного сертификата, но еще не с внешним контейнером. Adobe Acrobat всегда сообщает о проблемах с декодированием BER, что заставляет меня думать, что что-то идет не так с анализомЗначения моей стороны или подписи неверны.

Шаги подписи с примерами программного обеспечения следующие:

  1. Сначала добавьте пустую подпись, подпишите этот документ и затем сгенерируйтехеш (SHA-256).

    public static void CalculateHash(Stream fileStream, out byte[] docBytesHash, out byte[] preSignedBytes)
    {
        PdfName filter = PdfName.Adobe_PPKLite;
        PdfName subFilter = PdfName.Adbe_pkcs7_detached;
        int estimatedSize = 8192;
        PdfReader reader = new PdfReader(fileStream);
        MemoryStream baos = new MemoryStream();
        PdfSigner signer = new PdfSigner(reader, baos, new StampingProperties());
        signer.SetCertificationLevel(PdfSigner.CERTIFIED_NO_CHANGES_ALLOWED);
        PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
        appearance.SetLayer2Text("Signature field which signing is deferred.").SetPageRect(new Rectangle(36, 600,
            200, 100)).SetPageNumber(1);
        signer.SetFieldName("DeferredSignature1");
        DigestCalcBlankSigner external = new DigestCalcBlankSigner(filter, subFilter);
        //IExternalSignatureContainer external = new ExternalBlankSignatureContainer(filter, subFilter);
        signer.SignExternalContainer(external, estimatedSize);
    
        docBytesHash = external.GetDocBytesHash();
        preSignedBytes = baos.ToArray();
    }
    
  2. Хеш конвертируется в bytearray и отправляется на веб-сервис

    public static string ByteArrayToString(byte[] array)
    {
        StringBuilder stringBuilder = new StringBuilder();
    
        foreach (byte b in array)
            stringBuilder.AppendFormat("{0:x2}", b);
    
        return stringBuilder.ToString();
    }
    
  3. Веб-сервисотвечает данным подписных пример строки данных

"473e8e376ca067f3c806902f718be21bf8a788ddbd31786b14fc47678596d6993a4f1ecb80e091f93af4820a75d97aee4b1a15c4a7914b4f881ca86e5d06b429b176d5b663c986c9ce2824333c98e0b5def0af53178b9ce38aa4efaa0adce2eee409487fb7fecf58e4c5bfcc3a0d083e35a83f9c722c73b78784e9990b6f00b89ae4934714c92b34699ce00ad5a662d0058bd613021449e9d09ab2d25376230de75591ab6ce4b5c5d24216794e8c871a690b4e19011621d41c66f4b0048abc9f2d4449072ee9e70c30dcf9b8b5a1ea8ee3a285163c2c5b293a3798a4a13ca59e83c66d9148d519b55e13643a3a7e0794732b92f50c1424f7be5774f67e910076"

Затем строка преобразуется в bytearray со следующей функцией

public static byte[] StringToByteArray(String hex)
{
    int NumberChars = hex.Length;
    byte[] bytes = new byte[NumberChars / 2];
    for (int i = 0; i < NumberChars; i += 2)
        bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
    return bytes;
}

Контейнер подписи теперь создается с использованием сигнатуры байтового массива, и документподписанный с использованием контейнера и предварительно подписанных байтов документа

using (System.IO.FileStream outStream = new System.IO.FileStream(System.IO.Path.GetTempPath() + "tempout.pdf", System.IO.FileMode.Create))
{
    PdfName filter = PdfName.Adobe_PPKLite;
    PdfName subFilter = PdfName.Adbe_pkcs7_detached;

    MemoryStream baos = new MemoryStream();
    fileStream.CopyTo(baos); //temp

    byte[] preSignedBytes = baos.ToArray();



    ReadySignatureSigner extSigContainer = new ReadySignatureSigner(StringHelper.StringToByteArray(signature.data.attributes.signature)); //now use external provider signature                                               
    PdfDocument docToSign = new PdfDocument(new PdfReader(new MemoryStream(preSignedBytes)));
    PdfSigner.SignDeferred(docToSign, "DeferredSignature1", outStream, extSigContainer);
    docToSign.Close();
}

Я также добавил исходный PDF, неподписанный PDF и подписанный PDF для ссылки в приведенной ниже ссылке.Я надеюсь, что кто-то может взглянуть на содержимое и, возможно, сказать мне, что здесь происходит не так.Я уже много часов провожу в Интернете в поисках решений, но пока ничего не найдено.

С уважением, Джос Эйлерс

pdf

Благодаря ответуmkl Я переписал код для создания контейнера PKCS следующим образом, сначала создайте хэш и предварительно назначенные байты и отправьте его в службу подписи:

        Org.BouncyCastle.X509.X509Certificate[] signChain = new Org.BouncyCastle.X509.X509Certificate[1];
        signChain[0] = Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(signingcert);


        PdfName filter = PdfName.Adobe_PPKLite;
        PdfName subFilter = PdfName.Adbe_pkcs7_detached;
        int estimatedSize = 8192;
        PdfReader reader = new PdfReader(memoryStream);
        MemoryStream baos = new MemoryStream();
        PdfSigner signer = new PdfSigner(reader, baos, new StampingProperties());
        signer.SetCertificationLevel(PdfSigner.CERTIFIED_NO_CHANGES_ALLOWED);
        PdfSignatureAppearance appearance = signer.GetSignatureAppearance();
        appearance.SetLayer2Text("Signature field which signing is deferred.").SetPageRect(new Rectangle(36, 600,
            200, 100)).SetPageNumber(1);
        signer.SetFieldName("DeferredSignature1");
        DigestCalcBlankSigner external = new DigestCalcBlankSigner(filter, subFilter);

        signer.SignExternalContainer(external, estimatedSize);

        var signatureContainer = new PdfPKCS7(null, signChain, HASH_ALGORITHM, true);

        preSignedBytes = baos.ToArray();


        sh = signatureContainer.GetAuthenticatedAttributeBytes(preSignedBytes, null, null, CryptoStandard.CMS);

Затем я использую возвращенную подпись и создаю новый контейнер PKCS7.и выполните отложенную подпись следующим образом (упомянутый хеш - это байтовый массив sh из предыдущего раздела):

        var signatureContainer = new PdfPKCS7(null, signChain, HASH_ALGORITHM, true);

        signatureContainer.SetExternalDigest(StringHelper.StringToByteArray(signature.data.attributes.signature), null, "RSA");

        byte[] encodedSignature = signatureContainer.GetEncodedPKCS7(hash, null, null, null, CryptoStandard.CMS);
        ReadySignatureSigner extSigContainer = new ReadySignatureSigner(encodedSignature); //now use external provider signature
        memoryStream.Position = 0;
        PdfDocument docToSign = new PdfDocument(new PdfReader(memoryStream));

        MemoryStream memoryOutStream = new MemoryStream();
        PdfSigner.SignDeferred(docToSign, "DeferredSignature1", memoryOutStream, extSigContainer);

В данный момент сертификат отображается в pdf, но теперь у меня все еще есть ошибка, что документ былЯ немного застрял на данный момент, какие-либо предложения?Также мне любопытно, не требуется ли здесь использование закрытого ключа (я еще не получил ответа от провайдера, если это необходимо).

Есть ли у кого-нибудь какие-либо идеи, используемый веб-сервис отDigidentity

...