(outer *clientHelloMsg, encoded []byte)
| 284 | } |
| 285 | |
| 286 | func decodeInnerClientHello(outer *clientHelloMsg, encoded []byte) (*clientHelloMsg, error) { |
| 287 | // Reconstructing the inner client hello from its encoded form is somewhat |
| 288 | // complicated. It is missing its header (message type and length), session |
| 289 | // ID, and the extensions may be compressed. Since we need to put the |
| 290 | // extensions back in the same order as they were in the raw outer hello, |
| 291 | // and since we don't store the raw extensions, or the order we parsed them |
| 292 | // in, we need to reparse the raw extensions from the outer hello in order |
| 293 | // to properly insert them into the inner hello. This _should_ result in raw |
| 294 | // bytes which match the hello as it was generated by the client. |
| 295 | innerReader := cryptobyte.String(encoded) |
| 296 | var versionAndRandom, sessionID, cipherSuites, compressionMethods []byte |
| 297 | var extensions cryptobyte.String |
| 298 | if !innerReader.ReadBytes(&versionAndRandom, 2+32) || |
| 299 | !readUint8LengthPrefixed(&innerReader, &sessionID) || |
| 300 | len(sessionID) != 0 || |
| 301 | !readUint16LengthPrefixed(&innerReader, &cipherSuites) || |
| 302 | !readUint8LengthPrefixed(&innerReader, &compressionMethods) || |
| 303 | !innerReader.ReadUint16LengthPrefixed(&extensions) { |
| 304 | return nil, errors.New("tls: invalid inner client hello") |
| 305 | } |
| 306 | |
| 307 | // The specification says we must verify that the trailing padding is all |
| 308 | // zeros. This is kind of weird for TLS messages, where we generally just |
| 309 | // throw away any trailing garbage. |
| 310 | for _, p := range innerReader { |
| 311 | if p != 0 { |
| 312 | return nil, errors.New("tls: invalid inner client hello") |
| 313 | } |
| 314 | } |
| 315 | |
| 316 | rawOuterExts, err := extractRawExtensions(outer) |
| 317 | if err != nil { |
| 318 | return nil, err |
| 319 | } |
| 320 | |
| 321 | recon := cryptobyte.NewBuilder(nil) |
| 322 | recon.AddUint8(typeClientHello) |
| 323 | recon.AddUint24LengthPrefixed(func(recon *cryptobyte.Builder) { |
| 324 | recon.AddBytes(versionAndRandom) |
| 325 | recon.AddUint8LengthPrefixed(func(recon *cryptobyte.Builder) { |
| 326 | recon.AddBytes(outer.sessionId) |
| 327 | }) |
| 328 | recon.AddUint16LengthPrefixed(func(recon *cryptobyte.Builder) { |
| 329 | recon.AddBytes(cipherSuites) |
| 330 | }) |
| 331 | recon.AddUint8LengthPrefixed(func(recon *cryptobyte.Builder) { |
| 332 | recon.AddBytes(compressionMethods) |
| 333 | }) |
| 334 | recon.AddUint16LengthPrefixed(func(recon *cryptobyte.Builder) { |
| 335 | for !extensions.Empty() { |
| 336 | var extension uint16 |
| 337 | var extData cryptobyte.String |
| 338 | if !extensions.ReadUint16(&extension) || |
| 339 | !extensions.ReadUint16LengthPrefixed(&extData) { |
| 340 | recon.SetError(errors.New("tls: invalid inner client hello")) |
| 341 | return |
| 342 | } |
| 343 | if extension == extensionECHOuterExtensions { |
no test coverage detected
searching dependent graphs…