How to Verify the Digital Signature of a SLIC Table

Discussion in 'BIOS Mods' started by crypto, Aug 4, 2009.

  1. crypto

    crypto MDL Member

    Nov 3, 2008
    114
    363
    10
    #1 crypto, Aug 4, 2009
    Last edited by a moderator: Apr 20, 2017
    How to Decrypt and Verify the Digital Signature of a SLIC Table

    How to Decrypt and Verify the Digital Signature of a SLIC Table

    Now that we know how to match certificates with SLIC tables, I'm going to explain how to verify the Digital Signature of a SLIC table.
    This is very useful to make sure that a SLIC table is valid.

    I will show you the manual way, with all the details. If anyone wants to create a program to do this automatically, then the CryptVerifySignature Function might be helpful. ;)

    First, a bit of theory behind the authentication/verification process (if you think this is dull, then scroll down to the good part :D).


    Signature Creation

    Microsoft uses an asymmetric key algorithm (RSA) to create digital signatures and authenticate OEM licensing information, included in SLIC tables.

    The process starts with the OEM generating a pair of public and private keys.
    The private key remains secret and is never disclosed by the OEM, while the public key is published in the SLIC table.

    The OEM also creates its own OEM ID and OEM Table ID which, together with the Windows Marker version, Windows Flag and Reserved bytes, form the Message.

    The Message is hashed, using the SHA-256 hash function, resulting in the Message Digest.

    The Message Digest (or hash) is then DER encoded and signed/encrypted by the OEM private key, resulting in the 1024-bit (128 bytes) Digital Signature that we see in SLIC tables.


    Signature Decryption and Authentication/Verification

    In order to authenticate/verify signatures, we need to generate our own SHA-256 hash of the Message (Windows Marker version + OEM ID + OEM Table ID + Windows Flag + Reserved bytes) and then compare it with the SHA-256 hash in the Digital Signature.

    To do that, we need to decrypt the digital signature first.
    Decryption of the Digital Signature is done by using the public key, available in the SLIC table.
    It is done by performing a modular exponentiation:
    Decryption = s^e mod n

    Where s is the Digital Signature, e is the Public Key Exponent and n is the Public Key Modulus.

    Once the Digital Signature is successfully decrypted, we can then compare its SHA-256 hash (the message digest) with the one we calculated beforehand.
    If they match, then authentication is successful.


    SLIC Table Example

    Here is the breakdown of the 4 parts that are going to be used to decrypt and authenticate/verify the Digital Signature.
    NOTE: This is the ASUS SLIC table.

    Code:
    Offset      0  1  2  3  4  5  6  7   8  9 10 11 12 13 14 15
    
    00000000   53 4C 49 43 76 01 00 00  01 4B 5F 41 53 55 53 5F   SLICv....K_ASUS_
    00000010   4E 6F 74 65 62 6F 6F 6B  24 06 00 11 4D 53 46 54   Notebook$...MSFT
    00000020   97 00 00 00 00 00 00 00  9C 00 00 00 06 02 00 00   —.......œ.......
    00000030   00 24 00 00 52 53 41 31  00 04 00 00 01 00 01 00   .$..RSA1........
    00000040   6F 92 9D DC B3 79 EE 27  26 08 F8 DC 5B D8 5F 4B   o’ܳyî'&.øÜ[Ø_K
    00000050   21 34 AB 60 EC 90 C7 C2  D5 60 D5 F5 D9 82 F9 2E   !4«`ìÇÂÕ`ÕõÙ‚ù.
    00000060   BE E8 43 38 D5 C2 5B 9E  25 B8 93 CD 15 B8 1B C3   ¾èC8ÕÂ[ž%¸“Í.¸.Ã
    00000070   30 7D AD 55 69 79 BD 1A  7E 44 C8 BC 59 5A 17 BE   0}*Uiy½.~DȼYZ.¾
    00000080   81 AD EF EE 96 21 37 CC  8A 42 62 C6 14 05 09 21   *ïî–!7ÌŠBbÆ...!
    00000090   69 7A E1 8C 4A CE D6 C8  18 78 78 86 2B 30 63 A6   izáŒJÎÖÈ.xx†+0c¦
    000000A0   E5 64 B7 D2 14 5E 2B 44  BE 33 12 6B 6B A3 BD 9E   åd·Ò.^+D¾3.kk£½ž
    000000B0   85 BB BE 6C E1 B1 33 C2  DA 91 80 F3 44 B4 CA 9F   …»¾lá±3ÂÚ‘€óD´ÊŸ
    000000C0   01 00 00 00 B6 00 00 00  00 00 02 00 5F 41 53 55   ....¶......._ASU
    000000D0   53 5F 4E 6F 74 65 62 6F  6F 6B 57 49 4E 44 4F 57   S_NotebookWINDOW
    000000E0   53 20 00 00 00 00 00 00  00 00 00 00 00 00 00 00   S ..............
    000000F0   00 00 00 00 00 00 24 B0  89 CF B1 F3 1D B8 7A 80   ......$°‰Ï±ó.¸z€
    00000100   35 CB CD 4A C8 2F 84 CE  99 A0 4F 38 76 B0 04 F9   5ËÍJÈ/„Ι*O8v°.ù
    00000110   6F 05 33 C7 EC A8 58 A6  D7 B7 3F 5B 82 B1 EE 2B   o.3Çì¨X¦×·?[‚±î+
    00000120   A7 81 52 F3 45 13 CE EE  D5 57 37 FE 75 5F 5C 62   §RóE.ÎîÕW7þu_\b
    00000130   C4 53 DA 86 F1 34 FA ED  91 86 73 9E D2 65 FD 8A   ÄSÚ†ñ4ú푆sžÒeýŠ
    00000140   3D 86 94 2F 2A 65 18 5C  D9 E5 7C 15 1E F2 08 C5   =†”/*e.\Ùå|..ò.Å
    00000150   85 C4 8F 0B FA A5 C3 A9  B0 F1 B2 E7 6A 46 FB 18   …Ä.ú¥Ã©°ñ²çjFû.
    00000160   01 5D 4C 36 33 DE FB E7  1D E8 15 C2 85 9F 8A A9   .]L63Þûç.è.Â…ŸŠ©
    00000170   32 68 1F B4 BC A8                                  2h.´¼¨
    BROWN
    Public Key Exponent (in little-endian format) used to decrypt the digital signature.
    Byte offset: 0x3C
    Byte length: 4 bytes

    RED
    Public Key Modulus (in little-endian format) used to decrypt the digital signature.
    Byte offset: 0x40
    Byte length: 128 bytes

    GREEN
    Message to be SHA-256 hashed and compared against the SHA-256 hash in the decrypted digital signature.
    It is formed by the Windows Marker version (00 00 02 00) + OEM ID (5F 41 53 55 53 5F) + OEM Table ID (4E 6F 74 65 62 6F 6F 6B) + Windows Flag (57 49 4E 44 4F 57 53 20) + Reserved bytes (00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00).
    Byte offset: 0xC8
    Byte length: 46 bytes

    BLUE
    Digital signature to be decrypted by the Public Key, and then have its SHA-256 hash compared with the SHA-256 hash calculated beforehand.
    Byte offset: 0xF6
    Byte length: 128 bytes


    Manual Authentication/Verification

    Tools used:
    - WinHex
    - Hpmbcalc

    NOTE: I am using the above ASUS SLIC table as an example.

    1. Fire up WinHex and open the SLIC table file.

    2. Select the Message data and calculate the SHA-256 hash (press Ctrl+F2, choose "SHA-256 (256 bit)" and click the OK button).
    You will get the following SHA-256 hash (write it down):
    Code:
    DF 81 94 2A 19 4B 21 A3 40 B2 41 1F 42 9C 8A 2F D1 F6 45 AB F8 7D 2B 99 C5 B3 3B 27 38 FC 44 81
    3. Fire up Hpmbcalc and make sure it's in Hexadecimal mode.

    4. In WinHex, select the Digital Signature data, and press Ctrl+Shift+C to copy the hex values.
    Paste them in the first operand field (x), in Hpmbcalc.

    5. In WinHex, select the Public Key Exponent data, and press Ctrl+Shift+C to copy the hex values.
    Paste them in the second operand field (y), in Hpmbcalc.
    Because the data is in little-endian format, we need to reverse the byte order. To do this, simply click on the "Reverse" button, in Hpmbcalc.

    6. In WinHex, select the Public Key Modulus data, and press Ctrl+Shift+C to copy the hex values.
    Paste them in the third operand field (z), in Hpmbcalc.
    Because the data is in little-endian format, we need to reverse the byte order. To do this, simply click on the "Reverse" button, in Hpmbcalc.

    7. Click on the "PMod" button to perform a modular exponentiation.
    The result is the decrypted digital signature (DER encoded):

    Code:
    01 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
    FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
    FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
    FF FF FF 00 30 31 30 0D 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 DF
    81 94 2A 19 4B 21 A3 40 B2 41 1F 42 9C 8A 2F D1 F6 45 AB F8 7D 2B 99 C5
    B3 3B 27 38 FC 44 81
    The last 32 bytes are the SHA-256 hash of the Message.
    As you can see, it matches the SHA-256 hash we calculated beforehand:
    Code:
    DF 81 94 2A 19 4B 21 A3 40 B2 41 1F 42 9C 8A 2F D1 F6 45 AB F8 7D 2B 99 C5 B3 3B 27 38 FC 44 81
    This means that the Public Key, the Digital Signature and the Message are all valid and authentication is successful.
     
  2. zort

    zort MDL Expert

    Feb 19, 2008
    1,105
    18
    60
    Thanks for this guide, crypto!
     
  3. frwil

    frwil MDL Addicted

    Sep 22, 2008
    520
    158
    30
    Interesting topic. Wish there were command-line tools like that calculator...
    I think there's a similar way to verify xrm-ms files, and oem-certificates as an example. <DigestValue> is what they sign and it is SHA1 of yet unsigned license (without enveloped <Signature> elements).
     
  4. FreeStyler

    FreeStyler MDL Guru

    Jun 23, 2007
    3,501
    3,609
    120
    I wish i have known a way to calculate "s^e mod n" in ASP/VBScript :)
     
  5. justinkb

    justinkb MDL Member

    Jul 16, 2008
    181
    0
    10
    i dont know vb.net but (s^e) Mod n should work, otherwise try Math.Pow(s,e) Mod n
    thanks for this guide :)
     
  6. crypto

    crypto MDL Member

    Nov 3, 2008
    114
    363
    10
    Found a command line tool that calculates modular exponentiation:
    http://www.di-mgt.com.au/modarith.html

    I tested it and it works well.

    Certificates seem to be trickier.
    Decryption of the digital signature is done in the same way. No problem there.

    The problem is creating the SHA-1 hash, to compare with the one in the decrypted signature.

    According to the XML specification, the certificate needs to be transformed and canonicalized. Only then is the SHA-1 hash calculated.

    I'm still trying to figure this one out.
    Any help would be welcome. :D
     
  7. ionsmurf

    ionsmurf MDL Novice

    Jul 6, 2009
    6
    0
    0
    Attached is some code to validate a certificate. It is mainly based on http://www.woloszyn.org/2008/01/03/how-to-verify-digital-signatures-of-xml-documents-without-wse3/.
     
  8. frwil

    frwil MDL Addicted

    Sep 22, 2008
    520
    158
    30
    Yes, decrypting cert. signature produces some sha1 in DER format, but it doesn't coinside neither with DigestValue (which is theoretically sha1 of caniconized xml) nor with sha1, calculated in standart way?..


    There're tutorials and scripts on msdn:

    How to: Sign XML Documents with Digital Signatures
    http://msdn.microsoft.com/en-us/library/ms229745.aspx

    How to: Verify the Digital Signatures of XML Documents
    http://msdn.microsoft.com/en-us/library/ms229950.aspx

    So far it gives a way to produce the same DigestValue with signing scripts, didn't explore the verification scripts yet....
     
  9. ionsmurf

    ionsmurf MDL Novice

    Jul 6, 2009
    6
    0
    0
    The signature is to validate the SignedInfo data.

    {signature validation}
    Compute the hash of the canonicalization of the SignedInfo node.
    Decrypt the signature and compare the hashes, when the hashes match the signature is valid

    {content validation}
    Compute the hash from the result of transforms in
    Signature/SignedInfo/Reference/Transforms

    In the case of a xrm-ms file:
    - licenseTransform
    - canonicalization

    Compare the hash with DigestValue. When they match the content is valid.

    The link you gave is referring to the SignedXml class.
    I had not much success with that class, it throwed the following exception: "Unknown transform has been encountered"

    The code in my previous post does the verification of a xrm-ms file. The certs I checked with it came up as valid, so I think the verifiation is correct.
     
  10. frwil

    frwil MDL Addicted

    Sep 22, 2008
    520
    158
    30
    Thank you for the tips. If possible please could you provide an example with manual verification of Asus oem certificate? And more detailed how to do it with the tool in your previous post.
     
  11. ionsmurf

    ionsmurf MDL Novice

    Jul 6, 2009
    6
    0
    0
    The code posted earlier is more sample code. Here is a bit more of a tool.
    Usage: CertInfo "path to certificate" e.g. CertInfo "ASUS.XRM-MS"
     
  12. frwil

    frwil MDL Addicted

    Sep 22, 2008
    520
    158
    30
    Thank you again!
    And your previous command-line tool:
     
  13. chaddawkins

    chaddawkins MDL Senior Member

    Sep 16, 2007
    340
    61
    10
    SLIC Validation Tool v1.0 by MrFung

    SLIC Validation Tool v1.0 by MrFung

    http://forums.mydigitallife.net/attachment.php?attachmentid=1940&stc=1&d=1249896070
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...
  14. str8

    str8 MDL Expert

    Jul 3, 2009
    1,506
    56
    60
    crypto thank you VERY much for this interesting and valuable information. This should be a "sticky".
     
  15. crypto

    crypto MDL Member

    Nov 3, 2008
    114
    363
    10
    #15 crypto, Aug 20, 2009
    Last edited by a moderator: May 23, 2017
    (OP)
    Thank you ionsmurf and frwil for your great contributions.
    Now we can verify the integrity and validity of certificates as well.

    I spent some time trying to manually canonicalize and transform the certificate, in order to compare hashes. Had no luck, unfortunately.

    The tools and the code you posted seem to work very well, so thanks again. :D

    Thank you for your support.
    I personally think there are too many stickies already, so I have suggested an alternative to the mods/admins. ;)
     
  16. dobrogi

    dobrogi MDL Novice

    Apr 4, 2009
    5
    0
    0
  17. elffin

    elffin MDL Novice

    Sep 12, 2009
    3
    0
    0
    Thanks very much for your explaination.
    Some questions :
    Where did you get the name(description) of these segments ? I searched but could not find other materials. Are there official documents about this?
    if 0xC8 ~ 0xCB is called Windows Marker Version, what is its meaning (or function) ?
    How about 0xE2 ~ 0xE5, I think this part defines the SLIC version. ( It is 01 00 02 00 in SLIC2.1 ) what is its name ?

    Thanks again!
     
  18. crypto

    crypto MDL Member

    Nov 3, 2008
    114
    363
    10
    #18 crypto, Sep 15, 2009
    Last edited by a moderator: Apr 20, 2017
    (OP)
    The "Windows Marker Version" comes from the MGADiag tool.
    Here's an example:
    Code:
    OEM Activation 2.0 Data-->
    BIOS valid for OA 2.0: yes
    Windows marker version: 0x20000
    OEMID and OEMTableID Consistent: yes
    As you may already know, 00 00 02 00 is in little endian. If you reverse the byte order, you get 00 02 00 00 (0x20000).
    This is just the version number of the Windows Marker structure.


    Yes, that is the SLIC version number.
    Those bytes were reserved in SLIC 2.0, but now Microsoft has made use of them to identify SLIC 2.1 tables.
    01 00 02 00 (in little endian) becomes 00 02 00 01 (0x20001).

    You can also see a list of all the fields in a SLIC table, if you use the RW tool.
     
  19. chaiilee

    chaiilee MDL Novice

    Oct 8, 2009
    37
    0
    0
    I agree, @crypto all of your threads are awsome!
     
  20. MasterDisaster

    MasterDisaster MDL Expert

    Aug 29, 2009
    1,256
    670
    60
    #20 MasterDisaster, Nov 16, 2009
    Last edited by a moderator: Apr 20, 2017
    C# functions to verify SLIC bin and OEM Certificate

    Great tutorial crypto :)
    Was able to write this function by just following your instructions.

    Code:
    
    using System;
    using System.IO;
    using System.Security.Cryptography;
    
    /// <summary>
    /// Verifies the Digital Signature in the SLIC Table
    /// </summary>
    /// <param name="path">Path to the bin file</param>
    /// <returns>true if 'signature' matches the signature computed using the specified hash algorithm and key on 'messageHash'; otherwise, false.</returns>
    
    public bool VerifySign(string path)
    {
        byte[] bin = File.ReadAllBytes(path);
        byte[] exponent = new byte[4];
        byte[] modulus = new byte[128];
        byte[] message = new byte[46];
        byte[] signature = new byte[128];
        Array.Copy(bin, 0x3C, exponent, 0, exponent.Length);
        Array.Copy(bin, 0x40, modulus, 0, modulus.Length);
        Array.Copy(bin, 0xC8, message, 0, message.Length);
        Array.Copy(bin, 0xF6, signature, 0, signature.Length);
        Array.Reverse(exponent);
        Array.Reverse(modulus);
        RSAParameters parameter = new RSAParameters();
        parameter.Exponent = exponent;
        parameter.Modulus = modulus;
        RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
        RSA.ImportParameters(parameter);
        RSAPKCS1SignatureDeformatter RSADeformatter = new RSAPKCS1SignatureDeformatter(RSA);
        RSADeformatter.SetHashAlgorithm("SHA256");
        byte[] messageHash = new SHA256Managed().ComputeHash(message);
        return RSADeformatter.VerifySignature(messageHash, signature);
    }
    
    Function to verify integrity of signature and license info in certificate.

    Code:
    using System;
    using System.Text;
    using System.IO;
    using System.Security.Cryptography;
    using System.Security.Cryptography.Xml;
    using System.Xml;
    
    /// <summary>
    /// Verifies the Signature and Licence Info in the Certificate
    /// </summary>
    /// <param name="path">Path to the certificate file</param>
    /// <returns>true if 'sign' matches the signature computed using the specified hash algorithm and key on 'Signature' and 'Digest' matches the computed hash for license; otherwise, false.</returns>
    
    public bool VerifyCert(string path)
    {
        XmlDocument doc = new XmlDocument();
        doc.Load(path);
        XmlDsigC14NTransform transform = new XmlDsigC14NTransform();
        transform.LoadInput(new MemoryStream(Encoding.UTF8.GetBytes(doc.GetElementsByTagName("SignedInfo")[0].OuterXml)));
        byte[] siHash = transform.GetDigestedOutput(SHA1.Create());
        byte[] Signature = Convert.FromBase64String(doc.GetElementsByTagName("SignatureValue")[0].InnerText);
        byte[] Modulus = Convert.FromBase64String(doc.GetElementsByTagName("Modulus")[0].InnerText);
        byte[] Exponent = Convert.FromBase64String(doc.GetElementsByTagName("Exponent")[0].InnerText);
        string Digest = doc.GetElementsByTagName("DigestValue")[0].InnerText;
        RSAParameters parameter = new RSAParameters();
        parameter.Modulus = Modulus;
        parameter.Exponent = Exponent;
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
        rsa.ImportParameters(parameter);
        RSAPKCS1SignatureDeformatter rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
        rsaDeformatter.SetHashAlgorithm("SHA1");
        bool sign = rsaDeformatter.VerifySignature(siHash, Signature);
        XmlLicenseTransform License = new XmlLicenseTransform();
        License.Context = (XmlElement)doc.GetElementsByTagName("Signature")[0];
        License.LoadInput(doc);
        transform = new XmlDsigC14NTransform();
        transform.LoadInput(License.GetOutput());
        string dvHash = Convert.ToBase64String(transform.GetDigestedOutput(SHA1.Create()));
        return sign && dvHash.Equals(Digest);
    }
    
    Function to compare Certificate data with SLIC Table.

    Code:
    using System;
    using System.IO;
    using System.Xml;
    
    /// <summary>
    /// Compare Certificate data and SLIC Table
    /// </summary>
    /// <param name="binFile">Path to bin file</param>
    /// <param name="certFile">Path to certificate file</param>
    /// <returns>true if data matches; otherwise false.</returns>
    
    public bool Compare(string binFile, string certFile)
    {
        byte[] bin = File.ReadAllBytes(binFile);
        XmlDocument doc = new XmlDocument();
        doc.Load(certFile);
        byte[] cert = Convert.FromBase64String(doc.GetElementsByTagName("sl:data")[0].InnerText);
        int i = 0;
        int j = 0;
        bool match = cert.Length == cert;
        for (i = 4, j = 0xC8; i < 14; i++, j++)
            match &= cert == bin[j];
        for (j = 0x3C; i < cert.Length; i++, j++)
            match &= cert == bin[j];
        return match;
    }
    
     
    Stop hovering to collapse... Click to collapse... Hover to expand... Click to expand...