none
Issue validating ASHWID (HardwareToken) in the cloud

    Question

  • Hello,

    I'm trying to validate HardwareToken issued by HardwareIdentification.GetPackageSpecificToken with an azure (.net 4.5) service. I followed the official guidance. But i'm stuck in the very last checking. I can't figure why the signature checking is always failing (every other checks such as cheking certificate chain, weighted hardware token comparison or root certiticate publicKey matching are working fine).

    Here is the code i'm using to perform the signature validation :

    var publicKeyProvider = leaf.PublicKey.Key as System.Security.Cryptography.RSACryptoServiceProvider;
    
    var signedData = nonce.Concat(token).ToArray();
    SHA1Managed hash = new SHA1Managed();
    byte[] hashedData;
    hashedData = hash.ComputeHash(signedData);
    
    if (!publicKeyProvider.VerifyHash(hashedData, CryptoConfig.MapNameToOID("SHA1"), signature))
       throw new Exception("Invalid or Corrupted HardwareToken");

    I also tried using VerifyData with the same result, it is always returning False (no matter I use a nonce or not).

    Did someone faced/solved this issue?

    Best regards,

     


    Cyprien Autexier



    • Edited by sandør Friday, November 23, 2012 10:59 AM
    Friday, November 23, 2012 10:58 AM

Answers

  • Hello,

    Signature kind used by ASHWID is not supported by .net because it uses PSS, so I had to make a native call to NCryptVerifySignature.


    Cyprien Autexier

    • Marked as answer by sandør Thursday, December 20, 2012 1:37 PM
    Thursday, December 20, 2012 1:37 PM

All replies

  • Hi,

    Sorry for the delay. After a long time researching, I think the problem may due to the process you verify the ASHWID.

    The ASHWID has been signed by a privateKey, so you can't verify the nonce and token directly.

    In my opinion, you have to use a publickey to decrypt the signature. Then use SHA1 to verify the nonce+token. Here is the description of the official document:

    Use the leaf certificate to verify that the signed hash signature matches the original nonce that was sent from the cloud service and the received hardware byte stream.

    You could have a try and please tell me the result.


    Aaron Xue [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, November 29, 2012 7:11 AM
    Moderator
  • Hello,

    Thanks for your answer. Hello I checked with a coworker but I can't see where I'm doing something wrong. Schema says that the signature is the rsa-sha1 signature of  the nonce + hardware concatenation ( RSASignature(Sha1(Nonce + HardwareToken)).

    VerifyHash is decrypting the signature and checking it against the hash I provide. To my knowledge, there is no way of decrypting data with public key outside of the standard signature process with RSACryptoServiceProvider (i guess for security reasons).

    I uploaded a very basic sample project here : https://github.com/sandorfr/sandor/tree/master/W8/HardwareTokenSample .

    Best regards,

    Cyprien


    Cyprien Autexier


    • Edited by sandør Friday, November 30, 2012 10:38 AM English mistakes...
    Thursday, November 29, 2012 3:03 PM
  • Hi,

    Sorry, I didn't notice that. Please wait for a moment, I'll involve more experts in this issue.


    Aaron Xue [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, November 30, 2012 4:32 AM
    Moderator
  • Hello,

    Aaron asked me to help with this. My answer is... Yikes... I have no clue :( 

    If you still need help with this let me know and I'll track down a crypto guy to help us get this answered.

    Thanks,

    James


    Windows SDK Technologies - Microsoft Developer Services - http://blogs.msdn.com/mediasdkstuff/

    Monday, December 03, 2012 11:28 PM
    Moderator
  • Hi Cyprien,

    I've been researching the issue and your code looks fine. 
    I see your function is defined as
    bool ValidateToken(byte[] token, byte[] nonce, byte[] certificate, byte[] signature);

    Can you provide me with the base64 encoding of the token, nonce, certificate and signature?

    I should be able to determine why the verification is failing.  Either, the certificate's public key cannot decrypt the signature or the hashes don't match.


    Carlos Lopez - Microsoft Escalation Engineer

    Wednesday, December 05, 2012 12:06 AM
    Moderator
  • Hello,

    Yes I definitely need some help :). I have tried many things and none are working.

    here is a sample :

    CryptographicBuffer.EncodeToBase64String(nonce) 
    "y5XUaVs68k/0Blyabn6/ZtuFEk7u8TfXqhnQRmFVL98="
    CryptographicBuffer.EncodeToBase64String(token.Id) 
    "AwDiMwMAMrUDAGzLCAD3NwUAwggFAGcmBQAMrgYAAQAEAF8+BAA6UQEAoIACALZrCQD6+Q=="
    CryptographicBuffer.EncodeToBase64String(token.Signature)
    "KMRYVckDn/nuSPjETHWmiZDJHrHCHDJOB8l4YLfc4YVTE6X8KaIU95FFOp14BzmA7phMa8sryW2M9EftF4cjiQiRe4Ak2OD/45WpX2drgvtd9RYzbtzlYKVpxtZi6HO+uFFMKY27g0WFPP7K0mAWun9J53EFh2U3zxI3fwkZSNM="
    CryptographicBuffer.EncodeToBase64String(token.Certificate)
    "MIIR2gYJKoZIhvcNAQcCoIIRyzCCEccCAQExADALBgkqhkiG9w0BBwGgghGvMIIE3zCCAsegAwIBAgIKYQYL2gAAAAAADjANBgkqhkiG9w0BAQsFADCBhzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjExMC8GA1UEAxMoTWljcm9zb2Z0IEFzc3VyYW5jZSBEZXNpZ25hdGlvbiBQQ0EgMjAxMTAeFw0xMjA1MjEyMDQ1MjZaFw0xMzA4MjEyMDU1MjZaMCMxITAfBgNVBAMTGE1pY3Jvc29mdCBXaW5kb3dzIEFTSFdJRDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAruJC3ZkSUfXPC0uYhzgACFoAaInBKtRkmDitV+3noRWtk45WPv5yD0WfDStGTTgKzivGolIYqI3dmSduhrFatGLSX2u2Q+BYXBly4V7S62Q01r+8oRdnSDjho4O6zUVr3A3EcwXM2kT/5K7ywCgUCrdKeYFTMYf4V7z75AtNHwUCAwEAAaOCATIwggEuMA4GA1UdDwEB/wQEAwIHgDAVBgNVHSUEDjAMBgorBgEEAYI3CgUoMB0GA1UdDgQWBBQlOZgV9+11fEmlXRpakgNCt8aVnDAfBgNVHSMEGDAWgBRYQgkSKX0GY5S0TP8Rvtc4VDAlmTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNBc3NEZXNQQ0EyMDExXzIwMTEtMDYtMjguY3JsMGEGCCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNBc3NEZXNQQ0EyMDExXzIwMTEtMDYtMjguY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAGQFCukEKNKVuXtjIQgc3ClDscKAm6mByxhs/n4tcZM0wABMZb//5cm8DJufvvCD36+PZCrg3OKcZWTZPcE/XL9iOD1COaOvAK/RDM4qxAU/EUELb2ZS3+KomtocOr1Ws5CLS/d2cPMxYHtCKPLC8m6mDxhV09RCWAq+pT4aIrfZwgGauqokS6yOyd2dthR3iiJwnIo6yJ7wEene95PboP787sXgmHsBy890wXZ4feU1CAPOC/pJvpfXeJV0odi8qbVQIOfgoAWK3jnXRldsA7T8aPvyzwTeRrY7Xuv0FDlWdBPAYVyBuxl4ovz8ff9ennp9Skplef8JAemgjs0CxhZLKbKjR36ke+ASvf9WZoM7RL4jouQudVdTgeajlJ/7rfiWgpYNyLflrnZ3QPgVeNvvw4cdrjQpi1jd0Vpt23S393qRvfJoX8Y48MvnRw8HRaJKo8s+sDbG+Hy03xiKHjBDzwXlaByWpcXnif4Q1RW1uqoiFai0xeIWiR90i/OfFdFcReJPORbY6Jadiwd9IQsvzl5qARoZywL++YP4U1pXc2EL9fcpsxmCJusM7XFAvHkXFCx8b1E1mTexvIrIslpPlslSHCQ/TJdBQQ6Nb8znsEFmBYbR6WQOZFK+4pNKs6v8MQ8imJf3i1n3OCnA6Wm1Ko8BW5BxEZYOUXoDxfzJMIIF7TCCA9WgAwIBAgIQCxwEHJx0NK9BOjy/OfVWvzANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IEFzc3VyYW5jZSBEZXNpZ25hdGlvbiBSb290IDIwMTEwHhcNMTEwMzIzMTc0MTI3WhcNMzYwMzIzMTc0ODExWjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IEFzc3VyYW5jZSBEZXNpZ25hdGlvbiBSb290IDIwMTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCo787v7BKLkpTtz6qlgY1PpK1K7KXw2qg9tuVhAZnOOiNzWlhnn/W2W/VP+aCbdR7MU2IQPKelOjvmJCL0GJYu8vzZpYjG/VHwMcO9AdxFtvZAK7dFe0VP7cC0fFhE+Yn7anU7bfEurDWhX3qUzTptmLi4KeYzmC4zg3qGt6gKEPIHMmPkMu1NqwUModdySaw1LC5w7e4S/COx3FrfYeksRM2u2wZUj0/B1hVyrlCJOYn1lYLc/0HriW+84J95XSQW9x04qt7YJJf2l0d0WyM4yJ0uqtEfzglc8bmfkjjSEWg+zF1Oz5Sf0kK94vFL8aepXHkF+yX3wVP32cRNeQ+KTbQwcabpUeWO4MiDxzH8mEb2onb8poFtdpCNMiEfLT5pK0+q7HvTuWTB1rtf+jjEQaZtWsMRh/u8M3BKJovmRN3LuDDTm3saDgO0UeDKv3s8V5qg2Ev+fjbYgfolvX4D9Vks9tenbd0Qd3cJrnbihTOmfXEg+DpPKrbqQinQ08YpSwUs57hKz9K7giAwm6JNH3gs2VQT2CooaFFWpffbrlkOudEwl4IEZqUCPCX63e0JwmC8F2yhWraXzIoTVva0rt/PfkAvSUHgY45YIMyjTzM7m888cn5IQUI9Y+Ne53Vsf+9tgAmkK6Q+3uQrLCupRFaDvrZuYLkWGuFi6VSdvwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGqlTRTOO0G4iUlR2OXZDHv95FEEwEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQELBQADggIBAAsu+lTeEaRy5BMdi7xCNnz+dsMYPCcGCxqD+gBrB/41d3tcu4URKJJTVamxEjQM8UaVtZ6dVB09Afjn7ai2gLVv5U1jddZtw7xuOAtf/GpsoTjveKm4B0yDesG1r4aDlBQ4yiKtKZYxdSXsmyy6PghuvrWQnJ6xvvS803EdJ3IlriwPzBdm6hnjUMefZfipJ6lXwoqy5lPr23h8HLOn8lW/IRAeX1oVIEwMXpzhrtMU2RRW6M23xBfBRqqjGSDcDENLUbqqfa9LvTT5AATozCHVm8nMFc5YGn1Ey6KoSYEk5Lwn/dsrd7G5u+Qa2XswEWiR36wZBM3cP28iHCO38vQ8LKd4OLXNdpy7d5Vczy8AKYgPlhPyaMuqwDsGmv1uGUjt9rhRdtJy08GvXUD3CfAhaYb0YBAfmh4ZhA6w7g7lqDnb/u8OyrQp7MMI0IqwoMyJXiNMz5xT2UMCEj4ZCu/bZtJXXIfF+fDBWEj8GW/mYID4sie/KcHemfsiG4hRQHhQJBb4oPP+FKmksJG5pyjc9Eca3hmliMeTiKEC4IVRD2sHwH9ez+s+0CG0Nj4to5sLbCBwSqSyFifhTPSRVvee4rJE+113bZFz2xu/CHZVkMpq9GdZevaepgfbXt8ObEwkRyxCXPq+AlsawdlYZsIMs87ktOz061ZPmszMsqCkMIIG1zCCBL+gAwIBAgIKYRDHKgAAAAAAAjANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IEFzc3VyYW5jZSBEZXNpZ25hdGlvbiBSb290IDIwMTEwHhcNMTEwNjI4MTkyMTU5WhcNMzEwNjI4MTkzMTU5WjCBhzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjExMC8GA1UEAxMoTWljcm9zb2Z0IEFzc3VyYW5jZSBEZXNpZ25hdGlvbiBQQ0EgMjAxMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJbPzmFzKfyRtqdezYAmaTmZyToZbmgIldwY7dwdiyutmHbexkirDsvQj1otnVvKZfPAHvVPJWhQcSDXtgnXTFu/8SdY7YpudZOZ6hAQ3vYea7feQhgYN2T5ZrYOX6++sQwtJr96uDs0B4a6tbZA7cadMCicissnWjygpKba2Id45O2R0EwY4Ml83kH3OMWyVy+UUCCxkiqwyGb/gN6MpaljI9OiwMf7QXK35WRG2SFObQIlBb4YgLuoGlOIkDFGHPVgYcAF/CIapE6vtT44HaMkkPxUcLFHpZGdDA/wthbhaSV+5MiaBwMhQah8sDbl9JEWFNWcA654rLTkOHeg7klU8wO0yNjo7+pjdhcJz1PxYxItoxjxmoI/DVMm+XNeKr29+6Zhdn5n6DK0BB/z9j3U1whHNYmiuGdUAJUli718FXhWkYH7NKpS3eLBQg+QHbvgEO4bed2wQ2US4ZcSyd+boNwAkG/jHYrMPM7ObRMW+TAOvKtKHcEb3yWuHTbHViWBwQcdTiv7AAPH73neRzU3XHhqwxO/aqwbiFcvzBesqV6eh8TypwB8i+90f8nzR2YYXB1JsM74ggf6DC6/AO/qLPN1A/Zrba9xP1imddXJgvbvjcW+x/Ye2d+xNjH+33goPGJPSUyhkzUHVj0szJmRfOIqglHsBSirUiErBqgBAgMBAAGjggFAMIIBPDAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQUWEIJEil9BmOUtEz/Eb7XOFQwJZkwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUGqlTRTOO0G4iUlR2OXZDHv95FEEwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWljQXNzRGVzUm9vXzIwMTFfMDNfMjMuY3JsMF0GCCsGAQUFBwEBBFEwTzBNBggrBgEFBQcwAoZBaHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9jZXJ0cy9NaWNBc3NEZXNSb29fMjAxMV8wM18yMy5jcnQwDQYJKoZIhvcNAQELBQADggIBAIoMbZz985UPTHi2Cl6QPuj7s/+mCLJLWXRr37Wf20hmOKKMrb+TzV+ci22YJdsQ5ApbN9K3mDAPIClnnh89TrKFiuYSg9VgzrZ+m6D6LBL/karcuePObrVumNODVZxCTKNCiReJakfhsWyafz1J4Bpe2uH3NEzb+OnpOEDsKjhDMiywxfeKIJoMPRJYTDWmE8TcFx6E/fJbSxB9Ao0scyG/ClVpszDdl0SsXm2AGN3BWGOm7+5+UbbwQfFlOdWB46yI/KNmykosVZewv/w2nXxE7/oEPlbzhwr5ysQEe+hRyD/m4xDRYv9hjtClJMVxysCyVwVnTm5ejVbmue7W6vrmi1VNb2/DUt+0WBGM5/ixrQhwlEmNrMAhE1va75PMRzO/7hnD97m28buFQfQztYDiKKxYl68IOlZQqpY8TBry3qxF/Ds1NWa8kPvG1zbVz3HJeN0NNR7BO3/Z1D7ajIimPT8/K/EqSreNK7CGXwY9kGEvkf5cX88IuKcCdeWTkH8ltFihllsDTsPrpMlsHIClAkgzIbR7fE9wGIy300WShWEEQqxn1od+pDwsZfbG2T+NP5M7QLV8Wp+EqlpIc1OmOEW49ly/EeFjUuhpvkaxT93lRPYN3jxaumAZ4wXWlvUvqaYhqOzTMYMdOV71b76Nk6hR6LN+iQMbEDCEQheiMQA="
    Thanks for your help

    Cyprien Autexier


    • Edited by sandør Wednesday, December 05, 2012 4:45 PM
    Wednesday, December 05, 2012 4:44 PM
  • Hi Cyprien,

    I can reproduce the failure and it's occurring because the certificate's public key does not seem to match the private key that was used to generate the signature.  The decrypted signature should be a properly formatted PKCS1 buffer but it's just looks like random bytes. So the certificate that you're using to verify the signature doesn't look like the correct one.  However, you're getting these values directly from the token and the certificate meets all of the criteria outlined in the guidance so it's hard to say what the problem is here.  Only 2.2 below seems to be the hangup.  Not sure how to advise you past this point.

    1. Verify the trustworthiness and the validity of the certificate. This step assumes that the “Microsoft Assurance Designation Root 2011” root certificate is trusted on the cloud system. The root certificate needs to be manually added to the trusted root store on Windows-based servers.

    1. Certificate blob has the PKCS#7 formatted certificate chain. Build and verify that the cert chain is trusted. Trust chain verification failures due to expired leaf cert should be ignored.
    2. Make sure the certificate chain is checked against revocation failures. It is recommended to ignore the revocation failures due to offline CDPs.
    3. Check to make sure the leaf certificate has the “1.3.6.1.4.1.311.10.5.40” EKU.
    4. Query the public key for the root certificate in the cert chain, and check it against the public key of the “Microsoft Assurance Designation Root 2011” root certificate to make sure they match.

    2. Verify that the ASHWID is genuinely produced by trusted Windows code.

    1. Signature blob is the signed blob of the SHA1 hash of the concatenation of the nonce (when present) and the ASHWID.
    2. Use the leaf certificate to verify that the signed hash signature matches the original nonce that was sent from the cloud service and the received hardware byte stream.

    Carlos Lopez - Microsoft Escalation Engineer

    Wednesday, December 05, 2012 9:17 PM
    Moderator
  • Hello,

    Thanks for your answer but I was already checking the validity of the certificate chain (and i removed that from the sample because it was working pretty good). Here is the code I use to validate certificate chain and EKU

     SignedCms cms = new SignedCms();
                cms.Decode(rawCertificates);
    
                var certificates = cms.Certificates.Cast<X509Certificate2>().ToArray();
    
                var leaf = certificates.Single(cert => cert.Extensions.Cast<X509Extension>().Any(usage =>
                {
                    var eku = usage as X509EnhancedKeyUsageExtension;
                    if (eku != null)
                    {
                        return eku.EnhancedKeyUsages.Cast<Oid>().Any(oid => oid.Value == "1.3.6.1.4.1.311.10.5.40");
                    }
                    return false;
                }));
    
                var root = certificates.Single(cert => cert.IssuerName.Name == cert.SubjectName.Name);
    
                if (!trustedASHWIDRootPublicKey.Value.CompareTo(root.PublicKey.EncodedKeyValue.RawData))
                    throw new Exception("Unknown root certificate");
    
                if (!certificates.All(cert =>
                {
                    X509Chain chain = new X509Chain();
                    chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
                    chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline;
                    chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 1, 0);
    
                    if (cert == leaf)
                        chain.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreNotTimeValid;
                    else
                        chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
    
                    var isValid = chain.Build(cert);
                    chain.Reset();
    
                    return isValid;
                }))
                {
    
                    throw new Exception("Invalid or Expired Certificate");
                }
    It seems to be bug with the provided signature (or a wrong documentation) :(...

    Cyprien Autexier


    • Edited by sandør Thursday, December 06, 2012 1:11 AM
    Thursday, December 06, 2012 1:08 AM
  • Hello,

    Signature kind used by ASHWID is not supported by .net because it uses PSS, so I had to make a native call to NCryptVerifySignature.


    Cyprien Autexier

    • Marked as answer by sandør Thursday, December 20, 2012 1:37 PM
    Thursday, December 20, 2012 1:37 PM