How can I verify Win8 inapp-purchase receipt, using xmlsec1? Here is what I'm tyring to do:
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>
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-----
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?)?
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.