diff --git a/receipt_utility.ts b/receipt_utility.ts index f9ac867..1bb69b9 100644 --- a/receipt_utility.ts +++ b/receipt_utility.ts @@ -22,9 +22,12 @@ export class ReceiptUtility { ASN1HEX.getVblen = function(s, idx) { const c = ASN1HEX.getL(s, idx) const oldResult = prevGetVblenFunction(s, idx) - // Round up to the remaining length in the string, measured in bytes (2 hex values per byte) + // Round up to the remaining length in the string, measured in bytes (2 hex values per byte). + // The value starts after the tag and length octets, so measure from the value index rather + // than the tag index. jsrsasign 11.1.2 added a "c + getVblen * 2 > s.length" bounds check in + // getChildIdx; measuring from idx overshoots by the header length and trips that check. if (oldResult === 0 && c === '80') { - return (s.length - idx) / 2 + return (s.length - ASN1HEX.getVidx(s, idx)) / 2 } return oldResult } diff --git a/tests/unit-tests/receipt_utility.test.ts b/tests/unit-tests/receipt_utility.test.ts index 7717925..cc92bb5 100644 --- a/tests/unit-tests/receipt_utility.test.ts +++ b/tests/unit-tests/receipt_utility.test.ts @@ -23,4 +23,12 @@ describe('Receipt Utility Tets', () => { const extracted_transaction_id = receipt_utility.extractTransactionIdFromTransactionReceipt(receipt) expect(extracted_transaction_id).toBe("33993399") }) + it('should parse an indefinite length xcode receipt without throwing a too short ASN.1 value error', async () => { + // Regression test for the "too short ASN.1 value" bounds check added to jsrsasign getChildIdx in 11.1.2. + // Xcode receipts use indefinite length encoding, and the parse must succeed across jsrsasign versions. + const receipt = readFile('tests/resources/xcode/xcode-app-receipt-with-transaction') + const receipt_utility = new ReceiptUtility() + expect(() => receipt_utility.extractTransactionIdFromAppReceipt(receipt)).not.toThrow() + expect(receipt_utility.extractTransactionIdFromAppReceipt(receipt)).toBe("0") + }) }) \ No newline at end of file