Expand description
Libkeycard is an MPL2.0-licensed library for interacting with Mensago digital certificates called keycards.
No guarantees of any kind are provided with the library even though it has been written with care.
The Mensago Identity Services design document is required reading to use this library effectively.
§Usage
The main tasks for interacting with keycards can be broken down into a few tasks:
- Verifying a keycard
- Retrieving an encryption or signature verification key
- Adding a new entry
- Revoking a keycard
§Verifying a Keycard
The most common case for interacting with a keycard is obtaining a person’s most recent encryption or verification keys. For starters, you will need to obtain the complete keycard for the user’s organization along with the user’s complete keycard.
Once you have obtained a keycard’s raw text data from an organization’s server, verifying the organization’s keycard is relatively simple:
A user’s keycard is more involved to verify:
- Obtain, instantiate, and verify the organization’s keycard
- Obtain, instantiate, and verify the users’s keycard
- Find the branch point in the organization’s keycard for the user’s root keycard entry using
find()
- Get the root entry from the user’s keycard and use it to call
verify_chain()
on the branch point entry
§Retrieving a Key
Obtaining a key is as simple as getting the current entry of a keycard and getting the appropriate field using get_field()
. Once obtained, it can be passed directly to from_string()
/from_strings()
for encryption or signing keys/pairs or CryptoString::from()
, depending on the usage needs.
§Adding a New Organization Entry
Creating a brand-new root organization entry is done during the setup process of the organization’s server. New entries are added by creating a Keycard
instance from the organization’s keycard data and then calling chain()
, which generates a new entry, signs it and returns the new entry and the new key set. From there, the new entry is uploaded to the server via the ORGCHAIN
command sent by the client.
§Adding a New User Entry
Creating a new root user entry is the most complicated of all the keycard-related processes because the server and the user don’t trust one another.
- Generate a new user key set, consisting of a signing key pair for contact requests, an encryption key pair for contact requests, a signing key pair for general purpose use, an encryption key pair for general purpose use.
- Create a new Entry instance using
new()
ornew_from_str()
. - Set field data as appropriate, including the entry lifespan (expiration). The “Time-To-Live” field is set to the recommended 14 days and a timestamp is also automatically generated by the constructor.
- Confirm that the entry meets basic data compliance using
is_data_compliant()
. - Begin the signing process by submitting the entry data in its current form to the server to populate the
Organization-Signature
auth string. - Set the
Previous-Hash
field using the value from theHash
field of the current entry on the organization’s keycard. - Generate a hash of all current entry data by calling
hash()
with the desired hash algorithm. - Add a “User-Signature” signature using the contact request signing pair.
- Upload the entry to the server
Adding new non-root entries to a keycard is significantly less-involved.
- Create a new Keycard instance of the user’s keycard data.
- Call the keycard’s
chain()
method with the current entry’s contact request signing pair to generate the chain-of-custody signature and return the new entry and key set. - A client will then upload the new entry to the server for signing. A server utilizing this library will call
cross_sign()
to accomplish this. - Generate a hash of all current entry data by calling
hash()
with the desired hash algorithm. - Add a “User-Signature” signature using the contact request signing pair.
- Upload the entry to the server
§Revoking a User Keycard
Revoking a user keycard is not terribly involved.
- Create a new Keycard instance of the user’s keycard data.
- Call the keycard’s
revoke()
method to create a new root entry with an updatedIndex
field and new key set. - A client will then upload the new entry to the server for signing. A server utilizing this library will call
cross_sign()
to accomplish this. - Set the
Previous-Hash
field using the value from theHash
field of the current entry on the organization’s keycard. - Generate a hash of all current entry data by calling
hash()
with the desired hash algorithm. - Add a “User-Signature” signature using the contact request signing pair.
- Upload the entry to the server using the
REVOKE
command
§Revoking an Organization Keycard
In terms of time-to-recovery, this is the worst-case scenario, but the process itself isn’t difficult at all.
- Create a new Keycard instance of the user’s keycard data.
- Call the keycard’s
revoke()
method to create a new root entry with an updatedIndex
field and new key set. - A client will then upload the new entry to the server for signing. A server utilizing this library will call
cross_sign()
to accomplish this. - Set the
Previous-Hash
field using the value from theHash
field of the current entry on the organization’s keycard. - Generate a hash of all current entry data by calling
hash()
with the desired hash algorithm. - Add a “User-Signature” signature using the contact request signing pair.
- Upload the entry to the server using the
ORGREVOKE
command
By sending the ORGREVOKE
command, the server will replace the organization’s keycard tree with a new one and send revocation requests to all users.
Structs§
- Argon
Hash - A basic data type representing an Argon2id password hash. It is used to ensure passing around valid data within the library. This might someday be genericized, but for now it’s fine.
- Domain
- A basic data type for housing Internet domains.
- Entry
- Entry represents a single entry in a keycard and contains both fields and authentication strings, which can be a digital signature or a cryptographic hash.
- Keycard
- A Keycard object is a collection of entries tied together in an authenticated blockchain. It consists of the root entry for the entity all the way through the current entry.
- MAddress
- A basic data type representing a full Mensago address. It is used to ensure passing around valid data within the library.
- RandomID
- The RandomID class is similar to v4 UUIDs. To obtain the maximum amount of entropy, all bits are random and no version information is stored in them. The only null value for the RandomID is all zeroes. Lastly, the only permissible format for the string version of the RandomID has all letters in lowercase and dashes are placed in the same places as for UUIDs.
- Timestamp
- A basic data type for timestamps as used on Mensago. The type is timezone-agnostic as the platform operates on UTC time only. It can be used to just store dates or dates with times
- UserID
- A basic data type for housing Mensago user IDs. User IDs on the Mensago platform must be no more than 64 ASCII characters. These characters may be from the following: lowercase a-z, numbers, a dash, or an underscore. Periods may also be used so long as they are not consecutive.
- WAddress
- A basic data type representing a full Mensago address. It is used to ensure passing around valid data within the library.
Enums§
- Entry
Type - Denotes an entry’s type. None is only used for uninitialized Entry instances.
- IDType
- IDType identifies the type of RandomID used
- LKCError
Functions§
- get_
timestamp - Returns a string containing the current UTC with second precision in the format YYYYMMDDTHHMMSSZ.
- parse_
entries parse_entries()
is a generic helper function which reads keycard data and returns a Vector of entries. The data for each entry is validated and it ensures that types aren’t mixed, but no other validation is performed. This call is mostly for reading card data received from servers, which can be an entire keycard, part of one, or just one entry.