Завершение, подписание и создание сообщения 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 дней - я, конечно, не эксперт по цифровой подписи или сертификатам.
Из того, что я узнал до сих пор - чтобы создать такое сообщение, я должен сделать:
- Подпишите
xml
со мнойprivate key
- Конверт с моей
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 - в нем есть все, что вам нужно для этого: