Validation of electronic signatures in C # using CRIPTO PRO

 3r33333. 3r3-31. Continuing the conversation on the topic of electronic signatures (hereinafter referred to as ED), it is necessary to say about verification. In the previous article I examined the more difficult part of the task - the creation of a signature. This article is somewhat simpler. Most of the code is an adaptation of examples from the CRYPTO PRO .NET SDK. First of all, we will check signatures according to GOST R ???-2001 and GOST R ???-201? for which we need the CRIPTO PRO. 3r33333.  3r33333.
3r33333.  3r33333. The task for us is divided into 3 parts: a separated signature, a signature in PDF and a signature in MS Word. 3r33333.  3r33333. 3r33333.  3r33333. Verification of the separated signature:
 3r33333. 3r33333.  3r33333. 3r3185. 3r3186. //dataFileRawBytes is an array of bytes of the signed file
ContentInfo contentInfo = new ContentInfo (dataFileRawBytes); 3r33333. SignedCms signedCms = new SignedCms (contentInfo, true); 3r33333. //signatureFileRawBytes is an array of signature bytes
signedCms.Decode (signatureFileRawBytes); 3r33333. 3r33333. if (signedCms.SignerInfos.Count == 0)
{
//processing in the absence of signatures
}
3r33333. foreach (SignerInfo signerInfo in signedCms.SignerInfos)
{
//get the signing date
Datetime? signDate =
(SignerInfo. .SigningTime; 3r33333. bool valid; 3r33333. try
{
signerInfo.CheckSignature (true); 3r33333. valid = true; 3r33333.}
catch (CryptographicException exc)
{
valid = false; 3r33333.}
3r33333. //get the certificate to check. It is useful when checking the certificate
X509Certificate2 certificate = signerInfo.Certificate; 3r33333. 3r33347.
3r33333.  3r33333. Comments are all in the code, I’ll only draw your attention to the certificate, we will need it further, because certificate we will check separately. 3r33333.  3r33333. 3r33333.  3r33333. Well, do not forget to wrap everything in try-catch and others using. In the example, I intentionally do not do this to reduce the volume of 3r33353.  3r33333. 3r33333.  3r33333. Validation of the signature in PDF. Here we need iTextSharp (actual version at the time of writing ???): 3r333335.  3r33333. 3r33333.  3r33333. 3r3185. 3r3186. using (MemoryStream fileStream = new MemoryStream (dataFileRawBytes))
using (PdfReader pdfReader = new PdfReader (fileStream))
{
AcroFields acroFields = pdfReader.AcroFields; 3r33333. //we get the names of the containers of signatures
List
signatureNames = acroFields.GetSignatureNames (); 3r33333. if (! signatureNames.Any ())
{
//processing of the absence of EB
}
3r33333. foreach (string signatureName in signatureNames)
{
//followed by the magic of getting the signature from the
container. PdfDictionary singleSignature = acroFields.GetSignatureDictionary (signatureName); 3r33333. PdfString asString1 = singleSignature.GetAsString (PdfName.CONTENTS); 3r33333. byte[]signatureBytes = asString1.GetOriginalBytes (); 3r33333. 3r33333. RandomAccessFileOrArray safeFile = pdfReader.SafeFile; 3r33333. 3r33333. PdfArray asArray = singleSignature.GetAsArray (PdfName.BYTERANGE); 3r33333. using (
Stream stream =
new RASInputStream (
new RandomAccessSourceFactory (). CreateRanged (
safeFile.CreateSourceView (),
asArray.AsLongArray ())))
asArray.AsLongArray ()))
33333333. {
using (MemoryStream ms = new MemoryStream ((int) stream.Length))
{
stream.CopyTo (ms); 3r33333. byte[]data = ms.GetBuffer (); 3r33333. ContentInfo contentInfo = new ContentInfo (data); 3r33333. SignedCms signedCms = new SignedCms (contentInfo, true); 3r33333. signedCms.Decode (signatureBytes); 3r33333. bool checkResult; 3r33333. //got the signature and check it without checking the certificate 3r33333. try
{
signedCms.CheckSignature (true); 3r33333. checkResult = true; 3r33333.}
catch (Exception)
{
checkResult = false; 3r33333.}
3r33333. foreach (SignerInfo signerInfo in signedCms.SignerInfos)
{
//get the signing date
Datetime? signDate = (signerInfo.SignedAttributes
.Cast
()
.FirstOrDefault (x =>
x.Oid.Value == "???.???.5")
? voelstrnthardrnthardrntrnthardrntrnthardrntrfdrflfdhpf.a.al.a.a.al.a.al.ralr.???. as Pkcs9SigningTime) ?. SigningTime; 3r33333. //get the certificate
X509Certificate2 certificate = signerInfo.Certificate; 3r33333.}
}
}
}
}
3r33347.
3r33333.  3r33333. There is nothing special to comment again. Unless it is necessary to say about Oid "???.???.5" is the Oid of the date of signing. 3r33333.  3r33333. 3r33333.  3r33333. And the last one on our list is docx, perhaps the easiest option:
 3r33333. 3r33333.  3r33333. 3r3185. 3r3186. using (MemoryStream fileStream = new MemoryStream (dataFileRawBytes))
using (Package filePackage = Package.Open (fileStream))
{
PackageDigitalSignatureManager digitalSignatureManager =
new PackageDigitalSignatureManager (filePackage); 3r33333. if (! digitalSignatureManager.IsSigned)
{
//handle the absence of signatures
}
3r33333. foreach (Package Digital Signature in 3r3365. digitalSignatureManager.Signatures)
{
Datetime? signDate = signature.SigningTime; 3r33333. bool checkResult = signature.Verify () == VerifyResult.Success; 3r33333. //pay attention to how to get the certificate
X509Certificate2 certificate =
new X509Certificate2 (signature.Signer); 3r33333.}
}
3r33347.
3r33333.  3r33333. Now we will disassemble the certificate and validate the entire chain of certificates. Therefore, the assembly should work from a user who has access to the network. 3r33333.  3r33333. 3r33333.  3r33333. And here hell begins, because I do not know how to get information about the certificate owner through Oid, so I will parse the string. Laugh louder: the circus begins. 3r33333.  3r33333. 3r33333.  3r33333. But seriously, you are welcome to the comments of those who know how to do it through Oid-s:
 3r33333. 3r33333.  3r33333. 3r3185. 3r3186. private static void FillElectronicSignature (X509Certificate2 certificate)
{
foreach (KeyValuePair
item in ParseCertificatesSubject (certificate.Subject))
{
switch (item.Key)
{
case "C":
string certificatesCountryName =
item.Value; 3r33333. break; 3r33333. case "S":
string certificatesState =
item.Value; 3r33333. break; 3r33333. case "L":
string certificatesLocality =
item.Value; 3r33333. break; 3r33333. case "O":
string certificatesOrganizationName =
item.Value; 3r33333. break; 3r33333. case "OU":
string certificatesOrganizationalUnitName =
item.Value; 3r33333. break; 3r33333. case "CN":
string certificatesCommonName =
item.Value; 3r33333. break; 3r33333. case "E":
string certificatesEmail =
item.Value; 3r33333. break; 3r33333. case "STREET":
string certificatesStreet =
item.Value; 3r33333. break; 3r33333. //here is an interesting point, if the Window is Russian-speaking, then the CRIPTO PRO will return the TIN, and if the English-speaking, then the INN 3r33333. //it was here that I did not begin to understand that after deploy to the test bench
//works locally, on the test - no 3r33333. case "TIN":
case "INN":
case "???.???.1":
string certificatesInn =
item.Value; 3r33333. break; 3r33333. //similar to the previous 3r36565. case "OGRN":
                case "OGRN":
case "???.100.1":
string certificatesOgrn =
item.Value; 3r33333. break; 3r33333. //similar to the previous 3r36565. case "SNILS":
case "SNILS":
case "???.100.3":
string certificatesSnils =
item.Value; 3r33333. break; 3r33333. case "SN":
string certificatesOwnerLastName =
item.Value; 3r33333. break; 3r33333. case "G":
string certificatesOwnerFirstName =
item.Value; 3r33333. break; 3r33333. //here I recommend adding the default block and everything that could not be determined before writing to the 3r33333 log.}
}
DateTime certificateNotBefore =
certificate.NotBefore; 3r33333. DateTime certificateNotAfter =
certificate.NotAfter; 3r33333. string certificatesSerialNumber =
certificate.SerialNumber; 3r33333. 3r33333. 3r33333. if (! certificate.Verify ())
{
//build a certificate chain
using (X509Chain x509Chain = new X509Chain ())
{
x509Chain.Build (certificate); 3r33333. //get all the errors in the chain
X509ChainStatus[]statuses = x509Chain.ChainStatus; 3r33333. //collect all error flags into one int, it is easier to store
int certificatesErrorCode =
statuses.Aggregate (X509ChainStatusFlags.NoError,
(acc, chainStatus) => acc | chainStatus.Status, result => (int) result); 3r33333.}
}
}
3r33333. /// 3r33333. ///Parse the string with the certificate holder data
/// 3r33333. private static Dictionary
ParseCertificatesSubject (string subject)
{
Dictionary
result = new Dictionary
(); 3r33333. 3r33333. //number of double quotes to determine the end of the value 3r33333. int quotationMarksCount = 0; 3r33333. //sign that a "key or value" is being processed
bool isKey = true; 3r33333. //variable to collect the key
string key = string.Empty; 3r33333. //Variable to collect the value of
string value = string.Empty; 3r33333. 3r33333. for (int i = 0; i < subject.Length; i++)
{
char c = subject[i];
if (isKey && c == '=')
{
isKey = false;
3r36565. continue;}
If (isKey)
Key + = c; 3r33365. Else
{
If (c == '"')
QuotationMarksCount ++; 3r36533.
Bool isItemEnd-3) .3r3365. subject.Length> = i + 1 && subject[i + 1]== '');
bool isLastChar = subject.Length == i + 1;
3r36565. if (((IitEEnd && quotationMarksCount% 2 == 0) || isLastChar)
{
if (isItemEnd)
i ++;
if (i sLastChar)
value + = c; 3r33333. isKey = true; 3r33333. if (value.StartsWith ("" ") && value.EndsWith (" ""))
value = value.Substring (? value.Length - 2); 3r33333. value = value.Replace ("" "", "" ");
result.Add (key, value); 3rr3365. key = string.Empty; 3rr3365. value = string.Empty; 3rrr6565. quotationMarksCount = 0; 3rr3365
Continue;
}
Value + = c;
}
}
3r3333347. 3r33333.  3r33333. The code is shortened as much as possible, for a better understanding of the essence. 3r33333.  3r33333. 3r33333.  3r33333. In general, this is all, I am waiting for comments on receiving Oid-s from the certificate and any reasoned criticism. 3r33333. 3r33333. 3r33333. 3r33358. ! function (e) {function t (t, n) {if (! (n in e)) {for (var r, a = e.document, i = a.scripts, o = i.length; o-- ;) if (-1! == i[o].src.indexOf (t)) {r = i[o]; break} if (! r) {r = a.createElement ("script"), r.type = "text /jаvascript", r.async =! ? r.defer =! ? r.src = t, r.charset = "UTF-8"; var d = function () {var e = a.getElementsByTagName ("script")[0]; e.parentNode.insertBefore (r, e)}; "[object Opera]" == e.opera? a.addEventListener? a.addEventListener ("DOMContentLoaded", d,! 1): e.attachEvent ("onload", d ): d ()}}} t ("//mediator.mail.ru/script/2820404/"""_mediator") () ();
3r33333. 3r33333. 3r33333. 3r33333. 3r33333. 3r33333.
+ 0 -

Add comment