Important introduction
The guide describes the formation of a detached signature in the PKCS7 format (a file in the .sig format will appear next to the file). Such a signature can be requested by a notary, the Central Bank and anyone who needs a long-term storage of the signed document. The convenience of such a signature is that when it is upgraded to CAdES-X Long Type 1 (CMS Advanced Electronic Signatures [1]), a time stamp is added to it that generates TSA (Time-Stamp Protocol [2]) and the status of the certificate at the time Signatures (OCSP [3]) - the authenticity of such a signature can be verified over a long period (Enhanced Qualified Signature [4]).
corefx DotnetCoreSampleProject - corefx. [5], .NET Core -. . Visual Studio Community 2019.
TSP- http://qs.cryptopro.ru/tsp/tsp.srf
?
CSP 5.0 - (, )
TSP Client 2.0 -
OCSP Client 2.0 -
.NET Client -
- . .
34.11-2012/34.10-2012 256 bit,
CSP 5.0 - 5.0.11944 1, .
TSP Client 2.0 OCSP Client 2.0 - , .
.NET Client 1.0.7132.2 - . .
. , . , .
, ?
, .sig . :
34.11-2012 256 bit
. DotnetCoreSampleProject - .
... .
2 - , . .\runtime .\packages
I - corefx Windows
5.0 , . - ;
core 3.1 sdk runtime Visual C++ Visual Studio 2015 ; .: II C++ - DIA SDK.
DOTNET_MULTILEVEL_LOOKUP 0 - , ;
2 corefx (package_windows_debug.zip runtime-debug-windows.zip) - . v3.1.1-cprocsp-preview4.325 04.02.2021:
package_windows_debug.zip .\packages
runtime-debug-windows.zip .\runtime
NuGet %appdata%\NuGet\NuGet.Config - .\packages . . , VS Community;
NetStandard.Library .\ PowerShell ( ), $env:userprofile\.nuget\packages\
git clone https://github.com/CryptoProLLC/NetStandard.Library New-Item -ItemType Directory -Force -Path "$env:userprofile\.nuget\packages\netstandard.library" Copy-Item -Force -Recurse ".\NetStandard.Library\nugetReady\netstandard.library" -Destination "$env:userprofile\.nuget\packages\"
-
.\DotnetSampleProject\DotnetSampleProject.csproj - System.Security.Cryptography.Pkcs.dll System.Security.Cryptography.Xml.dll .\runtime;
. Visual Studio .
II - corefx Windows
1-3 6- I ;
corefx .\
.\corefx\build.cmd - DIA SDK
5, 7-9 I . .\packages .\corefx\artifacts\packages\Debug\NonShipping, .\runtime .\corefx\artifacts\bin\runtime\netcoreapp-Windows_NT-Debug-x64
, 34.11-2012 256 bit.
2 COM : "CAPICOM v2.1 Type Library" "Crypto-Pro CAdES 1.0 Type Library". .
BASE64 , PDF-. hash- .
PDF - Page 2 (cryptopro.ru) PDF c# (cryptopro.ru), PDF . .
4 :
- ;
;
;
.
using CAdESCOM;
using CAPICOM;
using System;
using System.Globalization;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Xml;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
public static void Main()
{
//
X509Certificate2 gostCert = GetX509Certificate2("");
//,
byte[] fileBytes = File.ReadAllBytes("C:\\ .pdf");
//
byte[] signatureBytes = SignWithAdvancedEDS(fileBytes, gostCert);
//
File.WriteAllBytes("C:\\Users\\mikel\\Desktop\\ .pdf.sig", signatureBytes);
}
//
public static X509Certificate2 GetX509Certificate2(string thumbprint)
{
X509Store store = CreateStoreObject("My", StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certCollection =
store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false);
X509Certificate2Enumerator enumerator = certCollection.GetEnumerator();
X509Certificate2 gostCert = null;
while (enumerator.MoveNext())
gostCert = enumerator.Current;
if (gostCert == null)
throw new Exception("Certificiate was not found!");
return gostCert;
}
//
public static byte[] SignWithAdvancedEDS(byte[] fileBytes, X509Certificate2 certificate)
{
string signature = "";
try
{
string tspServerAddress = @"http://qs.cryptopro.ru/tsp/tsp.srf";
CPSigner cps = new CPSigner();
cps.Certificate = GetCAPICOMCertificate(certificate.Thumbprint);
cps.Options = CAPICOM_CERTIFICATE_INCLUDE_OPTION.CAPICOM_CERTIFICATE_INCLUDE_WHOLE_CHAIN;
cps.TSAAddress = tspServerAddress;
CadesSignedData csd = new CadesSignedData();
csd.ContentEncoding = CADESCOM_CONTENT_ENCODING_TYPE.CADESCOM_BASE64_TO_BINARY;
csd.Content = Convert.ToBase64String(fileBytes);
// CAdES BES
signature = csd.SignCades(cps, CADESCOM_CADES_TYPE.CADESCOM_CADES_BES, true, CAdESCOM.CAPICOM_ENCODING_TYPE.CAPICOM_ENCODE_BASE64);
csd.VerifyCades(signature, CADESCOM_CADES_TYPE.CADESCOM_CADES_BES, true);
// CAdES BES CAdES X Long Type 1
//( , CAdES X Long Type 1)
signature = csd.EnhanceCades(CADESCOM_CADES_TYPE.CADESCOM_CADES_X_LONG_TYPE_1, tspServerAddress, CAdESCOM.CAPICOM_ENCODING_TYPE.CAPICOM_ENCODE_BASE64);
csd.VerifyCades(signature, CADESCOM_CADES_TYPE.CADESCOM_CADES_X_LONG_TYPE_1, true);
}
catch (Exception ex)
{
throw ex;
}
return Convert.FromBase64String(signature);
}
PDF-, " .":
:
. .
:
:
:
" ", " " " ":
, TSP- http://qs.cryptopro.ru/tsp/tsp.srf
.
Done.
- .NET Core 3.1 .
" " , .
?
.
[1] CMS Advanced Electronic Signatures (CAdES) - https://tools.ietf.org/html/rfc5126#ref-ISO7498-2
[2] Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP) - https://www.ietf.org/rfc/rfc3161.txt
[3] X.509 Internet Public Key Infrastructure Online Certificate Status Protocol - OCSP - https://tools.ietf.org/html/rfc2560
[4] β (kontur.ru)
[6] http://qs.cryptopro.ru/tsp/tsp.srf - CryptoPro TSP service
UPD1: Changed the variable in the code where the bytes of the signature file are written.
I also forgot to write a little about the time stamp signature - it is signed by the certificate of the owner of the TSP service. According to the guide, this is CRYPTO-PRO LLC: