]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/crypto/tls/ticket.go
crypto/tls: make SessionState.Extra a slice of byte slices
[gostls13.git] / src / crypto / tls / ticket.go
index 1a3d0c7cfdef254c10597a59e7a5e5beb2fc6e09..b43101ff6658c19476233e1b305f50729a480261 100644 (file)
@@ -27,13 +27,15 @@ type SessionState struct {
        //
        //   Certificate CertificateChain<0..2^24-1>;
        //
+       //   opaque Extra<0..2^24-1>;
+       //
        //   struct {
        //       uint16 version;
        //       SessionStateType type;
        //       uint16 cipher_suite;
        //       uint64 created_at;
        //       opaque secret<1..2^8-1>;
-       //       opaque extra<0..2^24-1>;
+       //       Extra extra<0..2^24-1>;
        //       uint8 ext_master_secret = { 0, 1 };
        //       uint8 early_data = { 0, 1 };
        //       CertificateEntry certificate_list<0..2^24-1>;
@@ -62,12 +64,13 @@ type SessionState struct {
        //
        // This allows [Config.UnwrapSession]/[Config.WrapSession] and
        // [ClientSessionCache] implementations to store and retrieve additional
-       // data.
+       // data alongside this session.
        //
-       // If Extra is already set, the implementation must preserve the previous
-       // value across a round-trip, for example by appending and stripping a
-       // fixed-length suffix.
-       Extra []byte
+       // To allow different layers in a protocol stack to share this field,
+       // applications must only append to it, not replace it, and must use entries
+       // that can be recognized even if out of order (for example, by starting
+       // with a id and version prefix).
+       Extra [][]byte
 
        // EarlyData indicates whether the ticket can be used for 0-RTT in a QUIC
        // connection. The application may set this to false if it is true to
@@ -115,7 +118,11 @@ func (s *SessionState) Bytes() ([]byte, error) {
                b.AddBytes(s.secret)
        })
        b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
-               b.AddBytes(s.Extra)
+               for _, extra := range s.Extra {
+                       b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+                               b.AddBytes(extra)
+                       })
+               }
        })
        if s.extMasterSecret {
                b.AddUint8(1)
@@ -176,19 +183,27 @@ func ParseSessionState(data []byte) (*SessionState, error) {
        s := cryptobyte.String(data)
        var typ, extMasterSecret, earlyData uint8
        var cert Certificate
+       var extra cryptobyte.String
        if !s.ReadUint16(&ss.version) ||
                !s.ReadUint8(&typ) ||
                (typ != 1 && typ != 2) ||
                !s.ReadUint16(&ss.cipherSuite) ||
                !readUint64(&s, &ss.createdAt) ||
                !readUint8LengthPrefixed(&s, &ss.secret) ||
-               !readUint24LengthPrefixed(&s, &ss.Extra) ||
+               !s.ReadUint24LengthPrefixed(&extra) ||
                !s.ReadUint8(&extMasterSecret) ||
                !s.ReadUint8(&earlyData) ||
                len(ss.secret) == 0 ||
                !unmarshalCertificate(&s, &cert) {
                return nil, errors.New("tls: invalid session encoding")
        }
+       for !extra.Empty() {
+               var e []byte
+               if !readUint24LengthPrefixed(&extra, &e) {
+                       return nil, errors.New("tls: invalid session encoding")
+               }
+               ss.Extra = append(ss.Extra, e)
+       }
        switch extMasterSecret {
        case 0:
                ss.extMasterSecret = false