Identity

The following explores in depth how identities are represented in tdx Volt and describes the interactions with other elements in the architecture.

At the heart of the identity management (and tdx Volt itself) is public key cryptography.

All identities known to a tdx Volt are associated with one or more public/private key pairs. By default, the tdx Volt never stores or even sees the private portion of the key, which must be kept private by the identity. The tdx Volt has a copy of the public key(s).

In order to perform any interaction with tdx Volt, an identity must prove that it is in possesion of the private key corresponding to one of the public keys the tdx Volt is holding for that identity.

This proof is usually achieved by the identity signing some message or claim with its private key, which tdx Volt can then verify using the public portion of the key. Another method is via an x509 certificate-backed TLS connection, which includes the key verification as part of the handshake.

Internally, an identity is represented by an immutable unique identifier rather than its public key. This is known as a ‘decentralised identifier’ or DID. This level of indirection ensures that an identity can easily periodically change keys as a security precaution or in case of compromise. This also allows for an identity to utilise more than one key pair which might be useful in certain scenarios to limit exposure.

Authentication

The core authentication mechanism is based on standard public key infrastructure (PKI) technology.

The tdx Volt acts as a certificate authority (CA), issuing certificates to clients that request access.

Any client wanting to access resources or services on the tdx Volt must present a certificate that has been issued by the tdx Volt CA, or a JWT that is signed by a key that the tdx Volt knows about.

A tdx Volt may prompt the tdx Volt owner to verify a bind request before issuing the certificate.

Each tdx Volt maintains a list of public keys that it knows about, and each public key has a mapping to a unique identity within the tdx Volt.

There are varying degrees of trust implemented, for example a tdx Volt may be configured to trust a public key to connect to and use services, or it may trust a public key to sign additional public keys for access to the Volt. The latter is achieved in combination with Verifiable Credentials.

This provides a flexible and scalable mechanism of establishing trust, whereby a tdx Volt can decide, on a case-by-case basis, to trust any client that presents a certificate signed by its own key or that of another trusted identity.

The following notes relate to the core tdx Volt management interface as well as any service registered with the tdx Volt by other applications/clients.

The Bind step

For the purposes of this discussion, a client is, for example, an application that wants to access some resource or service.

When a client first starts it must obtain a certificate from the tdx Volt in order to be able to connect to any service or resource. It does this by sending a bind request to the Volt. This is known as the Bind step.

The bind request includes the public key of the client, and a signature. Upon receipt of the bind request, the tdx Volt can infer that the client is in possession of the corresponding private key.

When submitting a bind request, a client may also supply one or more additional certificates or Verifiable Credentials that can be used to help the Volt decide whether or not to issue a certificate. For example, a Samsung device may submit a certificate that chains to the Samsung CA. If the tdx Volt has been configured to permit the Samsung CA to authenticate clients, it might automatically issue the certificate.

Once in possession of a certificate, the client can connect to the Volt. As part of the default TLS mechanism, the client provides one or more root certificates that it trusts. If the tdx Volt server does not present a certificate that chains to one of these root certificates the client will abort the call.

For example, Bob (the client) wants to access a resource on Alice’s tdx Volt.

  • Alice’s tdx Volt starts its grpc service using a certificate issued by her tdx Volt CA
  • Bob issues a call to Alice’s tdx Volt service. As part of the call Bob mandates that the server must present a certificate issued by the tdx Volt CA. Bob also sends his own certificate to the server, which has been issued by Alice’s tdx Volt CA.
  • Alice’s tdx Volt receives Bob’s request and verifies that a certificate was presented, and that it chains to the tdx Volt CA.
  • Alice’s tdx Volt extracts the public key from Bob’s client certificate and attempts to match it to an identity in the database. If no matching identity is found (or the identity has been revoked) the call is rejected.
  • Alice’s tdxVolt can now provide this identifier to the policy engine, which will determine if Bob has permission to access the resource or service he has requested.

Token authentication

Some grpc platforms do not support client certificate inspection from server implementations. In these scenarios, the client presents a certificate and grpc will enforce and verify the certificate requirement, but the actual service implementation has no visibility of the client certificate that was presented.

This makes it impossible for the service to identify the client without further information provided with the call.

This isn’t a problem for the tdx Volt itself which is implemented in C++ and can access the client certificate. However grpc is platform agnostic and third-party services that are registered with the tdx Volt may be implemented in any language. These third-party services need to be able to identify the client in order to determine if they have permission to access the service, among other things.

To address this the tdx Volt supports additional authentication by way of a JSON Web Token (JWT) that is sent as part of the grpc call metadata, which is available on all platforms.

The JWT contains a claim that identifies the client, which is the resource id that was assigned to the client at the bind stage. The JWT is then signed by the client private key.

Upon receipt of the token, a server can decode it to extract the resource id and then verify the signature using the client public key, which will be stored alongside the resource id in the tdx Volt database.

This is conceptually very similar to an x509 certificate in the sense that it is binding a public key to some identifier. The key difference is that the use of a client certificate (as used, for example, in TLS) requires the client to be in possession of the private key, whereas a token does not. Tokens are typically obtained through some authentication step that requires the private key or similar verification, and is then used subsequently for repeated calls to an API. It is therefore possible that if a token is misplaced or stolen it can be abused.

There are ways of limiting the vulnerability of tokens such as adding additional claims for expiry and such. In some situations a token is preferable to full- blown PKI, such as when securely storing a private key is impossible or impractical. As such, tdx Volt services can support a combination of authentication mechanisms tailored to suit their individual requirements.

Client AuthenticationServer AuthentiationSupportedNotes
certificatecertificateyesThis is the default configuration in which mutual certificate authentication is used
certificate + tokencertificateyesThe client provides both a certificate and JWT.
tokencertificateyesThe client only presents a JWT with no client certificate. This is useful in scenarios where storing a private key is impractical
nonecertificatenoThe client must always provide some authentication
certificatenonenoThe server must always present a certificate.
tokennonenoThe server must always present a certificate.
nonenonenoInsecure