Cryptographic Capabilities

Cryptographic capabilities are byte sequences that can be transmitted over a network, or stored for later use. When a process is asked to determine whether or not to permit an action, it can consult this byte sequence and authoritatively decide upon the result.

This is because capabilities are cryptographically signed authorization statements (tuples). When the signing key is known and the signature is verified, the process can safely assume that the signer agrees with the authorization tuple’s contents.

The abstract process is described in draft-jfinkhaeuser-caps-for-distributed-auth.

In this model, a grantor or issuer has authority over some resources. They can then issue a capability including one or more authorization tuples and sign it with their private key. Anyone in possession of their public key can verify the capability.

Authorization tuples consist of a subject identifier, that is, the entity to whom e.g. a privilege is granted. They contain an object identifier, which limits the scope of the privilege to this object only. Finally, they contain a predicate - the privilege itself.

The library prescribes little about what these fields mean. Issuers and subjects are best understood as identifiers derived from cryptographic public keys, so that a link to authentication can be made. But they can also describe groups or roles as part of a more complex authorization management scheme.

Similarly, object identifies are typically resources, such as files or devices. But they can also represent individuals or groups thereof.

Finally, predicates are arbitrary strings. Typical uses may be to grant write access to a file, or represent something similar to a mobile operating system’s privilege to e.g. access a camera, etc.

The entire point of authorization tuples is that they provide just enough structure so that queries can be made such as “does entity X have privilege Y as relating to resource Z?”. At the same time, no more restrictions as to the specific meaning of each of these components is enforced.

The point is, CAProck should not be thought of as a complete authorization system. Rather, it is the means by which an arbitrarily complex authorization system can be designed in a fully distributed manner.

System Design

Capabilities are made for distributed systems; it has little relevance here if the system is networked - also multiple processes on the same machine that have a means of inter-process communications (IPC) count as a distributed system.

In such systems, the each process may invoke functions that other processes offer. Sometimes these are tasks to execute - actual functions in the programming sense - and sometimes these are data to store or retrieve. In CAProck parlance, these are all resources, and they are assumed to have an identifier. This becomes the object of an authorization tuple.

The calling process may act on behalf of a user, or on behalf of itself. In either case, it needs to authenticate. While there are different methods of authentication available, challenge-response method using public-key cryptography cuts out authentication servers, and thus works best in a fully distributed system.

The other benefit of using public keys is that it’s easy to derive an identifier from such a key, such as a fingerprint. If the calling process has authenticated (i.e. proven they’re in possession of the corresponding private key), a fingerprint (cryptographic hash) of the public key works fine as an identifier for the subject of an authorization tuple.

The predicate or privilege in the authorization tuple must be system defined. It’s recommended to make them fairly fine-grained. The principle of least authority states that a process should have enough authority to conduct its work, but no more. That means oftentimes a privilege to permit access to a resource is too broad. Instead, one should distinguish between e.g. read and write, or execute and inspect or some such.

Finally, the called process needs to understand which resources “belong” to whom, that is, who has the authority to issue authorization tokens for them. This then becomes the issuer, and is again represented by at least a public key from which an identifier can be derived.

Processes that manage access to resources from multiple issuers should take care to isolate them, such that object idenfiers can be re-used. Given issuers I1 and I2, each of them should be able to “own” an object named O, where logically speaking the fully namespaced identifiers would be I1/O and I2/O respectively. It is up to the implementation to decide whether to use fully namespaced identifiers in capabilities, or derive the namespace from the issuer identifier – so long as processes take care that there can be no confusion.

To summarize:

  1. Use public key based cryptography to authenticate users.

  2. The caller provides a capability to the called processes using a subject identifier derived from it’s now-proven public key.

  3. The called process can proceed with the request if:

    • The issuer is known

    • The object is known

    • The predicate is understood

    • The capability names the authenticated key as subject

    • All is signed by the issuer

No authentication or authorization servers are required.

Authorization Management

By authorization management, we mean the system by which authorization tuples are created. These systems are outside the scope of CAProck.

It’s clear that a complete system must provide some answer here - something based e.g. on ACLs or RBAC, etc.

The important part is that such systems can work relatively independent of the process described above. Authorization management should focus on modelling privileges at the desired abstraction, and generation tuples from them. These tuples can then be stored for later querying, resulting in capabilities. Or such capabilities can immediately be created.

Capability Distribution

The distribution of capabilities to a calling process or the caller is outside the scope of CAProck.

Capabilities are designed so that they can be handed to a caller like a key, which can then present it to the called process (the lock). But there is no need for this to happen other than that caller and callee can negotiate an interaction without further need of an authority.

Instead, the authority can forward capabilities periodically to the callee, which then waits for callers to authenticate. The distribution channel and time point is relatively unimportant to the scheme.

The only thing one should take care of is not have the callee query the authorization management system for capabilities as part of processing a request. At that point, the system introduces a single point of failure again in the authorization management system.