What is Zot?
Zot is the revolutionary protocol that powers Hubzilla, providing communications, identity management, and access control across a fully decentralised network of independent websites, often called "the grid". The resulting platform is a robust system that supports privacy and security while enabling the kind of rich web services typically seen only in centralized, proprietary solutions.
Consider this typical scenario:
Jaquelina wishes to share photos with Roberto from her blog at jaquelina.org, but to nobody else. Roberto maintains his own family hub at roberto.net on a completely independent server. Zot allows Jaquelina to publish her photos using an access control list (ACL) that includes only Roberto. That means that while Roberto can see the photos when he visits her blog, his brother Marco cannot, and neither can any of his other family members who have accounts on roberto.net.
The magic in this scenario comes from the fact that Roberto never logged in to Jaquelina's website. Instead, he had to login only once using his password on his own website at roberto.net. When Roberto visits jaquelina.org, her hub seamlessly authenticates him by remotely querying his server in the background.
It is not uncommon for servers to have technical problems or become inaccessible for a variety of reasons. Zot provides robustness for Roberto's online activities by allowing him to have clones of his online identity, or channel, on multiple independent hubs. Imagine that Roberto's server crashes for some reason and he cannot log in there. He simply logs in to one of his clones at gadfly.com, a site operated by his friend Peter. Once authenticated at gadfly.com, Roberto can view Jaquelina's blog as before, without Jaquelina having to grant any additional access!
Communications and social networking are an integral part of the grid. Any channel (and any services provided by that channel) can make full use of feature-rich social communications on a global scale. These communications may be public or private - and private communications comprise not only fully encrypted transport, but also encrypted storage to help protect against accidental snooping and disclosure by rogue system administrators and internet service providers.
Zot supports a wide array of background services in the grid, from friend suggestions to directory services. New content and data updates are propagated in the background between hubs across the grid according to access control lists and permissions specified by both sender and receiver channels. Data is also synchronized between an arbitrary number of channel clones, allowing hub members to access data and continue collaborating seamlessly in the event that their primary hub is inaccessible or offline.
Zot's identity layer is unique. It provides invisible single sign-on across all sites in the grid.
It also provides nomadic identity, so that your communications with friends, family, and or anyone else you're communicating with won't be affected by the loss of your primary communication node - either temporarily or permanently.
The important bits of your identity and relationships can be backed up to a thumb drive, or your laptop, and may appear at any node in the grid at any time - with all your friends and preferences intact.
Crucially, these nomadic instances are kept in sync so any instance can take over if another one is compromised or damaged. This protects you against not only major system failure, but also temporary site overloads and governmental manipulation or censorship.
Nomadic identity, single sign-on, and Hubzilla's decentralisation of hubs, we believe, introduce a high degree of degree of resiliency and persistence in internet communications, that are sorely needed amidst global trends towards corporate centralization, as well as mass and indiscriminate government surveillance and censorship.
As you browse the grid, viewing channels and their unique content, you are seamlessly authenticated as you go, even across completely different server hubs. No passwords to enter. Nothing to type. You're just greeted by name on every new site you visit.
How does Zot do that? We call it magic-auth, because Hubzilla hides the details of the complexities that go into single sign-on logins, and nomadic identities, from the experience of browsing on the grid. This is one of the design goals of Hubzilla: to increase privacy, and freedom on the web, while reducing the complexity and tedium brought by the need to enter new passwords and login names for every different sight that someone might visit online. You login only once on your home hub (or any nomadic backup hub you have chosen). This allows you to access any authenticated services provided anywhere in the grid - such as shopping, blogs, forums, and access to private information. Your password isn't stored on a thousand different sites; it is stored on servers that you control or that you have chosen to trust.
You cannot be silenced. You cannot be removed from the grid unless you yourself choose to exit it.
Zot's identity layer allows you to provide fine-grained permissions to any content you wish to publish - and these permissions extend across the grid. This is like having one super huge website made up of an army of small individual websites - and where each channel in the grid can completely control their privacy and sharing preferences for any web resources they create.
Currently, Hubzilla supports access control for many types of data, including post/comment discussion threads, photo albums, events, cloud files, web pages, wikis, and more. Every object and how it is shared and with whom is completely under your control.
This type of control is trivial on large corporate providers because they own the user database. Within the grid, there is no need for a huge user database on your machine - because the grid is your user database. It has what is essentially infinite capacity (limited by the total number of hubs online across the internet), and is spread amongst hundreds, and potentially millions of computers.
Access can be granted or denied for any resource, to any channel, or any group of channels; anywhere within the grid. Others can access your content if you permit them to do so, and they do not even need to have an account on your hub.
Zot is a JSON-based web framework for implementing secure decentralised communications and services. In order to provide this functionality, Zot creates a decentralised globally unique identifier for each hub on the network. This global identifier is not linked inextricably to DNS, providing the requisite mobility. Many existing decentralised communications frameworks provide the communication aspect, but do not provide remote access control and authentication. Additionally most of these are based on 'webfinger', which still binds identity to domain names and cannot support nomadic identity.
The primary issues Zot addresses are
- completely decentralised communications
- independence from DNS-based identity
- node mobility
- seamless remote authentication
- high performance
We will rely on DNS-based user@host addresses as a "user-friendly" mechanism to let people know where you are, specifically on a named host with a given username, and communication will be carried out to DNS entities using TCP and the web.
But the underlying protocol will provide an abstraction layer on top of this, so that a communications node (e.g. "identity") can move to an alternate DNS location and (to the best of our ability) gracefully recover from site re-locations and/or maintain pre-existing communication relationships. A side effect of this requirement is the ability to communicate from alternate/multiple DNS locations and service providers and yet maintain a single online identity.
We will call this overlay network the "grid". Servers attached to this network are known as "hubs" and may support any number of individual identities.
An identity does not necessarily correspond to a person. It is just something which requires the ability to communicate within the grid.
The ability to recover will be accomplished by communication to the original location when creating a new or replacement identity, or as a fallback from a stored file describing the identity and their contacts in the case where the old location no longer responds.
At least on the short term, the mobility of existing content is not a top priority. This may or may not take place at a later stage. The most important things we want to keep are your identity and your friends.
Addresses which are shared amongst people are user@host, and which describe the current local account credentials for a given identity. These are DNS based addresses and used as a seed to locate a given identity within the grid. The machine communications will bind this address to a globally unique ID. A single globally unique ID may be attached or bound to any number of DNS locations. Once an identity has been mapped or bound to a DNS location, communications will consist of just knowing the globally unique address, and what DNS (url) is being used currently (in order to call back and verify/complete the current communication). These concepts will be specified in better detail.
In order for an identity to persist across locations, one must be able to provide or recover
- the globally unique ID for that identity
- the private key assigned to that identity
- (if the original server no longer exists) an address book of contacts for that identity.
This information will be exportable from the original server via API, and/or downloadable to disk or thumb-drive.
We may also attempt to recover with even less information, but doing so is prone to account hijacking and will require that your contacts confirm the change.
In order to implement high performance communications, the data transfer format for all aspects of Zot is JSON. XML communications require way too much overhead.
Bi-directional encryption is based on RSA 4096-bit keys expressed in DER/ASN.1 format using the PKCS#8 encoding variant, with AES encryption of variable length or large items. The precise encryption algorithms are negotiable between sites.
Some aspects of well known "federation protocols" (webfinger, salmon, activitystreams, portablecontacts, etc.) may be used in zot, but we are not tied to them and will not be bound by them. Hubzilla project is attempting some rather novel developments in decentralised communications and if there is any need to diverge from such "standard protocols" we will do so without question or hesitation.
In order to create a globally unique ID, we will base it on a whirlpool hash of the identity URL of the origination node and a psuedo-random number, which should provide us with a 256 bit ID with an extremely low probability of collision (256 bits represents approximately 115 quattuorviginitillion or 1.16 X 10^77 unique numbers). This will be represented in communications as a base64url-encoded string. We will not depend on probabilities however and the ID must also be attached to a public key with public key cryptography used to provide an assurance of identity which has not been copied or somehow collided in whirlpool hash space.
Basing this ID on DNS provides a globally unique seed, which would not be the case if it was based completely on psuedo-random number generation.
We will refer to the encoded globally unique uid string as zot_uid
As there may be more than one DNS location attached/bound to a given zot_uid identity, delivery processes should deliver to all of them - as we do not know for sure which hub instance may be accessed at any given time. However we will designate one DNS location as "primary" and which will be the preferred location to view web profile information.
We must also provide the ability to change the primary to a new location. A look-up of information on the current primary location may provide a "forwarding pointer" which will tell us to update our records and move everything to the new location. There is also the possibility that the primary location is defunct and no longer responding. In that case, a location which has already been mapped to this zot_uid can seize control, and declare itself to be primary. In both cases the primary designation is automatically approved and moved. A request can also be made from a primary location which requests that another location be removed.
In order to map a zot_uid to a second (or tertiary) location, we require a secure exchange which verifies that the new location is in possession of the private key for this zot_uid. Security of the private key is thus essential to avoid hijacking of identities.
Communications will then require
- zot_uid (string)
- callback (current location Zot endpoint url)
- spec (int)
passed with every communique. The spec is a revision number of the applicable Zot spec so that communications can be maintained with hubs using older and perhaps incompatible protocol specifications. Communications are verified using a stored public key which was copied when the connection to this zot_uid was first established.
Key revocation and replacement must take place from the primary hub. The exact form for this is still being worked out, but will likely be a notification to all other bound hubs to "phone home" (to the primary hub) and request a copy of the new key. This communique should be verified using a site or hub key; as the original identity key may have been compromised and cannot be trusted.
In order to eliminate confusion, there should be exactly one canonical url for any hub, so that these can be indexed and referenced without ambiguity.
So as to avoid ambiguity of scheme, it is strongly encouraged that all addresses to be https with a "browser valid" cert and a single valid host component (either www.domain.ext or domain.ext, but not both), which is used in all communications. Multiple URLs may be provided locally, but only one unique URL should be used for all Zot communications within the grid.
Test installation which do not connect to the public grid may use non-SSL, but all traffic flowing over public networks should be safe from session-hijacking, preferably with a "browser recognised" cert.
Where possible, Zot encourages the use of "batching" to minimise network traffic between two hubs. This means that site 'A' can send multiple messages to site 'B' in a single transaction, and also consolidate deliveries of identical messages to multiple recipients on the same hub.
Messages themselves may or may not be encrypted in transit, depending on the private nature of the messages. SSL (strongly encouraged) provides unconditional encryption of the data stream, however there is little point in encrypting public communications which have been designated as having unrestricted visibility. The encryption of data storage and so-called "end-to-end encryption" is outside the scope of zot. It is presumed that hub operators will take adequate safeguards to ensure the security of their data stores and these are functions of application and site integrity as opposed to protocol integrity.
Given the constraints listed previously, a Zot communique should therefore be a json array of individual messages. These can be mixed and combined within the same transmission.
Each message then requires:
- (optional) recipient list
Lack of a recipient list would indicate an unencrypted public or site level message. The recipient list would contain an array of zot_uid with an individual decryption key, and a common iv. The decryption key is encoded with the recipient identity's public key. The iv is encrypted with the sender's private key.
All messages should be digitally signed by the sender.
The type can be one of (this list is extensible):
- post (or activity)
Identity messages have no recipients and notify the system social graph of an identity update, which could be a new or deleted identity, a new or deleted location, or a change in primary hub. The signature for these messages uses system keys as opposed to identity-specific keys.
Posts include many different types of activities, such as top-level posts, likes/dislikes, comments, tagging activities, etc. These types are indicated within the message sturcture.
authenticate messages result in mutual authentication and browser redirect to protected resources on the remote hub such as the ability to post wall-to-wall messages and view private photo albums and events, etc.
A well-known url is used to probe a hub for Zot capabilities and identity lookups, including the discovery of public keys, profile locations, profile photos, and primary hub location.
The location for this service is /.well-known/zot-info - and must be available at the root of the chosen domain.
To perform a lookup, a POST request is made to the discovery location with the following parameters:
address => an address on the target system such as "john"
target => the Zot "guid" of the observer for evaluating permissions
target_sig => an RSA signature (base64url encoded) of the guid
key => The public key needed to verify the signature
token => a string (possibly random) chosen by the requesting service. If provided, an entry in the discovered packet will be provided called 'signed_token' which consists of the base64url_encoded RSA signature of the concatenation of the string 'token.' and the provided token using the private key of the discovered channel. This can be verified using the provided 'key' entry, and provides assurance that the server is in possession of the private key for the discovered identity. After 2017-01-01 it is required that a server provide a signed_token if a token was provided in the request.
With no target provided, the permissions returned will be generic permissions
for unknown or unauthenticated observers
Example of discovery packet for 'email@example.com'
"key": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA7QCwvuEIwCHjhjbpz3Oc\ntyei/Pz9nDksNbsc44Cm8jxYGMXsTPFXDZYCcCB5rcAhPPdZSlzaPkv4vPVcMIrw\n5cdX0tvbwa3rNTng6uFE7qkt15D3YCTkwF0Y9FVZiZ2Ko+G23QeBt9wqb9dlDN1d\nuPmu9BLYXIT/JXoBwf0vjIPFM9WBi5W/EHGaiuqw7lt0qI7zDGw77yO5yehKE4cu\n7dt3SakrXphL70LGiZh2XGoLg9Gmpz98t+gvPAUEotAJxIUqnoiTA8jlxoiQjeRK\nHlJkwMOGmRNPS33awPos0kcSxAywuBbh2X3aSqUMjcbE4cGJ++/13zoa6RUZRObC\nZnaLYJxqYBh13/N8SfH7d005hecDxWnoYXeYuuMeT3a2hV0J84ztkJX5OoxIwk7S\nWmvBq4+m66usn6LNL+p5IAcs93KbvOxxrjtQrzohBXc6+elfLVSQ1Rr9g5xbgpub\npSc+hvzbB6p0tleDRzwAy9X16NI4DYiTj4nkmVjigNo9v2VPnAle5zSam86eiYLO\nt2u9YRqysMLPKevNdj3CIvst+BaGGQONlQalRdIcq8Lin+BhuX+1TBgqyav4XD9K\nd+JHMb1aBk/rFLI9/f2S3BJ1XqpbjXz7AbYlaCwKiJ836+HS8PmLKxwVOnpLMbfH\nPYM8k83Lip4bEKIyAuf02qkCAwEAAQ==\n-----END PUBLIC KEY-----\n",
"name": "Mike Macgirvin",
"name_updated": "2012-12-06 04:59:13",
"photo_updated": "2012-12-06 05:06:11",
"description": "Freedom Fighter",
"next_birthday": "2013-05-14 00:00:00",
"marital": "It's complicated",
"sitekey": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1IWXwd/BZuevq8jzNFoR\n3VkenduQH2RpR3Wy9n4+ZDpbrUKGJddUGm/zUeWEdKMVkgyllVA/xHdB7jdyKs1X\nuIet9mIdnzvhdLO/JFD5hgbNG2wpSBIUY6aSNeCFTzszqXmuSXMW5U0Ef5pCbzEA\nnhoCoGL1KAgPqyxnGKUlj7q2aDwC9IRNtAqNyFQL67oT91vOQxuMThjlDhbR/29Q\ncYR4i1RzyahgEPCnHCPkT2GbRrkAPjNZAdlnk9UesgP16o8QB3tE2j50TVrbVc/d\nYRbzC56QMPP9UgUsapNeSJBHji75Ip/E5Eg/kfJC/HEQgyCqjCGfb7XeUaeQ7lLO\nqc7CGuMP+Jqr/cE54/aSHg8boTwxkMp11Ykb+ng17fl57MHTM2RJ99qZ1KBkXezR\nuH1lyvjzeJPxEFr9rkUqc4GH74/AgfbgaFvQc8TS7ovEa5I/7Pg04m7vLSEYc6UF\nYJYxXKrzmZT2TDoKeJzaBBx5MFLhW19l68h9dQ8hJXIpTP0hJrpI+Sr6VUAEfFQC\ndIDRiFcgjz6j7T/x8anqh63/hpsyf2PMYph1+4/fxtSCWJdvf+9jCRM8F1IDfluX\n87gm+88KBNaklYpchmGIohbjivJyru41CsSLe0uinQFvA741W00w6JrcrOAX+hkS\nRQuK1dDVwGKoIY85KtTUiMcCAwEAAQ==\n-----END PUBLIC KEY-----\n"
Discovery returns a JSON array with the following components:
'success' => (true or false) Operation was successful if true. Otherwise an optional 'message' may be present indicating the source of error.
'signed_token' => If a token parameter was provided in the request, it is prepended with the text 'token.' and then RSA signed with the channel private key and base64url encoded and returned as 'signed_token'.
'guid' => the guid of the address on the target system
'guid_sig' => the base64url encoded RSA signature of the guid, signed with the private key associated with that guid.
'key' => the public key associated with that guid
'name' => channel name
'name_updated' => MySQL style timestamp '2012-01-01 00:00:00' when the name was last changed (UTC)
'address' => "webbie" or user@host address associated with this channel
'photo' => URL of a profile photo for this channel (ideally 175x175)
'photo_mimetype' => content-type of the profile photo
'photo_updated' => MySQL style timestamp when photo was last updated (UTC)
'url' => location of channel homepage
'connections_url' => location of Portable Contacts (extended for zot) URL for this channel
'target' => if a permissions target was specified, it is mirrored
'target_sig' => if a permissions target was specified, the signature is mirrored.
'searchable' => (true or false) true indicates this entry can be searched in a directory
'permissions' => extensible array of permissions appropriate to this target, values are true or false
Permissions may include:
'profile' => array of important profile fields
- birthday YYYY-MM-DD , all fields are optional, any field (such as year) may be zero
- next_birthday => MySQL datetime string representing the next upcoming birthday, converted from the channel's default timezone to UTC.
- gender (free form)
- marital (marital status)
- sexual (preference)
- locale (city)
- region (state)
'locations' => array of registered locations (DNS locations) this channel may be visible or may be posting from
Each location is an array of
'host' => DNS hostname, e.g. example.com
'address' => the webbie or user@host identifier associated with this location
'primary' => (true or false) whether or not this is the primary location for this channel where files and web pages are generally found
'url' => url of the root of this DNS location e.g. https://example.com
'url_sig' => base64url encoded RSA signature of the URL, signed with the channel private key
'callback' => Zot communications endpoint on this site, usually https://example.com/post
'sitekey' => public key of this site/host
'site' => array providing the directory role of the site responding to this request
'url' => url of this site e.g. https://example.com
'directory_mode' => one of 'primary', 'secondary', 'normal', or 'standalone'
'directory_url' => if this is a directory server or standalone, the URL for the directory search module
So-called "magic auth" takes place by a special exchange. On the remote computer, a redirection is made to the Zot endpoint with special GET parameters.
where 'name' is the left hand side of the channel webbie, for instance 'mike' where the webbie is 'firstname.lastname@example.org'
Additionally four parameters are supplied:
- auth => the webbie of the person requesting access
- dest => the desired destination URL (urlencoded)
- sec => a random string which is also stored locally for use during the verification phase.
- version => the Zot revision
When this packet is received, a Zot message is initiated to the auth identity:
auth_check messages MUST be encrypted. This message is sent to the origination site, which checks the 'secret' to see if it is the same as the 'sec' which it passed originally. It also checks the secret_sig which is the secret signed by the destination channel's private key and base64url encoded. If everything checks out, a json packet is returned:
'confirm' in this case is the base64url encoded RSA signature of the concatenation of 'secret' with the base64url encoded whirlpool hash of the source guid and guid_sig; signed with the source channel private key. This prevents a man-in-the-middle from inserting a rogue success packet. Upon receipt and successful verification of this packet, the destination site will redirect to the original destination URL and indicate a successful remote login.
All signed data in Zot is accomplished by performing an RSA sign operation using the private key of the initiator. The binary result is then base64url encoded for transport.
Encryption is currently provided by AES256CTR. Additional algorithms MAY be supported. A 32-octet key and 16-octet initialisation vector are randomly generated. The desired data is then encrypted using these generated strings and the result base64url encoded. Then we build an array:
- The base64url encoded encrypted data
- The chosen algorithm, in this case the string 'aes256ctr'.
- The randomly generated key, RSA encrypted using the recipients public key, and the result base64url encoded
- The randomly generated initialization vector, RSA encrypted using the recipient's public key, and the result base64url encoded
Basic Zot Packet
Used for initiating a dialogue with another Zot site. This packet MAY be encrypted. The presence of an array element 'iv' indicates encryption has been applied. When sending an 'auth_check' packet type, this packet MUST be encrypted, using the public key of the destination site (the site key, as opposed to a sender key).
"sitekey":"-----BEGIN PUBLIC KEY-----
-----END PUBLIC KEY-----
- The message type: notify, purge, refresh, force_refresh, auth_check, ping or pickup. The packet contents vary by message type. Here we will describe the notify packet.
- A string to be appended onto the url which identifies the Zot communications endpoint on this system. It is typically the string "/post".
- The Zot protocol identifier, to allow future protocol revisions to co-exist.
- array of supported encryption algorithms, order by decreasing preference. If no compatible encryption methods are provided, applications MUST use 'aes256cbc'.
- A 64-char string which is randomly generated by the sending site.
- The RSA signature of the secret, signed with the sender's private key.
- An array of four components that provide a portable identity. We can contact the URL provided and download a Zot info packet to obtain the public key of the sender, and use that to verify the sender guid and the posting URL signatures.
- Typically a 64 character base64url encoded string. This is generated when an identity is created and an attempt is made that it be unique; though this isn't required.
- The RSA signature of the guid, signed by the sender's private key and base64url encoded.
- The base url of the location this post is originating from.
- The RSA signature of url, signed by the sender's private key and base64url encoded.
- The public key of the website specified in the url
- Only used for private messages. An array of envelope recipients. Each recipient is represented by an array of guid and guid_sig. When recipients are specified, the entire packet is also encapsulated using a negotiated cryptographic algorithm or 'aes256cbc' if none could be negotiated.
- The guid of a private recipient.
- The RSA signature of the guid, signed by the recipient's private key and base64url encoded