'SignedCms.CheckSignature with SAP certificate is failing

This is a follow-up of this question.

I am writing an external server which gets called by a SAP-Server. The SAP-Server signs the URL with a certificate before it is transmitted. In a previous step the SAP-Server sent the certificate it will be using to sign the URL to my server. So my server has the certificate the SAP-Server is using for signing.

From the SAP-documentation I know the following.

  1. The unsigned URL looks like this

    http://pswdf009:1080/ContentServer/ContentServer.dll?get&pVersion=0046&contRep=K1&docId=361A524A3ECB5459E0000800099245EC&accessMode=r&authId=pawdf054_BCE_26&expiration=19981104091537

  2. The values of important QueryString-parameters are concatenated (in the same order they appear in the QueryString) to form the "message".
    For the given QueryString-Parameters

     ContRep = K1  
     DocId = 361A524A3ECB5459E0000800099245EC  
     AccessMode = r  
     AuthId = pawdf054_BCE_26  
     Expiration = 19981104091537  
    

    the generated "message" looks like this:

     K1361A524A3ECB5459E0000800099245ECrpawdf054_BCE_2619981104091537
    
  3. The "message" is used to calculate the hash from which the SecKey is calculated. SAP uses the Digital Signature Standard (DSS) to digitally sign the hash value according to PKCS#. The digital signature is appended to the querystring in a parameter with the name SecKey. The SecKey for the chosen procedure is about 500 bytes long. In the example from the SAP-documentation, the arbitary values 0x83, 0x70, 0x21, 0x42 are chosen for the secKey, for the sake of clarity.

  4. The SecKey is base64 encoded and added to the URL.

     0x83, 0x70, 0x21, 0x42   gets to    "g3AhQg=="
    

    and the transferred URL looks like this

    http://pswdf009:1080/ContentServer/ContentServer.dll?get&pVersion=0046&contRep=K1&docId=361A524A3ECB5459E0000800099245EC&accessMode=r&authId=pawdf054_BCE_26&expiration=19981104091537&secKey=g3AhQg%3D%3D

  5. When my server receives the URL I need to check the signature. I recreate the "message" by concatenating the QueryString-parameters the same way as it was described in point 2. (as it is described in the SAP-documentation)

    SAP gives this Summary of Technical Information
    Format of digital signature: PKCS#7 "signed data"
    Public key procedure: DSS
    Key length: 512 - 1024 bits
    Public exponent: 2^16 + 1
    Public key format: X.509 v3 certificate MD (message digest) algorithm: MD5 or RIPEMD-160
    The library for checking signatures can be obtained from SAP AG. Because the standard format PKCS#7 was used for the signature, other products can also be used for decoding.

    I receive an "The hash value is not correct"-Exception on line cms.CheckSignature(certificates, true);

     private void CheckSignature(string secKey, string message, X509Certificate2 cert)
     {
         byte[] signature = Convert.FromBase64String(secKey);
         ContentInfo ci = new ContentInfo(System.Text.Encoding.ASCII.GetBytes(message));
         SignedCms cms = new SignedCms(ci, true);
         X509Certificate2Collection certificates = new X509Certificate2Collection(cert);
         cms.Decode(signature);
         try
         {
             cms.CheckSignature(certificates, true);
         }
         catch(Exception ex)
         {
             log.Error(ex.ToString());
         }  
     }
    

Can anybody help, or knows what I am doing wrong?



Solution 1:[1]

Actually the above function CheckSignature works correct

BUT the second parameter 'message' has to be URL-encoded. Or to be more precise, when concatenating you must use the NOT-URL-DECODED queryString values. [with the same spelling (uppercase/lowercase) SAP uses]

ContRep = AA  
DocId = 53730C7E18661EDCB1F816798DAA18B2  
AccessMode = r  
AuthId = CN=NPL          (for concatenating 'CN%3DNPL' is used)
Expiration = 20220511173746

will become the message

AA53730C7E18661EDCB1F816798DAA18B2rCN%3DNPL20220511173746


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Markus1980Wien