Good day! There was a question to fasten authorization on a site through esia (Gosuslugi). Surely someone has already done this! Help please, I am very far from this, but I have to do it ...

In general, there is a site on ASP.NET (c #, Windows Forms).

The selected authentication type is OAuth 2.0 and OpenID Connect 1.0.

Already, as indicated, on the website of the Ministry of Communications and Mass Communications formed an application for connection to the ESIA test environment. Approved the application, sent a document with the instruction and 3 files. There are no steps in the tool as such, only logins and passwords for entering public services are test ones and a description of what should come in response.

Files of type .rar - according to the instructions, they are supposedly containers with keys for EDS. for example, the archive EsiaTest.006.rar contains the following files:

  • header.key
  • masks.key
  • masks2.key
  • name.key
  • primary.key
  • primary2.key

All parameters for authorization, in principle, are clear, except just the signature. That's just the formation of EDS I have problems.

The document says to form it like this:

Signature of the request in the PKCS # 7 format detached signature in UTF-8 encoding from the values ​​of the four parameters of the HTTP – request: scope, timestamp, clientId, state (I have them). The signature must be encoded in base64 url ​​safe format. The certificate used to verify the signature must be previously registered in the ESIA and linked to the account of the client system in the ESIA. ESIA supports X.509 certificates. ESIA supports RSA electronic signature generation algorithms with a key length of 2048 and SHA-256 cryptographic hashing algorithm, as well as the GOST R 34.10-2001 electronic signature algorithm and the GOST R 34.11-94 cryptographic hashing algorithm.

Help form this signature! How to implement all this on c #? Thank you in advance

  • open or crypto you need - eri
  • @eri CryptoPro is. As I understand it, I need something like that, on the basis of the keys (the .key files that I was sent) to form a certificate and use it to sign the request? So does it work? - Irina Ugryumova
  • If you are given an exhaustive answer, mark it as correct (a daw opposite the selected answer). If you have a new question, ask it using the " Ask a Question " button. If you need to specify the context, give a link to this question. - Nicolas Chabanovsky

3 answers 3

Integration steps you can hardly find anywhere. There are only guidelines and regulations for working with the ESIA, but there is no adequate description of the procedure “how to do it in C #” :)

What you received along with the response to the application is just examples of different test accounts for debugging work, i.e. it is NOT CONNECTED with the signature of your requests to the ESIA.

Here are the commands that we generate the correct certificate:

openssl req -nodes -sha256 -newkey rsa:2048 -keyout secret.key -out request.csr -subj /C=RU/ST=Rostov-na-Donu/L=city/O=COMPANY\/emailAddress=EMAIL@site.ru/ openssl x509 -req -sha256 -days 3650 -in request.csr -signkey secret.key -out cert.crt -extfile /etc/ssl/openssl.cnf -extensions v3_ca openssl x509 -in cert.crt -text 

Accordingly, in the right places you need to substitute the correct information about the company mail, etc. This command works under Linux, and in the file /etc/ssl/openssl.cnf you need to add (change) the following section:

 [ v3_ca ] # Extensions for a typical CA # PKIX recommendation. keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment extendedKeyUsage = emailProtection, clientAuth subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer 

as a result, you will receive a working certificate cert.crt and the secret.key key

But it will be only the beginning. There is also a carriage and a small truck of nuances regarding the exchange of data with the ESIA.

Here is a ready-made solution, incl. and in C #: esia.pro

It is paid, but in addition to the finished implementation, they will also consult on the integration process and organizational issues.

  • Thanks for the answer! I'm already basically on the path of signing the string with a certificate. True signature does not pass and falls. It is also written in the instructions: the electronic signature of the employee of the Organization must be formed using the private key attached to the instruction. Actually these are the files of the private key in the archive. Gostovskie certificates. Now I fight with CryptoPro.Sharpei. Maybe you have experience with this library? need help too - Irina Ugryumova

Our signature has earned something like this:

 public static byte[] Sign(X509Certificate2 certificate, byte[] data) { if (data == null) throw new ArgumentNullException("data"); if (certificate == null) throw new ArgumentNullException("certificate"); // setup the data to sign ContentInfo content = new ContentInfo(data); SignedCms signedCms = new SignedCms(content, true); CmsSigner signer = new CmsSigner(certificate); var sha256 = new Oid("2.16.840.1.101.3.4.2.1", "sha256"); signer.DigestAlgorithm = sha256; // create the signature signedCms.ComputeSignature(signer); var signature = signedCms.Encode(); return signature; } 

With base64, everything is not obvious there: Convert.ToBase64String is not suitable, it does not implement the standard quite accurately. I used this method here:

 public static string Base64UrlEncode(byte[] arg) { string s = Convert.ToBase64String(arg); // Regular base64 encoder s = s.Split('=')[0]; // Remove any trailing '='s s = s.Replace('+', '-'); // 62nd char of encoding s = s.Replace('/', '_'); // 63rd char of encoding return s; } 

Verifying their signatures is another rebus. It can be assumed that this process is inverse to the signing process something like this:

 public static bool ValidateCmsSignature(byte[] data, byte[] signature, X509Certificate2 certificate) { bool result = false; if (data == null) throw new ArgumentNullException("data"); if (signature == null) throw new ArgumentNullException("signature"); if (certificate == null) throw new ArgumentNullException("certificate"); // setup the data to sign ContentInfo content = new ContentInfo(data); SignedCms signedCms = new SignedCms(content, true); try { signedCms.Decode(signature); signedCms.CheckSignature(new X509Certificate2Collection(certificate), true); result = true; } catch (Exception ex) { var msg = ex.Message; } return result; } 

And this method works to verify our signature, but is not suitable for their signature. And why?

If we first form a text string, then create a detached signature on it, and then encode it all in base64, then they form two JSONs: HEADER and PAYLOAD, then they encode them separately in base64, and then they form a signature on the string HEADERbase64 .PAYLOADbase64. And then the signature is encoded in base64.

Thus, the method for verifying their signature looks something like this:

 public static bool ValidateSignature(byte[] data, byte[] signature, X509Certificate2 certificate) { bool result = false; using (var csp = (RSACryptoServiceProvider) certificate.PublicKey.Key) { using (var hasher = new SHA256Managed()) { var hash = hasher.ComputeHash(data); string id = CryptoConfig.MapNameToOID("SHA256"); bool isDataok = csp.VerifyData(data, id, signature); bool isHashOk = csp.VerifyHash(hash, id, signature); // можно ещё так //RSAPKCS1SignatureDeformatter rsaDeformatter = new RSAPKCS1SignatureDeformatter(csp); //rsaDeformatter.SetHashAlgorithm("SHA256"); //bool isHashOk2 = rsaDeformatter.VerifySignature(hash, signature); result = isDataok && isHashOk; } } return result; } 
  • And do not tell me how you debug everything? I wrote the code for authnrequest and just looked at how similar it was to the query from the manual. Response, I sent it through POST via an extension for firefox, but I don’t see a session session in a cookie when you do this. I deployed OpenAM, but in all lessons one OpenAM is looped to another OpenAM. I tried to create my own SP in OpenAM, but it swears at the metadata file - Alex Mandelbrot
  • I debugged with a regular debug in Visual Studio, I send requests via HttpWebRequest. Also, you may know, there is an authorization log on the side of the ESIA: esia-portal1.test.gosuslugi.ru/logs/auth - Arthur
  • Please tell me, HEADERbase64.PAYLOADbase64 need to be checked right since they came? They are in base64urlsafe. Do not transcode to base64? Took the certificate from esia-portal1.test.gosuslugi.ru/idp/shibboleth but ValidateSignature returns false steadily. - rfg
  • I have HEADER.PAYLOAD.SIGNATURE . In VerifyData I pass: Encoding.UTF8.GetBytes(HEADER.PAYLOAD), Convert.FromBase64String(SIGNATURE), esiaCert - rfg
  • It has been a long time, but I remember something that was not checked on their part as it was signed. If in their direction you need to sign JSON, then from them, it seems, comes the signature on base64. And you need to remember that base64 in .NET does not quite meet the standards and you need to look for the implementation of the methods according to the standards. - Arthur

In general, NuGet already has a useful library with which everything becomes easier:

https://www.nuget.org/packages?q=esia.net

In our times, pioneers did not indulge so :))