Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TLS with Ethereum Keys #437

Open
j0sh opened this issue May 22, 2018 · 3 comments
Open

TLS with Ethereum Keys #437

j0sh opened this issue May 22, 2018 · 3 comments
Labels
area: blockchain area: orchestrator QoL need: investigation need to investigate what is happening before proceeding status: icebox type: feature New feature or request

Comments

@j0sh
Copy link
Collaborator

j0sh commented May 22, 2018

(This post assumes some familiarity with the mechanics of TLS because it was getting long enough, but I've added some links around important concepts. Happy to elaborate on anything.)

Justification

The proposal for Broadcaster-Transcoder Networking v2 does not address authenticity and integrity of the protocol messages. Both the v2 proposal and basicnet are vulnerable to MITM-style attacks (injection, tampering, withholding, etc), and do not guarantee message confidentiality in transit.

While the smart-contract protocol has its own defenses against fraudulent activity, there are still concerns external to the smart contract. For example: the broadcaster may have confidentiality concerns, and may want to be reassured they are talking to the expected transcoder. TLS provides both confidentiality and authentication.

Orchestrators might want to ensure that a broadcaster's query for a job is legitimate. For example, they may want to avoid distributing transcode credentials unnecessarily. Over an unauthenticated connection, replay attacks are possible. Hence, mutual authentication is a nice property to have.

Transcoders, especially those part of a public pool, may want to ensure that broadcasters are communicating with the correct transcoder and eg, not being spoofed by a competing transcoder in the pool. Going further with mutual authentication, the transcoder could ensure a broadcaster's transcode request is legitimate by looking at a broadcaster certificate which has been issued by the orchestrator.

Right now, we sign certain protocol messages on an ad-hoc basis[1][2]. This leads to uneven coverage and more difficulty reasoning about the security properties of the network protocol. By using TLS, we avoid the need to manually sign messages, except for those signatures intended for the blockchain. This substantially reduces the uncertainty and error surface within the v2 protocol.

Livepeer

The fundamental challenge in using TLS with Livepeer is in key management and the absence of a truly decentralized root CA. However, the blockchain gives us the essential ingredients to establish a PKI.

We take the Ethereum keys and generate "root" CAs by self-signing certificates. Since the broadcaster and orchestrator keys are already known, the keys can be used to verify signatures on incoming certificates during the TLS handshake phase. Thereafter, TLS gives us authentication, integrity and confidentiality for the duration of the message exchange.

Discovering the Root

The problem here is that most TLS implementations expect a pre-installed list of root certificates. We don't have such a list for all our transcoders (or broadcasters). However, all we need to do is verify that a cert's root is signed with the keys that we expect. This requires some trickery, but I think we can get away with it.

An alternative is to use ENS to store the certificates and retrieve them on-demand, but those may be too large to store on-chain, several KB. Or the client could simply request a copy of the certificate from the server via plaintext HTTP, prior to the actual HTTPS connection.

While we can sign root certificates using Ethereum keys, we also want to take advantage of X.509's chain-of-trust property, for two reasons: to keep the root keys in cold storage, and to delegate transcoding authority. The result being that each transcoder pool ends up with its own mini-PKI that can be traced back to the on-chain orchestrator address.

Orchestrator Intermediate Certificates

  • Each orchestrator generates a certificate, self-signed with their own Ethereum private key. Call this the "eth cert."
    • This may be done offline.
  • Each orchestrator node should generate a CSR, and the eth cert issues (signs) an intermediate orchestrator cert
    • Allows for reassigning "hot" orchestrators as needed without moving private key(s) around, whether Ethereum keys, TLS keys, etc.
    • Safeguards the eth key in case of orchestrator compromise

Transcoder Certificates

Transcoders generate a CSR, have cert issued by the orchestrator's intermediate cert.

  • Broadcasters should ensure that the cert's root is issued by the orchestrator assigned to the job
  • Should also associate the transcoder's domain or IP address with each transcoder cert
    • Offers transcoders reassurance the broadcaster won't send work to a spoofed node (eg, within a public transcoder pool).
  • When transcoder == orchestrator, just reuse the intermediate cert from the orchestrator.
  • Transcoders do not actually need an Ethereum key this way

Transcoders may be issued multiple certs if they are part of several pools (one per orchestrator).

  • For TLS 1.3, use certification_authorities (TLS 1.3) to indicate which orchestrator the job belongs to
  • But TLS 1.3 isn't in golang yet. Use trusted_ca_keys or SNI
  • Also enables concurrent support for blockchains other than Ethereum
  • Doesn't need to be implemented now; can be deferred until we need it

Broadcaster Certificates

  • Broadcasters can self-sign their own certificate (or use it to sign an intermediate).
    • Could use a SAN to ease checking
      • RFC3986-style URIs, eg livepeer+eth://<eth-account>
      • Allows support for other types of blockchains, not just Ethereum, eg livepeer+cosmos://<cosmos-id>
    • Orchestrator to check and ensure broadcaster matches an assigned job.

Once we have transcoders acting independently of the orchestrator, mutual auth can then be used for the transcoder to authenticate the broadcaster.

  • The broadcaster uses ephemeral certificates: it generates a a CSR for each job. Orchestrator signs. Broadcaster offers this as proof to the transcoder that the broadcast is authorized.
    • Cert would probably have to include job details (streamid, jobid, last seen sequence number, etc).
  • Alternative to an opaque JWT-style token that the broadcaster passes between orchestrator and transcoder
    • Can reject the connection during the handshake, rather than completing the set-up only to find the credentials are invalid
      • Technically the transcoder could check the broadcaster's certificate verify on-chain from there, but that's onerous

Certificate Revocation

As of yet undefined, especially for revoking orchestrator certs.

  • No canonical root CA, so no canonical CRL yet.
  • Encourage short-lived certs, esp for "hot" nodes
  • Orchestrators can submit CRLs for individual transcoders under their control
  • Various possible solutions for orchestrator revocation; can be solved later

Mutual (Broadcaster) Authentication

Not strictly necessary, but certainly doable with TLS as described earlier. The alternatives (eg, transcoder authentication tokens) would work just as well. The concern about replay attacks on the Job request is minor, since any data messages would still be sent encrypted.

[1] Job request from the broadcaster to the orchestrator
[2] TranscodeSub request in basicnet, MsgSubReq has signing as a todo

@yondonfu
Copy link
Member

Generally, I like the property described of keeping any Ethereum keys registered on-chain in cold storage with other authorized keys being used for signing networking protocol messages. In theory, I think the parties could also discard keys used in a connection once its closed to reduce key management overhead.

The transcoder certificates seem like they would work with a trusted pool operated by an orchestrator, but just noting that we might not want to rely on the orchestrator as a CA in a untrusted pool.

Perhaps something to keep in mind is that in TLS 1.3 the curves allowed for the ECDSA signature scheme are limited to secp256r1, secp384r1 and secp521r1[1], but Ethereum uses the secp256k1 curve[2]. Looks like TLS 1.2 does not contain any restrictions on the curves for ECDSA so this wouldn't be a problem at the moment since TLS 1.3 isn't in golang yet, but might be if TLS 1.3 is used later on.

[1] https://timtaubert.de/blog/2016/07/the-evolution-of-signatures-in-tls/
[2] https://ethereum.github.io/yellowpaper/paper.pdf

@j0sh
Copy link
Collaborator Author

j0sh commented May 25, 2018

The transcoder certificates seem like they would work with a trusted pool operated by an orchestrator, but just noting that we might not want to rely on the orchestrator as a CA in a untrusted pool.

Right now, orchestrators need to be trusted, so even for a public pool composed of transcoders that don't trust one another, they all need to trust the orchestrator. Some pools might devise a "provably fair" sharing system where transcoders can be assured that they're receiving an equal slice of the work/rewards from the orchestrator, but the transcoder-orchestrator flow is rather decoupled from the broadcaster-related networking protocol. Otherwise, I think we may be looking at changes to the smart contract / economic protocol.

Perhaps something to keep in mind is that in TLS 1.3 the curves allowed for the ECDSA signature scheme are limited to secp256r1, secp384r1 and secp521r1[1], but Ethereum uses the secp256k1 curve[2]. Looks like TLS 1.2 does not contain any restrictions on the curves for ECDSA so this wouldn't be a problem at the moment since TLS 1.3 isn't in golang yet, but might be if TLS 1.3 is used later on.

You are correct. While we can generate and validate such Ethereum-signed certificates through OpenSSL, golang doesn't (easily) expose the ability to use such certs with its native TLS.

How's this for a workaround: in the SubjectAltName dNSName extension, we append the ENS path. By default, this could be <broadcaster-addr>.transcoder.eth . Then we can store the hash of the certificate within ENS (or a hash of the public key). Upon connection with the orchestrator, the broadcaster ensures the cert's root CA hash matches what's in ENS. That also allows to use the same cert for multiple blockchains, and segues nicely into the broadcaster's use of SNI.

This also serves as a revocation mechanism; revoking a cert is a matter of replacing the hash in ENS. While this may become inconvenient later on (eg, revoking a leaf transcoder's cert means replacing all certs), it should be enough to get us started.

Another way to save on costs and avoid putting anything in ENS, is to put an Ethereum signature from the orchestrator somewhere else in the cert (eg, a URI or custom SubjectAltName), but that doesn't really lend itself to revocation.

@iameli-streams
Copy link

I love that this is the top Google result for "TLS Cert with Ethereum keys."

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: blockchain area: orchestrator QoL need: investigation need to investigate what is happening before proceeding status: icebox type: feature New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants