Skip to content
This repository has been archived by the owner on Apr 28, 2022. It is now read-only.

IAB: Public/private keys for app should be distributed together with app #8

Open
oorlov opened this issue Nov 8, 2013 · 14 comments
Open

Comments

@oorlov
Copy link
Contributor

oorlov commented Nov 8, 2013

If distributorstore doesn't use the same key as sourcestore for signing receipts, OpenIAB will fail reciept verification

@henriklewander
Copy link

I propose we use an external service to retrieve the public key for a certain app store.

It can be just a simple text file in json format that holds information of how to retrieve the public key from each store:
http://trusted.onepf.org/stores.json (see example at the end)
Or a simple service
http://trusted.onepf.org/store?name=Appland

Signed with a master private key that perhaps one person at Yandex and one backup person at another party (like Appland) has access to. This key is not distributed and must not be compromised. If so, an SDK update is needed.

To identify each store (name above) it is possible to use the method getStoreName() that is a part of SDK.

Advantages:

  1. No key is needed to be included in the AppDF package meaning the developer does not need to bother with keys (except for Google Play etc)
  2. A compromised key can be changed without the need for recompiling or releasing a new SDK or App.
  3. There is no need of recompiles on the developers side to support OpenIAB in a new store.

The main problem with distributed the public/private keys together with the app is if the private key is compromised in any store the developers of the app must release a new version of the app with a new public key and add that to all stores.

This problem does not exist in this proposal for two reasons:

  1. If a private key in a store has been compromised it is only necessary to change the key in that store.
  2. If a store misbehaves (which is worst case) the store can be removed from the list of trusted stores which will prevent all in app purchases through OpenIAB from this store.

Example of a stores.json signed with the master private key:

{
  "last_update":"2013-11-08 15:43",
  "stores":{
    "Appland":"http://applandinc.com/openiab/public_key?package={app_package_name}",
    "Yandex":"https://www.yandex.ru/openiab/publickey/{app_package_name}",
  }
}
Signature: 0784580aca28e024ba80710bebb06681

@henriklewander
Copy link

Or better:

  1. The store (e g Appland) generates one private/public key pair.
  2. The public key is signed with the OpenIAB master private key.
  3. The store's signed public key is added to the list available at http://trusted.onepf.org/stores.json

If the key is compromised, the store generates a new key pair and the public key will be signed by the OpenIAB master private key and added to the list.

@oorlov
Copy link
Contributor Author

oorlov commented Dec 2, 2013

It should work. Only issue I see here is need to change developer's habit. Stores provide publicKey in developer console. It's typical to take publicKey and put in code side by side with Google Play publicKey. Some developers don't even put publicKey in Android code and keep everything on backend. With 3rd party keystore and auto-loading of publickKeys developer lose control on publicKey

@henriklewander
Copy link

Do you have another solution where the developer does not need to change habit and still be able to compile once?

@oorlov
Copy link
Contributor Author

oorlov commented Dec 2, 2013

Another suggestion:

Process purchase in Distributor store, but sign receipts on Source store by server-to-server call. Source store doesn't need to share private key. Distributor and Source stores both have to maintain highload backends and have to communicate to each other to share purchases and other data.

Source backend is responsible for keep private key not compromised. Source and Distributor stores can agree on any security level of connection between each other. And if private key is compromised Source store is responsible to notify developer and ask him to submit another build as it happens right now

@oorlov
Copy link
Contributor Author

oorlov commented Dec 2, 2013

Or generate and keep private/public keys on 3rd party service and sign receipt there, but such service should be independent and technically reliable. But I'm not sure onepf.org could bring good enough backend soon

@jesper-sjovall
Copy link
Contributor

I think Henlew suggestion is best here, True as your say it will need to be a change in the developers habits.
And as that has be point out the main issues with this suggestion is the developers lost control of the app to Open IAB Servers.

Else I think use of a global key-server that store all keys and handle sign of punchers is the second best as this will remove complexity for the appstore. As an appstore can have open IAB apps from more then 1 source and in this case need to hold track of witch store this apps is from and maby also need to implement some different authentication methods.

@henriklewander
Copy link

Perhaps we can just add both keys together with the list of products, in AppDF or outside.

@henriklewander
Copy link

Then collaborating app stores can just send the apps to each other using AppDF and OpenAEP.

@oorlov
Copy link
Contributor Author

oorlov commented Dec 6, 2013

It looks like just sharing keys is only suitable option for now.
Currently I don't see workaround for moving ownership of publicKey from developer to OpenIAB if we use signed list of appstore urls for public keys.
And signing receipts on 3rd party node will cause plenty of unexpected problems.

I suggest to share public/private keys by additional server-2-server request.
And provide Export/Import keys functionality in Developer Console. When developer press "export private key" message with token should be sent to developer's email. Developer should specify token in Developer Console to access private key (2 passwords needed to access private key)

Last part is about OpenIAB:
If signature is verified on server (Bookmate, Yandex.Music, etc) it requires 3 params to be passed from app to server: receipt, signature, and appstoreName. appstoreName is used to choose proper key for verification in server code./
To make such if() works Distributor store should specify Source store name for OpenIAB (currently OpenIAB returns name of store it connected to)
At the same time Distributor store name should be also specified in Purchase JSON to avoid customer confusion when he paid in SlideME but of Service UI says item is paid in Yandex

Thoughts?

@jesper-sjovall
Copy link
Contributor

Yes, This is a very hard problem without a simple solution, and as point out, for now each store must have a public/private key to be enable to process download.

I think we for now want to skip the parts a user manual will export/import public/private keys between stores.
Or do this very simple if need.

As your say, for get it work (correct me if I misunderstand your) the flow will be as follow:

  • Appland and Yandex have a cooperating, Yandex exports apps and the public/private key to Appland that Appland store in their own database.
  • A user has an app TrivalDrive the app ask the who has Open IAB, Appland Appstore response it support
    Open IAB as Appland and on behalf of Yandex
  • TrivalDrive that was build for Yandex and has a public key for Yandex store. TrivalDrive say to Appland Appstore
    I want to buy a product "sku_gas" from your and I have public key for Yandex
  • Appland Appstore UI is display and allow the user to confirm the punches, after this Appland Backend-server is verify the transaction and final sign the transaction with Yandex private key that Appland has.

As also point out for get it work, we must change the Open IAB Java Lib parts to support a "Appstore" also can work as behalf of for one or more Appstores.

@morozstepan
Copy link

Hi!
I also see financial issues and troubles, if we make the exchanging of the keys.
For example, store1 is source store, store2 is distributor.
Store1 exports it's key into store2, and store2 is now able to sign transactions, so, store1 is not able to check this process.
I suggest signing on the side of source store. So, every time store2 wants to sell something, it goes to store1 and signs the transaction. The disadvantage of this scheme is that store2 will be unable to sell anything if store1 is down, but all the selling process will be more transparent.

@jesper-sjovall
Copy link
Contributor

Morozstepan, in this case my case above will have change in step nr 1 that Appland do not get public/private key from Yandex.
And in my final step (nr 4) Appland will send a sign request to Yandex that Yandex will sing the data for Appland.

Example to protocol:

https://singserver.com/openAEP/sing?data={urlencode JSON-String}
-> HTTP Error code or base64 encode sign.


https://singserver.com/openAEP/sing?data=%7B%22sku%22%3A%22buy_gas%22%2C%22payload%22%3A%22userpayload%22%7D
-> HTTP 200.
YXNkYXNkYXNkYXNkJTdCJTIyc2t1JTIyJTNBJTIyYnV5X2dhcyUyMiUyQyUyMnBheWxvYWQlMjIl
M0ElMjJ1c2VycGF5bG9hZCUyMiU3RCU3QiUyMnNrdSUyMiUzQSUyMmJ1eV9nYXMlMjIlMkMlMjJw
YXlsb2FkJTIyJTNBJTIydXNlcnBheWxvYWQlMjIlN0Q=

Obvious is also some user permissions can be add.

@henriklewander
Copy link

Stepan: There will be lots of singing requests going between our servers, e g when an app may download its purchase history every time it starts up. For every item, a signing request will need to be exchanged between our servers. This will be a lot of communication and of course the latency will rise for the end users.

I think the exchange of the keys is the only plausible solution.
The source store needs to relinquish a bit of control but the same problem applies to sharing of the premium apps, the upfront paid apps. There, the source store does not control the payment process either. The stores need to trust each other for app sharing to work.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Development

No branches or pull requests

4 participants