Good afternoon! I am writing integration with esia via opendid connect in java. The issue of verifying the signature of the access token /identification is ripe. Briefly what is said in the guidelines for signature verification:

The access /identification token looks like HEADER.PAYLOAD.SIGNATURE in Base64Url format. SIGNATURE is a PKCS # 7 detached signature signature in UTF-8 encoding from the values ​​of the first two parts of the access token (HEADER.PAYLOAD). It is necessary to verify this electronic signature using the certificate of the ESIA electronic signature verification key.

Actually the questions themselves:

How to do this signature verification if there is only the signature of the line (signature) and the line itself that was signed (header.payload)?

Where can I get the certificate of the ESIA electronic signature verification key (I saw a similar question on stackoverflow but no answers)?

Or maybe this part of the signature has some certificate and key data in it, and you can check it somehow? if so how to do it?

@Zergatul I have not a file but just a line, well, it doesn't matter. That is, it contains what it signs? And then why do we need information about what she signs? it is probably not just sent. And another question, what is the meaning of the signature verification then? There is a signature in the pkcs format # 7, we take out the certificate and the verifier from there and check, it is not clear anything, why do we check ourselves?

Эльдар Зиятдинов2021-02-23 09:07:03

PKCS-7 format may or may not contain signed data. I'm not sure, perhaps the detached signature just means that the data itself is not inside. You have to check in yourself whether you trust this certificate or not. This is the essence of signature verification. And you already do it as you want. Either check your local trust store, or hardcode your certificate serial number /SHA-1 fingerprint.

Zergatul2021-02-23 09:07:03

@Zergatul the problem is missing certificate. There is a signature -an array of 256 bytes, there is no certificate. The certificate does not fit at esia-portal1.test.gosuslugi.ru/idp/shibboleth.

rfg2021-02-23 09:07:03

@Zergatul Now I do not understand at the expense of checking in the local store of the certificate or the serial number sha1. As if the certificate itself and the keys are not provided by ESIA which he signs. But I read that pkcs # 7 contains a public key certificate. I wrote the code in my answers, but I don't know if it's correct.

Эльдар Зиятдинов2021-02-23 09:07:03
  • Answer # 1

    I understand that pkcs7 stores a certificate in itself, and you just check this signature with this certificate (that is, yourself), maybe I misunderstood something .. Here is the code:

    public boolean verify (byte [] data) {
        try {
            CMSSignedData cmsSignedData= new CMSSignedData (data);
            //get a list of certificates that are contained in the file
            Store <
    X509CertificateHolder >
     certs= cmsSignedData.getCertificates ();
            //p7s file can contain data that has been signed, i.e. your pdf file
            byte [] content= (byte []) cmsSignedData.getSignedContent (). getContent ();
            //go through the list of signatures, usually one signature, but the standard supports multiple signatures
            for (SignerInformation si: cmsSignedData.getSignerInfos ()) {
                //list of all attributes signed with the file
                AttributeTable signedAttributes= si.getSignedAttributes ();
                //attribute named
                Attribute attrSurname= signedAttributes.get (new ASN1ObjectIdentifier (""));
                //attribute named 2
                Attribute attrGivenName= signedAttributes.get (new ASN1ObjectIdentifier (""));
                //attribute with signature date
                Attribute attrSigningTime= signedAttributes.get (new ASN1ObjectIdentifier ("1.2.840.113549.1.9.5"));
                //display the date of signature
                System.out.println (attrSigningTime.getAttributeValues ​​() [0] .toString ());
                //maybe some attributes were not part of the signature, the format also supports such
                //AttributeTable unsignedAttributes= si.getUnsignedAttributes ();
                //get the identifier of the certificate that signed the data
                SignerId signerId= si.getSID ();
                //look for a certificate in the collection by ID
                Collection certCollection= certs.getMatches (signerId);
                //select the first certificate, there should not be more than one
                Iterator certIt= certCollection.iterator ();
                X509CertificateHolder certHolder= (X509CertificateHolder) certIt.next ();
                //create a Verifier based on the certificate, Verifier uses the public key of the certificate
                SignerInformationVerifier verifier= new JcaSimpleSignerInfoVerifierBuilder (). Build (certHolder);
                //check the signature
                return si.verify (verifier);
        } catch (CertificateException | OperatorCreationException | CMSException e) {
            logger.error (e);
        return false;

    As I understand it, byte [] content may not contain the data itself that it signs, or it may contain. Also Attribute *** are written purely for testing purposes. And the marker also consists of header.payload.signature in base64url format, so the signature must be decoded like this:

    byte [] data= Base64.getUrlDecoder (). decode (a);

    And already this data must be sent to this function public boolean verify (byte [] data). Perhaps this decision is not correct, I do not know for sure. If this is correct /incorrect then write that everything is ok or tell me how to do it correctly.

    I'm not sure, but maybe the CMSSignedData constructor is able to detect base64 and decodes it itself. This is easily verified. If PKCS7 does not contain the data that it signs inside it, it contains their hash, you must check this hash with the hash from your data to make sure that the signature actually signed what you need (and not some left data) ...

    Zergatul2021-02-23 09:07:03

    @Zergatul How to get hash from pkcs7? the second question is how to get the hash from what he signed without knowing the hash function: he signs such a thing-header.payload and header and payload are in base64 format but connected through a dot. Everything is very complicated and nothing is clear ..

    Эльдар Зиятдинов2021-02-23 09:07:03

    If I am not mistaken, the hash will be among the signedAttributes. If possible, attach an example of your data along with a signature. A live example will make it easier to understand. Somewhere inside PKCS7 it is indicated which hash function is used (using ASN1 object identifier)

    Zergatul2021-02-23 09:07:03