This directory contains a client for the Continusec Key Server. See https://github.com/continusec/key-transparency for the source code for the server component.
The Continusec Key Server Client is distributed under the Apache 2 License.
The client is written in Go, begin by installing the Go compiler from: https://golang.org/doc/install.
Once installed, install the client:
go get github.com/continusec/key-transparency/cmd/cks
And then to run:
cks help
The cks
application maintains state in $HOME/.cksdb
. This state is used to verify consistency of answers returned by the server, and also maintains a cache of all responses received from the key server.
To initialize the state, run:
cks init
Since this will remove any existing local database, it will prompt before continuing:
Initialize new database with server: https://continusec-key-server.appspot.com? (this will overwrite any existing database) Type yes or no to continue:
Type yes
to continue, or invoke with --yes
to bypass the prompt.
If you wish to test with a different server, for example for testing your own server, invoke with the --server
option as follows:
cks init --server http://localhost:8080
During initializing any requests sent to the server will be printed, for example:
Fetching: https://continusec-key-server.appspot.com/v1/config/serverPublicKey
Fetching: https://continusec-key-server.appspot.com/v1/config/vufPublicKey
Fetching: https://continusec-key-server.appspot.com/v1/wrappedMap/tree/0
Fetching: https://continusec-key-server.appspot.com/v1/wrappedMap/log/treehead/tree/0
Fetching: https://continusec-key-server.appspot.com/v1/wrappedMap/log/treehead/tree/1/inclusion/h/26e9bd9ddc8c362224fb8d6c62c16cc4c95875647e19ff93debded6deb236630
Initialization complete.
A new Continusec Key Server begins at sequence 0 which increases over time as entries are modified. The client keeps track of what sequence number is currently in effect.
To see the current sequence number in effect:
cks status
Results in:
Tracking revision: 1
To check for updates from the server use:
cks update
Which shows any requests sent to the server for fresh state, and completes by displaying the revision in effect (in this case, unchanged):
Fetching: https://continusec-key-server.appspot.com/v1/wrappedMap/tree/0
Tracking revision: 1
If desired once can request that the client act upon an earlier version of server state, this is done by passing a sequence number as an argument like follows:
cks update 4
Which in our client resulted in the following requests:
Fetching: https://continusec-key-server.appspot.com/v1/wrappedMap/tree/4
Fetching: https://continusec-key-server.appspot.com/v1/wrappedMap/log/mutation/tree/6/consistency/4
Fetching: https://continusec-key-server.appspot.com/v1/wrappedMap/log/treehead/tree/6/inclusion/h/171f79df147a5f4070718de0f7d4b4b2e60c4e48f4b749ec1cb4f2c50119d28d
Tracking revision: 4
It can be useful to output a small piece of information that can be gossiped to detect misbehavior by the key server:
cks gossip
Will output such information, suitable for automated processing:
eyJzaWciOiJNRVFDSUMwVWlJZUNqWElpd25wWVJTTys4YnFwSTZIZzczTTBSWVRpSnFiclJ0Y2VBaUJnNml2UnRHNC94b2F2U0l0ZEVIb1AzR05CaTdFTE1YRDdMQVlvTFV2bDJnPT0iLCJ0aGx0aCI6ImV5SjBjbVZsWDNOcGVtVWlPakVzSW5SeVpXVmZhR0Z6YUNJNklrcDFiVGx1WkhsTlRtbEpheXMwTVhOWmMwWnplRTFzV1dSWFVpdEhaaXRVTTNJemRHSmxjMnBhYWtFOUluMEsifQo=
If you base-64 decode this, we get:
{
"sig": "MEQCIC0UiIeCjXIiwnpYRSO+8bqpI6Hg73M0RYTiJqbrRtceAiBg6ivRtG4/xoavSItdEHoP3GNBi7ELMXD7LAYoLUvl2g==",
"thlth": "eyJ0cmVlX3NpemUiOjEsInRyZWVfaGFzaCI6Ikp1bTluZHlNTmlJays0MXNZc0ZzeE1sWWRXUitHZitUM3IzdGJlc2paakE9In0K"
}
The thlth
field is base-64 encoded JSON as received by the client for the latest tree head log tree head for the map and the sig
field is the base-64 encoded ASN.1 signature over the JSON bytes as returned by the Key Server.
If two inconsistent thlth
values are emitted by the Key Server, that is a sign of misbehavior.
To upload your own public key, either new or as an update, first request an authorization token be sent to your email address, for example:
cks mail [email protected]
Type yes
to continue:
Are you sure you want to generate and send a token to address ([email protected])? Please only do so if you own that email account. Type yes or no to continue: yes
And upon success:
Sending mail to [email protected] with token...
Success. See email for further instructions.
Wait for an email including the token, and then use this to upload your key, which can should be the output of gpg --armor --export
. Either pipe this as follows:
gpg --armor --export [email protected] | cks upload [email protected] - ME0wRQIge+mIyeT/eJjZyh+FeB4NWdxn23a5eD8d8K23ZTeetsMCIQDl9Ye7bXvfP6sNbzjpn9v6UrKipxwdeHYN3698W5YN+gIEV5r3Jw==
Or save in a file, and repalce the -
with the filename. Result:
Setting key for [email protected] with token...
Success. Leaf hash of mutation: 9y1sTCXsI/1sGCB6jEq1629fNHbYEqFwVWrJlmpLk5w=
Done, your key has been added to the key server.
To see the status of update key requests:
cks log
Will show a table of updates:
+---------------------+----------------------------------------------+---------------------+----------------------------------------------+-------------------+---------------+
| EMAIL | VALUE HASH | TIMESTAMP | MUTATION LOG ENTRY | MAP SEQUENCE | USER SEQUENCE |
+---------------------+----------------------------------------------+---------------------+----------------------------------------------+-------------------+---------------+
| [email protected] | mGng5V2kf9NREaeOke3bAaMJLHOgAa4YulFgisVErcI= | 2016-07-29 15:28:19 | 9y1sTCXsI/1sGCB6jEq1629fNHbYEqFwVWrJlmpLk5w= | Not yet sequenced | |
+---------------------+----------------------------------------------+---------------------+----------------------------------------------+-------------------+---------------+
To refresh this table and display the log again:
cks update && cks log
Result:
Fetching: https://continusec-key-server.appspot.com/v1/wrappedMap/tree/0
Fetching: https://continusec-key-server.appspot.com/v1/wrappedMap/log/mutation/tree/2/consistency/1
Fetching: https://continusec-key-server.appspot.com/v1/wrappedMap/log/treehead/tree/0
Fetching: https://continusec-key-server.appspot.com/v1/wrappedMap/log/treehead/tree/2/consistency/1
Fetching: https://continusec-key-server.appspot.com/v1/wrappedMap/log/treehead/tree/2/inclusion/h/623c4ebd680004167341c4e713418f86f89521d5e61528edb34708059a3e8c03
Fetching: https://continusec-key-server.appspot.com/v1/wrappedMap/log/mutation/tree/2/inclusion/h/f72d6c4c25ec23fd6c18207a8c4ab5eb6f5f3476d812a170556ac9966a4b939c
Fetching: https://continusec-key-server.appspot.com/v1/publicKey/[email protected]/at/2
Tracking revision: 2
+---------------------+----------------------------------------------+---------------------+----------------------------------------------+--------------+---------------+
| EMAIL | VALUE HASH | TIMESTAMP | MUTATION LOG ENTRY | MAP SEQUENCE | USER SEQUENCE |
+---------------------+----------------------------------------------+---------------------+----------------------------------------------+--------------+---------------+
| [email protected] | mGng5V2kf9NREaeOke3bAaMJLHOgAa4YulFgisVErcI= | 2016-07-29 15:28:19 | 9y1sTCXsI/1sGCB6jEq1629fNHbYEqFwVWrJlmpLk5w= | 1 | 0 |
+---------------------+----------------------------------------------+---------------------+----------------------------------------------+--------------+---------------+
Not yet sequenced
means that the mutation log entry has not yet been sequenced and added to the map. Once it has been sequenced (that is a number appears in this column), then any revision of the map greater than that number will reflect this value. So here mutation 1 is reflected in map sequence number 2 and beyond.
The User sequence
column shows an increasing sequence number for just this user. The initial value for each user is 0 and this increases with each successful update. If a fresh update is requested for a user while another update is pending to apply, it will result in a Conflict - not sequenced
message like below:
+---------------------+----------------------------------------------+---------------------+----------------------------------------------+--------------+--------------------------+
| EMAIL | VALUE HASH | TIMESTAMP | MUTATION LOG ENTRY | MAP SEQUENCE | USER SEQUENCE |
+---------------------+----------------------------------------------+---------------------+----------------------------------------------+--------------+--------------------------+
| [email protected] | mGng5V2kf9NREaeOke3bAaMJLHOgAa4YulFgisVErcI= | 2016-07-29 15:28:19 | 9y1sTCXsI/1sGCB6jEq1629fNHbYEqFwVWrJlmpLk5w= | 1 | 0 |
| [email protected] | or/a9EtFEwy+sdGs53Jv/6+gmCtOAcTMFXXlsOWKKRc= | 2016-07-29 15:33:09 | 1PgRupcjard1bpHd2aYHckq1XTKBDoS5P2n9jQ8EEM0= | 2 | 1 |
| [email protected] | 995GpJzmXOa8RQ3TAQNtzJfwtv3gJdOsPIqVpYml4AA= | 2016-07-29 15:33:13 | O9oFUxckh7pemYLywENdZup6QIkwIQFv0RmHfudhwCI= | 3 | Conflict - not sequenced |
+---------------------+----------------------------------------------+---------------------+----------------------------------------------+--------------+--------------------------+
This occurs as each update request is conditional on a previous value - here the previous value (map sequence number 2) was not yet available when map sequence 3 was requested, and as such the update for 3 did not have the expected previous value and thus it was never applied to the map. In such a case you can simply try again:
+---------------------+----------------------------------------------+---------------------+----------------------------------------------+--------------+--------------------------+
| EMAIL | VALUE HASH | TIMESTAMP | MUTATION LOG ENTRY | MAP SEQUENCE | USER SEQUENCE |
+---------------------+----------------------------------------------+---------------------+----------------------------------------------+--------------+--------------------------+
| [email protected] | mGng5V2kf9NREaeOke3bAaMJLHOgAa4YulFgisVErcI= | 2016-07-29 15:28:19 | 9y1sTCXsI/1sGCB6jEq1629fNHbYEqFwVWrJlmpLk5w= | 1 | 0 |
| [email protected] | or/a9EtFEwy+sdGs53Jv/6+gmCtOAcTMFXXlsOWKKRc= | 2016-07-29 15:33:09 | 1PgRupcjard1bpHd2aYHckq1XTKBDoS5P2n9jQ8EEM0= | 2 | 1 |
| [email protected] | 995GpJzmXOa8RQ3TAQNtzJfwtv3gJdOsPIqVpYml4AA= | 2016-07-29 15:33:13 | O9oFUxckh7pemYLywENdZup6QIkwIQFv0RmHfudhwCI= | 3 | Conflict - not sequenced |
| [email protected] | 995GpJzmXOa8RQ3TAQNtzJfwtv3gJdOsPIqVpYml4AA= | 2016-07-29 15:34:40 | 6BE4IhuPxv3RZ6RsdSVP0zVzhvhkuxSKJF0TwHrIBhA= | 4 | 2 |
+---------------------+----------------------------------------------+---------------------+----------------------------------------------+--------------+--------------------------+
It is also possible to see multiple entries with the same Value Hash
and User Sequence
- this occurs if duplicate requests arrive at once. Technically only one of the mutation operation actually takes effect, however for the purpose of the console report we simply show th same user sequence against each, signifying that that value hash was in effect at that map mutation size.
To indicate interest in watching the key that belongs to another user, run this command:
cks follow [email protected]
Result:
Following [email protected].
Then run:
cks list
To see the status of all keys followed:
+---------------------+------------+---------------+--------------+
| EMAIL | VALUE HASH | USER SEQUENCE | LAST UPDATED |
+---------------------+------------+---------------+--------------+
| [email protected] | (none) | No key found | Never |
+---------------------+------------+---------------+--------------+
To update, run:
cks update && cks list
Result:
Fetching: https://continusec-key-server.appspot.com/v1/wrappedMap/tree/0
Tracking revision: 5
+---------------------+----------------------------------------------+---------------+--------------+
| EMAIL | VALUE HASH | USER SEQUENCE | LAST UPDATED |
+---------------------+----------------------------------------------+---------------+--------------+
| [email protected] | 995GpJzmXOa8RQ3TAQNtzJfwtv3gJdOsPIqVpYml4AA= | 2 | 5 |
+---------------------+----------------------------------------------+---------------+--------------+
Like before, User Sequence
is an incrmenting index per-user of key changes. Last Updated
is the size of the map when this was last checked, and should match the number shown by cks status
.
Let's follow some more users and show what happens if no key is found:
cks follow [email protected] [email protected] [email protected]
Result:
Following [email protected].
Following [email protected].
Following [email protected].
Now:
cks update && cks list
Gives:
+------------------------+----------------------------------------------+---------------+--------------+
| EMAIL | VALUE HASH | USER SEQUENCE | LAST UPDATED |
+------------------------+----------------------------------------------+---------------+--------------+
| [email protected] | (none) | No key found | 5 |
| [email protected] | 995GpJzmXOa8RQ3TAQNtzJfwtv3gJdOsPIqVpYml4AA= | 2 | 5 |
| [email protected] | (none) | No key found | 5 |
| [email protected] | (none) | No key found | 5 |
+------------------------+----------------------------------------------+---------------+--------------+
Note that we can use cks update <number>
to get a previous view in time:
cks update 2 && cks list
Gives:
Tracking revision: 2
+------------------------+----------------------------------------------+---------------+--------------+
| EMAIL | VALUE HASH | USER SEQUENCE | LAST UPDATED |
+------------------------+----------------------------------------------+---------------+--------------+
| [email protected] | (none) | No key found | 2 |
| [email protected] | mGng5V2kf9NREaeOke3bAaMJLHOgAa4YulFgisVErcI= | 0 | 2 |
| [email protected] | (none) | No key found | 2 |
| [email protected] | (none) | No key found | 2 |
+------------------------+----------------------------------------------+---------------+--------------+
And no number brings us back to the future:
cks update
Fetching: https://continusec-key-server.appspot.com/v1/wrappedMap/tree/0
Fetching: https://continusec-key-server.appspot.com/v1/publicKey/[email protected]/at/7
Fetching: https://continusec-key-server.appspot.com/v1/publicKey/[email protected]/at/7
Fetching: https://continusec-key-server.appspot.com/v1/publicKey/[email protected]/at/7
Fetching: https://continusec-key-server.appspot.com/v1/publicKey/[email protected]/at/7
Tracking revision: 7
To see the history for a user (going back from the current value):
cks history [email protected]
Result:
+---------------------+----------------------------------------------+---------------+-----------------------+
| EMAIL | VALUE HASH | USER SEQUENCE | MAP SIZE RETRIEVED AT |
+---------------------+----------------------------------------------+---------------+-----------------------+
| [email protected] | QYgxE60mYrQ2SySCIWAxGWZmFDH8hLHf/9OFSA6cC04= | 4 | 7 |
| [email protected] | i6haduuzv+1zdaEhVT3+Gfl8aiPER3cJNc8aLvVIExk= | 3 | 6 |
| [email protected] | 995GpJzmXOa8RQ3TAQNtzJfwtv3gJdOsPIqVpYml4AA= | 2 | 5 |
| [email protected] | or/a9EtFEwy+sdGs53Jv/6+gmCtOAcTMFXXlsOWKKRc= | 1 | 4 |
| [email protected] | mGng5V2kf9NREaeOke3bAaMJLHOgAa4YulFgisVErcI= | 0 | 2 |
+---------------------+----------------------------------------------+---------------+-----------------------+
To export a key for a user for the current map state in effect:
cks export [email protected]
Result:
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
mQENBFecOPQBCACi5bv0wIX98XJsmav9CFr/BuJhbPqTUMl6rsq/qwdQozINqsp7
...
J6+8EaWXuQ7l8WAu4HCvUaJ5EMchhYOL
=D+Qt
-----END PGP PUBLIC KEY BLOCK-----
To export a specific sequence number (user sequence):
cks export [email protected]/3
Result:
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
mQENBFecOPQBCACi5bv0wIX98XJsmav9CFr/BuJhbPqTUMl6rsq/qwdQozINqsp7
...
o1GadEzRvUjN9F6jkjh7x1PrOXb50nyowBZ4pzL0mlfxNU0Z
=8N9S
-----END PGP PUBLIC KEY BLOCK-----
For any questions / feedback, please open an issue in Github, or send mail to: [email protected]
The primary purpose of developing the Continusec Key Server was to provide an effective demonstration of the capabilities of the Continusec Verifiable Data Structures API.
We thank the CONIKS folk for the inspiration to build this demonstration.