Skip to content

encrypted_card

Olivier Yiptong edited this page Nov 6, 2017 · 32 revisions

Encrypted Card Payment Handler

Overview

This document describes a proposal for a payment handler that behaves like basic card, but provides additional security, by ensuring that the card information is not transmitted in the clear to the merchant.

This reduces PCI scope for the merchant, especially v3+

Payment Handler Properties

We'd like to consider this colloquially as "BasicCard++". In that sense, there are a few things that a similar to BasicCard and a few differences.

Similarities:

  • Form Fills are used to populate payment instruments
  • Payment Request invocation is similar

Differences:

  • The PAN is encrypted following an exchange with a key provider
  • The returned value from the PaymentRequest API does not contain the PAN, but contains an opaque blob
  • The returned blob can only be used to process the transaction with the key provider that created it
  • Additional constraints may be put by the key provider on the blob (could be a nonce, time bounded, or permanent)

image

PaymentMethodData Specification

URL specification

The payment handler can be specified using the same syntax as BasicCard with a notable difference: a key provider will be specified.

This parameter will be provided in addition to those specified in basic-card:

dictionary EncryptedCardRequest {
             sequence<DOMString>       supportedNetworks; // Defined in Basic Card
             sequence<CardType>        supportedTypes; // Defined in Basic Card
             DOMString                 keyProviderURL;
};

The Javascript would look as follows:

var supportedInstruments = [
  {
    supportedMethods: ['encrypted-card']
    data: {
      supportedNetworks: ['amex', 'discover', 'mastercard', 'visa'],
      supportedTypes: ['credit', 'debit'],
      keyProviderURL: 'https://www.bobpay.com/encrypted-cards'
    }
  },
  ...,
];
var payment = new PaymentRequest(
  supportedInstruments,
  details,
  options
);

The public key is specified using some concepts from the WebCrypto API, specifically, a subset of the [importKey](https://www.w3.org/TR/WebCryptoAPI/#dfn-SubtleCrypto-method-importKey) argument specification.

The payment handler will issue a request to the key provider URL and expect a valid public key to be provided. The response is expected to be as follows:

dictionary PublicKey {
             KeyFormat                    format;
             (BufferSource or JsonWebKey) keyData;
             AlgorithmIdentifier          algorithm;
}

In contrast to the Web Crypto API:

  • the extractable parameter is assumed to be false
  • the usages parameter is assumed to be ['encrypt']

This implies that if an algorithm is specified that doesn't support the encrypt usage, the payment method declaration will fail.

Inline specification

An alternative is to use public key cryptography. The merchant specifies the public key in the payment method specification and that data is used in the encryption process later on. As above, the data is specified similar to basic-card.

The public key is specified using same concepts from the WebCrypto API as above.

dictionary EncryptedCardRequest {
             sequence<DOMString>       supportedNetworks; // Defined in Basic Card
             sequence<CardType>        supportedTypes; // Defined in Basic Card
             PublicKey                 publicKey;
};

The Javascript would look as follows:

  var supportedInstruments = [{
    supportedMethods: 'encrypted-card',
    data: {
      publicKey: {
        format: 'jwk',
        keyData: {
          alg: 'RSA-OAEP-256',
          e: 'AQAB',
          ext: true,
          key_ops: ['encrypt'],
          kty: 'RSA',
          n: 'vVf4OM-GXBF_r-mtGfNVuMiF99x55p-q2ZYYhNKMoDo3PgVWwdq3lYRyWLro0mRomYWcETlitE_L69P-bnOe65_DJs1y6_kp7m1jU2hNreZ7fmxv4osFNBOC7VOL0UK8LTTt4la0OBDx2omGwtt-UHBvYOkO_RhZI_JpGQfcHZbCYXA4qdk6URbLtJ-DMfm4RRk7OTpTgBkbtX7kC-r_L-5uMPndCzXkp7roEjVVt6CDo0hp_OeRWIverrNub5f6vxFM0WlR309ulWaq9shDKioAvB6aSwLhCBPNaRM40PHkzY9WLw2QF7tfzX3XpREnmufOLyq3KHyyIQ6N8xEOIIXdekAP4lJFUIZ4YfwtgK71N-aPukMlIRn0FDMq8RX8rmDFqxuxaty1rmP-uKe282Cna4M4cTJdprcjnurYaRig2BbCIlTBDBx0onLbIr0TQGtqSNQzxttHADqIcSMuOKTnmWI3dUvj8YJ-eaNw6Ge_Z7Z1x0tIwM424-6cYKwz4UROXL0ifzgzaeezaFd_t4p1oV9hQRbqVdilLOXuZ25rIBmWUzEzWm8XHo4sDPdyv8YulziBNvOhipObOBe9LWMVpDzulk2gotm7L7_uFxBf4kKA3oEFVxR3r9n0Eljrxr8os19db3z59dsfEDMwSLAkARyfll0KECVZAsZ8HFE'
        },
        algo: {name: 'RSA-OAEP', hash: {name: 'SHA-256'}},
      }
    }
  }];

Card Encryption

The exact same data contained in the BasicCardResponse dictionary, is encrypted.

dictionary EncryptedCardData {
    required DOMString       cardNumber;
             DOMString       cardholderName;
             DOMString       cardSecurityCode;
             DOMString       expiryMonth;
             DOMString       expiryYear;
             PaymentAddress? billingAddress;
};

PaymentRequest Response

This data is returned as part of the PaymentResponse as follows:

dictionary EncryptedCardResponse {
             DOMString       cardholderName; // data from BasicCardResponse
    optional DOMString       suffix; // Last four digits of card number
    required DOMString       encryptedCardData; // base64-encoded string
};

Sample Javascript response:

{
  "requestId": "e2b74536-919e-4098-bcda-f8c9957081a1",
  "methodName": "encrypted-card",
  "details": {
    "cardholderName": "Kaiser Soze",
    "suffix": "1111",
    "encryptedCardData": "aEkQ+UKnKHKY8rhKriejMwQazMkE/6By4zjvJDcdgPrlGtE5xGBdIWJI31UqzZIrIMAyI3CpTnF6fJpuPfNW/A2Pc8Stk7FdHbtsJfzI5afJIAHbXEQF0kZ2ZYX7MfKYLudP12ipnbOtYXaOSqSl38uxaLcTx4kQHU2YbCLWlfY1Jh4grhU2ZLUT95NCV+gC5gJJ4ewuzIkUK4qQ+yOXeXNxTZKavWdx9hgOPXtLdOcbWyihzSzkmNcixDxwBSP7oeB8VMLvIy+iPLo7LsQUtrYEkoYC/Lp8knz6WZcDghramRd/IdidJjgMQbVT6ej4yud/+eSOmETgEbx517hC8npEquS37MNSuRMslxMlY5IiVeKi9rUp6WjdNqTEgkB0zpGb8ACebsJXP/Q5rGn+ReaJewGHoP1GWmhyLAKHFnPgWBncs9Ff6tQkC9QyDDqQV49GvpYs5e93/OqkAZSUSvqI16skDoglfLFboxcMGll1jggf3tR53X367y9B9o4E/xPG4k4z72vke1VgpJFOCSp3ev2F0QHcBXevov4n6v29DmA/pybDDc+9ci5HnFs3ZjV9ZoNknkuQmp/Dt+ylRYwg4RPGuTg2oK8Sbxg5ckspfoJ5OFoZxZLSh2py8kD1yZLrUt2WYCjfQMvc1EIfEJP/NAiHsmo4APVWeINN7sM="
  },
  "shippingAddress": null,
  "shippingOption": null,
  "payerName": null,
  "payerEmail": null,
  "payerPhone": null
}

Discussion: Encryption

The encryption can occur in one of these ways:

  1. through the public key in the TLS certificate of the key provider if a manifest is not found or the parameter is not found in the manifest
  2. through a Web App Manifest parameter on the key provider's origin, specifying a public key and list of ciphers as defined by WebCrypto
  3. through a public key provided as part of the PaymentMethodData dictionary
  4. Key provided in key request API call

1. Public Key Cryptography using TLS certificate

There's an inherent advantage to re-use the public key in the TLS certificate. This is because a lot can be cached/short circuited.

If there has already been a cipher exchange, the public key is potentially in the Browser's cache, and the result of the TLS handshaking will have selected a cipher suite for the key exchange step in TLS. The same cipher suite can be used to encrypt the card data.

That said, re-using the public key, where TLS expressly chooses not to for Forward Secrecy for transport makes this method less ideal for that reason.

2. Encryption using Manifest

A web manifest file can be provided with additional parameters specifying cryptographic parameters. Here's a quick example:

{
  encryptedCardKey: {
    format,
    keyData,
    algo,
    extractable,
    usages
  }
}

This data will be fed directly in SubtleCrypto's importKey IDL function.

3. Encryption options specified in PaymentMethodData

note: feedback incorporated in proposal above

Alternatively, encryption configuration can be specified in PaymentMethodData. It can use the same parameters specified above in the web app manifest, as defined by importKey IDL.

dictionary EncryptedCardRequest {
             sequence<DOMString>       supportedNetworks; // Defined in Basic Card
             sequence<CardType>        supportedTypes; // Defined in Basic Card
             KeyFormat format;
             (BufferSource or JsonWebKey) keyData;
             AlgorithmIdentifier algorithm;
             boolean extractable;
             sequence<KeyUsage> keyUsages;
}

4. Key provided in key request API call

note: feedback incorporated in proposal above

When making a GET request to the keyProviderURL, the response will be a public key as defined in Web Crypto.

Clone this wiki locally