xmlwindows-8in-app-purchasexmlsecxmlsec1

Verifying Windows 8 inapp-purchase receipt with xmlsec1


How can I verify Win8 inapp-purchase receipt, using xmlsec1? Here is what I'm tyring to do:

  1. My sample receipt (saved in file receipt.xml):

    <?xml version="1.0"?>
    <Receipt Version="1.0" ReceiptDate="2012-08-30T23:10:05Z" CertificateId="b809e47cd0110a4db043b3f73e83acd917fe1336" ReceiptDeviceId="4e362949-acc3-fe3a-e71b-89893eb4f528">
    <AppReceipt Id="8ffa256d-eca8-712a-7cf8-cbf5522df24b" AppId="55428GreenlakeApps.CurrentAppSimulatorEventTest_z7q3q7z11crfr" PurchaseDate="2012-06-04T23:07:24Z" LicenseType="Full" />
    <ProductReceipt Id="6bbf4366-6fb2-8be8-7947-92fd5f683530" ProductId="Product1" PurchaseDate="2012-08-30T23:08:52Z" ExpirationDate="2012-09-02T23:08:49Z" ProductType="Durable" AppId="55428GreenlakeApps.CurrentAppSimulatorEventTest_z7q3q7z11crfr" />
    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
        <SignedInfo>
            <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
            <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
            <Reference URI="">
                <Transforms>
                    <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
                </Transforms>
                <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
                <DigestValue>cdiU06eD8X/w1aGCHeaGCG9w/kWZ8I099rw4mmPpvdU=</DigestValue>
            </Reference>
        </SignedInfo>
        <SignatureValue>SjRIxS/2r2P6ZdgaR9bwUSa6ZItYYFpKLJZrnAa3zkMylbiWjh9oZGGng2p6/gtBHC2dSTZlLbqnysJjl7mQp/A3wKaIkzjyRXv3kxoVaSV0pkqiPt04cIfFTP0JZkE5QD/vYxiWjeyGp1dThEM2RV811sRWvmEs/hHhVxb32e8xCLtpALYx3a9lW51zRJJN0eNdPAvNoiCJlnogAoTToUQLHs72I1dECnSbeNPXiG7klpy5boKKMCZfnVXXkneWvVFtAA1h2sB7ll40LEHO4oYN6VzD+uKd76QOgGmsu9iGVyRvvmMtahvtL1/pxoxsTRedhKq6zrzCfT8qfh3C1w==</SignatureValue>
    </Signature>
    

  2. Using CertificateId, I retrieve certificate using this url and save it to file cert. Here are its contents:

    -----BEGIN CERTIFICATE-----
    MIIDyTCCArGgAwIBAgIQNP+YKvSo8IVArhlhpgc/xjANBgkqhkiG9w0BAQsFADCB
    jjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1Jl
    ZG1vbmQxHjAcBgNVBAoMFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEWMBQGA1UECwwN
    V2luZG93cyBTdG9yZTEgMB4GA1UEAwwXV2luZG93cyBTdG9yZSBMaWNlbnNpbmcw
    HhcNMTExMTE3MjMwNTAyWhcNMzYxMTEwMjMxMzQ0WjCBjjELMAkGA1UEBhMCVVMx
    EzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1JlZG1vbmQxHjAcBgNVBAoM
    FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEWMBQGA1UECwwNV2luZG93cyBTdG9yZTEg
    MB4GA1UEAwwXV2luZG93cyBTdG9yZSBMaWNlbnNpbmcwggEiMA0GCSqGSIb3DQEB
    AQUAA4IBDwAwggEKAoIBAQCcr4/vgqZFtzMqy3jO0XHjBUNx6j7ZTXEnNpLl2VSe
    zVQA9KK2RlvroXKhYMUUdJpw+txm1mqi/W7D9QOYTq1e83GLhWC9IRh/OSmSYt0e
    kgVLB+icyRH3dtpYcJ5sspU2huPf4I/Nc06OuXlMsD9MU4Ug9IBD2HSDBEquhGRo
    xV64YuEH4645oB14LlEay0+JZlkKZ/mVhx/sdzSBfrda1X/Ckc7SOgnTSM3d/DnO
    5DKwV2WYn+7i/rBqe4/op6IqQMrPpHyem9Sny+i0xiUMA+1IwkX0hs0gvHM6zDww
    TMDiTapbCy9LnmMx65oMq56hhsQydLEmquq8lVYUDEzLAgMBAAGjITAfMB0GA1Ud
    DgQWBBREzrOBz7zw+HWskxonOXAPMa6+NzANBgkqhkiG9w0BAQsFAAOCAQEAeVtN
    4c6muxO6yfht9SaxEfleUBIjGfe0ewLBp00Ix7b7ldJ/lUQcA6y+Drrl7vjmkHQK
    OU3uZiFbCxTvgTcoz9o+1rzR/WPXmqH5bqu6ua/UrobGKavAScqqI/G6o56Xmx/y
    oErWN0VapN370crKJvNWxh3yw8DCl+W0EcVRiWX5lFsMBNBbVpK4Whp+VhkSJilu
    iRpe1B35Q8EqOz/4RQkOpVI0dREnuSYkBy/h2ggCtiQ5yfvH5zCdcfhFednYDevS
    axmt3W5WuHz8zglkg+OQ3qpXaXySRlrmLdxEmWu2MOiZbQkU2ZjBSQmvFAOy0dd6
    P1YLS4+Eyh5drQJc0Q==
    -----END CERTIFICATE-----
    
  3. And then I try this: xmlsec1 --verify --print-debug --pubkey-cert-pem cert receipt.xml. Here is the output:

    func=xmlSecOpenSSLEvpDigestVerify:file=digests.c:line=229:obj=sha256:subj=unknown:error=12:invalid data:data and digest do not match
    FAIL
    SignedInfo References (ok/all): 0/1
    Manifests References (ok/all): 0/0
    = VERIFICATION CONTEXT
    == Status: invalid
    == flags: 0x00000000
    == flags2: 0x00000000
    == Key Info Read Ctx:
    = KEY INFO READ CONTEXT
    == flags: 0x00000000
    == flags2: 0x00000000
    == enabled key data: all
    == RetrievalMethod level (cur/max): 0/1
    == TRANSFORMS CTX (status=0)
    == flags: 0x00000000
    == flags2: 0x00000000
    == enabled transforms: all
    === uri: NULL
    === uri xpointer expr: NULL
    == EncryptedKey level (cur/max): 0/1
    === KeyReq:
    ==== keyId: NULL
    ==== keyType: 0x00000000
    ==== keyUsage: 0xffffffff
    ==== keyBitsSize: 0
    === list size: 0
    == Key Info Write Ctx:
    = KEY INFO WRITE CONTEXT
    == flags: 0x00000000
    == flags2: 0x00000000
    == enabled key data: all
    == RetrievalMethod level (cur/max): 0/1
    == TRANSFORMS CTX (status=0)
    == flags: 0x00000000
    == flags2: 0x00000000
    == enabled transforms: all
    === uri: NULL
    === uri xpointer expr: NULL
    == EncryptedKey level (cur/max): 0/1
    === KeyReq:
    ==== keyId: NULL
    ==== keyType: 0x00000001
    ==== keyUsage: 0xffffffff
    ==== keyBitsSize: 0
    === list size: 0
    == Signature Transform Ctx:
    == TRANSFORMS CTX (status=0)
    == flags: 0x00000000
    == flags2: 0x00000000
    == enabled transforms: all
    === uri: NULL
    === uri xpointer expr: NULL
    === Transform: exc-c14n (href=http://www.w3.org/2001/10/xml-exc-c14n#)
    === Transform: rsa-sha256 (href=http://www.w3.org/2001/04/xmldsig-more#rsa-sha256)
    == Signature Method:
    === Transform: rsa-sha256 (href=http://www.w3.org/2001/04/xmldsig-more#rsa-sha256)
    == SignedInfo References List:
    === list size: 1
    = REFERENCE VERIFICATION CONTEXT
    == Status: invalid
    == URI: ""
    == Reference Transform Ctx:
    == TRANSFORMS CTX (status=2)
    == flags: 0x00000000
    == flags2: 0x00000000
    == enabled transforms: all
    === uri: NULL
    === uri xpointer expr: NULL
    === Transform: enveloped-signature (href=http://www.w3.org/2000/09/xmldsig#enveloped-signature)
    === Transform: c14n (href=http://www.w3.org/TR/2001/REC-xml-c14n-20010315)
    === Transform: sha256 (href=http://www.w3.org/2001/04/xmlenc#sha256)
    === Transform: membuf-transform (href=NULL)
    == Digest Method:
    === Transform: sha256 (href=http://www.w3.org/2001/04/xmlenc#sha256)
    == Manifest References List:
    === list size: 0
    Error: failed to verify file "receipt.xml"
    

Am I doing something wrong? What params should I provide to verify the receipt properly? Or is it indeed invalid (then can someone provide me with valid receipt?)?


Solution

  • I found that verification succeeds if all of the extra whitespace is removed from receipt.xml. If the file really does contain this when it's downloaded and saved, you may have to run the file through sed or something to remove it (if it's actually there and you didn't just add it yourself accidentally).

    # xmlsec1 --verify --print-debug --pubkey-cert-pem cert receipt.xml
    OK
    SignedInfo References (ok/all): 1/1
    Manifests References (ok/all): 0/0
    = VERIFICATION CONTEXT
    == Status: succeeded
    == flags: 0x00000000
    == flags2: 0x00000000
    == Key Info Read Ctx:
    = KEY INFO READ CONTEXT
    == flags: 0x00000000
    == flags2: 0x00000000
    == enabled key data: all
    == RetrievalMethod level (cur/max): 0/1
    == TRANSFORMS CTX (status=0)
    == flags: 0x00000000
    == flags2: 0x00000000
    == enabled transforms: all
    === uri: NULL
    === uri xpointer expr: NULL
    == EncryptedKey level (cur/max): 0/1
    === KeyReq:
    ==== keyId: rsa
    ==== keyType: 0x00000001
    ==== keyUsage: 0x00000002
    ==== keyBitsSize: 0
    === list size: 0
    == Key Info Write Ctx:
    = KEY INFO WRITE CONTEXT
    == flags: 0x00000000
    == flags2: 0x00000000
    == enabled key data: all
    == RetrievalMethod level (cur/max): 0/1
    == TRANSFORMS CTX (status=0)
    == flags: 0x00000000
    == flags2: 0x00000000
    == enabled transforms: all
    === uri: NULL
    === uri xpointer expr: NULL
    == EncryptedKey level (cur/max): 0/1
    === KeyReq:
    ==== keyId: NULL
    ==== keyType: 0x00000001
    ==== keyUsage: 0xffffffff
    ==== keyBitsSize: 0
    === list size: 0
    == Signature Transform Ctx:
    == TRANSFORMS CTX (status=2)
    == flags: 0x00000000
    == flags2: 0x00000000
    == enabled transforms: all
    === uri: NULL
    === uri xpointer expr: NULL
    === Transform: exc-c14n (href=http://www.w3.org/2001/10/xml-exc-c14n#)
    === Transform: rsa-sha256 (href=http://www.w3.org/2001/04/xmldsig-more#rsa-sha256)
    === Transform: membuf-transform (href=NULL)
    == Signature Method:
    === Transform: rsa-sha256 (href=http://www.w3.org/2001/04/xmldsig-more#rsa-sha256)
    == Signature Key:
    == KEY
    === method: RSAKeyValue
    === key type: Private
    === key usage: -1
    === rsa key: size = 2048
    === list size: 1
    === X509 Data:
    ==== Certificate:
    ==== Subject Name: /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/OU=Windows Store/CN=Windows Store Licensing
    ==== Issuer Name: /C=US/ST=Washington/L=Redmond/O=Microsoft Corporation/OU=Windows Store/CN=Windows Store Licensing
    ==== Issuer Serial: 34FF982AF4A8F08540AE1961A6073FC6
    == SignedInfo References List:
    === list size: 1
    = REFERENCE VERIFICATION CONTEXT
    == Status: succeeded
    == URI: ""
    == Reference Transform Ctx:
    == TRANSFORMS CTX (status=2)
    == flags: 0x00000000
    == flags2: 0x00000000
    == enabled transforms: all
    === uri: NULL
    === uri xpointer expr: NULL
    === Transform: enveloped-signature (href=http://www.w3.org/2000/09/xmldsig#enveloped-signature)
    === Transform: c14n (href=http://www.w3.org/TR/2001/REC-xml-c14n-20010315)
    === Transform: sha256 (href=http://www.w3.org/2001/04/xmlenc#sha256)
    === Transform: membuf-transform (href=NULL)
    == Digest Method:
    === Transform: sha256 (href=http://www.w3.org/2001/04/xmlenc#sha256)
    == Manifest References List:
    === list size: 0
    

    Remember that the signature is valid for the exact file, character for character. Any changes to the file, even whitespace for formatting, will invalidate the signature. I suspect that there is some formatting going on when you opened the file, maybe you saved it with that formatting.

    Edit

    I forgot that you're also missing the closing tag in what you posted for receipt.xml. I suspect it's there in your copy of the file, though, since xmlsec1 would have told you so if it wasn't (as it told me; I had to manually add it).

    Try xmllint --noblanks --output receipt.xml receipt.xml to remove the unwanted spaces and CR/LFs.