github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/docs/content/adr/001/_index.md (about)

     1  +++
     2  title = "V2 Network Protocol"
     3  toc = true
     4  weight = 10
     5  pre = "<b>1. </b>"
     6  +++
     7  
     8  ## Background
     9  
    10  ### Current State
    11  
    12  The Choria V1 protocol requires x509, there is no other option.
    13  
    14  Experience with `mcollective` showed that companies had little appetite to understand or use esoteric security protocols, even those based on sound industry standard cryptographic methods. Further most companies already had mature x509 infrastructure either standalone or part of systems like Puppet which made for an easy adoption path.
    15  
    16  Choria therefor is built on a protocol that requires x509 semantics and supports nothing else:
    17  
    18  * Every message is signed by a x509 key
    19  * Every client-initiated message contains the x509 public key
    20  * Servers listen on TLS using x509 public and private keys
    21  * User identities are tied to the properties of the certificates
    22  * User permissions and roles are tied to the identity of the certificate, very limited support for fine-grained roles
    23  * All JWT files are signed by x509 keys
    24  * Generally only RSA is supported
    25  * mTLS is used to create a private network - requiring a purpose specific CA or intermediate CA in practice
    26  * A local cache of certificates is used like a kind of safety check to catch credentials being re-issued
    27  * Any NATS client connecting to Choria broker requires a cert/key/ca and do full mTLS
    28  
    29  Choria supports a mode combined with the AAA Server where a user does not need her own x509 certificate but holds a JWT instead obtained from an SSO service. In this scenario the AAA Server still holds a x509 cert (called a privileged certificate) and is allowed to sign and encode requests on behalf of others (holders of a JWT) by using its x509 key pair to sign on behalf of the user.
    30  
    31  ### Problem Statement
    32  
    33  In practice this works well for most users, but those with very large or complex networks can run into problems either with corporate Certificate Authority policies or corporate CA configuration making it very hard to achieve a secure network with the facilities available. General CA infrastructure is also just getting a bit old and better alternatives exist. JWTs are now used pervasively in modern IT and the user based are more likely to accept their use for our needs.
    34  
    35  We would like to explore, and enable, other use cases outside of server management such as IoT, purpose built backplanes, Kubernetes side cars and more, integration into Certificate Authorities in those cases is really problematic.
    36  
    37  * x509 signatures are big and slow
    38  * x509 certificates are also huge and these go with every request
    39  * x509 certificate management, especially across multiple client machines is very difficult
    40  * Dealing with short-lived (minutes) x509 certificates can be really hard
    41  * Not all CAs have sane enrollment, some requires private keys to be copied around making them useless
    42  * Newer technologies like ed25519 is attractive as they use small keys and signatures and can also do things like DH Key exchange
    43  * Using ed25519 opens the possibility of using ssh keys as signing keys, something many users have requested
    44  * Obtaining private CAs or intermediate CAs is often impossible forcing CA reuse and nullifying the usefulness of the mTLS security
    45  * Verification of certificates happen during caching rather than a separate check, more importantly the cache is used often as a means of retrieving privileged certs and more by id
    46  * The local cert cache is deeply embedded in the v1 protocol, but it's proven to be useless and most people disable its enforcing features - it cannot be disabled entirely
    47  * As Choria have evolved we need a much more granular role based permissions on each connection - can they use streams, can they admin streams, can they make rpc requests etc
    48  * More and more servers need to be able to make request either when publishing signed registration payloads or when interacting with Choria Services from within autonomous agents.  With v1 protocol this was not possible.
    49  
    50  ### Solution Overview
    51  
    52  We will support an additional protocol, while maintaining v1 protocol, that will be based on JWTs signed using ed25519 that embed their public component in the signed JWT.
    53  
    54  We have already done the work to design and incorporate the JWTs for clients and servers at the transport level but now need to move that work into the Choria protocol so clients can communicate with Choria without x509 certificates.
    55  
    56  #### Transport Security
    57  
    58  Transport security is primarily about how the packets between Choria Broker and Choria Client/Server are secured but touches a bit on how users with access to the NATS Server are limited to just their traffic.
    59  
    60  ##### mTLS optional Chain of Trust for transport security
    61  
    62  In a mTLS secured network trust is established by way of the CA signing all certificates and all parties verifying this fact. Both sides of the TLS connection will verify the other side to ensure its certificate is signed by a cached local CA chain.
    63  
    64  This way there can be no untrusted middlemen or session hijacking in the network path.
    65  
    66  In practice, in enterprise networks, there are many challenges:
    67  
    68  * it's often highly desirable to be able to hijack connections, for example to audit that PII doesn't leave the legal jurisdiction it belongs in, many companies wish to disable the full mTLS while still maintaining strong identification of entities.
    69  * it's also desirable to deploy Choria Brokers using websocket protocol and offload the TLS work onto a load balancer - this would be quite complex with the current model.
    70  * most enterprise have policies making CA rotation necessary and quite frequent, this makes mTLS completely unworkable at scale.
    71  * dropping mTLS, or not being able to do mTLS, would impact the strength of identity since we combine the transport and identity in one cert
    72  * certificate enrolment is done poorly, there are few protocols like ACME in use in Enterprises, often they would design their own enrollment, and mostly it involves moving keys between machines and are very slow
    73  
    74  So we will support verified or unverified TLS to the brokers, but clients and servers all must present a signed JWT when not in mTLS mode. This will split the identity from transport security and give people the choice to pick one without compromising the other.
    75  
    76  Servers and clients will have:
    77  
    78  * An ed25519 seed file example `server.seed` kept private and never transmitted over the network
    79  * A JWT file that holds:
    80      * the public key of the ed25519 seed
    81      * an identity
    82      * a private network ID derived from the identity or seed
    83      * Standard items like expiry times etc
    84      * Additional permissions to control access to broker subjects
    85  * The JWT will be signed by a trusted ed25519 key
    86  
    87  The broker will only allow connections that holds a valid, signed JWT where the signature is made using a trusted ed25519 key.
    88  
    89  ##### Organization and Chained Issuers
    90  
    91  Conceptually Choria Broker can separate connections into something called "accounts" in NATS terms, for Choria we call this an Organization. Today we support just one Organization - `choria` - but we will look to support more in future.
    92  
    93  We will add a concept called an Organization Issuer that is a ed25519 key that must, on a basic level, sign all tokens. To facilitate separation of concerns in our centralized AAA mode the Issuer can delegate JWT issuing in a chain to downstream issuers.  The tokens will validate as being signed by the issuer essentially.
    94  
    95  We support storing the Organization Issuer offline in something like Vault and at the "AAA Login Server" level that issuing key can also be stored in a Vault like system.
    96  
    97  ![Chain Issuers](/org-issuers.png)
    98  
    99  Thus, we achieve the following chain of trust:
   100  
   101  * We know the JWT was issued by a trusted issuer
   102  * We verify the connecting server or client has the ed25519 seed that match the JWT because the broker force a [NONCE](https://en.wikipedia.org/wiki/Cryptographic_nonce) to be signed using the seed, the seed never traverse the network since the public part is embedded in the signed JWT
   103  * The JWT tokens are therefor not bearer tokens and if they are stolen in-flight (remember no mTLS), one cannot connect with them or make any requests using them
   104  * We have an identity that isn't tied to the common name of a cert and so is more fluid and adaptable
   105  * The broker should support [denying all clients without JWTs](https://github.com/choria-io/go-choria/issues/1837)
   106  
   107  In this way we can pick full mTLS when needed or JWT+ed25519 mode when needed and even mix and match the modes.
   108  
   109  #### Reply Security
   110  
   111  Reply security is a quite difficult problem to solve since every reply would need to be individually encrypted and decrypted - unlike transport security - this is very CPU intensive, so we have never really done it at scale.
   112  
   113  Still, its highly desirable to hide replies destined for a specific user from other users, even those with access to the broker using their own JWT tokens.
   114  
   115  Using the callerID as key we calculate a private inbox using the hex encoded `md5(callerID)`, we use this to construct reply subjects for all uses, even access to other subjects like the Streams API.
   116  
   117  The broker will set up permissions ensuring that only the callerID can access replies. This way as long as there are unique callerIDs the replies from all systems are private.
   118  
   119  We still do not encrypt the traffic in-transit (see point about PII and desired man-in-the-middle in Enterprises), but the replies are private to the user.
   120  
   121  ```
   122  % sudo choria jwt client.jwt
   123  ...
   124     Private Network ID: 7419405695a186147a0de38f7e31a509...
   125  ...
   126  
   127  % choria req choria_util info --debug
   128  DEBU[0000] Publishing message with reply to choria.reply.7419405695a186147a0de38f7e31a509.4e27ca6493cb4576bb78e90ea35df38c  component=client
   129  ```
   130  
   131  Here we can see the reply is set to match `<collective>.reply.<private network id>.<request id>`, the broker ensures the holder of this JWT cannot subscribe to other users replies.
   132  
   133  To facilitate debugging users with the `OrgAdmin` permission, default not granted, on their tokens can view all replies.
   134  
   135  #### Submission and Registration Data Security
   136  
   137  As each server will have a ed25519 seed and a JWT embedding the public key we will support, optionally, signing Choria Submission and Registration messages. Signatures and Tokens will be included in headers.
   138  
   139  This way should a system need to be created where the node will ask in an async manner for operations to be done against it, think host-detected issues triggering auto remediation, these messages originating from Submission will be signed.
   140  
   141  Recipients of these messages can be certain that the message originated from a place that had access to the nodes private key.
   142  
   143  See [#1873](https://github.com/choria-io/go-choria/issues/1873)
   144  
   145  #### Identity
   146  
   147  Identity primarily concerns Choria Requests, this is who is the one making the request for the use by AAA.
   148  
   149  Traditionally this is extracted from the x509 certificate common name and have some dumb rules like `x.choria` or `x.privileged.choria` since x509 certificates don't really have a strong concept of boolean permissions.
   150  
   151  This is awful and arbitrary, in the new model callers should be whatever they like and a flag on the JWT would identify it as privileged or not ([#1836](https://github.com/choria-io/go-choria/issues/1836)).
   152  
   153  #### Caller Identity
   154  
   155  Identity would always be extracted from the JWT of the final client. In the case of the AAA Service we would need to have the ability to include the client JWT as well as the signer JWT and the signature:
   156  
   157  * When the signer JWT isn't set we ensure the client signed it.
   158  * When the signer JWT is set we ensure the JWT has the right permission to sign others requests ([#1836](https://github.com/choria-io/go-choria/issues/1836))
   159  * The identity of the client JWT is used for the request
   160  * We should be able to issue JWTs that can only be used in conjunction with an AAA server who signs their requests ([#1840](https://github.com/choria-io/go-choria/issues/1840))
   161  
   162  This would be the identity used in things like RBAC, Audit logs and more.
   163  
   164  The broker might set the NATS user to the identity to assist with debugging.
   165  
   166  #### Request Signatures
   167  
   168  Today requests are signed by the x509/RSA key, we'd just sign it with the ed25519 seed instead. We would not support any form of server side cache.
   169  
   170  Client JWTs will gain permissions that state they have fleet management access and, optionally, that fleet management access requires signatures.
   171  
   172  ### Issuing JWT tokens
   173  
   174  Traditionally you would use whatever your CA does for enrolling certificates and `choria enroll` might help you out if you're lucky to have a system that supports that.
   175  
   176  For others, it would be up to the user to deliver the key, cert and ca to the right locations.
   177  
   178  Having Server enroll separate from Client enroll is good, since its conceivable that those will be done in very different places and with different auth mechanisms.
   179  
   180  #### Servers
   181  
   182  Servers would get their JWT token from the Choria Provisioner, this is supported today and that supports setting permissions and more. The Provisioner would hold a JWT that is a Chain Issuer allowing it to sign JWTs for servers.
   183  
   184  #### Clients
   185  
   186  The current AAA Server should be extended to allow client enrollment, essentially this is already supported but there is no allowance for the client seed and new behaviors. The signing request should be extended with a signature made using the seed and the service should verify it - essentially same as the NONCE in the broker.
   187  
   188  The AAA Service would support marking a user as standalone - he can make his own requests without AAA and has his own seed - or as requiring AAA service ([#1840](https://github.com/choria-io/go-choria/issues/1840)). He might have his own seed for signing the broker NONCE but cannot make RPC requests that were not signed by AAA service.
   189  
   190  The AAA Login handler would hold a JWT that is a Chain Issuer allow it to sign JWTs for the clients and set policies and permissions.
   191  
   192  The `choria jwt` command must also be able to issue client credentials.
   193  
   194  Non Choria clients - like lets say a random node nats client - would need to get their hands on a JWT and seed as well, and they will have to connect with that. So there will have to be a way to enroll them, probably `choria jwt` or `choria login` with their user marked as being long term valid.
   195  
   196  A final class of client is one that needs a short-lived permission to make a very specific request.  Imagine some external orchestrator wants to invoke `choria req` or `choria kv` for a particular use. Ideally this external Orchestrator would be able to issue a JWT that would allow this to happen on any unix user. In this scenario `choria login` should be able to take a bearer token and present that to AAA service during `choria login`. The bearer token would be signed by the orchestrator and trusted by the AAA, the bearer token would be very short-lived and essentially single use. It will be used to facilitate login, Choria JWT creation and more so that the unix user would still have an ed25519 seed, but the Choria Client JWT would be custom and short-lived and restricted to purpose.
   197  
   198  ### Federation
   199  
   200  The federation system allows for moving requests and replies between uncoupled networks - essentially it's a protocol converter and gateway.
   201  
   202  We would not in the past create federation that would cross CA boundaries as resigning all the requests and replies was impossible.  With the new system the Federation Broker should be able to have a token with Authentication Delegation set and just re-sign the request en-route.  This will allow it to do translation between networks and ID schemes.
   203  
   204  ## Implementation
   205  
   206  The protocol in Choria largely defines the bytes that traverse the network and couples quite tightly with the security providers for encoding, signing etc.
   207  
   208  In the work to support v2 protocol we are also revisiting the design of the security plugins to be more generic and support non x509 key data.
   209  
   210  ### Protocol
   211  
   212  Layered protocols are used widely and bring with them a lot of flexibility in replacing some layer with another, for example: Ethernet -> IP -> TCP -> HTTP -> REST.
   213  
   214  Choria has a similar design:
   215  
   216  ```
   217  ( Transport
   218    ( Secure Request or Reply
   219      ( Request or Reply
   220        ( Any bytes, often: RPC Request or Reply )
   221      )
   222    )
   223  )
   224  ```
   225  
   226  The efforts with v2 protocol is to replace Transport, Secure and Request/Reply with a new design, still based on JSON, but with better choices internally.
   227  
   228  #### Request
   229  
   230  A request holds the actual bytes being moved around and various claims about who is making the request.
   231  
   232  | Field        | v1           | Description                                                                                | 
   233  |--------------|--------------|--------------------------------------------------------------------------------------------|
   234  | `protocol`   | `protocol`   | The protocol version for this request `io.choria.protocol.v2.request`                      |
   235  | `message`    | `payload`    | The arbitrary data contained in the request - like a RPC request - as base64 encoded bytes |
   236  | `id`         | `requestid`  | The unique ID for the request, logged in AAA etc                                           |
   237  | `sender`     | `senderid`   | Typically the host that the request was initiated from                                     |
   238  | `caller`     | `callerid`   | Who made the request in the form of `kind=name`                                            |
   239  | `collective` | `collective` | Collective this request is targeted at                                                     |
   240  | `agent`      | `agent`      | The agent this request is targeted at                                                      |
   241  | `ttl`        | `ttl`        | How long this request is valid for                                                         |
   242  | `time`       | `time`       | The unix nano time the request was created (unix time in v1)                               |
   243  | `filter`     | `filter`     | The request filter                                                                         |
   244  
   245  #### Secure Request
   246  
   247  A secure request wraps a `Request`, signs it and prevents any tampering with its content. 
   248  
   249  The signature - having been made with a private key - also conveys identity and confirms the claimed identity in the Request matches what cryptographic keys are held.
   250  
   251  The main purpose of the Secure Request is to verify what can be verified about the Request and make immutable the rest. For example, we can't exactly verify the request time and TTL, but we can prevent it from being changed by an attacker by signing it.  The caller in the `Request` is not verified in the `Request` since it's just an arbitrary string, however the Secure Request being signed using something unique to the caller, private key, confirms the information in the request.
   252  
   253  So the end result is immutable, or at least tamper evident, metadata about a request and likewise the request payload or message.
   254  
   255  | Field       | v1          | Description                                                                         |
   256  |-------------|-------------|-------------------------------------------------------------------------------------|
   257  | `protocol`  | `protocol`  | The protocol version for this secure request `io.choria.protocol.v2.secure_request` |
   258  | `request`   | `message`   | The request held in the Secure Request as base64 bytes                              |
   259  | `signature` | `signature` | A signature made of the request using the ed25519 seed of the caller                |
   260  | `caller`    | `pubcert`   | The JWT of the caller                                                               |
   261  | `signer`    | n/a         | The JWT of the delegated signer, present when the AAA server is used                |
   262  
   263  #### Reply
   264  
   265  A reply is created in response from a request and holds the request id in its payload
   266  
   267  | Field      | v1          | Description                                                       |
   268  |------------|-------------|-------------------------------------------------------------------|
   269  | `protocol` | `protocol`  | The protocol version for this reply `io.choria.protocol.v2.reply` |
   270  | `message`  | `payload`   | The arbitrary data contained in the reply - like a RPC reply      |
   271  | `request`  | `requestid` | The ID of the request this reply relates to                       |
   272  | `sender`   | `senderid`  | The host sending the reply                                        |
   273  | `agent`    | `agent`     | The agent the reply originates from                               |
   274  | `time`     | `time`      | The unix nano time the request was created (unix time in v1)      |
   275  
   276  #### Secure Reply
   277  
   278  A secure reply wraps a `Reply`, signs it and prevents any tampering with its content. The hash is a fast way to test validity of the reply.
   279  
   280  Like the Secure Request the Secure Reply wraps the Reply in a way that makes it tamper evident via signatures and hashes.
   281  
   282  The v2 protocol includes a signature and sender JWT however in practice this is mostly not going to be used as too costly on the receiver, however might be used for registration payload verification.
   283  
   284  Signatures add quite a bit to the payload here, as the JWT has to be sent with, so it can be disabled using `plugin.security.choria.sign_replies` in the new security provider.
   285  
   286  | Field       | v1         | Description                                                                     |
   287  |-------------|------------|---------------------------------------------------------------------------------|
   288  | `protocol`  | `protocol` | The protocol version for this secure reply `io.choria.protocol.v2.secure_reply` |
   289  | `reply`     | `message`  | The reply held in the Secure Request as base64 bytes                            |
   290  | `hash`      | `hash`     | A sha256 of the reply                                                           |
   291  | `signature` | n/a        | A signature made using the ed25519 seed of the sender                           |
   292  | `sender`    | n/a        | The JWT of the sending host                                                     |
   293  
   294  #### Transport
   295                          
   296  The transport packet is the last layer that gets sent over NATS, it holds no message specific data.
   297  
   298  | Field        | v1           | Description                                                                  |
   299  |--------------|--------------|------------------------------------------------------------------------------|
   300  | `protocol`   | `protocol`   | The protocol version for this transport `io.choria.protocol.v2.transport`    |
   301  | `data`       | `data`       | The payload to be transport, a Secure Request or Secure Reply base64 encoded |
   302  | `headers`    | `headers`    | Optional headers                                                             |
   303  
   304  Headers:
   305  
   306  | Field        | v1           | Description                                                              |
   307  |--------------|--------------|--------------------------------------------------------------------------|
   308  | `reply`      | `reply-to`   | A transport specific response channel for this message, used in requests |
   309  | `sender`     | `mc_sender`  | The host that sent this message                                          |
   310  | `trace`      | `seen-by`    | A trace of host/broker pairs that the message traversed                  |
   311  | `federation` | `federation` | Headers to assist federation                                             |
   312  
   313  Federation:
   314  
   315  | Field     | v1         | Description                                     |
   316  |-----------|------------|-------------------------------------------------|
   317  | `request` | `req`      | The request ID a federated message belongs to   |
   318  | `reply`   | `reply-to` | The original `reply` before federation          |
   319  | `targets` | `targets`  | The identities who the federated message is for | 
   320  
   321  ### Chained Tokens Verification
   322  
   323  We created a Chained Token system in [#1900](https://github.com/choria-io/go-choria/issues/1900) that allows a Organization Issuer to delegate Client and Server creation to Chained Issuers.
   324  
   325  From a usage perspective you can say `tokens.ParseClientIDToken(t, pubk)` where the public key is the public part of the Organization Issuer, even when the token `t` is signed by a Chain Issuer. The intention is to make the configuration of a chain much easier, you only have to configure the issuer for an Organization.
   326  
   327  Additionally the expiry of the Chain Issuer is encoded in the token, if the issuer expires first the issued token is also considered expired.
   328  
   329  The way this is achieved is with a series of claims and signatures as described here:
   330  
   331  The Organization Issuer for an Organization is simply an `ed25519` key for the moment. If that Org Issuer is just signing some client, server or provisioner nothing special is done, it's just signing a JWT like normal.
   332  
   333  However if the Org Issuer wants to create a token that can sign other tokens additional information is added a Clent token, it's called the **Chain Issuer**:
   334  
   335  ```json
   336  {
   337    "iss": "I-514969e316eb4a7146b8066feb6af5dbc05da0965ec57c9d3a7d3299d5d98fec",
   338    "jti": "0ujsswThIGTUYm2K8FjOOfXtY1K",
   339    "ou": "choria",
   340    "public_key": "bd2588d3dc309d536461caa11c0d6f639e89d7a09dc43eae052f3fb32e2d8687",
   341    "purpose": "choria_client_id",
   342    "tcs": "3f815723734c78ceaba5fb506347565f85fe2a0334c038ba2370c7f53f35e6c7c75ed3e95b531b6049426638201c39639dbf9b711fba5d866e7e3e30be02b401"
   343  }
   344  ```
   345  
   346  * `jti` is a unique ID for this token. It's a [kskuid](https://github.com/segmentio/ksuid), the time component must match the issued at time
   347  * `iss` field indicates it is signed by a Issuer with public key `514969e316eb4a7146b8066feb6af5dbc05da0965ec57c9d3a7d3299d5d98fec`.
   348  * `public_key` is the public part of the ed25519 seed for the Chain Issuer `aaa_chain_delegator`
   349  * `tcs` is a signature made of `[chain issuer id].[chain issuer public key]` using the Org Issuer private key, in other words `sig("0ujsswThIGTUYm2K8FjOOfXtY1K.bd2588d3dc309d536461caa11c0d6f639e89d7a09dc43eae052f3fb32e2d8687", orgIssuerPrik)`
   350  * The Chain Issuer JWT is signed by the Organization Issuer
   351  
   352  This way we can verify that the Chain Issuer comes from the Issuer both by verifying the signature but also we have a piece of information that cannot be changed down the line (the `tcs`, signed by the Org Issuer key) which we will see again later.
   353  
   354  In code this information, signatures etc can all be added using `chainIssuer.AddOrgIssuerData(issuerPrik)`, with this added the token `chainIssuer` can issue other tokens. For a possible future integration with systems like Vault we would call out to the Vault API to sign the `tcs` plain text and then sign the token, hence the Organization Issuer private key never needs to leave Vault.
   355  
   356  Now when the Chain Issuer wants to issue a new Client or Server token additional information is again added:
   357  
   358  ```json
   359  {
   360    "callerid": "up=rip",
   361    "iss": "C-0ujsswThIGTUYm2K8FjOOfXtY1K.bd2588d3dc309d536461caa11c0d6f639e89d7a09dc43eae052f3fb32e2d8687",
   362    "issexp": 1700153647,
   363    "jti": "b2375f965abe4bfbaf131b585cf5e1a1",
   364    "ou": "choria",
   365    "public_key": "676d07de6721ee396754d4e4d5fa4ee2b59a6f3b8208e760ca614bc66000e740",
   366    "purpose": "choria_client_id",
   367    "tcs": "3f815723734c78ceaba5fb506347565f85fe2a0334c038ba2370c7f53f35e6c7c75ed3e95b531b6049426638201c39639dbf9b711fba5d866e7e3e30be02b401.a9da5f3946c1b472f1c886912bfe5559f261e4663016846e231095bd2e16a8a253657196a5c17231fb095bc3a2d1e89e1edaddcec35dd050303e5d9cda968a04"
   368  }
   369  ```
   370  
   371  * `jti` is a unique id for this token
   372  * `iss` indicates a Chain Issuer with token ID (`jti`) `0ujsswThIGTUYm2K8FjOOfXtY1K` issued this token and his public key is `bd2588d3dc309d536461caa11c0d6f639e89d7a09dc43eae052f3fb32e2d8687` (the one from the previous example) 
   373  * `issexp` indicates when the Chain Issuer expires
   374  * `tcs` is made up of first creating `sigdata` `[client token jti].[chain issuer tcs]` and then combining that `[chain issuer tcs].[sig(sigdata, chainIssuerPrik)]`  
   375  
   376  This way we can, given the signed Client token and the Org Issuer Public key, validate by going backwards over these claims:
   377  
   378  1. Extract the Chain Issuer `tcs`, `public key` and `id` from `iss` and `tcs`
   379  2. Verify the Organization Issuer signed the `tcs` of the Chain Issuer in this token, which also verifies the public key in the issuer
   380  3. Verify the `tcs` signature part of the Client using public key of the Chain Issuer
   381  4. Verify the expiry of the Chain Issuer
   382  
   383  ### General Improvements
   384  
   385  The security plugins handle signing, encoding, extracting of IDs and validating signatures. The current security plugins are all implemented around x509.
   386  
   387  We will make some general improvements, rename some functions and add a few bits to the interface, detail to be discovered during implementation.
   388  
   389  * Move the API to `[]byte` based API [#1844](https://github.com/choria-io/go-choria/pull/1844)
   390  * Remove some string orientated security apis [](https://github.com/choria-io/go-choria/pull/1843)
   391  * Make the JWT authoritative for the secure channel name so we can stop using md5
   392  * Develop a tool that can decode and dump/view network packets [#1484](https://github.com/choria-io/go-choria/pull/1848)
   393  * The entire concept of the cache to be removed [#1842](https://github.com/choria-io/go-choria/pull/1842)
   394  * Default collective when v2 is used will be `choria` [#1885](https://github.com/choria-io/go-choria/pull/1885)
   395  * Submission can sign messages [#1873](https://github.com/choria-io/go-choria/issues/1873)
   396  * The protocol code should be instances not a singleton so each can have unique contexts and logging
   397  * Stronger AAA interactions by signing NONCE like data in login and sign requests
   398  * Potentially entirely remove the concept of Trusted Signers that was a mid term stop gap till this work is complete, only used by 1 users as far as we are aware