Skip to content

Interface specification between Self-Sovereign Identity and passport-level authentication #74

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
qstokkink opened this issue Mar 16, 2018 · 9 comments
Labels
priority: low Should be addressed at some point in the future priority: medium Enhancements, features or exotic bugs

Comments

@qstokkink
Copy link
Collaborator

qstokkink commented Mar 16, 2018

M.V.P. IDEMIA Interface

This document will entail the interface specifications for the onboarding procedure between the TU Delft IPv8 Blockchain solution (IPv8) and the IDEMIA biometry platform, from IPv8’s point of view. The Public Key based claim is the preferred solution from an ideological “the user is in control” perspective.

Context

This work defines the communication standard between 2 stand-alone apps. We provide an open standard for multiple biometric vendors, this is the key factor for large-scale adoption. As such and for security, the applications should be isolated as much as possible. Therefore any authentication app can talk to the IPv8 app. Alternative identity management apps such as Soverin or uPort can also use this neutral interface definition. This specification is specifically crafted to protect against man-in-the-middle attacks on the phone of a user. To deal with the isolation we need secure bi-directional authentication between apps. A simple REST api is used to communicate. For external communication QR-codes must be used.

There are two keypairs:

  • An IDEMIA keypair, assigned by IDEMIA
  • An IPv8 keypair, generated by the user through IPv8

Onboarding claim: Public Key based

The onboarding claim has the following format in IPv8:

Claim property Type Content
Name String “IDEMIA_ONBOARD_PK”
Format String “IDEMIA_CURVE”
Link String <IDEMIA Public Key>

Use-case

At the municipality:

  1. IDEMIA: During the onboarding process in the municipality, the user onboards using the IDEMIA onboarding process (as specified in previous documents).
  2. IDEMIA: The IDEMIA public key is sent to IPv8.
  3. IPv8: IPv8 packs the public key into the claim format, as shown above.
  4. IPv8: The municipality signs the claim format using the IPv8 key.
  5. IPv8: The user signs the claim format signed by the municipality using the IPv8 key and publishes this.

At the verifier (store/airport/business/etc.):

  1. IPv8: The user presents the claim to the verifier.
  2. IPv8: The verifier issues a challenge (random data) to the user.
  3. IDEMIA: Through the IDEMIA app, the user signs the challenge with his IDEMIA private key
  4. IPv8: The verifier confirms that the signature belongs to the public key, as advertised through the claim format.

Required interface IDEMIA -> IPv8

Interface Type Details
sign(String: challenge) String Sign data using the Private Key for this device

Required interface IPv8 -> IDEMIA

Interface Type Details
createPKClaim(String: publicKey) None Create the IDEMIA_ONBOAD_PK claim for a certain IDEMIA public key

Onboarding claim: IDEMIA identifier based

The onboarding claim has the following format in IPv8:

Claim property Type Content
Name String “IDEMIA_ONBOARD_ID”
Format String “IDEMIA_ID”
Link String <IDEMIA identifier>

Use-case

At the municipality:

  1. IDEMIA: During the onboarding process in the municipality, the user onboards using the IDEMIA onboarding process (as specified in previous documents).
  2. IDEMIA: The IDEMIA identifier is sent to IPv8.
  3. IPv8: IPv8 packs the identifier into the claim format, as shown above.
  4. IPv8: The municipality signs the claim format using the IPv8 key.
  5. IPv8: The user signs the claim format signed by the municipality using the IPv8 key and publishes this.

At the verifier (store/airport/business/etc.):

  1. IPv8: The user presents the claim to the verifier.
  2. IDEMIA: The verifier contacts IDEMIA with the identifier and verifies the user based on the reported attributes.

Required interface IPv8 -> IDEMIA

Interface Type Details
createIDClaim(String: identifier) None Create the IDEMIA_ONBOAD_ID claim for a certain IDEMIA id
@qstokkink qstokkink added the priority: medium Enhancements, features or exotic bugs label Mar 16, 2018
@qstokkink qstokkink changed the title Integration of Self-Sovereign Identity with passport-level authentication Interface specification between Self-Sovereign Identity and passport-level authentication Mar 16, 2018
@qstokkink
Copy link
Collaborator Author

qstokkink commented Apr 6, 2018

EC25519 Key generation

EC25519 key generation in IPv8 is handled by libsodium, which is available on a lot of platforms.

Python

First install the libnacl dependency (using pip): pip install libnacl.
Then you can run the following code to generate a key:

import libnacl.dual

key = libnacl.dual.DualSecret()
serialized = self.key.sk + self.key.seed

This key can then be loaded again as follows:

import libnacl
import libnacl.dual

crypt, seed = serialized[:libnacl.crypto_box_SECRETKEYBYTES], \
                         serialized[libnacl.crypto_box_SECRETKEYBYTES :
                                    libnacl.crypto_box_SECRETKEYBYTES + libnacl.crypto_sign_SEEDBYTES]
key = libnacl.dual.DualSecret(crypt, seed)

Java (Android)

For Android, the libsodium-jni library can be used.
The encryption and signing key can be created as shown in this example (see the generate() method):
https://github.com/joshjdevl/libsodium-jni/blob/master/example/Sodium/app/src/main/java/android/alex/com/sodium/MainActivity.java

Note that for intercompatibility with Python we use the concatenation of the short (32-byte) key representation of the secret and signing key. Concretely the serialized key is then as follows:

[ -- 32 bytes: encryption secret key -- ][ -- 32 bytes: signing secret key -- ]

The dual key then has a total length of 64 bytes.

@qstokkink
Copy link
Collaborator Author

qstokkink commented Apr 9, 2018

IPv8 Attestation REST API

IPv8 has two major REST interfaces: one for attribute attestation and one for attribute verification.
This post will describe the attestation interface and showcase an example which can be run on a single machine.

Setup

IPv8 requires several third party libraries, make sure that these dependencies are satisfied as described in https://github.com/Tribler/py-ipv8/blob/master/README.md .

Once you have the dependencies installed, create a new working directory. In this directory, copy the files from this gist: https://gist.github.com/qstokkink/5c9feb674f9d5e315872a1529f2da433

You should now have two files in your new working directory: main.py and roles.py. These are respectively the main executable and the supporting boilerplate code for local execution.

Lastly in the working directory fetch the IPv8 repository, using git you can do this as follows:

git clone https://github.com/Tribler/py-ipv8.git pyipv8

Or, you can download the code from https://github.com/Tribler/py-ipv8 and save it into a folder called pyipv8 in your working directory. Your working directory should now be filled with the folder pyipv8/, the file main.py and the file roles.py.

The setup step is now complete.

Note: this guide was made using commit b722384. As IPv8 is continuously receiving updates this guide may no longer be valid for newer commits.

Running the example

The example is made for Python 2.7, you can run it from your working directory using:

python main.py

If you also have Python 3 installed you can explicitly run python2 main.py

This will start the demo. This demo will create an attestation and attest to it using a 1024-bit key (mapped onto a 1048576-bit space), this is incredible overkill but it slows down the application enough that it is easy to follow.

You should see something like this appear in your terminal window (this example is using DHT over the internet, finding others may take some time):

Initializing peers
	[HTTP-GET] http://localhost:8086/attestation?type=peers
No peers have connected yet, waiting for 4 seconds!
	[HTTP-GET] http://localhost:8086/attestation?type=peers
No peers have connected yet, waiting for 4 seconds!
	[HTTP-GET] http://localhost:8086/attestation?type=peers
No peers have connected yet, waiting for 4 seconds!
	[HTTP-GET] http://localhost:8086/attestation?type=peers
No peers have connected yet, waiting for 4 seconds!
	[HTTP-GET] http://localhost:8086/attestation?type=peers
No peers have connected yet, waiting for 4 seconds!
	[HTTP-GET] http://localhost:8086/attestation?type=peers
No peers have connected yet, waiting for 4 seconds!
	[HTTP-GET] http://localhost:8086/attestation?type=peers
No peers have connected yet, waiting for 4 seconds!
	[HTTP-GET] http://localhost:8086/attestation?type=peers
No peers have connected yet, waiting for 4 seconds!
	[HTTP-GET] http://localhost:8086/attestation?type=peers
Known peers for id owner: ["5Oc2uB/9haXoQmrNlYSqNxDUppY=", "R9DGjmjBwYCURiNxOAxyQN/8M2Q="]
Requesting attestation for QR from 5Oc2uB/9haXoQmrNlYSqNxDUppY= (generates one-time 1024-bit EC key)
	[HTTP-POST] http://localhost:8086/attestation?attribute_name=QR&type=request&mid=5Oc2uB/9haXoQmrNlYSqNxDUppY%3D
	[HTTP-GET] http://localhost:8087/attestation?type=outstanding
Pending attestation request for attester: [["x/lN2cWghbqOOFHt9a9kgdRAXQg=", "QR"]]
Attesting QR for x/lN2cWghbqOOFHt9a9kgdRAXQg=
	[HTTP-POST] http://localhost:8087/attestation?attribute_name=QR&type=attest&mid=x/lN2cWghbqOOFHt9a9kgdRAXQg%3D&attribute_value=YmluYXJ5ZGF0YQ%3D%3D
	[HTTP-GET] http://localhost:8086/attestation?type=attributes&mid=5Oc2uB/9haXoQmrNlYSqNxDUppY%3D
ID Owner attributes: [["QR", "Li3AX3eoHC686SNiEDzVV4QjNFQ="]]

What does the output mean

The output of running main.py consists of both debug info and (indented) verbose HTTP requests.
The perform the following actions:

[HTTP-GET] http://localhost:8086/attestation?type=peers

This REST call retrieves the other peers the user knows. For instance, in the group of user 1, 2 and 3: user 1 would report [1, 2]. The result is a (JSON) list of identifiers by which to reference these peers. They are actually the SHA-1 hashes of the public keys.

[HTTP-POST] http://localhost:8086/attestation?attribute_name=QR&type=request&mid=5Oc2uB/9haXoQmrNlYSqNxDUppY%3D

This REST call instructs IPv8 to perform a request for attestation to another peer with the identifier specified by mid for the attribute called QR.

[HTTP-GET] http://localhost:8087/attestation?type=outstanding

This REST call retrieves the requests for attestation which have been received by this user. Note that another peer has sent us one of these requests using the previously mentioned type=request call. The result is a (JSON) list of 2-tuples (formally a list of lists in JSON) consisting of the identifier of the request issuer and the requested attribute.

[HTTP-POST] http://localhost:8087/attestation?attribute_name=QR&type=attest&mid=x/lN2cWghbqOOFHt9a9kgdRAXQg%3D&attribute_value=YmluYXJ5ZGF0YQ%3D%3D

This REST call should be called when the attester decides to attest to the value of the requester. The call is targeted to a specific peer identifier mid, for a specific attribute name attribute_name and some binary value attribute_value.

[HTTP-GET] http://localhost:8086/attestation?type=attributes&mid=5Oc2uB/9haXoQmrNlYSqNxDUppY%3D

The last REST call shows the output of a succesful attestation of an attribute. If an attribute shows up here it is added both to the blockchain and the local claim database.

@qstokkink
Copy link
Collaborator Author

The above interface can also be captured in a set of Java interfaces, for clarity. This would lead to the following two files:

AttestorInterface.java

import java.util.List;

public interface AttestorInterface{

	static class AttestationRequest{
		private final String identifier;
		private final String attributeName;

		public AttestationRequest(String identifier, String attributeName){
			this.identifier = identifier;
			this.attributeName = attributeName;
		}

		public String getIdentifier(){
			return this.identifier;
		}

		public String getAttributeName(){
			return this.attributeName;
		}
	}

    public List<AttestorInterface.AttestationRequest> getAttestationRequests();
    public void sendAttestation(String identifier, String attributeName, String attributeValue);
}

AttesteeInterface.java

import java.util.List;

public interface AttesteeInterface{

	static class Attribute{
		private final String name;
		private final String hash;

		public Attribute(String name, String hash){
			this.name = name;
			this.hash = hash;
		}

		public String getName(){
			return this.name;
		}

		public String getHash(){
			return this.hash;
		}
	}

    public List<String> getPeerIdentifiers();
    public void requestAttestation(String identifier, String attributeName);
    public List<AttesteeInterface.Attribute> getMyAttributes();
}

@qstokkink
Copy link
Collaborator Author

qstokkink commented Apr 20, 2018

The actual implementations of the attestor and attestee interfaces can be found here:

These can be approached through the AttestationInterface class.

The (current) master branch is now almost completely without any GUI.

@qstokkink
Copy link
Collaborator Author

qstokkink commented May 16, 2018

You can find an updated script with verification here.
You can find the script for verification with a mobile phone here.

Output for the latter script will look something like this, you can see a 99.998% match ratio here:

$ python main.py 
Initializing peers
	[HTTP-GET] http://localhost:8086/attestation?type=peers
Known peers: ["Odl1gQkOFh/8pOVgA/qm/kT5BpY="]
	[HTTP-GET] http://localhost:8086/attestation?type=attributes&mid=Odl1gQkOFh/8pOVgA/qm/kT5BpY=
[[u'QR', u'rkVwqwPOWiSG+Mw4pUKBbxOy2W0=']]
	[HTTP-POST] http://localhost:8086/attestation?attribute_values=YmluYXJ5ZGF0YQ%3D%3D&type=verify&mid=Odl1gQkOFh/8pOVgA/qm/kT5BpY=&attribute_hash=rkVwqwPOWiSG%2BMw4pUKBbxOy2W0%3D
	[HTTP-GET] http://localhost:8086/attestation?type=verification_output
Verifications: {u'rkVwqwPOWiSG+Mw4pUKBbxOy2W0=': [[u'YmluYXJ5ZGF0YQ==', 0.9999847412109375]]}

Furthermore, you can find demo-specific documentation here:
https://github.com/DanGraur/IPv8-documentation

The full-on server script:
stable_server.zip

@qstokkink qstokkink added the priority: low Should be addressed at some point in the future label Jun 12, 2018
@qstokkink
Copy link
Collaborator Author

qstokkink commented Jul 3, 2018

The final polished-up POC server code can be found on this Gist:
https://gist.github.com/qstokkink/90fdcba7144a60ca697a41e0e7327dac

This server acts as the attesting counterparty for apps.

@qstokkink
Copy link
Collaborator Author

qstokkink commented Oct 10, 2018

This issue has been superseded by #326 and #325.

@synctext
Copy link
Member

Fundamental question after discussion with @TimSpeelman about the integrity of the smartphone. We can assume the client is fully in the hands of the adversary. Can we really protect against deep-fakes for face recognition or Android emulator detectors? A simplistic binary blob will not protect you against tampering in the client.
For airport checks we obviously need a trustworthy client to capture the selfie + liveliness detector. Will open source client fix any illusion of security?

@qstokkink
Copy link
Collaborator Author

Will open source client fix any illusion of security?

We specifically do not solve this in our client. We just provide the means for building identity. We depend upon third parties, with years of experience, to provide strong unfakeable biometric authentication.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
priority: low Should be addressed at some point in the future priority: medium Enhancements, features or exotic bugs
Development

No branches or pull requests

2 participants