In decentralized identity, an identity Hub is the off-chain storage location for all data owned by a DID. This may include user profile info, attestations, activity history, and much more. To keep this data secure, any request requires that a caller authenticate to a DID’s Hub.
DID authentication is a term primarily used to describe the process by which an identity owner (often a user) proves their identity to a relying party. This process can take many different forms, several of which are described in DIF’s working DID auth document .
This document describes an implementation of DID authentication in one specific topology: a client authenticates to an Identity Hub, which is running as a web service exposed on the public internet over HTTP.
We assume that the client has access to a credential (a private key) that is linked to the Hub owner’s DID via their DDO.
Note that in most scenarios, the client will not have access to the identity owner’s keys. We envision that the client would use its own dedicated key pair that is somehow resolvable by the hub and authorized to access the owner’s data. Provided such keys exists, the client could use the protocol in this document to authenticate to the hub.
To keep things simple, we’ll leave this problem out of scope and address it in another document. Moreover, all Hub authorization logic is omitted from this document. This document only describes how the Hub securely identifies the caller, not what access the caller is granted.
A simple use case that captures the scope of this document is:
Alice has just registered her first DID by downloading & installing a popular user agent mobile application. Her user agent has access to her new DID’s private key. After registering, Alice wants to add some simple profile data to her Hub. She inputs a name and a photo into her user agent app, which then writes each to Alice’s Hub.
In addition to securing data that resides in the Hub, user’s data should be protected while in transit to/from the Hub, even when the HTTP channel used to transmit data is compromised. This means not only should the Hub authenticate the client, but also:
These are the basic goals of TLS (as well as message integrity). Unfortunately, TLS and its dependencies have proven to be insecure against certain attacks. Consider the following attack:
There have been many documented cases (see appendix) where certificate authorities have failed to protect users from such an attack, resulting in widespread violations of user privacy.
By circumventing the use of DNS and CAs, our DID authentication protocols can protect against their vulnerabilities while providing many of the same security and privacy guarantees of traditional TLS.
In designing Hub authentication, we strive to meet the following goals:
More concretely, we have identified the following basic qualities security requirements of existing for authentication and encryption schemes that we to aim to meetmust be met:
There are certainly additional security properties that could be incorporated over time, but we believe this set is sufficient for the near future.
The Hub requires end-to-end (two-way) authenticated encryption for all request-response exchanges using the JWS scheme. As a result of the additional message confidentiality requirement described earlier, all requests and responses are first JWS signed, then JWE encrypted. Specifically, every request sent to the Hub must be JWE encrypted using a public key specified in a Hub’s DID document. The ID of the public key must be specified in the kid JWE header parameter as a DID fragment.
Requester -> Requester: 1. Creates signed access request + nonce as a JWS.
Requester -> Requester: 1. Encrypts the JWS as a JWE using Hub's public-key.
Requester -> Hub: 2. JWE encrypted access request
Hub -> Hub: 3. Decrypts JWE blob.
Hub -> Hub: 3. Verifies requester-signed JWS.
Hub -> Hub: 4. Creates signed JWT.
Hub -> Hub: 5. Wraps signed JWT + requester-issued nonce as a JWS.
Hub -> Hub: 5. Encrypts JWS as a JWE using requester's public-key.
Hub --> Requester: 6. JWE encrypted Hub-signed JWT
Requester -> Requester: 7. Decrypts JWE blob.
Requester -> Requester: 7. Verifies Hub-signed JWS.
Requester -> Requester: 8. Verifies requester-issued nonce in JWS.
Note right of Requester: Note: Hub is authenticated at this point.
Requester -> Requester: 9. The requester caches the JWT for future communication.
Note right of Requester: Note: the cached JWT can be reused until expiry.
Requester -> Requester: 10. Creates Hub request and new nonce.
Requester -> Requester: 11. Signs Hub request + Hub-issued JWT + nonce as a JWS.
Requester -> Requester: 11. Encrypts JWS as a JWE using Hub's public-key.
Requester -> Hub: 12. JWE encrypted Hub request.
Hub -> Hub: 13. Decrypts JWE blob.
Hub -> Hub: 13. Verifies requester-signed JWS.
Hub -> Hub: 14. Verifies Hub-issued JWT.
Note right of Hub: Note: requester is authenticated at this point.
Hub -> Hub: 15. Processes the request.
Hub -> Hub: 16. Signs Hub response + requester-issued nonce as a JWS.
Hub -> Hub: 16. Encrypts JWS as a JWE using requester's public-key.
Hub --> Requester: 17. JWE encrypted Hub response
Requester -> Requester: 18. Decrypts JWE blob.
Requester -> Requester: 18. Verifies Hub-signed JWS.
Requester -> Requester: 19. Verifies requester-issued nonce.
Requester -> Requester: Parses Hub response.
Example JWE header:
{
"kid": "did:example:123456789abcdef#keys-1",
"alg": "RSA-OAEP-256",
"enc": "A128GCM",
}
Example JWS header:
{
"kid": "did:example:123456789abcdef#keys-1",
"alg": "RS256",
"did-requester-nonce": "p6OLLpeRafCWbOAEYp",
"did-access-token": "..."
}
Example JWT payload:
{
"jti": "3e2c9b3a-da11-47e2-a5d8-12a23a9...",
"iss": "did:example:Hub-did",
"sub": "did:example:requester-did",
"iat": 1533168455,
"exp": 1533172655
}
Since all messages exchanged are protected by JWE, JWE encryption and decryption steps are intentionally omitted to highlight the authentication steps in the description below.
Note: Currently JWT encryption and decryption uses DID keys directly – this does not provide forward secrecy for messages. Future implementations should use a shared symmetric ephemeral key for encryption.
Note: Verification of JWS using public keys obtained via DID resolution is pending real implementation.
Note: Currently the DID Hub Core library authentication implementation is stateless, thus it is subject to request replays within the time-bound window allowed by the JWT. In the future, the requester nonce can be cached on the Hub to prevent all request replays.
Note: Currently the client will resolve the Hub’s DID by sending a request to a Universal Resolver web service. Future implementations will need to employ other means of public key resolution that do not depend on TLS & DNS security. See appendix for a brief discussion of options.
This section lists the signature and encryption algorithms currently supported (implemented and tested). In reality, the implementation uses Cisco’s JOSE library, which officially supports a few more algorithms such as ECDSA P256, but since we have not tested those curves end-to-end and those are considered insecure by some, they have not been added to the supported list.
Serialization | Support |
---|---|
Compact Serialization | Yes |
JSON Serialization | No |
Algorithm | Support | JOSE specified | JWK specified |
---|---|---|---|
RS256 | Yes | Yes | Yes |
ED25519 | To be implemented | To be added | Yes |
SECP256K1 | To be implemented | To be added | To be added |
Algorithm | Support | JOSE specified | JWK specified |
---|---|---|---|
RS256 | Yes | Yes | Yes |
RS512 | Yes | Yes | Yes |
ED25519 | To be implemented | To be added | Yes |
SECP256K1 | To be implemented | To be added | To be added |
Note: ED25519 is defined in JWK specification, while SECP256K1 is not. Neither algorithms are listed in the JOSE signature and encryption algorithms, and are not implemented in the node-jose NPM package used in the current implementation.
Serialization | Support |
---|---|
Compact Serialization | Yes |
JSON Serialization | No |
Discussion: Current implementation assumes Compact Serialization in the HTTP POST body and payload. We might want to support JSON serialization for POST body instead/in addition.
Asymmetric algorithms that can be used by the Hub to encrypt the symmetric content encryption key in the Hub response JWE:
Algorithm | Support | JOSE specified | JWK specified |
---|---|---|---|
RSA-OAEP | Yes | Yes | Yes |
ED25519 | To be implemented | To be added | Yes |
SECP256K1 | To be implemented | To be added | To be added |
Asymmetric algorithms that can be used by the Hub to decrypt the symmetric content encryption key in the Hub request JWE:
Algorithm | Support | JOSE specified | JWK specified |
---|---|---|---|
RSA-OAEP | Yes | Yes | Yes |
RSA-OAEP-256 | Yes | Yes | Yes |
ED25519 | To be implemented | To be added | Yes |
SECP256K1 | To be implemented | To be added | To be added |
Symmetric algorithms that can be used by the Hub to encrypt the content of the Hub response JWE:
Algorithm | Support | JOSE specified |
---|---|---|
A128GCM | Yes | Yes |
XSalsa20-Poly1305 | To be implemented | To be added |
Symmetric algorithms that can be used by the Hub to decrypt the content of the Hub request JWE:
Algorithm | Support | JOSE specified |
---|---|---|
A128GCM | Yes | Yes |
XSalsa20-Poly1305 | To be implemented | To be added |
This section describes how to add additional cryptographic algorithm support in the Hub.
Follow the steps below to add an additional algorithm for asymmetric key encryption:
getKeyEncryptionAlgorithm(...)
method in JweToken.ts
to support a new JWK format.EncryptDelegate
definition found in JweToken.ts
.encryptContentEncryptionKey(...)
method found in JweToken.ts
.These extensibility points are sufficient to allow users/clients of the hub to choose their own key types and algorithms used for authentication and encryption. They do not, however, enable hub implementers to choose their own key types and algorithms – the current implementation forces the use of RSA (see future work).
Follow the steps below to add an additional algorithm for signature verification:
VerifySignatureDelegate
definition found in JwsToken.ts
.verifySignature(...)
method found in JwsToken.ts
.We’ve identified the following areas of investment to improve the Hub authentication scheme:
TLS and its predecessor SSL provide message integrity and confidentiality by encrypting messages between a client and server and authenticating the identity of the server. Without going into detail, it is dependent on the client trusting a set of certificate authorities (CAs) to remain robust to compromise. Some examples and reasons for lack of trust in CAs:
While the TLS protocol provides many of the security and privacy guarantees necessary for secure Hub communication, it the dependency on CAs and DNS security that motivates a different solution. By replacing the role of CAs with a distributed ledger, we provide a stronger degree of message security.
There are several companies/projects today that are exploring the use of blockchains to replace existing internet infrastructure. Primary examples include Namecoin and Blockstack (to a degree), but a quick search will reveal several other efforts as well:
Blockchain based solutions, however, are not the only ongoing attempt to reduce reliance on/trust in CAs. Some other solutions, some active, some now discontinued, include:
Beyond CA vulnerabilities, TLS typically does not do anything to authenticate the identity of the client to the server – that is left as an exercise to the server developer, and different services take many different approaches. Client authentication is one of the main requirements for a complete Hub authentication proposal, which makes TLS on its own insufficient for our purposes.
A purported solution for client authentication based on TLS is known as Client TLS or Mutual TLS, in which the client authenticates the server and the server also authenticates the client. Mutual TLS is popular for server to server communication where both servers are owned by a single party.
While Client TLS integrates nicely with the exiting TLS infrastructure, it has its drawbacks in user-facing scenarios. Most importantly, using Client TLS requires the user to obtain and install a certificate from a trusted CA, which often involves interacting with low-level functionality on the device. Furthermore, use of the certificate must typically be approved by the user before any website or server can perform mutual authentication. Finally, the certificate used in Client TLS is shared across all applications on the device, rather than maintaining per-application credentials. This makes it more difficult to authenticate which client application might be making a particular request. For more detail on the shortcomings of client TLS, please refer to the following pages:
The goal of this proposal is two-fold:
Admittedly, this proposal does not quite achieve the latter. As noted in step 7 of the authentication protocol, the client must validate the signature provided by the Hub using the Hub’s public keys. The Hub’s public keys, however, are located on the distributed ledger where the Hub registered its DID.
The typical solution for resolving a DID into its public keys is to run an instance of the Universal Resolver. But unfortunately verifying the authenticity of the response received from a Universal Resolver requires an HTTPS request with reliance on the very PKI we were trying to circumvent.
To actually remove reliance on CAs, we must come up with an alternative strategy for resolving a Hub’s DID to its public keys in its DDO. Some possible solutions might include:
Section III of this pape provides a nice comparison of different technologies that are used for establishing trust in secure messages exchanges.