Завершение, подписание и создание сообщения PKCS#7 DER с сертификатом.pfx

Моя задача - создать данные с цифровой подписью в формате PKCS#7 version 1.5 (RFC 2315) DER (ITU-T Recommendation X.690) - в принципе ANSI.1 с X.509 signature?

сообщение должно удовлетворять следующему:

  • должен быть типа signedData
  • должен содержать подписанные данные
  • должен содержать сертификат подписавшего
  • должен содержать одну цифровую подпись

Мой код следующий

static void Main(string[] args)
{

    string pfx = @"C:\Users\marek\Downloads\mfcr\marek-pfx.pfx";
    string xml = @"C:\Users\marek\Downloads\mfcr\souhr20141.xml";
    X509Certificate2 cert = new X509Certificate2(pfx, "thepass");

    byte[] publicBytes = cert.RawData;

    //var f = new FileStream(xml, System.IO.FileMode.Open);
    var fileContent = System.IO.File.ReadAllBytes(xml);

    char[] cArray = System.Text.Encoding.ASCII.GetString(fileContent).ToCharArray();
    RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PrivateKey;

    byte[] signedData = rsa.SignData(new System.Text.UTF8Encoding().GetBytes(cArray), new SHA1CryptoServiceProvider());

    RSACryptoServiceProvider rsa2 = (RSACryptoServiceProvider)new X509Certificate2(publicBytes).PublicKey.Key;

    var dataGenerator = new CmsEnvelopedDataStreamGenerator();
    bool verified = rsa2.VerifyData(new System.Text.UTF8Encoding().GetBytes(cArray), new SHA1CryptoServiceProvider(), signedData);

    File.WriteAllBytes(@"C:\Users\marek\Downloads\mfcr\Foo.p7b", signedData);
 }

WebService что я посылаю Foo.p7b отвечает: Файл не соответствует ожидаемому формату PKCS7(DER).

Этот код для отправки HttpWebRequest:

static void Main(string[] args)
    {
        try
        {

            string fileName = (@"C:\Users\marek\Downloads\mfcr\Foo.p7b");
            WebResponse rsp = null;
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("https://adisepo.mfcr.cz/adistc/epo_podani");
            request.ClientCertificates.Add(new X509Certificate(pfx,"thepass"));
            request.Method = "POST";
            request.ContentType = "application/pkcs7-signature";
            request.Credentials = CredentialCache.DefaultNetworkCredentials;
            var encoder = new UTF8Encoding();
            var reqStream = request.GetRequestStream();
            StreamWriter writer = new StreamWriter(request.GetRequestStream());
            // Write the XML text into the stream
            writer.WriteLine(GetTextFromXMLFile(fileName));
            writer.Close();
            reqStream.Close();
            rsp = request.GetResponse();
            StreamReader sr = new StreamReader(rsp.GetResponseStream());
            string result = sr.ReadToEnd();
            sr.Close();
            Console.Write("\n příkaz odeslán  \n");
            Console.Write(result);
            Console.ReadLine();
            Console.Read();
        }
        catch (Exception ex)
        { Console.WriteLine(ex.ToString());
        Console.ReadLine();
        }

    }
    private static string GetTextFromXMLFile(string file)
    {
        StreamReader reader = new StreamReader(file);
        string ret = reader.ReadToEnd();
        reader.Close();
        return ret;
    }
}

Я борюсь с этой проблемой почти 5 дней - я, конечно, не эксперт по цифровой подписи или сертификатам.

Из того, что я узнал до сих пор - чтобы создать такое сообщение, я должен сделать:

  1. Подпишите xml со мной private key
  2. Конверт с моей public key

Но как получатель может проверить, являюсь ли я настоящим отправителем? Должен ли я добавить к HttpWebRequest параметр с моим сертификатом? Или этот шаг 2 - Достаточно конвертировать сообщение, чтобы он это проверил?

Спасибо всем за ваше время и ответы.

2 ответа

Решение

Ваш код пытается цифровой подписи байтового представления XML, но подписывание XML требует дополнительной обработки перед подписанием. Например, XML требует канонизации (или подписанное сообщение может быть введено с неподписанными данными), и существует специальный формат для конвертов с подписью. Я не знаю, какой именно метод использует Danovy Portal, но если он использует стандартный способ, вы можете перейти по ссылкам ниже и подписать свои данные.

MSDN: Как: подписывать XML-документы с помощью цифровых подписей

Как выглядят конверты в подписи

И просто для информации (не думаю, что вам действительно нужно это прочитать) Спецификация W3C Xml Signature

РЕДАКТИРОВАТЬ: чтобы отправить сообщение pkcs#7 изменить код. При генерации

        ContentInfo contentInfo = new ContentInfo(new System.Text.UTF8Encoding().GetBytes(cArray));
        SignedCms cms = new SignedCms (contentInfo);
        CmsSigner signer = new CmsSigner (cert);
        cms.ComputeSignature (signer);
        byte[] pkcs7=cms.Encode ();
        File.WriteAllBytes(@"../../Foo.p7b", pkcs7);

Когда отправить:

            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("https://adisepo.mfcr.cz/adistc/epo_podani");
            //we don't need to add certificate to POST
    //      request.ClientCertificates.Add(new X509Certificate(pfx,"test"));
            request.Method = "POST";
            request.ContentType = "application/pkcs7-signature";
            request.Credentials = CredentialCache.DefaultNetworkCredentials;
            var encoder = new UTF8Encoding();
            using (var reqStream = request.GetRequestStream())
            {
                // Write pkcs#7 into the stream
                byte[] pkcs = File.ReadAllBytes(@"../../Foo.p7b");
                reqStream.Write(pkcs, 0, pkcs.Length);
            }
            rsp = request.GetResponse();

Взгляните на BouncyCastle - в нем есть все, что вам нужно для этого:

http://www.bouncycastle.org/csharp/

Другие вопросы по тегам